From 20e7b345e10a183d8e38012431ef74dfc72544b8 Mon Sep 17 00:00:00 2001 From: Stefan Date: Tue, 19 Apr 2022 21:45:26 +0400 Subject: [PATCH] tests(general): refactor tests Enhance the CMake strucuture of thests Update documentation --- CMakeLists.txt | 5 +++ tests/{TestControls => }/CMakeLists.txt | 15 ++++--- .../StatusQ/TestHelpers/TestUtils.qml | 14 ------ .../TestHelpers/MonitorQtOutput.h | 32 -------------- .../TestControls/tst_test-StatusBaseInput.qml | 3 +- tests/TestControls/tst_test-StatusInput.qml | 3 +- tests/Testing/Temporary/CTestCostData.txt | 1 + tests/Testing/Temporary/LastTest.log | 3 ++ tests/{TestControls => }/main.cpp | 6 +-- tests/qml/StatusQ/TestHelpers/TestUtils.qml | 23 ++++++++++ .../StatusQ/TestHelpers/qmldir | 0 tests/readme.md | 13 +++--- tests/src/CMakeLists.txt | 6 +++ .../TestHelpers/CMakeLists.txt | 5 --- .../TestHelpers/MonitorQtOutput.cpp | 22 ++++++++-- tests/src/TestHelpers/MonitorQtOutput.h | 43 +++++++++++++++++++ 16 files changed, 122 insertions(+), 72 deletions(-) create mode 100644 CMakeLists.txt rename tests/{TestControls => }/CMakeLists.txt (68%) delete mode 100644 tests/TestControls/StatusQ/TestHelpers/TestUtils.qml delete mode 100644 tests/TestControls/TestHelpers/MonitorQtOutput.h create mode 100644 tests/Testing/Temporary/CTestCostData.txt create mode 100644 tests/Testing/Temporary/LastTest.log rename tests/{TestControls => }/main.cpp (81%) create mode 100644 tests/qml/StatusQ/TestHelpers/TestUtils.qml rename tests/{TestControls => qml}/StatusQ/TestHelpers/qmldir (100%) create mode 100644 tests/src/CMakeLists.txt rename tests/{TestControls => src}/TestHelpers/CMakeLists.txt (69%) rename tests/{TestControls => src}/TestHelpers/MonitorQtOutput.cpp (64%) create mode 100644 tests/src/TestHelpers/MonitorQtOutput.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..89d54b3a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.19) + +project(StatusQ) + +add_subdirectory(tests) diff --git a/tests/TestControls/CMakeLists.txt b/tests/CMakeLists.txt similarity index 68% rename from tests/TestControls/CMakeLists.txt rename to tests/CMakeLists.txt index c45a108e..9c51d315 100644 --- a/tests/TestControls/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,11 +1,11 @@ cmake_minimum_required(VERSION 3.5) -project(TestControls LANGUAGES CXX) +project(TestStatusQ LANGUAGES CXX) enable_testing() # TODO: Workaround until we make StatusQ a CMake library -list(APPEND QML_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../../src/") +list(APPEND QML_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../src/") set(QML_IMPORT_PATH "${QML_DIRS}" CACHE STRING "Qt Creator extra qml import paths") set(QML2_IMPORT_PATH "${QML_DIRS}" CACHE STRING "Qt Creator extra qml import paths") @@ -14,18 +14,20 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS QuickTest Qml Quick REQUIRED) set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # no need to copy around qml test files for shadow builds - just set the respective define add_definitions(-DQUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}") add_executable(${PROJECT_NAME} main.cpp) -add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) + +add_test(NAME ${PROJECT_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME} -input "${CMAKE_CURRENT_SOURCE_DIR}") +add_custom_target("Run_${PROJECT_NAME}" COMMAND ${CMAKE_CTEST_COMMAND} --test-dir "${CMAKE_CURRENT_BINARY_DIR}") +add_dependencies("Run_${PROJECT_NAME}" ${PROJECT_NAME}) # TODO: move this to a test helpers library target_include_directories(${PROJECT_NAME} @@ -33,11 +35,10 @@ target_include_directories(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR} ) -add_subdirectory(TestHelpers) +add_subdirectory(src) target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::QuickTest Qt${QT_VERSION_MAJOR}::Qml Qt${QT_VERSION_MAJOR}::Quick ) - diff --git a/tests/TestControls/StatusQ/TestHelpers/TestUtils.qml b/tests/TestControls/StatusQ/TestHelpers/TestUtils.qml deleted file mode 100644 index 6c89bc33..00000000 --- a/tests/TestControls/StatusQ/TestHelpers/TestUtils.qml +++ /dev/null @@ -1,14 +0,0 @@ -pragma Singleton - -import QtQml 2.14 -import QtTest 1.0 - -QtObject { - - //> Simulate key and wait for side effects - function pressKeyAndWait(test, item, key) { - test.keyClick(key) - - test.waitForRendering(item) - } -} diff --git a/tests/TestControls/TestHelpers/MonitorQtOutput.h b/tests/TestControls/TestHelpers/MonitorQtOutput.h deleted file mode 100644 index c482f0f6..00000000 --- a/tests/TestControls/TestHelpers/MonitorQtOutput.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -/// -/// \brief Monitor output for tests and declarativelly control message handler availability -/// \todo Check that QML doesn't keep instance between test runs -/// -class MonitorQtOutput : public QQuickItem -{ - Q_OBJECT -public: - MonitorQtOutput(); - ~MonitorQtOutput(); - - Q_INVOKABLE QString qtOuput(); - -signals: - -private: - static void qtMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg); - - // Use it to keep track of qInstallMessageHandler call - static std::weak_ptr m_qtMessageOutputForSharing; - static std::mutex m_mutex; - std::shared_ptr m_thisMessageOutput; - int m_start = 0; -}; diff --git a/tests/TestControls/tst_test-StatusBaseInput.qml b/tests/TestControls/tst_test-StatusBaseInput.qml index af283280..b842445e 100644 --- a/tests/TestControls/tst_test-StatusBaseInput.qml +++ b/tests/TestControls/tst_test-StatusBaseInput.qml @@ -26,7 +26,8 @@ Item { // // Test guards - function initTestCase() { + function init() { + qtOuput.restartCapturing() } function cleanup() { diff --git a/tests/TestControls/tst_test-StatusInput.qml b/tests/TestControls/tst_test-StatusInput.qml index d7b4e943..c87af502 100644 --- a/tests/TestControls/tst_test-StatusInput.qml +++ b/tests/TestControls/tst_test-StatusInput.qml @@ -38,7 +38,8 @@ Item { // // Test guards - function initTestCase() { + function init() { + qtOuput.restartCapturing() mouseClick(statusInput) } diff --git a/tests/Testing/Temporary/CTestCostData.txt b/tests/Testing/Temporary/CTestCostData.txt new file mode 100644 index 00000000..ed97d539 --- /dev/null +++ b/tests/Testing/Temporary/CTestCostData.txt @@ -0,0 +1 @@ +--- diff --git a/tests/Testing/Temporary/LastTest.log b/tests/Testing/Temporary/LastTest.log new file mode 100644 index 00000000..b3246465 --- /dev/null +++ b/tests/Testing/Temporary/LastTest.log @@ -0,0 +1,3 @@ +Start testing: Apr 18 18:49 CEST +---------------------------------------------------------- +End testing: Apr 18 18:49 CEST diff --git a/tests/TestControls/main.cpp b/tests/main.cpp similarity index 81% rename from tests/TestControls/main.cpp rename to tests/main.cpp index d825604a..924f9a26 100644 --- a/tests/TestControls/main.cpp +++ b/tests/main.cpp @@ -14,13 +14,11 @@ public slots: void qmlEngineAvailable(QQmlEngine *engine) { // TODO: Workaround until we make StatusQ a CMake library - engine->addImportPath("../../src/"); - engine->addImportPath("."); + engine->addImportPath("../src/"); + engine->addImportPath("./qml/"); // TODO: Alternative to not yet supported QML_ELEMENT qmlRegisterType("StatusQ.TestHelpers", 0, 1, "MonitorQtOutput"); } -private: - MonitorQtOutput _monitorOutput; }; QUICK_TEST_MAIN_WITH_SETUP(TestControls, TestSetup) diff --git a/tests/qml/StatusQ/TestHelpers/TestUtils.qml b/tests/qml/StatusQ/TestHelpers/TestUtils.qml new file mode 100644 index 00000000..c51d747a --- /dev/null +++ b/tests/qml/StatusQ/TestHelpers/TestUtils.qml @@ -0,0 +1,23 @@ +pragma Singleton + +import QtQml 2.14 +import QtTest 1.0 + +QtObject { + + //> Simulate key and wait for side effects + function pressKeyAndWait(test, item, key) { + test.keyClick(key) + + ensureRendered(test, item) + } + + function ensureRendered(test, item) { + test.verify(test.waitForRendering(item, 1000)) + } + + function expectRendering(test, item) { + test.verify(test.isPolishScheduled(item)) + test.verify(test.waitForRendering(item, 1000)) + } +} diff --git a/tests/TestControls/StatusQ/TestHelpers/qmldir b/tests/qml/StatusQ/TestHelpers/qmldir similarity index 100% rename from tests/TestControls/StatusQ/TestHelpers/qmldir rename to tests/qml/StatusQ/TestHelpers/qmldir diff --git a/tests/readme.md b/tests/readme.md index 15811986..d739ddd3 100644 --- a/tests/readme.md +++ b/tests/readme.md @@ -5,18 +5,21 @@ CMake ```sh -cd StatusQ/tests/TestControls +cd ./tests/ cmake -B ./build/ -S . cmake --build ./build/ -./build/TestControls +ctest --test-dir ./build/ ``` QtCreator -- Open the StatusQ/tests/CMakeLists.txt +- Open the `./tests/CMakeLists.txt` - Choose a QT kit to run the tests -- In the `Test Results` panel choose Run All Tests +- Set `%{sourceDir}/tests` as Working Directory for the TestStatusQ target +- In the *Test Results* panel choose Run All Tests or just run the *TestStatusQ* target ## TODO -- [ ] Consolidate and integrate with https://github.com/status-im/desktop-ui-tests \ No newline at end of file +- [ ] TestHelpers library +- [ ] Consolidate and integrate with https://github.com/status-im/desktop-ui-tests +- [ ] Separate projects per scope: TestControls, TestComponents diff --git a/tests/src/CMakeLists.txt b/tests/src/CMakeLists.txt new file mode 100644 index 00000000..3220944c --- /dev/null +++ b/tests/src/CMakeLists.txt @@ -0,0 +1,6 @@ +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_subdirectory(TestHelpers) \ No newline at end of file diff --git a/tests/TestControls/TestHelpers/CMakeLists.txt b/tests/src/TestHelpers/CMakeLists.txt similarity index 69% rename from tests/TestControls/TestHelpers/CMakeLists.txt rename to tests/src/TestHelpers/CMakeLists.txt index d10b0a82..c6a78106 100644 --- a/tests/TestControls/TestHelpers/CMakeLists.txt +++ b/tests/src/TestHelpers/CMakeLists.txt @@ -1,8 +1,3 @@ -target_include_directories(${PROJECT_NAME} - PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} -) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/MonitorQtOutput.h diff --git a/tests/TestControls/TestHelpers/MonitorQtOutput.cpp b/tests/src/TestHelpers/MonitorQtOutput.cpp similarity index 64% rename from tests/TestControls/TestHelpers/MonitorQtOutput.cpp rename to tests/src/TestHelpers/MonitorQtOutput.cpp index 49c68945..1c6aeefb 100644 --- a/tests/TestControls/TestHelpers/MonitorQtOutput.cpp +++ b/tests/src/TestHelpers/MonitorQtOutput.cpp @@ -5,19 +5,21 @@ std::weak_ptr MonitorQtOutput::m_qtMessageOutputForSharing; std::mutex MonitorQtOutput::m_mutex; +QtMessageHandler MonitorQtOutput::m_previousHandler = nullptr; MonitorQtOutput::MonitorQtOutput() { // Ensure only one instance registers a handler - // Warning: don't QT's call loger functions inside the critical section + // Warning: don't call QT's logger functions inside the critical section std::unique_lock localLock(m_mutex); auto globalMsgOut = m_qtMessageOutputForSharing.lock(); + auto prev = qInstallMessageHandler(qtMessageOutput); + if(prev != qtMessageOutput) + m_previousHandler = prev; if(!globalMsgOut) { - // Install message handler if not already done m_thisMessageOutput = std::make_shared(); m_qtMessageOutputForSharing = m_thisMessageOutput; - qInstallMessageHandler(qtMessageOutput); } else { m_thisMessageOutput = globalMsgOut; @@ -42,11 +44,25 @@ MonitorQtOutput::qtMessageOutput(QtMsgType type, const QMessageLogContext &conte auto globalMsgOut = m_qtMessageOutputForSharing.lock(); assert(globalMsgOut != nullptr); globalMsgOut->append(msg + '\n'); + // Also reproduce the default output + m_previousHandler(type, context, msg); } QString MonitorQtOutput::qtOuput() { + std::unique_lock localLock(m_mutex); assert(m_thisMessageOutput->length() >= m_start); return m_thisMessageOutput->right(m_thisMessageOutput->length() - m_start); } + +void +MonitorQtOutput::restartCapturing() +{ + std::unique_lock localLock(m_mutex); + // Ensure the messageHandler is installed. Foun to be reset at test initializaiton + auto prev = qInstallMessageHandler(qtMessageOutput); + if(prev != qtMessageOutput) + m_previousHandler = prev; + m_start = m_thisMessageOutput->length(); +} diff --git a/tests/src/TestHelpers/MonitorQtOutput.h b/tests/src/TestHelpers/MonitorQtOutput.h new file mode 100644 index 00000000..657ed79b --- /dev/null +++ b/tests/src/TestHelpers/MonitorQtOutput.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +#include +#include + +/// +/// \brief Monitor output for tests and declaratively control message handler availability +/// +/// The captured buffer is global and each instance has a reference to it and a start pointer +/// from its creation or last clear call +/// The first instance installs a QT message handler @see Qt::qInstallMessageHandler then +/// All other instances share the global buffer until the last instance goes out of scope and deregisters +/// from Qt's global message handler and destroyes the buffer +/// +/// \todo Check that QML doesn't keep instance between test runs +/// +class MonitorQtOutput : public QQuickItem +{ + Q_OBJECT +public: + MonitorQtOutput(); + ~MonitorQtOutput(); + + /// Return captured output from the global buffer. That is from the instantiation or last `clear()` was called + Q_INVOKABLE QString qtOuput(); + /// Reset buffer start after the last line. qtOutput won't return anything until new output is captured + Q_INVOKABLE void restartCapturing(); + +signals: + +private: + static void qtMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg); + static QtMessageHandler m_previousHandler; + + // Use it to keep track of qInstallMessageHandler call + static std::weak_ptr m_qtMessageOutputForSharing; + static std::mutex m_mutex; + std::shared_ptr m_thisMessageOutput; + int m_start = 0; +};