diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index 5f6c969cd27..c036cb52914 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -16,17 +16,6 @@ using namespace Utils; using namespace Utils::Tasking; -enum class Handler { - Setup, - Done, - Error, - GroupSetup, - GroupDone, - GroupError -}; - -using Log = QList>; - class tst_TaskTree : public QObject { Q_OBJECT @@ -37,15 +26,12 @@ private slots: void validConstructs(); // compile test void processTree_data(); void processTree(); - void storage_data(); - void storage(); void storageOperators(); void storageDestructor(); void cleanupTestCase(); private: - Log m_log; FilePath m_testAppPath; }; @@ -105,61 +91,88 @@ void tst_TaskTree::validConstructs() static const char s_processIdProperty[] = "__processId"; +enum class Handler { + Setup, + Done, + Error, + GroupSetup, + GroupDone, + GroupError +}; + +using Log = QList>; + +struct CustomStorage +{ + CustomStorage() { ++s_count; } + ~CustomStorage() { --s_count; } + Log m_log; + static int instanceCount() { return s_count; } +private: + static int s_count; +}; + +int CustomStorage::s_count = 0; + + void tst_TaskTree::processTree_data() { using namespace std::placeholders; QTest::addColumn("root"); + QTest::addColumn>("storage"); QTest::addColumn("expectedLog"); QTest::addColumn("runningAfterStart"); QTest::addColumn("success"); QTest::addColumn("taskCount"); - const auto setupProcessHelper = [this](QtcProcess &process, const QStringList &args, int processId) { - process.setCommand(CommandLine(m_testAppPath, args)); + TreeStorage storage; + + const auto setupProcessHelper = [storage, testAppPath = m_testAppPath] + (QtcProcess &process, const QStringList &args, int processId) { + process.setCommand(CommandLine(testAppPath, args)); process.setProperty(s_processIdProperty, processId); - m_log.append({processId, Handler::Setup}); + storage->m_log.append({processId, Handler::Setup}); }; const auto setupProcess = [setupProcessHelper](QtcProcess &process, int processId) { setupProcessHelper(process, {"-return", "0"}, processId); }; -// const auto setupErrorProcess = [setupProcessHelper](QtcProcess &process, int processId) { -// setupProcessHelper(process, {"-return", "1"}, processId); -// }; const auto setupCrashProcess = [setupProcessHelper](QtcProcess &process, int processId) { setupProcessHelper(process, {"-crash"}, processId); }; - const auto readResultAnonymous = [this](const QtcProcess &) { - m_log.append({-1, Handler::Done}); + const auto readResultAnonymous = [storage](const QtcProcess &) { + storage->m_log.append({-1, Handler::Done}); }; - const auto readResult = [this](const QtcProcess &process) { + const auto readResult = [storage](const QtcProcess &process) { const int processId = process.property(s_processIdProperty).toInt(); - m_log.append({processId, Handler::Done}); + storage->m_log.append({processId, Handler::Done}); }; - const auto readError = [this](const QtcProcess &process) { + const auto readError = [storage](const QtcProcess &process) { const int processId = process.property(s_processIdProperty).toInt(); - m_log.append({processId, Handler::Error}); + storage->m_log.append({processId, Handler::Error}); }; - const auto groupSetup = [this](int processId) { - m_log.append({processId, Handler::GroupSetup}); + const auto groupSetup = [storage](int processId) { + storage->m_log.append({processId, Handler::GroupSetup}); }; - const auto groupDone = [this](int processId) { - m_log.append({processId, Handler::GroupDone}); + const auto groupDone = [storage](int processId) { + storage->m_log.append({processId, Handler::GroupDone}); }; - const auto rootDone = [this] { - m_log.append({-1, Handler::GroupDone}); + const auto rootDone = [storage] { + storage->m_log.append({-1, Handler::GroupDone}); }; - const auto rootError = [this] { - m_log.append({-1, Handler::GroupError}); + const auto rootError = [storage] { + storage->m_log.append({-1, Handler::GroupError}); }; const Group emptyRoot { + Storage(storage), OnGroupDone(rootDone) }; const Log emptyLog{{-1, Handler::GroupDone}}; - QTest::newRow("Empty") << emptyRoot << emptyLog << false << true << 0; + QTest::newRow("Empty") << emptyRoot << storage << emptyLog << false << true << 0; const Group nestedRoot { + Storage(storage), Group { Group { Group { @@ -196,9 +209,10 @@ void tst_TaskTree::processTree_data() {2, Handler::GroupDone}, {1, Handler::GroupDone}, {-1, Handler::GroupDone}}; - QTest::newRow("Nested") << nestedRoot << nestedLog << true << true << 1; + QTest::newRow("Nested") << nestedRoot << storage << nestedLog << true << true << 1; const Group parallelRoot { + Storage(storage), parallel, Process(std::bind(setupProcess, _1, 1), readResultAnonymous), Process(std::bind(setupProcess, _1, 2), readResultAnonymous), @@ -218,9 +232,10 @@ void tst_TaskTree::processTree_data() {-1, Handler::Done}, {-1, Handler::Done}, {-1, Handler::GroupDone}}; // Done handlers may come in different order - QTest::newRow("Parallel") << parallelRoot << parallelLog << true << true << 5; + QTest::newRow("Parallel") << parallelRoot << storage << parallelLog << true << true << 5; const Group sequentialRoot { + Storage(storage), Process(std::bind(setupProcess, _1, 1), readResult), Process(std::bind(setupProcess, _1, 2), readResult), Process(std::bind(setupProcess, _1, 3), readResult), @@ -229,6 +244,7 @@ void tst_TaskTree::processTree_data() OnGroupDone(rootDone) }; const Group sequentialEncapsulatedRoot { + Storage(storage), Group { Process(std::bind(setupProcess, _1, 1), readResult) }, @@ -248,13 +264,20 @@ void tst_TaskTree::processTree_data() }; auto setupSubTree = [=](TaskTree &taskTree) { const Group nestedRoot { + Storage(storage), Process(std::bind(setupProcess, _1, 2), readResult), Process(std::bind(setupProcess, _1, 3), readResult), Process(std::bind(setupProcess, _1, 4), readResult), }; taskTree.setupRoot(nestedRoot); + CustomStorage *activeStorage = storage.activeStorage(); + auto collectSubLog = [activeStorage](CustomStorage *subTreeStorage){ + activeStorage->m_log += subTreeStorage->m_log; + }; + taskTree.onStorageDone(storage, collectSubLog); }; const Group sequentialSubTreeRoot { + Storage(storage), Process(std::bind(setupProcess, _1, 1), readResult), Tree(setupSubTree), Process(std::bind(setupProcess, _1, 5), readResult), @@ -271,13 +294,14 @@ void tst_TaskTree::processTree_data() {5, Handler::Setup}, {5, Handler::Done}, {-1, Handler::GroupDone}}; - QTest::newRow("Sequential") << sequentialRoot << sequentialLog << true << true << 5; - QTest::newRow("SequentialEncapsulated") << sequentialEncapsulatedRoot << sequentialLog - << true << true << 5; - QTest::newRow("SequentialSubTree") << sequentialSubTreeRoot << sequentialLog + QTest::newRow("Sequential") << sequentialRoot << storage << sequentialLog << true << true << 5; + QTest::newRow("SequentialEncapsulated") << sequentialEncapsulatedRoot << storage + << sequentialLog << true << true << 5; + QTest::newRow("SequentialSubTree") << sequentialSubTreeRoot << storage << sequentialLog << true << true << 3; // We don't inspect subtrees const Group sequentialNestedRoot { + Storage(storage), Group { Process(std::bind(setupProcess, _1, 1), readResult), Group { @@ -316,10 +340,11 @@ void tst_TaskTree::processTree_data() {2, Handler::GroupDone}, {1, Handler::GroupDone}, {-1, Handler::GroupDone}}; - QTest::newRow("SequentialNested") << sequentialNestedRoot << sequentialNestedLog + QTest::newRow("SequentialNested") << sequentialNestedRoot << storage << sequentialNestedLog << true << true << 5; const Group sequentialErrorRoot { + Storage(storage), Process(std::bind(setupProcess, _1, 1), readResult), Process(std::bind(setupProcess, _1, 2), readResult), Process(std::bind(setupCrashProcess, _1, 3), readResult, readError), @@ -335,11 +360,12 @@ void tst_TaskTree::processTree_data() {3, Handler::Setup}, {3, Handler::Error}, {-1, Handler::GroupError}}; - QTest::newRow("SequentialError") << sequentialErrorRoot << sequentialErrorLog + QTest::newRow("SequentialError") << sequentialErrorRoot << storage << sequentialErrorLog << true << false << 5; const auto constructSimpleSequence = [=](const Workflow &policy) { return Group { + Storage(storage), policy, Process(std::bind(setupProcess, _1, 1), readResult), Process(std::bind(setupCrashProcess, _1, 2), readResult, readError), @@ -355,7 +381,7 @@ void tst_TaskTree::processTree_data() {2, Handler::Setup}, {2, Handler::Error}, {-1, Handler::GroupError}}; - QTest::newRow("StopOnError") << stopOnErrorRoot << stopOnErrorLog << true << false << 3; + QTest::newRow("StopOnError") << stopOnErrorRoot << storage << stopOnErrorLog << true << false << 3; const Group continueOnErrorRoot = constructSimpleSequence(continueOnError); const Log continueOnErrorLog{{1, Handler::Setup}, @@ -365,14 +391,14 @@ void tst_TaskTree::processTree_data() {3, Handler::Setup}, {3, Handler::Done}, {-1, Handler::GroupError}}; - QTest::newRow("ContinueOnError") << continueOnErrorRoot << continueOnErrorLog + QTest::newRow("ContinueOnError") << continueOnErrorRoot << storage << continueOnErrorLog << true << false << 3; const Group stopOnDoneRoot = constructSimpleSequence(stopOnDone); const Log stopOnDoneLog{{1, Handler::Setup}, {1, Handler::Done}, {-1, Handler::GroupDone}}; - QTest::newRow("StopOnDone") << stopOnDoneRoot << stopOnDoneLog + QTest::newRow("StopOnDone") << stopOnDoneRoot << storage << stopOnDoneLog << true << true << 3; const Group continueOnDoneRoot = constructSimpleSequence(continueOnDone); @@ -383,9 +409,11 @@ void tst_TaskTree::processTree_data() {3, Handler::Setup}, {3, Handler::Done}, {-1, Handler::GroupDone}}; - QTest::newRow("ContinueOnDone") << continueOnDoneRoot << continueOnDoneLog << true << true << 3; + QTest::newRow("ContinueOnDone") << continueOnDoneRoot << storage << continueOnDoneLog + << true << true << 3; const Group optionalRoot { + Storage(storage), optional, Process(std::bind(setupCrashProcess, _1, 1), readResult, readError), Process(std::bind(setupCrashProcess, _1, 2), readResult, readError), @@ -397,7 +425,7 @@ void tst_TaskTree::processTree_data() {2, Handler::Setup}, {2, Handler::Error}, {-1, Handler::GroupDone}}; - QTest::newRow("Optional") << optionalRoot << optionalLog << true << true << 2; + QTest::newRow("Optional") << optionalRoot << storage << optionalLog << true << true << 2; const auto stopWithDoneSetup = [] { return GroupConfig{GroupAction::StopWithDone}; }; const auto stopWithErrorSetup = [] { return GroupConfig{GroupAction::StopWithError}; }; @@ -405,6 +433,7 @@ void tst_TaskTree::processTree_data() const auto continueSelSetup = [] { return GroupConfig{GroupAction::ContinueSelected, {0, 2}}; }; const auto constructDynamicSetup = [=](const DynamicSetup &dynamicSetup) { return Group { + Storage(storage), Group { Process(std::bind(setupProcess, _1, 1), readResult) }, @@ -422,14 +451,14 @@ void tst_TaskTree::processTree_data() const Log dynamicSetupDoneLog{{1, Handler::Setup}, {1, Handler::Done}, {-1, Handler::GroupDone}}; - QTest::newRow("DynamicSetupDone") << dynamicSetupDoneRoot << dynamicSetupDoneLog + QTest::newRow("DynamicSetupDone") << dynamicSetupDoneRoot << storage << dynamicSetupDoneLog << true << true << 4; const Group dynamicSetupErrorRoot = constructDynamicSetup({stopWithErrorSetup}); const Log dynamicSetupErrorLog{{1, Handler::Setup}, {1, Handler::Done}, {-1, Handler::GroupError}}; - QTest::newRow("DynamicSetupError") << dynamicSetupErrorRoot << dynamicSetupErrorLog + QTest::newRow("DynamicSetupError") << dynamicSetupErrorRoot << storage << dynamicSetupErrorLog << true << false << 4; const Group dynamicSetupAllRoot = constructDynamicSetup({continueAllSetup}); @@ -442,7 +471,7 @@ void tst_TaskTree::processTree_data() {4, Handler::Setup}, {4, Handler::Done}, {-1, Handler::GroupDone}}; - QTest::newRow("DynamicSetupAll") << dynamicSetupAllRoot << dynamicSetupAllLog + QTest::newRow("DynamicSetupAll") << dynamicSetupAllRoot << storage << dynamicSetupAllLog << true << true << 4; const Group dynamicSetupSelRoot = constructDynamicSetup({continueSelSetup}); @@ -453,30 +482,40 @@ void tst_TaskTree::processTree_data() {4, Handler::Setup}, {4, Handler::Done}, {-1, Handler::GroupDone}}; - QTest::newRow("DynamicSetupSelected") << dynamicSetupSelRoot << dynamicSetupSelLog + QTest::newRow("DynamicSetupSelected") << dynamicSetupSelRoot << storage << dynamicSetupSelLog << true << true << 4; } void tst_TaskTree::processTree() { - m_log = {}; - QFETCH(Group, root); + QFETCH(TreeStorage, storage); QFETCH(Log, expectedLog); QFETCH(bool, runningAfterStart); QFETCH(bool, success); QFETCH(int, taskCount); QEventLoop eventLoop; - TaskTree processTree(root); - QCOMPARE(processTree.taskCount(), taskCount); + TaskTree taskTree(root); + QCOMPARE(taskTree.taskCount(), taskCount); int doneCount = 0; int errorCount = 0; - connect(&processTree, &TaskTree::done, this, [&doneCount, &eventLoop] { ++doneCount; eventLoop.quit(); }); - connect(&processTree, &TaskTree::errorOccurred, this, [&errorCount, &eventLoop] { ++errorCount; eventLoop.quit(); }); - processTree.start(); - QCOMPARE(processTree.isRunning(), runningAfterStart); + connect(&taskTree, &TaskTree::done, this, [&doneCount, &eventLoop] { + ++doneCount; + eventLoop.quit(); + }); + connect(&taskTree, &TaskTree::errorOccurred, this, [&errorCount, &eventLoop] { + ++errorCount; + eventLoop.quit(); + }); + Log actualLog; + auto collectLog = [&actualLog](CustomStorage *storage){ + actualLog = storage->m_log; + }; + taskTree.onStorageDone(storage, collectLog); + taskTree.start(); + QCOMPARE(taskTree.isRunning(), runningAfterStart); if (runningAfterStart) { QTimer timer; @@ -490,142 +529,10 @@ void tst_TaskTree::processTree() timer.start(); eventLoop.exec(); QCOMPARE(timedOut, false); - QCOMPARE(processTree.isRunning(), false); + QCOMPARE(taskTree.isRunning(), false); } - QCOMPARE(processTree.progressValue(), taskCount); - QCOMPARE(m_log, expectedLog); - - const int expectedDoneCount = success ? 1 : 0; - const int expectedErrorCount = success ? 0 : 1; - QCOMPARE(doneCount, expectedDoneCount); - QCOMPARE(errorCount, expectedErrorCount); -} - -struct CustomStorage -{ - CustomStorage() { ++s_count; } - ~CustomStorage() { --s_count; } - Log m_log; - static int instanceCount() { return s_count; } -private: - static int s_count; -}; - -int CustomStorage::s_count = 0; - -void tst_TaskTree::storage_data() -{ - using namespace std::placeholders; - - QTest::addColumn("root"); - QTest::addColumn>("storage"); - QTest::addColumn("expectedLog"); - QTest::addColumn("runningAfterStart"); - QTest::addColumn("success"); - - TreeStorage storageLog; - - const auto setupProcessHelper = [storageLog, testAppPath = m_testAppPath] - (QtcProcess &process, const QStringList &args, int processId) { - process.setCommand(CommandLine(testAppPath, args)); - process.setProperty(s_processIdProperty, processId); - storageLog->m_log.append({processId, Handler::Setup}); - }; - const auto setupProcess = [setupProcessHelper](QtcProcess &process, int processId) { - setupProcessHelper(process, {"-return", "0"}, processId); - }; - const auto readResult = [storageLog](const QtcProcess &process) { - const int processId = process.property(s_processIdProperty).toInt(); - storageLog->m_log.append({processId, Handler::Done}); - }; - const auto groupSetup = [storageLog](int processId) { - storageLog->m_log.append({processId, Handler::GroupSetup}); - }; - const auto groupDone = [storageLog](int processId) { - storageLog->m_log.append({processId, Handler::GroupDone}); - }; - const auto rootDone = [storageLog] { - storageLog->m_log.append({-1, Handler::GroupDone}); - }; - - const Log expectedLog{{1, Handler::GroupSetup}, - {2, Handler::GroupSetup}, - {3, Handler::GroupSetup}, - {4, Handler::GroupSetup}, - {5, Handler::GroupSetup}, - {5, Handler::Setup}, - {5, Handler::Done}, - {5, Handler::GroupDone}, - {4, Handler::GroupDone}, - {3, Handler::GroupDone}, - {2, Handler::GroupDone}, - {1, Handler::GroupDone}, - {-1, Handler::GroupDone}}; - - const Group root { - Storage(storageLog), - Group { - Group { - Group { - Group { - Group { - Process(std::bind(setupProcess, _1, 5), readResult), - OnGroupSetup(std::bind(groupSetup, 5)), - OnGroupDone(std::bind(groupDone, 5)) - }, - OnGroupSetup(std::bind(groupSetup, 4)), - OnGroupDone(std::bind(groupDone, 4)) - }, - OnGroupSetup(std::bind(groupSetup, 3)), - OnGroupDone(std::bind(groupDone, 3)) - }, - OnGroupSetup(std::bind(groupSetup, 2)), - OnGroupDone(std::bind(groupDone, 2)) - }, - OnGroupSetup(std::bind(groupSetup, 1)), - OnGroupDone(std::bind(groupDone, 1)) - }, - OnGroupDone(rootDone) - }; - - QTest::newRow("Storage") << root << storageLog << expectedLog << true << true; -} - -void tst_TaskTree::storage() -{ - QFETCH(Group, root); - QFETCH(TreeStorage, storage); - QFETCH(Log, expectedLog); - QFETCH(bool, runningAfterStart); - QFETCH(bool, success); - - QVERIFY(storage.isValid()); - QCOMPARE(CustomStorage::instanceCount(), 0); - - Log actualLog; - QEventLoop eventLoop; - TaskTree processTree(root); - auto collectLog = [&actualLog](CustomStorage *storage){ - actualLog = storage->m_log; - }; - processTree.onStorageDone(storage, collectLog); - int doneCount = 0; - int errorCount = 0; - connect(&processTree, &TaskTree::done, this, [&doneCount, &eventLoop] { ++doneCount; eventLoop.quit(); }); - connect(&processTree, &TaskTree::errorOccurred, this, [&errorCount, &eventLoop] { ++errorCount; eventLoop.quit(); }); - processTree.start(); - QCOMPARE(CustomStorage::instanceCount(), 1); - QCOMPARE(processTree.isRunning(), runningAfterStart); - - QTimer timer; - connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit); - timer.setInterval(2000); - timer.setSingleShot(true); - timer.start(); - eventLoop.exec(); - - QVERIFY(!processTree.isRunning()); + QCOMPARE(taskTree.progressValue(), taskCount); QCOMPARE(actualLog, expectedLog); QCOMPARE(CustomStorage::instanceCount(), 0); @@ -650,8 +557,8 @@ void tst_TaskTree::storageDestructor() { QCOMPARE(CustomStorage::instanceCount(), 0); { - const auto setupProcess = [this](QtcProcess &process) { - process.setCommand(CommandLine(m_testAppPath, {"-sleep", "1"})); + const auto setupProcess = [testAppPath = m_testAppPath](QtcProcess &process) { + process.setCommand(CommandLine(testAppPath, {"-sleep", "1"})); }; const Group root { Storage(TreeStorage()),