Browse Source

Implement basic QML gRPC API

- Add gRPC QML methods generation
- Remove invokable markers from part of client methods
- Implement qml grpc test

Fixes: #69
Alexey Edelev 4 years ago
parent
commit
a940c0e966

+ 6 - 0
src/generator/clientdeclarationprinter.cpp

@@ -48,7 +48,10 @@ ClientDeclarationPrinter::ClientDeclarationPrinter(const ::google::protobuf::Ser
 void ClientDeclarationPrinter::printClientClass()
 {
     mPrinter->Print({{"classname", mName}, {"parent_class", "QtProtobuf::QAbstractGrpcClient"}}, Templates::ClassDefinitionTemplate);
+    Indent();
     mPrinter->Print(Templates::QObjectMacro);
+    mPrinter->Print("\n");
+    Outdent();
 }
 
 void ClientDeclarationPrinter::printConstructor()
@@ -83,6 +86,9 @@ void ClientDeclarationPrinter::printClientMethodsDeclaration()
             mPrinter->Print(parameters, Templates::ClientMethodDeclarationSyncTemplate);
             mPrinter->Print(parameters, Templates::ClientMethodDeclarationAsyncTemplate);
             mPrinter->Print(parameters, Templates::ClientMethodDeclarationAsync2Template);
+            if (GeneratorOptions::instance().hasQml()) {
+                mPrinter->Print(parameters, Templates::ClientMethodDeclarationQmlTemplate);
+            }
         }
         mPrinter->Print("\n");
     }

+ 3 - 0
src/generator/clientdefinitionprinter.cpp

@@ -54,6 +54,9 @@ void ClientDefinitionPrinter::printMethods()
             mPrinter->Print(parameters, Templates::ClientMethodDefinitionSyncTemplate);
             mPrinter->Print(parameters, Templates::ClientMethodDefinitionAsyncTemplate);
             mPrinter->Print(parameters, Templates::ClientMethodDefinitionAsync2Template);
+            if (GeneratorOptions::instance().hasQml()) {
+                mPrinter->Print(parameters, Templates::ClientMethodDefinitionQmlTemplate);
+            }
         }
     }
 }

+ 2 - 0
src/generator/multifilegenerator.cpp

@@ -145,6 +145,8 @@ bool MultiFileGenerator::Generate(const FileDescriptor *file,
         sourcePrinter->Print({{"include", includeFileName}}, Templates::InternalIncludeTemplate);
         if (GeneratorOptions::instance().hasQml()) {
             sourcePrinter->Print({{"include", "QQmlEngine"}}, Templates::ExternalIncludeTemplate);
+            sourcePrinter->Print({{"include", "QJSEngine"}}, Templates::ExternalIncludeTemplate);
+            sourcePrinter->Print({{"include", "QJSValue"}}, Templates::ExternalIncludeTemplate);
         }
 
         printQtProtobufUsingNamespace(sourcePrinter);

+ 7 - 0
src/generator/singlefilegenerator.cpp

@@ -200,6 +200,13 @@ bool SingleFileGenerator::GenerateServices(const ::google::protobuf::FileDescrip
         headerPrinter->Print({{"include", include}}, Templates::InternalIncludeTemplate);
     }
 
+    if (GeneratorOptions::instance().hasQml()) {
+        sourcePrinter->Print({{"include", "QQmlEngine"}}, Templates::ExternalIncludeTemplate);
+        sourcePrinter->Print({{"include", "QJSEngine"}}, Templates::ExternalIncludeTemplate);
+        sourcePrinter->Print({{"include", "QJSValue"}}, Templates::ExternalIncludeTemplate);
+    }
+
+
     printQtProtobufUsingNamespace(sourcePrinter);
 
     for (int i = 0; i < file->service_count(); i++) {

+ 26 - 2
src/generator/templates.cpp

@@ -283,9 +283,11 @@ const char *Templates::QEnumTemplate = "Q_ENUM($type$)\n";
 const char *Templates::ClassDefinitionTemplate = "\nclass $classname$ : public $parent_class$\n"
                                                  "{\n";
 const char *Templates::QObjectMacro = "Q_OBJECT";
-const char *Templates::ClientMethodDeclarationSyncTemplate = "Q_INVOKABLE QtProtobuf::QGrpcStatus $method_name$(const $param_type$ &$param_name$, const QPointer<$return_type$> &$return_name$);\n";
-const char *Templates::ClientMethodDeclarationAsyncTemplate = "Q_INVOKABLE QtProtobuf::QGrpcAsyncReply *$method_name$(const $param_type$ &$param_name$);\n";
+const char *Templates::ClientMethodDeclarationSyncTemplate = "QtProtobuf::QGrpcStatus $method_name$(const $param_type$ &$param_name$, const QPointer<$return_type$> &$return_name$);\n";
+const char *Templates::ClientMethodDeclarationAsyncTemplate = "QtProtobuf::QGrpcAsyncReply *$method_name$(const $param_type$ &$param_name$);\n";
 const char *Templates::ClientMethodDeclarationAsync2Template = "Q_INVOKABLE void $method_name$(const $param_type$ &$param_name$, const QObject *context, const std::function<void(QtProtobuf::QGrpcAsyncReply *)> &callback);\n";
+const char *Templates::ClientMethodDeclarationQmlTemplate = "Q_INVOKABLE void $method_name$($param_type$ *$param_name$, const QJSValue &callback);";
+
 const char *Templates::ServerMethodDeclarationTemplate = "Q_INVOKABLE virtual $return_type$ $method_name$(const $param_type$ &$param_name$) = 0;\n";
 
 
@@ -308,6 +310,28 @@ const char *Templates::ClientMethodDefinitionAsync2Template = "\nvoid $classname
                                                               "    });\n"
                                                               "}\n";
 
+const char *Templates::ClientMethodDefinitionQmlTemplate = "\nvoid $classname$::$method_name$($param_type$ *$param_name$, const QJSValue &callback)\n"
+                                                           "{\n"
+                                                           "    if (!callback.isCallable()) {\n"
+                                                           "        qProtoWarning() << \"Unable to call $classname$::$method_name$, callback is not callable\";\n"
+                                                           "        return;\n"
+                                                           "    }\n\n"
+                                                           "    if (arg == nullptr) {\n"
+                                                           "        qProtoWarning() << \"Invalid argument provided for method $classname$::$method_name$, argument of type 'qtprotobufnamespace::tests::SimpleStringMessage *' expected\";\n"
+                                                           "        return;\n"
+                                                           "    }\n\n"
+                                                           "    QJSEngine *jsEngine = qjsEngine(this);\n"
+                                                           "    if (jsEngine == nullptr) {\n"
+                                                           "        qProtoWarning() << \"Unable to call $classname$::$method_name$, it's only callable from JS engine context\";\n"
+                                                           "        return;\n"
+                                                           "    }\n\n"
+                                                           "    QtProtobuf::QGrpcAsyncReply *reply = call(\"$method_name$\", *$param_name$);\n"
+                                                           "    QObject::connect(reply, &QtProtobuf::QGrpcAsyncReply::finished, jsEngine, [this, reply, callback, jsEngine]() {\n"
+                                                           "        auto result = new $param_type$(reply->read<$param_type$>());\n"
+                                                           "        qmlEngine(this)->setObjectOwnership(result,  QQmlEngine::JavaScriptOwnership);\n"
+                                                           "        QJSValue(callback).call(QJSValueList{jsEngine->toScriptValue(result)});\n"
+                                                           "    });\n"
+                                                           "}\n";
 const char *Templates::RegisterSerializersTemplate = "qRegisterProtobufType<$classname$>();\n";
 const char *Templates::RegisterEnumSerializersTemplate = "qRegisterProtobufEnumType<$full_type$>();\n";
 const char *Templates::RegistrarTemplate = "static QtProtobuf::ProtoTypeRegistrar<$classname$> ProtoTypeRegistrar$classname$(qRegisterProtobufType<$classname$>);\n";

+ 3 - 0
src/generator/templates.h

@@ -183,11 +183,14 @@ public:
     static const char *ClientMethodDeclarationSyncTemplate;
     static const char *ClientMethodDeclarationAsyncTemplate;
     static const char *ClientMethodDeclarationAsync2Template;
+    static const char *ClientMethodDeclarationQmlTemplate;
+
     static const char *ServerMethodDeclarationTemplate;
 
     static const char *ClientMethodDefinitionSyncTemplate;
     static const char *ClientMethodDefinitionAsyncTemplate;
     static const char *ClientMethodDefinitionAsync2Template;
+    static const char *ClientMethodDefinitionQmlTemplate;
 
     //Streaming
     static const char *ClientMethodSignalDeclarationTemplate;

+ 1 - 0
tests/CMakeLists.txt

@@ -1,5 +1,6 @@
 add_subdirectory("test_protobuf")
 add_subdirectory("test_grpc")
+add_subdirectory("test_grpc_qml")
 add_subdirectory("test_qml")
 add_subdirectory("test_protobuf_multifile")
 add_subdirectory("test_qprotobuf_serializer_plugin")

+ 1 - 1
tests/test_grpc/CMakeLists.txt

@@ -2,7 +2,7 @@ include(${QT_PROTOBUF_CMAKE_DIR}/QtProtobufTest.cmake)
 
 # clients
 add_test_target(TARGET qtgrpc_test
-    SOURCES clienttest.cpp)
+    SOURCES clienttest.cpp QML)
 add_target_windeployqt(TARGET qtgrpc_test
     QML_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 

+ 1 - 1
tests/test_grpc/sslclienttest.cpp

@@ -70,5 +70,5 @@ TEST_F(ClientTest, IncorrectSecureCredentialsTest)
     testClient.attachChannel(std::make_shared<QtProtobuf::QGrpcHttp2Channel>(QUrl("https://localhost:60051", QUrl::StrictMode), QtProtobuf::QGrpcInsecureCallCredentials()|QtProtobuf::QGrpcSslCredentials(conf)));
 
     std::unique_ptr<SimpleStringMessage> result = std::make_unique<SimpleStringMessage>();
-    EXPECT_FALSE(testClient.testMethod(SimpleStringMessage{"Hello beach!"}, result.get()) == QGrpcStatus::Ok);
+    EXPECT_FALSE(testClient.testMethod(SimpleStringMessage{"Hello beach!"}, QPointer<SimpleStringMessage>(result.get())) == QGrpcStatus::Ok);
 }

+ 39 - 0
tests/test_grpc_qml/CMakeLists.txt

@@ -0,0 +1,39 @@
+set(TARGET qtgrpc_qml_test)
+
+find_package(Qt5 COMPONENTS Core Quick Network Test QuickTest REQUIRED)
+find_package(QtProtobufProject COMPONENTS QtGrpc REQUIRED)
+
+include(${QT_PROTOBUF_CMAKE_DIR}/QtProtobufTest.cmake)
+
+set(CMAKE_AUTOMOC OFF)
+
+file(GLOB SOURCES main.cpp)
+file(GLOB QML_FILES qml/tst_grpc.qml)
+
+qt5_wrap_cpp(MOC_SOURCES test.h)
+
+add_executable(${TARGET} ${MOC_SOURCES} ${SOURCES} ${QML_FILES})
+target_link_libraries(${TARGET} PRIVATE Qt5::Qml Qt5::Quick Qt5::Test Qt5::QuickTest QtProtobufProject::QtGrpc)
+
+if(QT_PROTOBUF_STATIC)
+    target_link_libraries(${TARGET} PRIVATE protobufquickplugin)
+endif()
+
+qtprotobuf_link_target(${TARGET} qtgrpc_test_qtprotobuf_gen)
+
+if(UNIX)
+    set(TEST_DRIVER_NAME "test_driver.sh")
+elseif(WIN32)
+    set(TEST_DRIVER_NAME "test_driver.bat")
+endif()
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../test_grpc/${TEST_DRIVER_NAME}.in ${TEST_DRIVER_NAME} @ONLY)
+add_test(NAME ${TARGET}
+         COMMAND ${TEST_DRIVER_NAME} $<TARGET_FILE:${TARGET}> $<TARGET_FILE:echoserver> $<TARGET_FILE_NAME:${TARGET}> $<TARGET_FILE_NAME:echoserver>
+)
+
+add_target_qml(TARGET ${TARGET} QML_FILES ${QML_FILES})
+add_target_windeployqt(TARGET ${TARGET} QML_DIR ${CMAKE_CURRENT_SOURCE_DIR}/qml)
+
+set_tests_properties(${TARGET} PROPERTIES
+    ENVIRONMENT QML2_IMPORT_PATH=$<TARGET_FILE_DIR:protobufquickplugin>/..)

+ 30 - 0
tests/test_grpc_qml/main.cpp

@@ -0,0 +1,30 @@
+/*
+ * 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 "test.h"
+
+QUrl TestSetup::m_echoServerAddress("http://localhost:50051", QUrl::StrictMode);
+
+QUICK_TEST_MAIN_WITH_SETUP(qtgrpc_qml_test, TestSetup)

+ 47 - 0
tests/test_grpc_qml/qml/tst_grpc.qml

@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+import QtQuick 2.12
+import QtTest 1.0
+
+import QtProtobuf 0.3
+import qtprotobufnamespace.tests 1.0
+
+TestCase {
+    name: "gRPC client qml test"
+    SimpleStringMessage {
+        id: stringMsg
+        testFieldString: "Test string"
+    }
+
+    function test_stringEchoTest() {
+        var called = false;
+        TestServiceClient.testMethod(stringMsg, function(result) {
+            called = result.testFieldString === stringMsg.testFieldString;
+        })
+        wait(500)
+        compare(called, true, "testMethod was not called proper way")
+    }
+}

+ 60 - 0
tests/test_grpc_qml/test.h

@@ -0,0 +1,60 @@
+/*
+ * 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 <QtQuickTest>
+#include <QUrl>
+#include <QQmlEngine>
+#include <QQmlContext>
+#include <QQmlExtensionPlugin>
+#include <QGrpcHttp2Channel>
+#include <QGrpcInsecureCredentials>
+#include <QMetaObject>
+
+#include "testservice_grpc.qpb.h"
+
+using namespace qtprotobufnamespace::tests;
+using namespace QtProtobuf;
+
+class TestSetup : public QObject {
+    Q_OBJECT
+public:
+    static QUrl m_echoServerAddress;
+    TestSetup() {
+        QtProtobuf::qRegisterProtobufTypes();
+        Q_PROTOBUF_IMPORT_QUICK_PLUGIN()
+        qmlRegisterSingletonType<TestServiceClient>("qtprotobufnamespace.tests", 1, 0, "TestServiceClient", [](QQmlEngine *engine, QJSEngine *) -> QObject *{
+            static TestServiceClient clientInstance;
+            clientInstance.attachChannel(std::make_shared<QGrpcHttp2Channel>(m_echoServerAddress, QGrpcInsecureChannelCredentials() | QGrpcInsecureCallCredentials()));
+            engine->setObjectOwnership(&clientInstance, QQmlEngine::CppOwnership);
+            return &clientInstance;
+        });
+    }
+    ~TestSetup() = default;
+public slots:
+    void qmlEngineAvailable(QQmlEngine *engine)
+    {
+        engine->rootContext()->setContextProperty("qVersion", QT_VERSION);
+    }
+};

+ 5 - 1
tests/test_qml/CMakeLists.txt

@@ -5,10 +5,14 @@ find_package(QtProtobufProject COMPONENTS QtProtobuf REQUIRED)
 
 include(${QT_PROTOBUF_CMAKE_DIR}/QtProtobufTest.cmake)
 
+set(CMAKE_AUTOMOC OFF)
+
 file(GLOB SOURCES main.cpp)
 file(GLOB QML_FILES qml/tst_simple.qml)
 
-add_executable(${TARGET} ${SOURCES} ${QML_FILES})
+qt5_wrap_cpp(MOC_SOURCES test.h)
+
+add_executable(${TARGET} ${MOC_SOURCES} ${SOURCES} ${QML_FILES})
 target_link_libraries(${TARGET} PRIVATE Qt5::Core Qt5::Qml Qt5::Network Qt5::Quick Qt5::Test Qt5::QuickTest QtProtobufProject::QtProtobuf)
 
 if(TARGET QtProtobufProject::QtProtobufWellKnownTypes)

+ 2 - 26
tests/test_qml/main.cpp

@@ -1,7 +1,7 @@
 /*
  * MIT License
  *
- * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
+ * Copyright (c) 2020 Alexey Edelev <semlanik@gmail.com>
  *
  * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
  *
@@ -23,30 +23,6 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include <QtQuickTest>
-#include <QQmlEngine>
-#include <QQmlContext>
-#include <QQmlExtensionPlugin>
-
-#include "simpletest.qpb.h"
-
-using namespace qtprotobufnamespace::tests;
-
-class TestSetup : public QObject {
-    Q_OBJECT
-public:
-    TestSetup() {
-        QtProtobuf::qRegisterProtobufTypes();
-        Q_PROTOBUF_IMPORT_QUICK_PLUGIN()
-    }
-    ~TestSetup() = default;
-public slots:
-    void qmlEngineAvailable(QQmlEngine *engine)
-    {
-        engine->rootContext()->setContextProperty("qVersion", QT_VERSION);
-    }
-};
+#include "test.h"
 
 QUICK_TEST_MAIN_WITH_SETUP(qtprotobuf_qml_test, TestSetup)
-
-#include "main.moc"

+ 0 - 119
tests/test_qml/main.moc

@@ -1,119 +0,0 @@
-/****************************************************************************
-** Meta object code from reading C++ file 'main.cpp'
-**
-** Created by: The Qt Meta Object Compiler version 67 (Qt 5.12.5)
-**
-** WARNING! All changes made in this file will be lost!
-*****************************************************************************/
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qmetatype.h>
-#if !defined(Q_MOC_OUTPUT_REVISION)
-#error "The header file 'main.cpp' doesn't include <QObject>."
-#elif Q_MOC_OUTPUT_REVISION != 67
-#error "This file was generated using the moc from 5.12.5. It"
-#error "cannot be used with the include files from this version of Qt."
-#error "(The moc has changed too much.)"
-#endif
-
-QT_BEGIN_MOC_NAMESPACE
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
-struct qt_meta_stringdata_TestSetup_t {
-    QByteArrayData data[5];
-    char stringdata0[49];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
-    Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
-    qptrdiff(offsetof(qt_meta_stringdata_TestSetup_t, stringdata0) + ofs \
-        - idx * sizeof(QByteArrayData)) \
-    )
-static const qt_meta_stringdata_TestSetup_t qt_meta_stringdata_TestSetup = {
-    {
-QT_MOC_LITERAL(0, 0, 9), // "TestSetup"
-QT_MOC_LITERAL(1, 10, 18), // "qmlEngineAvailable"
-QT_MOC_LITERAL(2, 29, 0), // ""
-QT_MOC_LITERAL(3, 30, 11), // "QQmlEngine*"
-QT_MOC_LITERAL(4, 42, 6) // "engine"
-
-    },
-    "TestSetup\0qmlEngineAvailable\0\0QQmlEngine*\0"
-    "engine"
-};
-#undef QT_MOC_LITERAL
-
-static const uint qt_meta_data_TestSetup[] = {
-
- // content:
-       8,       // revision
-       0,       // classname
-       0,    0, // classinfo
-       1,   14, // methods
-       0,    0, // properties
-       0,    0, // enums/sets
-       0,    0, // constructors
-       0,       // flags
-       0,       // signalCount
-
- // slots: name, argc, parameters, tag, flags
-       1,    1,   19,    2, 0x0a /* Public */,
-
- // slots: parameters
-    QMetaType::Void, 0x80000000 | 3,    4,
-
-       0        // eod
-};
-
-void TestSetup::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
-{
-    if (_c == QMetaObject::InvokeMetaMethod) {
-        auto *_t = static_cast<TestSetup *>(_o);
-        Q_UNUSED(_t)
-        switch (_id) {
-        case 0: _t->qmlEngineAvailable((*reinterpret_cast< QQmlEngine*(*)>(_a[1]))); break;
-        default: ;
-        }
-    }
-}
-
-QT_INIT_METAOBJECT const QMetaObject TestSetup::staticMetaObject = { {
-    &QObject::staticMetaObject,
-    qt_meta_stringdata_TestSetup.data,
-    qt_meta_data_TestSetup,
-    qt_static_metacall,
-    nullptr,
-    nullptr
-} };
-
-
-const QMetaObject *TestSetup::metaObject() const
-{
-    return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
-}
-
-void *TestSetup::qt_metacast(const char *_clname)
-{
-    if (!_clname) return nullptr;
-    if (!strcmp(_clname, qt_meta_stringdata_TestSetup.stringdata0))
-        return static_cast<void*>(this);
-    return QObject::qt_metacast(_clname);
-}
-
-int TestSetup::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
-{
-    _id = QObject::qt_metacall(_c, _id, _a);
-    if (_id < 0)
-        return _id;
-    if (_c == QMetaObject::InvokeMetaMethod) {
-        if (_id < 1)
-            qt_static_metacall(this, _c, _id, _a);
-        _id -= 1;
-    } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
-        if (_id < 1)
-            *reinterpret_cast<int*>(_a[0]) = -1;
-        _id -= 1;
-    }
-    return _id;
-}
-QT_WARNING_POP
-QT_END_MOC_NAMESPACE

+ 48 - 0
tests/test_qml/test.h

@@ -0,0 +1,48 @@
+/*
+ * 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 <QtQuickTest>
+#include <QQmlEngine>
+#include <QQmlContext>
+#include <QQmlExtensionPlugin>
+
+#include "simpletest.qpb.h"
+
+using namespace qtprotobufnamespace::tests;
+
+class TestSetup : public QObject {
+    Q_OBJECT
+public:
+    TestSetup() {
+        QtProtobuf::qRegisterProtobufTypes();
+        Q_PROTOBUF_IMPORT_QUICK_PLUGIN()
+    }
+    ~TestSetup() = default;
+public slots:
+    void qmlEngineAvailable(QQmlEngine *engine)
+    {
+        engine->rootContext()->setContextProperty("qVersion", QT_VERSION);
+    }
+};