diff --git a/src/libs/utils/tasktree.cpp b/src/libs/utils/tasktree.cpp index 528127a97cf..73e468f818a 100644 --- a/src/libs/utils/tasktree.cpp +++ b/src/libs/utils/tasktree.cpp @@ -87,6 +87,7 @@ public: void selectChildren(); void stop(); bool isRunning() const; + int taskCount() const; void childDone(bool success); void invokeEndHandler(bool success); void resetSuccessBit(); @@ -97,6 +98,7 @@ public: const TaskItem::ExecuteMode m_executeMode = TaskItem::ExecuteMode::Parallel; TaskItem::WorkflowPolicy m_workflowPolicy = TaskItem::WorkflowPolicy::StopOnError; const TaskItem::GroupHandler m_groupHandler; + int m_taskCount = 0; GroupConfig m_groupConfig; QList m_children; QList m_selectedChildren; @@ -116,7 +118,9 @@ public: bool start(); void stop(); - bool isRunning(); + bool isRunning() const; + bool isTask() const; + int taskCount() const; private: const TaskItem::TaskHandler m_taskHandler; @@ -154,8 +158,11 @@ TaskContainer::TaskContainer(TaskTreePrivate *taskTreePrivate, TaskContainer *pa , m_groupHandler(task.groupHandler()) { const QList &children = task.children(); - for (const TaskItem &child : children) - m_children.append(new TaskNode(m_taskTreePrivate, this, child)); + for (const TaskItem &child : children) { + TaskNode *node = new TaskNode(m_taskTreePrivate, this, child); + m_children.append(node); + m_taskCount += node->taskCount(); + } } TaskContainer::~TaskContainer() @@ -231,6 +238,11 @@ bool TaskContainer::isRunning() const return m_currentIndex >= 0; } +int TaskContainer::taskCount() const +{ + return m_taskCount; +} + void TaskContainer::childDone(bool success) { if ((m_workflowPolicy == TaskItem::WorkflowPolicy::StopOnDone && success) @@ -300,7 +312,7 @@ void TaskContainer::updateSuccessBit(bool success) bool TaskNode::start() { - if (!m_taskHandler.m_createHandler || !m_taskHandler.m_setupHandler) { + if (!isTask()) { m_container.start(); return true; } @@ -334,11 +346,21 @@ void TaskNode::stop() m_container.stop(); } -bool TaskNode::isRunning() +bool TaskNode::isRunning() const { return m_task || m_container.isRunning(); } +bool TaskNode::isTask() const +{ + return m_taskHandler.m_createHandler && m_taskHandler.m_setupHandler; +} + +int TaskNode::taskCount() const +{ + return isTask() ? 1 : m_container.taskCount(); +} + /*! \class Utils::TaskTree @@ -415,4 +437,9 @@ bool TaskTree::isRunning() const return d->m_root.isRunning(); } +int TaskTree::taskCount() const +{ + return d->m_root.taskCount(); +} + } // namespace Utils diff --git a/src/libs/utils/tasktree.h b/src/libs/utils/tasktree.h index 20bcce0725a..1a1a7150d3a 100644 --- a/src/libs/utils/tasktree.h +++ b/src/libs/utils/tasktree.h @@ -245,6 +245,7 @@ public: void start(); void stop(); bool isRunning() const; + int taskCount() const; signals: void done(); diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index a5c3a30facf..e899bc00fa3 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -113,6 +113,7 @@ void tst_TaskTree::processTree_data() 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)); @@ -156,6 +157,7 @@ void tst_TaskTree::processTree_data() OnGroupDone(rootDone) }; const Log emptyLog{{-1, Handler::GroupDone}}; + QTest::newRow("Empty") << emptyRoot << emptyLog << false << true << 0; const Group nestedRoot { Group { @@ -194,6 +196,7 @@ void tst_TaskTree::processTree_data() {2, Handler::GroupDone}, {1, Handler::GroupDone}, {-1, Handler::GroupDone}}; + QTest::newRow("Nested") << nestedRoot << nestedLog << true << true << 1; const Group parallelRoot { parallel, @@ -215,6 +218,7 @@ 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; const Group sequentialRoot { Process(std::bind(setupProcess, _1, 1), readResult), @@ -253,6 +257,9 @@ 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; const Group sequentialNestedRoot { Group { @@ -293,6 +300,8 @@ void tst_TaskTree::processTree_data() {2, Handler::GroupDone}, {1, Handler::GroupDone}, {-1, Handler::GroupDone}}; + QTest::newRow("SequentialNested") << sequentialNestedRoot << sequentialNestedLog + << true << true << 5; const Group sequentialErrorRoot { Process(std::bind(setupProcess, _1, 1), readResult), @@ -310,14 +319,8 @@ void tst_TaskTree::processTree_data() {3, Handler::Setup}, {3, Handler::Error}, {-1, Handler::GroupError}}; - - const QList simpleSequence { - Process(std::bind(setupProcess, _1, 1), readResult), - Process(std::bind(setupCrashProcess, _1, 2), readResult, readError), - Process(std::bind(setupProcess, _1, 3), readResult), - OnGroupDone(rootDone), - OnGroupError(rootError) - }; + QTest::newRow("SequentialError") << sequentialErrorRoot << sequentialErrorLog + << true << false << 5; const auto constructSimpleSequence = [=](const WorkflowPolicy &policy) { return Group { @@ -336,6 +339,7 @@ void tst_TaskTree::processTree_data() {2, Handler::Setup}, {2, Handler::Error}, {-1, Handler::GroupError}}; + QTest::newRow("StopOnError") << stopOnErrorRoot << stopOnErrorLog << true << false << 3; const Group continueOnErrorRoot = constructSimpleSequence(continueOnError); const Log continueOnErrorLog{{1, Handler::Setup}, @@ -345,11 +349,15 @@ void tst_TaskTree::processTree_data() {3, Handler::Setup}, {3, Handler::Done}, {-1, Handler::GroupError}}; + QTest::newRow("ContinueOnError") << continueOnErrorRoot << 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 + << true << true << 3; const Group continueOnDoneRoot = constructSimpleSequence(continueOnDone); const Log continueOnDoneLog{{1, Handler::Setup}, @@ -359,6 +367,7 @@ void tst_TaskTree::processTree_data() {3, Handler::Setup}, {3, Handler::Done}, {-1, Handler::GroupDone}}; + QTest::newRow("ContinueOnDone") << continueOnDoneRoot << continueOnDoneLog << true << true << 3; const Group optionalRoot { optional, @@ -372,6 +381,7 @@ void tst_TaskTree::processTree_data() {2, Handler::Setup}, {2, Handler::Error}, {-1, Handler::GroupDone}}; + QTest::newRow("Optional") << optionalRoot << optionalLog << true << true << 2; const auto stopWithDoneSetup = [] { return GroupConfig{GroupAction::StopWithDone}; }; const auto stopWithErrorSetup = [] { return GroupConfig{GroupAction::StopWithError}; }; @@ -396,10 +406,16 @@ void tst_TaskTree::processTree_data() const Log dynamicSetupDoneLog{{1, Handler::Setup}, {1, Handler::Done}, {-1, Handler::GroupDone}}; + QTest::newRow("DynamicSetupDone") << dynamicSetupDoneRoot << 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 + << true << false << 4; + const Group dynamicSetupAllRoot = constructDynamicSetup({continueAllSetup}); const Log dynamicSetupAllLog{{1, Handler::Setup}, {1, Handler::Done}, @@ -410,6 +426,9 @@ void tst_TaskTree::processTree_data() {4, Handler::Setup}, {4, Handler::Done}, {-1, Handler::GroupDone}}; + QTest::newRow("DynamicSetupAll") << dynamicSetupAllRoot << dynamicSetupAllLog + << true << true << 4; + const Group dynamicSetupSelRoot = constructDynamicSetup({continueSelSetup}); const Log dynamicSetupSelLog{{1, Handler::Setup}, {1, Handler::Done}, @@ -418,23 +437,8 @@ void tst_TaskTree::processTree_data() {4, Handler::Setup}, {4, Handler::Done}, {-1, Handler::GroupDone}}; - - QTest::newRow("Empty") << emptyRoot << emptyLog << false << true; - QTest::newRow("Nested") << nestedRoot << nestedLog << true << true; - QTest::newRow("Parallel") << parallelRoot << parallelLog << true << true; - QTest::newRow("Sequential") << sequentialRoot << sequentialLog << true << true; - QTest::newRow("SequentialEncapsulated") << sequentialEncapsulatedRoot << sequentialLog << true << true; - QTest::newRow("SequentialNested") << sequentialNestedRoot << sequentialNestedLog << true << true; - QTest::newRow("SequentialError") << sequentialErrorRoot << sequentialErrorLog << true << false; - QTest::newRow("StopOnError") << stopOnErrorRoot << stopOnErrorLog << true << false; - QTest::newRow("ContinueOnError") << continueOnErrorRoot << continueOnErrorLog << true << false; - QTest::newRow("StopOnDone") << stopOnDoneRoot << stopOnDoneLog << true << true; - QTest::newRow("ContinueOnDone") << continueOnDoneRoot << continueOnDoneLog << true << true; - QTest::newRow("Optional") << optionalRoot << optionalLog << true << true; - QTest::newRow("DynamicSetupDone") << dynamicSetupDoneRoot << dynamicSetupDoneLog << true << true; - QTest::newRow("DynamicSetupError") << dynamicSetupErrorRoot << dynamicSetupErrorLog << true << false; - QTest::newRow("DynamicSetupAll") << dynamicSetupAllRoot << dynamicSetupAllLog << true << true; - QTest::newRow("DynamicSetupSelected") << dynamicSetupSelRoot << dynamicSetupSelLog << true << true; + QTest::newRow("DynamicSetupSelected") << dynamicSetupSelRoot << dynamicSetupSelLog + << true << true << 4; } void tst_TaskTree::processTree() @@ -446,9 +450,11 @@ void tst_TaskTree::processTree() QFETCH(Log, expectedLog); QFETCH(bool, runningAfterStart); QFETCH(bool, success); + QFETCH(int, taskCount); QEventLoop eventLoop; TaskTree processTree(root); + QCOMPARE(processTree.taskCount(), taskCount); int doneCount = 0; int errorCount = 0; connect(&processTree, &TaskTree::done, this, [&doneCount, &eventLoop] { ++doneCount; eventLoop.quit(); });