diff --git a/rust_qt_binding_generator/rust_qt_binding_generator.cpp b/rust_qt_binding_generator/rust_qt_binding_generator.cpp index 95cf0fe..b2b6c63 100644 --- a/rust_qt_binding_generator/rust_qt_binding_generator.cpp +++ b/rust_qt_binding_generator/rust_qt_binding_generator.cpp @@ -364,11 +364,9 @@ public: } ~DifferentFileWriter() { const QByteArray old = read(); - // write if file does not exists - if ((!old.isNull() && overwrite) || old == buffer) { - return; + if (old != buffer && (old.isNull() || overwrite)) { + write(); } - write(); } QByteArray read() const { QByteArray content; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 08c0d8b..019584e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,32 +1,53 @@ enable_testing() -add_custom_command( - OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/rust_object/src/interface.rs" - COMMAND ${CMAKE_BINARY_DIR}/rust_qt_binding_generator/rust_qt_binding_generator --overwrite-implementation "${CMAKE_CURRENT_SOURCE_DIR}/test_object.json" - DEPENDS rust_qt_binding_generator test_object.json -) +SET(GENERATOR "${CMAKE_BINARY_DIR}/rust_qt_binding_generator/rust_qt_binding_generator") -add_custom_command( - OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/rust_object/${RUST_TARGET_DIR}/librust.a" - COMMAND cargo build ${RUST_BUILD_FLAG} - DEPENDS rust_object/src/lib.rs - rust_object/src/implementation.rs - rust_object/src/interface.rs - rust_object/src/types.rs - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/rust_object" -) -add_custom_target(test_rust_object DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/rust_object/${RUST_TARGET_DIR}/librust.a") +function(rust_test NAME DIRECTORY) + set(SRC "${CMAKE_CURRENT_SOURCE_DIR}") + set(DIR "${SRC}/${DIRECTORY}") -add_executable(test_object test_object.cpp test_object_rust.cpp) -add_dependencies(test_object test_rust_object) -target_link_libraries(test_object - Qt5::Core - Qt5::Test - "${CMAKE_CURRENT_SOURCE_DIR}/rust_object/${RUST_TARGET_DIR}/librust.a" -) + add_custom_command( + OUTPUT "${DIR}/src/interface.rs" + "${DIR}/src/implementation.rs" + "${SRC}/${NAME}_rust.h" + # if the cpp file is marked GENERATED, CMake will not check it for moc + # "${SRC}/${NAME}_rust.cpp" + COMMAND "${GENERATOR}" --overwrite-implementation "${SRC}/${NAME}.json" + MAIN_DEPENDENCY "${NAME}.json" + DEPENDS "${GENERATOR}" + ) +# add_custom_target("${DIRECTORY}" +# DEPENDS "${DIR}/src/inferface.rs") + + add_custom_command( + OUTPUT "${DIR}/${RUST_TARGET_DIR}/librust.a" + COMMAND cargo build ${RUST_BUILD_FLAG} + DEPENDS "${DIRECTORY}/src/lib.rs" + "${DIRECTORY}/src/implementation.rs" + "${DIRECTORY}/src/interface.rs" + "${DIRECTORY}/src/types.rs" + WORKING_DIRECTORY "${DIR}" + ) + add_custom_target("test_${DIRECTORY}" + DEPENDS "${DIR}/${RUST_TARGET_DIR}/librust.a") + + add_executable("${NAME}" "${NAME}.cpp" "${NAME}_rust.cpp" "${NAME}_rust.h") + add_dependencies("${NAME}" "test_${DIRECTORY}") + target_link_libraries("${NAME}" + Qt5::Core + Qt5::Test + "${DIR}/${RUST_TARGET_DIR}/librust.a" + ) + set_property(TARGET ${NAME} + APPEND PROPERTY AUTOGEN_TARGET_DEPENDS "${SRC}/${NAME}_rust.h") + + add_test("build_${NAME}" + "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target "${NAME}") + add_test("${NAME}" "${NAME}") + set_tests_properties("${NAME}" PROPERTIES DEPENDS "build_${NAME}") + +endfunction(rust_test) + +rust_test(test_object rust_object) +rust_test(test_object_types rust_object_types) -add_test(remove_test_object "${CMAKE_COMMAND}" -E remove test_object) -add_test(build_test_object "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target test_object) -set_tests_properties(build_test_object PROPERTIES DEPENDS remove_test_object) -add_test(test_object test_object) -set_tests_properties(test_object PROPERTIES DEPENDS build_test_object) diff --git a/tests/rust_object_types/Cargo.toml b/tests/rust_object_types/Cargo.toml new file mode 100644 index 0000000..b52f0f0 --- /dev/null +++ b/tests/rust_object_types/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rust_object" +version = "1.0.0" + +[dependencies] +libc = "*" + +[lib] +name = "rust" +crate-type = ["staticlib"] diff --git a/tests/rust_object_types/src/lib.rs b/tests/rust_object_types/src/lib.rs new file mode 100644 index 0000000..94e4632 --- /dev/null +++ b/tests/rust_object_types/src/lib.rs @@ -0,0 +1,5 @@ +extern crate libc; + +mod types; +pub mod interface; +mod implementation; diff --git a/tests/test_object_types.cpp b/tests/test_object_types.cpp new file mode 100644 index 0000000..5791b9c --- /dev/null +++ b/tests/test_object_types.cpp @@ -0,0 +1,41 @@ +#include "test_object_rust.h" +#include +#include + +class TestRustObject : public QObject +{ + Q_OBJECT +private slots: + void testConstructor(); + void testStringGetter(); + void testStringSetter(); +}; + +void TestRustObject::testConstructor() +{ + Person person; +} + +void TestRustObject::testStringGetter() +{ + Person person; + person.setUserName("Konqi"); +} + +void TestRustObject::testStringSetter() +{ + // GIVEN + Person person; + QSignalSpy spy(&person, &Person::userNameChanged); + + // WHEN + person.setUserName("Konqi"); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(spy.count(), 1); + QCOMPARE(person.userName(), QString("Konqi")); +} + +QTEST_MAIN(TestRustObject) +#include "test_object_types.moc" diff --git a/tests/test_object_types.json b/tests/test_object_types.json new file mode 100644 index 0000000..7948a0e --- /dev/null +++ b/tests/test_object_types.json @@ -0,0 +1,17 @@ +{ + "cppFile": "test_object_types_rust.cpp", + "rust": { + "dir": "rust_object_types", + "interfaceModule": "interface", + "implementationModule": "implementation" + }, + "objects": [{ + "name": "Person", + "type": "Object", + "properties": [{ + "name": "userName", + "type": "QString", + "write": true + }] + }] +} diff --git a/tests/test_object_types_rust.cpp b/tests/test_object_types_rust.cpp new file mode 100644 index 0000000..5b238c1 --- /dev/null +++ b/tests/test_object_types_rust.cpp @@ -0,0 +1,132 @@ +/* generated by rust_qt_binding_generator */ +#include "test_object_types_rust.h" +#include + +namespace { + struct qbytearray_t { + private: + const char* data; + int len; + public: + qbytearray_t(const QByteArray& v): + data(v.data()), + len(v.size()) { + } + operator QByteArray() const { + return QByteArray(data, len); + } + }; + struct qstring_t { + private: + const void* data; + int len; + public: + qstring_t(const QString& v): + data(static_cast(v.utf16())), + len(v.size()) { + } + operator QString() const { + return QString::fromUtf8(static_cast(data), len); + } + }; + struct qmodelindex_t { + int row; + int column; + uint64_t id; + qmodelindex_t(const QModelIndex& m): + row(m.row()), column(m.column()), id(m.internalId()) {} + }; + struct qvariant_t { + unsigned int type; + int value; + const char* data; + }; + QVariant variant(const qvariant_t& v) { + switch (v.type) { + case QVariant::Bool: return QVariant((bool)v.value); + case QVariant::String: return QString::fromUtf8(static_cast(v.data), v.value); + default:; + } + return QVariant(); + } + void variant(const QByteArray& v, void* d, void (*set)(void*, qvariant_t)) { + set(d, { + .type = QVariant::ByteArray, + .value = v.length(), + .data = v.data() + }); + } + void variant(const QString& v, void* d, void (*set)(void*, qvariant_t)) { + set(d, { + .type = QVariant::String, + .value = v.size(), + .data = static_cast(static_cast(v.utf16())) + }); + } + void variant(const QVariant& v, void* d, void (*set)(void*, qvariant_t)) { + switch (v.type()) { + case QVariant::Bool: + set(d, { + .type = QVariant::Bool, + .value = v.toBool(), + .data = 0 + }); + break; + case QVariant::Int: + set(d, { + .type = QVariant::Int, + .value = v.toInt(), + .data = 0 + }); + break; + case QVariant::ByteArray: + variant(v.toByteArray(), d, set); + break; + case QVariant::String: + variant(v.toString(), d, set); + break; + default: + set(d, { + .type = QVariant::Invalid, + .value = 0, + .data = 0 + }); + } + } +} +typedef void (*qstring_set)(QString*, qstring_t*); +void set_qstring(QString* v, qstring_t* val) { + *v = *val; +} +typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); +void set_qbytearray(QByteArray* v, qbytearray_t* val) { + *v = *val; +} +typedef void (*qvariant_set)(QVariant*, qvariant_t*); +void set_qvariant(QVariant* v, qvariant_t* val) { + *v = variant(*val); +} + +extern "C" { + PersonInterface* person_new(Person*, void (*)(Person*)); + void person_free(PersonInterface*); + void person_user_name_get(PersonInterface*, QString*, qstring_set); + void person_user_name_set(void*, qstring_t); +}; +Person::Person(QObject *parent): + QObject(parent), + d(person_new(this, + [](Person* o) { emit o->userNameChanged(); })) {} + +Person::~Person() { + person_free(d); +} +QString Person::userName() const +{ + QString v; + person_user_name_get(d, &v, set_qstring); + return v; +} +void Person::setUserName(const QString& v) { + person_user_name_set(d, v); +} diff --git a/tests/test_object_types_rust.h b/tests/test_object_types_rust.h new file mode 100644 index 0000000..ff3448b --- /dev/null +++ b/tests/test_object_types_rust.h @@ -0,0 +1,25 @@ +/* generated by rust_qt_binding_generator */ +#ifndef TEST_OBJECT_TYPES_RUST_H +#define TEST_OBJECT_TYPES_RUST_H + +#include +#include +#include + +class PersonInterface; +class Person : public QObject +{ + Q_OBJECT + PersonInterface * const d; + Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged FINAL) +public: + explicit Person(QObject *parent = nullptr); + ~Person(); + QString userName() const; + void setUserName(const QString& v); +signals: + void userNameChanged(); +private: + QString m_userName; +}; +#endif // TEST_OBJECT_TYPES_RUST_H