Browse Source

Complete implementation of Qt types support

- Implement QtGui part
- Add tests

TODO: Documentation left

Fixes: #78
Alexey Edelev 4 years ago
parent
commit
d91f94c4ca

+ 52 - 29
src/qttypes/QtProtobuf/QtGui.proto

@@ -8,39 +8,62 @@ message QColor {
     sint32 blue = 3;
     sint32 alpha = 4;
 }
- 
-// message QImage {
-// }
 
-// message QPixmap {
-// }
-
-// message QIcon {
-// }
-
-// message QBitmap {
-// }
-
-// message QQuaternion {
-// }
-
-// message QTransform {
-// }
+message QMatrix4x4 {
+    float m11 = 1;
+    float m12 = 2;
+    float m13 = 3;
+    float m14 = 4;
+    float m21 = 5;
+    float m22 = 6;
+    float m23 = 7;
+    float m24 = 8;
+    float m31 = 9;
+    float m32 = 10;
+    float m33 = 11;
+    float m34 = 12;
+    float m41 = 13;
+    float m42 = 14;
+    float m43 = 15;
+    float m44 = 16;
+}
 
-// message QMatrix {
-// }
+message QVector2D {
+    float xpos = 1;
+    float ypos = 2;
+}
 
-// message QMatrix4x4 {
-// }
+message QVector3D {
+    float xpos = 1;
+    float ypos = 2;
+    float zpos = 3;
+}
 
-// message QVector2D {
-// }
+message QVector4D {
+    float xpos = 1;
+    float ypos = 2;
+    float zpos = 3;
+    float wpos = 4;
+}
 
-// message QVector3D {
-// }
+message QTransform {
+    double m11 = 1;
+    double m12 = 2;
+    double m13 = 3;
+    double m21 = 4;
+    double m22 = 5;
+    double m23 = 6;
+    double m31 = 7;
+    double m32 = 8;
+    double m33 = 9;
+}
 
-// message QVector4D {
-// }
+message QQuaternion {
+    float scalar = 1;
+    QtProtobuf.QVector3D vector = 2;
+}
 
-// message QEasingCurve {
-// }
+message QImage {
+    bytes data = 1;
+    string format = 2; //see https://doc.qt.io/qt-5/qimagewriter.html#supportedImageFormats
+}

+ 88 - 0
src/qttypes/qtprotobufqttypes.cpp

@@ -40,6 +40,14 @@
 #include <QRectF>
 #include <QPolygon>
 #include <QPolygonF>
+#include <QMatrix4x4>
+#include <QVector2D>
+#include <QVector3D>
+#include <QVector4D>
+#include <QTransform>
+#include <QQuaternion>
+#include <QImage>
+#include <QBuffer>
 
 #include <qtprotobuftypes.h>
 #include <qtprotobufqttypes.h>
@@ -194,6 +202,79 @@ namespace QtProtobuf {
     return polygon;
 }
 
+
+::QMatrix4x4 convert(const ::QtProtobuf::QMatrix4x4 &from) {
+    return ::QMatrix4x4(from.m11(), from.m12(), from.m13(), from.m14(),
+                        from.m21(), from.m22(), from.m23(), from.m24(),
+                        from.m31(), from.m32(), from.m33(), from.m34(),
+                        from.m41(), from.m42(), from.m43(), from.m44());
+}
+
+::QtProtobuf::QMatrix4x4 convert(const ::QMatrix4x4 &from) {
+    //QMatrix4x4::data returned in column-major format
+    return ::QtProtobuf::QMatrix4x4(from.data()[0], from.data()[4], from.data()[8],  from.data()[12],
+                                    from.data()[1], from.data()[5], from.data()[9],  from.data()[13],
+                                    from.data()[2], from.data()[6], from.data()[10], from.data()[14],
+                                    from.data()[3], from.data()[7], from.data()[11], from.data()[15]);
+}
+
+::QVector2D convert(const ::QtProtobuf::QVector2D &from) {
+    return ::QVector2D(from.xpos(), from.ypos());
+}
+
+::QtProtobuf::QVector2D convert(const ::QVector2D &from) {
+    return ::QtProtobuf::QVector2D(from.x(), from.y());
+}
+
+::QVector3D convert(const ::QtProtobuf::QVector3D &from) {
+    return ::QVector3D(from.xpos(), from.ypos(), from.zpos());
+}
+
+::QtProtobuf::QVector3D convert(const ::QVector3D &from) {
+    return ::QtProtobuf::QVector3D(from.x(), from.y(), from.z());
+}
+
+::QVector4D convert(const ::QtProtobuf::QVector4D &from) {
+    return ::QVector4D(from.xpos(), from.ypos(), from.zpos(), from.wpos());
+}
+
+::QtProtobuf::QVector4D convert(const ::QVector4D &from) {
+    return ::QtProtobuf::QVector4D(from.x(), from.y(), from.z(), from.w());
+}
+
+::QTransform convert(const ::QtProtobuf::QTransform &from) {
+    return ::QTransform(from.m11(), from.m12(), from.m13(),
+                        from.m21(), from.m22(), from.m23(),
+                        from.m31(), from.m32(), from.m33());
+}
+
+::QtProtobuf::QTransform convert(const ::QTransform &from) {
+    return ::QtProtobuf::QTransform(from.m11(), from.m12(), from.m13(),
+                                    from.m21(), from.m22(), from.m23(),
+                                    from.m31(), from.m32(), from.m33());
+}
+
+::QQuaternion convert(const ::QtProtobuf::QQuaternion &from) {
+    return ::QQuaternion(from.scalar(), convert(from.vector()));
+}
+
+::QtProtobuf::QQuaternion convert(const ::QQuaternion &from) {
+    return ::QtProtobuf::QQuaternion(from.scalar(), convert(from.vector()));
+}
+
+::QImage convert(const ::QtProtobuf::QImage &from) {
+    return ::QImage::fromData(from.data(), from.format().toLatin1().data());
+}
+
+::QtProtobuf::QImage convert(const ::QImage &from) {
+    QByteArray data;
+    QBuffer buffer(&data);
+    buffer.open(QIODevice::WriteOnly);
+    from.save(&buffer, "PNG");
+    qProtoWarning() << "QImage always is sent in PNG format";
+    return ::QtProtobuf::QImage(data, "PNG");
+}
+
 template <typename QType, typename PType>
 void registerQtTypeHandler() {
     QtProtobufPrivate::registerHandler(qMetaTypeId<QType>(), {
@@ -226,6 +307,13 @@ void qRegisterProtobufQtTypes() {
     registerQtTypeHandler<::QPolygonF, ::QtProtobuf::QPolygonF>();
 
     registerQtTypeHandler<::QColor, ::QtProtobuf::QColor>();
+    registerQtTypeHandler<::QMatrix4x4, ::QtProtobuf::QMatrix4x4>();
+    registerQtTypeHandler<::QVector2D, ::QtProtobuf::QVector2D>();
+    registerQtTypeHandler<::QVector3D, ::QtProtobuf::QVector3D>();
+    registerQtTypeHandler<::QVector4D, ::QtProtobuf::QVector4D>();
+    registerQtTypeHandler<::QTransform, ::QtProtobuf::QTransform>();
+    registerQtTypeHandler<::QQuaternion, ::QtProtobuf::QQuaternion>();
+    registerQtTypeHandler<::QImage, ::QtProtobuf::QImage>();
 }
 
 }

+ 4 - 1
tests/test_qttypes/CMakeLists.txt

@@ -4,7 +4,8 @@ include(${QT_PROTOBUF_CMAKE_DIR}/QtProtobufTest.cmake)
 find_package(QtProtobufProject CONFIG COMPONENTS QtProtobuf QtGrpc QtProtobufQtTypes REQUIRED)
 
 file(GLOB SOURCES
-    simpletest.cpp)
+    qtcoretest.cpp
+    qtguitest.cpp)
 
 add_test_target(TARGET ${TARGET}
     SOURCES ${SOURCES}
@@ -13,5 +14,7 @@ add_test_target(TARGET ${TARGET}
 add_target_windeployqt(TARGET ${TARGET}
     QML_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testimage.png ${CMAKE_CURRENT_BINARY_DIR}/testimage.png COPYONLY)
+
 target_link_libraries(${TARGET} PRIVATE ${QT_PROTOBUF_PROJECT}::QtProtobufQtTypes)
 add_test(NAME ${TARGET} COMMAND ${TARGET})

+ 35 - 0
tests/test_qttypes/proto/qttypes.proto

@@ -2,6 +2,7 @@ syntax = "proto3";
 
 package qtprotobufnamespace.qttypes.tests;
 import "QtProtobuf/QtCore.proto";
+import "QtProtobuf/QtGui.proto";
 
 message QUrlMessage {
     QtProtobuf.QUrl testField = 1;
@@ -58,3 +59,37 @@ message QPolygonMessage {
 message QPolygonFMessage {
     QtProtobuf.QPolygonF testField = 1;
 }
+
+//Gui
+
+message QColorMessage {
+    QtProtobuf.QColor testField = 1;
+}
+
+message QMatrix4x4Message {
+    QtProtobuf.QMatrix4x4 testField = 1;
+}
+
+message QVector2DMessage {
+    QtProtobuf.QVector2D testField = 1;
+}
+
+message QVector3DMessage {
+    QtProtobuf.QVector3D testField = 1;
+}
+
+message QVector4DMessage {
+    QtProtobuf.QVector4D testField = 1;
+}
+
+message QTransformMessage {
+    QtProtobuf.QTransform testField = 1;
+}
+
+message QQuaternionMessage {
+    QtProtobuf.QQuaternion testField = 1;
+}
+
+message QImageMessage {
+    QtProtobuf.QImage testField = 1;
+}

+ 17 - 17
tests/test_qttypes/simpletest.cpp → tests/test_qttypes/qtcoretest.cpp

@@ -41,11 +41,11 @@
 namespace QtProtobuf {
 namespace tests {
 
-class QtTypesTest : public ::testing::Test
+class QtTypesQtCoreTest : public ::testing::Test
 {
 public:
     // see simpletest.proto for property names and their field indices
-    QtTypesTest() {
+    QtTypesQtCoreTest() {
     }
 
     static void SetUpTestCase() {
@@ -57,9 +57,9 @@ public:
     static std::unique_ptr<QProtobufSerializer> serializer;
 };
 
-std::unique_ptr<QProtobufSerializer> QtTypesTest::serializer;
+std::unique_ptr<QProtobufSerializer> QtTypesQtCoreTest::serializer;
 
-TEST_F(QtTypesTest, QUrlTest)
+TEST_F(QtTypesQtCoreTest, QUrlTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QUrlMessage, QUrl>(1, "QUrl", "testField");
 
@@ -74,7 +74,7 @@ TEST_F(QtTypesTest, QUrlTest)
     EXPECT_STREQ("https://github.com/semlanik", msg.testField().url().toStdString().c_str());
 }
 
-TEST_F(QtTypesTest, QCharTest)
+TEST_F(QtTypesQtCoreTest, QCharTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QCharMessage, QChar>(1, "QChar", "testField");
 
@@ -90,7 +90,7 @@ TEST_F(QtTypesTest, QCharTest)
 }
 
 
-TEST_F(QtTypesTest, QUuidTest)
+TEST_F(QtTypesQtCoreTest, QUuidTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QUuidMessage, QUuid>(1, "QUuid", "testField");
 
@@ -106,7 +106,7 @@ TEST_F(QtTypesTest, QUuidTest)
     EXPECT_TRUE(QUuid("{4bcbcdc3-c5b3-4d34-97fe-af78c825cc7d}") == msg.testField());
 }
 
-TEST_F(QtTypesTest, QTimeTest)
+TEST_F(QtTypesQtCoreTest, QTimeTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QTimeMessage, QTime>(1, "QTime", "testField");
 
@@ -124,7 +124,7 @@ TEST_F(QtTypesTest, QTimeTest)
     EXPECT_EQ(msg.testField().msec(), 321);
 }
 
-TEST_F(QtTypesTest, QDateTest)
+TEST_F(QtTypesQtCoreTest, QDateTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QDateMessage, QDate>(1, "QDate", "testField");
     qtprotobufnamespace::qttypes::tests::QDateMessage msg;
@@ -140,7 +140,7 @@ TEST_F(QtTypesTest, QDateTest)
     EXPECT_EQ(msg.testField().day(), 14);
 }
 
-TEST_F(QtTypesTest, QDateTimeTest)
+TEST_F(QtTypesQtCoreTest, QDateTimeTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QDateTimeMessage, QDateTime>(1, "QDateTime", "testField");
     qtprotobufnamespace::qttypes::tests::QDateTimeMessage msg;
@@ -158,7 +158,7 @@ TEST_F(QtTypesTest, QDateTimeTest)
     EXPECT_TRUE(msg.testField() == QDateTime(QDate(1856, 6, 10), QTime(5, 30, 48, 123)));
 }
 
-TEST_F(QtTypesTest, QSizeTest)
+TEST_F(QtTypesQtCoreTest, QSizeTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QSizeMessage, QSize>(1, "QSize", "testField");
     qtprotobufnamespace::qttypes::tests::QSizeMessage msg;
@@ -179,7 +179,7 @@ TEST_F(QtTypesTest, QSizeTest)
     EXPECT_EQ(msg.testField().height(), 1024);
 }
 
-TEST_F(QtTypesTest, QSizeFTest)
+TEST_F(QtTypesQtCoreTest, QSizeFTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QSizeFMessage, QSizeF>(1, "QSizeF", "testField");
     qtprotobufnamespace::qttypes::tests::QSizeFMessage msg;
@@ -200,7 +200,7 @@ TEST_F(QtTypesTest, QSizeFTest)
     EXPECT_EQ(msg.testField().height(), 1024.0);
 }
 
-TEST_F(QtTypesTest, QPointTest)
+TEST_F(QtTypesQtCoreTest, QPointTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QPointMessage, QPoint>(1, "QPoint", "testField");
     qtprotobufnamespace::qttypes::tests::QPointMessage msg;
@@ -221,7 +221,7 @@ TEST_F(QtTypesTest, QPointTest)
     EXPECT_EQ(msg.testField().y(), 1024);
 }
 
-TEST_F(QtTypesTest, QPointFTest)
+TEST_F(QtTypesQtCoreTest, QPointFTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QPointFMessage, QPointF>(1, "QPointF", "testField");
     qtprotobufnamespace::qttypes::tests::QPointFMessage msg;
@@ -242,7 +242,7 @@ TEST_F(QtTypesTest, QPointFTest)
     EXPECT_EQ(msg.testField().y(), 1024.0);
 }
 
-TEST_F(QtTypesTest, QRectTest)
+TEST_F(QtTypesQtCoreTest, QRectTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QRectMessage, QRect>(1, "QRect", "testField");
     qtprotobufnamespace::qttypes::tests::QRectMessage msg;
@@ -268,7 +268,7 @@ TEST_F(QtTypesTest, QRectTest)
     EXPECT_EQ(msg.testField().height(), 769); //WTF Qt, siriously why?
 }
 
-TEST_F(QtTypesTest, QRectFTest)
+TEST_F(QtTypesQtCoreTest, QRectFTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QRectFMessage, QRectF>(1, "QRectF", "testField");
     qtprotobufnamespace::qttypes::tests::QRectFMessage msg;
@@ -294,7 +294,7 @@ TEST_F(QtTypesTest, QRectFTest)
     EXPECT_EQ(msg.testField().height(), 768.0);
 }
 
-TEST_F(QtTypesTest, QPolygonTest)
+TEST_F(QtTypesQtCoreTest, QPolygonTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QPolygonMessage, QPolygon>(1, "QPolygon", "testField");
     qtprotobufnamespace::qttypes::tests::QPolygonMessage msg;
@@ -312,7 +312,7 @@ TEST_F(QtTypesTest, QPolygonTest)
     EXPECT_EQ(msg.testField()[2], QPoint(0, 20));
 }
 
-TEST_F(QtTypesTest, QPolygonFTest)
+TEST_F(QtTypesQtCoreTest, QPolygonFTest)
 {
     assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QPolygonFMessage, QPolygonF>(1, "QPolygonF", "testField");
     qtprotobufnamespace::qttypes::tests::QPolygonFMessage msg;

+ 188 - 0
tests/test_qttypes/qtguitest.cpp

@@ -0,0 +1,188 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2020 Alexey Edelev <semlanik@gmail.com>
+ *
+ * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies
+ * or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <QVariantList>
+#include <QMetaProperty>
+#include <QSignalSpy>
+#include <QProtobufSerializer>
+#include <QProtobufJsonSerializer>
+#include <QDateTime>
+
+#include <stdio.h>
+#include <iostream>
+#include <gtest/gtest.h>
+
+#include "../testscommon.h"
+
+#include "qttypes.qpb.h"
+
+namespace QtProtobuf {
+namespace tests {
+
+class QtTypesQtGuiTest : public ::testing::Test
+{
+public:
+    // see simpletest.proto for property names and their field indices
+    QtTypesQtGuiTest() {
+    }
+
+    static void SetUpTestCase() {
+        QtProtobuf::qRegisterProtobufTypes();
+        QtProtobuf::qRegisterProtobufQtTypes();
+        serializer.reset(new QProtobufSerializer);
+    }
+
+    static std::unique_ptr<QProtobufSerializer> serializer;
+};
+
+std::unique_ptr<QProtobufSerializer> QtTypesQtGuiTest::serializer;
+
+TEST_F(QtTypesQtGuiTest, QColorTest)
+{
+    assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QColorMessage, QColor>(1, "QColor", "testField");
+
+    qtprotobufnamespace::qttypes::tests::QColorMessage msg;
+    msg.setTestField(QColor("red"));
+    auto result = msg.serialize(serializer.get());
+    EXPECT_TRUE(QByteArray::fromHex("0a0620fe0308fe03") ==
+               result || QByteArray::fromHex("0a0608fe0320fe03") == result);
+
+    msg.setTestField({});
+    msg.deserialize(serializer.get(), QByteArray::fromHex("0a0608fe0320fe03"));
+
+    EXPECT_EQ(QColor("red"), msg.testField());
+}
+
+TEST_F(QtTypesQtGuiTest, QMatrix4x4Test)
+{
+    assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QMatrix4x4Message, QMatrix4x4>(1, "QMatrix4x4", "testField");
+
+    qtprotobufnamespace::qttypes::tests::QMatrix4x4Message msg;
+    msg.setTestField({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15});
+    auto result = msg.serialize(serializer.get());
+    EXPECT_TRUE(QByteArray::fromHex("0a518501000070417d0000604175000050416d0000404165000030415d0000204155000010414d00000041450000e0403d0000c040350000a0402d0000804025000040401d00000040150000803f0d00000000") ==
+               result || QByteArray::fromHex("0a4c150000803f1d0000004025000040402d00008040350000a0403d0000c040450000e0404d0000004155000010415d0000204165000030416d0000404175000050417d00006041850100007041") == result);
+
+    msg.setTestField({});
+    msg.deserialize(serializer.get(), QByteArray::fromHex("0a4c150000803f1d0000004025000040402d00008040350000a0403d0000c040450000e0404d0000004155000010415d0000204165000030416d0000404175000050417d00006041850100007041"));
+
+    EXPECT_EQ(QMatrix4x4(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), msg.testField());
+}
+
+TEST_F(QtTypesQtGuiTest, QVector2DTest)
+{
+    assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QVector2DMessage, QVector2D>(1, "QVector2D", "testField");
+
+    qtprotobufnamespace::qttypes::tests::QVector2DMessage msg;
+    msg.setTestField(QVector2D(42, 24));
+    auto result = msg.serialize(serializer.get());
+    EXPECT_TRUE(QByteArray::fromHex("0a0a150000c0410d00002842") ==
+               result);
+
+    msg.setTestField({});
+    msg.deserialize(serializer.get(), QByteArray::fromHex("0a0a0d0000c0411500002842"));
+
+    EXPECT_EQ(QVector2D(24, 42), msg.testField());
+}
+
+TEST_F(QtTypesQtGuiTest, QVector3DTest)
+{
+    assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QVector3DMessage, QVector3D>(1, "QVector3D", "testField");
+
+    qtprotobufnamespace::qttypes::tests::QVector3DMessage msg;
+    msg.setTestField(QVector3D(42, 24, 11));
+    auto result = msg.serialize(serializer.get());
+    EXPECT_TRUE(QByteArray::fromHex("0a0f1d00003041150000c0410d00002842") ==
+               result);
+
+    msg.setTestField({});
+    msg.deserialize(serializer.get(), QByteArray::fromHex("0a0f0d0000c04115000030411d00002842"));
+
+    EXPECT_EQ(QVector3D(24, 11, 42), msg.testField());
+}
+
+TEST_F(QtTypesQtGuiTest, QVector4DTest)
+{
+    assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QVector4DMessage, QVector4D>(1, "QVector4D", "testField");
+
+    qtprotobufnamespace::qttypes::tests::QVector4DMessage msg;
+    msg.setTestField({24, 11, 42, 0});
+    auto result = msg.serialize(serializer.get());
+    EXPECT_TRUE(QByteArray::fromHex("0a1425000000001d0000284215000030410d0000c041") ==
+               result || QByteArray::fromHex("0a0f0d0000c04115000030411d00002842") == result);
+
+    msg.setTestField({});
+    msg.deserialize(serializer.get(), QByteArray::fromHex("0a0f0d0000c04115000030411d00002842"));
+
+    EXPECT_EQ(QVector4D(24, 11, 42, 0), msg.testField());
+}
+
+TEST_F(QtTypesQtGuiTest, QTransformTest)
+{
+    assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QTransformMessage, QTransform>(1, "QTransform", "testField");
+
+    qtprotobufnamespace::qttypes::tests::QTransformMessage msg;
+    msg.setTestField(QTransform(0, 1, 2, 3, 4, 5, 6, 7, 8));
+    auto result = msg.serialize(serializer.get());
+    EXPECT_TRUE(QByteArray::fromHex("0a51490000000000002040410000000000001c4039000000000000184031000000000000144029000000000000104021000000000000084019000000000000004011000000000000f03f090000000000000000") ==
+               result || QByteArray::fromHex("0a4811000000000000f03f190000000000000040210000000000000840290000000000001040310000000000001440390000000000001840410000000000001c40490000000000002040") == result);
+
+    msg.setTestField({});
+    msg.deserialize(serializer.get(), QByteArray::fromHex("0a48090000000000002040110000000000001c4019000000000000184021000000000000144029000000000000104031000000000000084039000000000000004041000000000000f03f"));
+    EXPECT_EQ(QTransform(8, 7, 6, 5, 4, 3, 2, 1, 0), msg.testField());
+}
+
+TEST_F(QtTypesQtGuiTest, QQuaternionTest)
+{
+    assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QQuaternionMessage, QQuaternion>(1, "QQuaternion", "testField");
+
+    qtprotobufnamespace::qttypes::tests::QQuaternionMessage msg;
+    msg.setTestField(QQuaternion(14, 10, 24, 22));
+    auto result = msg.serialize(serializer.get());
+    EXPECT_TRUE(QByteArray::fromHex("0a16120f1d0000b041150000c0410d000020410d00006041") ==
+               result || QByteArray::fromHex("0a160d00006041120f0d00002041150000c0411d0000b041") == result);
+
+    msg.setTestField({});
+    msg.deserialize(serializer.get(), QByteArray::fromHex("0a160d00006041120f0d00002041150000c0411d0000b041"));
+
+    EXPECT_EQ(QQuaternion(14, 10, 24, 22), msg.testField());
+}
+
+TEST_F(QtTypesQtGuiTest, QImageTest)
+{
+    assertMessagePropertyRegistered<qtprotobufnamespace::qttypes::tests::QImageMessage, QImage>(1, "QImage", "testField");
+
+    qtprotobufnamespace::qttypes::tests::QImageMessage msg;
+    QImage initialImage("./testimage.png");
+    msg.setTestField(QImage("./testimage.png"));
+    ASSERT_FALSE(msg.testField().isNull());
+
+    auto result = msg.serialize(serializer.get());
+    msg.setTestField({});
+    msg.deserialize(serializer.get(), result);
+    EXPECT_EQ(initialImage, msg.testField());
+}
+}
+}

BIN
tests/test_qttypes/testimage.png