diff --git a/src/qtism/common/collections/AbstractCollection.php b/src/qtism/common/collections/AbstractCollection.php index 2c3c57ccd..d17354245 100644 --- a/src/qtism/common/collections/AbstractCollection.php +++ b/src/qtism/common/collections/AbstractCollection.php @@ -96,6 +96,11 @@ public function count(): int return count($this->dataPlaceHolder); } + public function isEmpty(): bool + { + return empty($this->dataPlaceHolder); + } + /** * Return the current element of the collection while iterating. * diff --git a/src/qtism/data/AssessmentSection.php b/src/qtism/data/AssessmentSection.php index 58f0f59da..698be5585 100644 --- a/src/qtism/data/AssessmentSection.php +++ b/src/qtism/data/AssessmentSection.php @@ -288,6 +288,15 @@ public function getSectionParts(): SectionPartCollection */ public function setSectionParts(SectionPartCollection $sectionParts): void { + if (!$sectionParts->isEmpty()) { + /** @var SectionPart $sectionPart */ + foreach ($sectionParts as $sectionPart) { + $sectionPart->setParent($this); + } + + $sectionPart->setIsLast(true); + } + $this->sectionParts = $sectionParts; } @@ -320,4 +329,11 @@ public function getComponents(): QtiComponentCollection return new QtiComponentCollection($comp); } + + public function isLastSectionPart(SectionPart $sectionPart): bool + { + $sectionParts = $this->getSectionParts()->getArrayCopy(); + + return end($sectionParts) === $sectionPart; + } } diff --git a/src/qtism/data/SectionPart.php b/src/qtism/data/SectionPart.php index c146c58d0..298cfecd0 100644 --- a/src/qtism/data/SectionPart.php +++ b/src/qtism/data/SectionPart.php @@ -117,6 +117,10 @@ class SectionPart extends QtiComponent implements QtiIdentifiable, Shufflable */ private $timeLimits = null; + private ?SectionPart $parent = null; + + private bool $isLast = false; + /** * Create a new instance of SectionPart. * @@ -363,4 +367,24 @@ public function __clone() // Reset observers. $this->setObservers(new SplObjectStorage()); } + + public function getParent(): ?SectionPart + { + return $this->parent; + } + + public function setParent(SectionPart $parent): void + { + $this->parent = $parent; + } + + public function isLast(): bool + { + return $this->isLast; + } + + public function setIsLast(bool $isLast): void + { + $this->isLast = $isLast; + } } diff --git a/src/qtism/data/TestPart.php b/src/qtism/data/TestPart.php index b9e7a01bf..5453db2d9 100644 --- a/src/qtism/data/TestPart.php +++ b/src/qtism/data/TestPart.php @@ -348,20 +348,24 @@ public function getAssessmentSections(): SectionPartCollection */ public function setAssessmentSections(SectionPartCollection $assessmentSections): void { - if (count($assessmentSections) > 0) { - // Check that we have only AssessmentSection and/ord AssessmentSectionRef objects. - foreach ($assessmentSections as $assessmentSection) { - if (!$assessmentSection instanceof AssessmentSection && !$assessmentSection instanceof AssessmentSectionRef) { - $msg = 'A TestPart contain only contain AssessmentSection or AssessmentSectionRef objects.'; - throw new InvalidArgumentException($msg); - } - } + if ($assessmentSections->isEmpty()) { + throw new InvalidArgumentException('A TestPart must contain at least one AssessmentSection.'); + } - $this->assessmentSections = $assessmentSections; - } else { - $msg = 'A TestPart must contain at least one AssessmentSection.'; - throw new InvalidArgumentException($msg); + foreach ($assessmentSections as $assessmentSection) { + if ( + !$assessmentSection instanceof AssessmentSection + && !$assessmentSection instanceof AssessmentSectionRef + ) { + throw new InvalidArgumentException( + 'A TestPart contain only contain AssessmentSection or AssessmentSectionRef objects.' + ); + } } + + $assessmentSection->setIsLast(true); + + $this->assessmentSections = $assessmentSections; } /** @@ -419,4 +423,11 @@ public function __clone() { $this->setObservers(new SplObjectStorage()); } + + public function isLastSection(AssessmentSection $assessmentSection): bool + { + $sections = $this->getAssessmentSections()->getArrayCopy(); + + return end($sections) === $assessmentSection; + } } diff --git a/src/qtism/runtime/tests/AbstractSessionManager.php b/src/qtism/runtime/tests/AbstractSessionManager.php index f4ebb03c7..1c0012431 100644 --- a/src/qtism/runtime/tests/AbstractSessionManager.php +++ b/src/qtism/runtime/tests/AbstractSessionManager.php @@ -31,6 +31,7 @@ use qtism\data\IAssessmentItem; use qtism\data\NavigationMode; use qtism\data\SubmissionMode; +use qtism\data\TestPart; /** * The AbstractSessionManager class is a bed for instantiating @@ -159,6 +160,7 @@ protected function createRoute(AssessmentTest $test): Route { $routeStack = []; + /** @var TestPart $testPart */ foreach ($test->getTestParts() as $testPart) { $assessmentSectionStack = []; @@ -203,16 +205,6 @@ protected function createRoute(AssessmentTest $test): Route $route->appendRoute($r); } - // Add to the last item of the selection the branch rules of the AssessmentSection/testPart - // on which the selection is applied... Only if the route contains something (empty assessmentSection edge case). - if ($route->count() > 0) { - $route->getLastRouteItem()->addBranchRules($current->getBranchRules()); - - // Do the same as for branch rules for pre conditions, except that they must be - // attached on the first item of the route. - $route->getFirstRouteItem()->addPreConditions($current->getPreConditions()); - } - array_push($routeStack, $route); array_pop($assessmentSectionStack); } elseif ($current instanceof AssessmentItemRef) { @@ -227,6 +219,8 @@ protected function createRoute(AssessmentTest $test): Route $finalRoutes = $routeStack; $route = new SelectableRoute(); + + /** @var SelectableRoute $finalRoute */ foreach ($finalRoutes as $finalRoute) { $route->appendRoute($finalRoute); } diff --git a/src/qtism/runtime/tests/AssessmentTestSession.php b/src/qtism/runtime/tests/AssessmentTestSession.php index 84283c389..8085ca1ab 100644 --- a/src/qtism/runtime/tests/AssessmentTestSession.php +++ b/src/qtism/runtime/tests/AssessmentTestSession.php @@ -43,6 +43,8 @@ use qtism\data\IAssessmentItem; use qtism\data\NavigationMode; use qtism\data\processing\ResponseProcessing; +use qtism\data\rules\BranchRule; +use qtism\data\rules\PreConditionCollection; use qtism\data\ShowHide; use qtism\data\state\Weight; use qtism\data\storage\php\PhpStorageException; @@ -2406,10 +2408,12 @@ protected function nextRouteItem($ignoreBranchings = false, $ignorePreConditions $stop = false; while ($route->valid() === true && $stop === false) { + $branchRules = $route->current()->getEffectiveBranchRules(); + $numberOfBranchRules = $branchRules->count(); + // Branchings? - if ($ignoreBranchings === false && count($route->current()->getBranchRules()) > 0 && $this->mustApplyBranchRules() === true) { - $branchRules = $route->current()->getBranchRules(); - for ($i = 0; $i < count($branchRules); $i++) { + if ($ignoreBranchings === false && $numberOfBranchRules > 0 && $this->mustApplyBranchRules() === true) { + for ($i = 0; $i < $numberOfBranchRules; $i++) { $engine = new ExpressionEngine($branchRules[$i]->getExpression(), $this); $condition = $engine->process(); if ($condition !== null && $condition->getValue() === true) { @@ -2438,20 +2442,7 @@ protected function nextRouteItem($ignoreBranchings = false, $ignorePreConditions } // Preconditions on target? - if ($ignorePreConditions === false && $route->valid() === true && ($preConditions = $route->current()->getPreConditions()) && count($preConditions) > 0 && $this->mustApplyPreConditions() === true) { - for ($i = 0; $i < count($preConditions); $i++) { - $engine = new ExpressionEngine($preConditions[$i]->getExpression(), $this); - $condition = $engine->process(); - - if ($condition !== null && $condition->getValue() === true) { - // The item must be presented. - $stop = true; - break; - } - } - } else { - $stop = true; - } + $stop = !($ignorePreConditions === false) || $this->routeMatchesPreconditions($route); // After a first iteration, we will not performed branching again, as they are executed // as soon as we leave an item. Chains of branch rules are not expected. @@ -2465,6 +2456,47 @@ protected function nextRouteItem($ignoreBranchings = false, $ignorePreConditions } } + public function routeMatchesPreconditions(Route $route = null): bool + { + $route = $route ?? $this->getRoute(); + + if (!$route->valid()) { + return true; + } + + $routeItem = $route->current(); + $testPart = $routeItem->getTestPart(); + $navigationMode = $testPart->getNavigationMode(); + + if ($navigationMode === NavigationMode::LINEAR || $this->mustForcePreconditions()) { + return $this->preConditionsMatch($routeItem->getEffectivePreConditions()); + } + + if ($navigationMode === NavigationMode::NONLINEAR) { + return $this->preConditionsMatch($testPart->getPreConditions()); + } + + return true; + } + + private function preConditionsMatch(PreConditionCollection $preConditions): bool + { + if ($preConditions->count() === 0) { + return true; + } + + for ($i = 0; $i < $preConditions->count(); $i++) { + $engine = new ExpressionEngine($preConditions[$i]->getExpression(), $this); + $condition = $engine->process(); + + if ($condition === null || $condition->getValue() === false) { + return false; + } + } + + return true; + } + /** * Set the position in the Route at the very next TestPart in the Route sequence or, if the current * testPart is the last one of the test session, the test session ends gracefully. If the submission mode @@ -2483,8 +2515,21 @@ public function moveNextTestPart(): void $route = $this->getRoute(); $from = $route->current(); + $branchRules = $from->getTestPart()->getBranchRules(); while ($route->valid() === true && $route->current()->getTestPart() === $from->getTestPart()) { + /** @var BranchRule $branchRule */ + foreach ($branchRules as $branchRule) { + $engine = new ExpressionEngine($branchRule->getExpression(), $this); + $condition = $engine->process(); + + if ($condition !== null && $condition->getValue() === true) { + $route->branch($branchRule->getTarget()); + + break 2; + } + } + $route->next(); } @@ -3053,7 +3098,7 @@ public function isNextRouteItemPredictible(): bool } // Case 4. The next item has preconditions. - if ($this->mustApplyPreConditions(true) && count($this->getRoute()->getNext()->getPreConditions()) > 0) { + if ($this->mustApplyPreConditions(true)) { return false; } @@ -3133,7 +3178,24 @@ protected function mustApplyBranchRules(): bool */ protected function mustApplyPreConditions($nextRouteItem = false): bool { - $routeItem = ($nextRouteItem === false) ? $this->getCurrentRouteItem() : $this->getRoute()->getNext(); - return ($routeItem->getTestPart()->getNavigationMode() === NavigationMode::LINEAR || $this->mustForcePreconditions() === true); + if ($this->mustForcePreconditions()) { + return true; + } + + $routeItem = $nextRouteItem === false ? $this->getCurrentRouteItem() : $this->getRoute()->getNext(); + + if (!$routeItem instanceof RouteItem) { + return false; + } + + $testPart = $routeItem->getTestPart(); + $navigationMode = $testPart->getNavigationMode(); + + if ($navigationMode === NavigationMode::LINEAR) { + return $routeItem->getEffectivePreConditions()->count() > 0; + } + + // Now NonLinear Test part pre-conditions must be considered + return $navigationMode === NavigationMode::NONLINEAR && $testPart->getPreConditions()->count() > 0; } } diff --git a/src/qtism/runtime/tests/Route.php b/src/qtism/runtime/tests/Route.php index 6263cb33b..e2f36f71b 100644 --- a/src/qtism/runtime/tests/Route.php +++ b/src/qtism/runtime/tests/Route.php @@ -1117,10 +1117,11 @@ public function branch($identifier): void if ($targetRouteItems[$occurence]->getTestPart() !== $this->current()->getTestPart()) { // From IMS QTI: - // In case of an item or section, the target must refer to an item or section - // in the same testPart [...] - $msg = 'Branchings to items outside of the current testPart is forbidden by the QTI 2.1 specification.'; - throw new OutOfBoundsException($msg); + // In the case of an item or section, the target must refer to an item or section in the same test-part + // that has not yet been presented. + $this->next(); + + return; } $this->setPosition($this->getRouteItemPosition($targetRouteItems[$occurence])); @@ -1133,10 +1134,11 @@ public function branch($identifier): void if (isset($assessmentSectionIdentifierMap[$id])) { if ($assessmentSectionIdentifierMap[$id][0]->getTestPart() !== $this->current()->getTestPart()) { // From IMS QTI: - // In case of an item or section, the target must refer to an item or section - // in the same testPart [...] - $msg = 'Branchings to assessmentSections outside of the current testPart is forbidden by the QTI 2.1 specification.'; - throw new OutOfBoundsException($msg); + // In the case of an item or section, the target must refer to an item or section in the same test-part + // that has not yet been presented. + $this->next(); + + return; } // We branch to the first RouteItem belonging to the section. @@ -1148,14 +1150,6 @@ public function branch($identifier): void // Check for a testPart. $testPartIdentifierMap = $this->getTestPartIdentifierMap(); if (isset($testPartIdentifierMap[$id])) { - // We branch to the first RouteItem belonging to the testPart. - if ($testPartIdentifierMap[$id][0]->getTestPart() === $this->current()->getTestPart()) { - // From IMS QTI: - // For testParts, the target must refer to another testPart. - $msg = 'Cannot branch to the same testPart.'; - throw new OutOfBoundsException($msg); - } - // We branch to the first RouteItem belonging to the testPart. $this->setPosition($this->getRouteItemPosition($testPartIdentifierMap[$id][0])); diff --git a/src/qtism/runtime/tests/RouteItem.php b/src/qtism/runtime/tests/RouteItem.php index 444d19cbd..c29e9a75b 100644 --- a/src/qtism/runtime/tests/RouteItem.php +++ b/src/qtism/runtime/tests/RouteItem.php @@ -268,6 +268,30 @@ public function getPreConditions(): PreConditionCollection return $this->preConditions; } + /** + * Get the PreConditions that actually need to be applied considering all the parent elements: TestPart and Section + * + * @return PreConditionCollection A collection of PreCondition objects. + */ + public function getEffectivePreConditions(): PreConditionCollection + { + $routeItemPreConditions = new PreConditionCollection([]); + + foreach ($this->getTestPart()->getPreConditions() as $preCondition) { + $routeItemPreConditions->attach($preCondition); + } + + foreach ($this->getAssessmentSection()->getPreConditions() as $preCondition) { + $routeItemPreConditions->attach($preCondition); + } + + foreach ($this->getPreConditions() as $preCondition) { + $routeItemPreConditions->attach($preCondition); + } + + return $routeItemPreConditions; + } + /** * Set the PreCondition objects to be applied prior to the RouteItem. * @@ -426,4 +450,34 @@ public function getTimeLimits($excludeItem = false): RouteTimeLimitsCollection return $timeLimits; } + + public function getEffectiveBranchRules(): BranchRuleCollection + { + // Checking branching rules at the Item level + if (!$this->getBranchRules()->isEmpty()) { + return $this->getBranchRules(); + } + + if (!$this->getAssessmentItemRef()->isLast()) { + return new BranchRuleCollection(); + } + + $parentSection = $this->getAssessmentSection(); + + // Checking branching rules at the Section/Subsection level + // To get branching rules for the current section, you need to make sure that the current part of the + // section is the last part of the current section. + do { + if (!$parentSection->getBranchRules()->isEmpty()) { + return $parentSection->getBranchRules(); + } + + if (!$parentSection->isLast()) { + return new BranchRuleCollection(); + } + } while ($parentSection = $parentSection->getParent()); + + // Return branching rules from the Test Part level + return $this->getTestPart()->getBranchRules(); + } } diff --git a/test/qtismtest/runtime/tests/AssessmentTestSessionBranchingsTest.php b/test/qtismtest/runtime/tests/AssessmentTestSessionBranchingsTest.php index 7265502f1..9523d1fcb 100644 --- a/test/qtismtest/runtime/tests/AssessmentTestSessionBranchingsTest.php +++ b/test/qtismtest/runtime/tests/AssessmentTestSessionBranchingsTest.php @@ -248,4 +248,62 @@ public function testBranchingOnPreconditon(): void $this::assertNull($session['Q03.SCORE']); $this::assertSame(1.0, $session['Q04.SCORE']->getValue()); } + + public function testBranchingOnTestPartsSimple1(): void + { + $session = self::instantiate(self::samplesDir() . 'custom/runtime/branchings/branchings_testparts.xml'); + $session->beginTestSession(); + + // We are starting at item Q01, in testPart P01. + $this->assertEquals('Q01', $session->getCurrentAssessmentItemRef()->getIdentifier()); + + // Let's jump to testPart P03. + $session->beginAttempt(); + $session->endAttempt(new State([new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('GotoP03'))])); + $session->moveNext(); + + // We expect to land in testPart P03, item Q03. + $this->assertEquals('Q03', $session->getCurrentAssessmentItemRef()->getIdentifier()); + $this->assertEquals('P03', $session->getCurrentTestPart()->getIdentifier()); + } + + public function testBranchingRules(): void + { + $session = self::instantiate(self::samplesDir() . 'custom/runtime/branchings/branching_rules.xml'); + $session->beginTestSession(); + + $this->assertEquals('testPart-1', $session->getCurrentTestPart()->getIdentifier()); + $this->assertEquals('assessmentSection-1', $session->getCurrentAssessmentSection()->getIdentifier()); + $this->assertEquals('item-1', $session->getCurrentAssessmentItemRef()->getIdentifier()); + + $session->moveNext(); + + $this->assertEquals('testPart-1', $session->getCurrentTestPart()->getIdentifier()); + $this->assertEquals('assessmentSection-1', $session->getCurrentAssessmentSection()->getIdentifier()); + $this->assertEquals('item-3', $session->getCurrentAssessmentItemRef()->getIdentifier()); + + $session->moveNext(); + + $this->assertEquals('testPart-1', $session->getCurrentTestPart()->getIdentifier()); + $this->assertEquals('assessmentSection-3', $session->getCurrentAssessmentSection()->getIdentifier()); + $this->assertEquals('item-5', $session->getCurrentAssessmentItemRef()->getIdentifier()); + + $session->moveNext(); + + $this->assertEquals('testPart-3', $session->getCurrentTestPart()->getIdentifier()); + $this->assertEquals('assessmentSection-5', $session->getCurrentAssessmentSection()->getIdentifier()); + $this->assertEquals('item-7', $session->getCurrentAssessmentItemRef()->getIdentifier()); + + $session->moveNext(); + + $this->assertEquals('testPart-4', $session->getCurrentTestPart()->getIdentifier()); + $this->assertEquals('subsection-1', $session->getCurrentAssessmentSection()->getIdentifier()); + $this->assertEquals('item-9', $session->getCurrentAssessmentItemRef()->getIdentifier()); + + $session->moveNext(); + + $this->assertEquals('testPart-5', $session->getCurrentTestPart()->getIdentifier()); + $this->assertEquals('assessmentSection-8', $session->getCurrentAssessmentSection()->getIdentifier()); + $this->assertEquals('item-11', $session->getCurrentAssessmentItemRef()->getIdentifier()); + } } diff --git a/test/qtismtest/runtime/tests/AssessmentTestSessionPreConditionsTest.php b/test/qtismtest/runtime/tests/AssessmentTestSessionPreConditionsTest.php index 9030ba643..31a9af711 100644 --- a/test/qtismtest/runtime/tests/AssessmentTestSessionPreConditionsTest.php +++ b/test/qtismtest/runtime/tests/AssessmentTestSessionPreConditionsTest.php @@ -163,4 +163,35 @@ public function testKillerTestEpicWin(): void $this::assertFalse($testSession->isRunning()); } + + public function testTestParAndSectionAndItemPreConditionOnLinearTestWorks(): void + { + $testSession = self::instantiate(self::samplesDir() . 'custom/runtime/preconditions/preconditions_on_test_part_section_item_combined_linear.xml'); + $testSession->beginTestSession(); + $testSession->beginAttempt(); + $testSession->moveNext(); + + // P02, S03, Q04 are skipped due precondition, but Q04.1 is passed + $this::assertSame($testSession->getRoute()->current()->getAssessmentItemRef()->getIdentifier(), 'Q04.1'); + + $testSession->moveNext(); + + // P05 precondition passed + $this::assertSame($testSession->getRoute()->current()->getAssessmentItemRef()->getIdentifier(), 'Q05'); + + $testSession->moveNext(); + + // S06 precondition passed + $this::assertSame($testSession->getRoute()->current()->getAssessmentItemRef()->getIdentifier(), 'Q06'); + + $testSession->moveNext(); + + // S07 precondition passed + $this::assertSame($testSession->getRoute()->current()->getAssessmentItemRef()->getIdentifier(), 'Q07'); + + $testSession->moveNext(); + + // P08 is nonlinear, but it will be skipped, cause pre-conditions apply to non-linear test parts + $this::assertSame($testSession->getRoute()->current()->getAssessmentItemRef()->getIdentifier(), 'Q09'); + } } diff --git a/test/qtismtest/runtime/tests/RouteTest.php b/test/qtismtest/runtime/tests/RouteTest.php index a5b66b178..298f1b779 100644 --- a/test/qtismtest/runtime/tests/RouteTest.php +++ b/test/qtismtest/runtime/tests/RouteTest.php @@ -601,18 +601,18 @@ public function testBranchUnknownTarget(): void public function testBranchToAssessmentItemRefOutsideOfTestPart(): void { - $route = self::buildSimpleRoute(Route::class, 2, 1); - $this->expectException(OutOfBoundsException::class); - $this->expectExceptionMessage('Branchings to items outside of the current testPart is forbidden by the QTI 2.1 specification.'); - $route->branch('Q2'); + $route = self::buildSimpleRoute(Route::class, 2, 2); + $route->branch('Q3'); + + $this->assertEquals('Q2', $route->current()->getAssessmentItemRef()->getIdentifier()); } public function testBranchToSameTestPart(): void { $route = self::buildSimpleRoute(Route::class, 2, 1); - $this->expectException(OutOfBoundsException::class); - $this->expectExceptionMessage('Cannot branch to the same testPart.'); $route->branch('T1'); + + $this->assertEquals('T1', $route->current()->getTestPart()->getIdentifier()); } public function testBranchToAnotherTestPart(): void @@ -655,24 +655,27 @@ public function testBranchToSectionOutsideOfTestPart(): void $assessmentItemRef1 = new AssessmentItemRef('Q1', 'Q1.xml'); $assessmentItemRef2 = new AssessmentItemRef('Q2', 'Q2.xml'); + $assessmentItemRef3 = new AssessmentItemRef('Q3', 'Q3.xml'); $assessmentSection1 = new AssessmentSection('S1', 'Section 1', true); - $assessmentSection1->setSectionParts(new SectionPartCollection([$assessmentItemRef1])); + $assessmentSection1->setSectionParts(new SectionPartCollection([$assessmentItemRef1, $assessmentItemRef2])); $assessmentSection2 = new AssessmentSection('S2', 'Section 2', true); - $assessmentSection2->setSectionParts(new SectionPartCollection([$assessmentItemRef2])); + $assessmentSection2->setSectionParts(new SectionPartCollection([$assessmentItemRef3])); $testPart1 = new TestPart('T1', new AssessmentSectionCollection([$assessmentSection1])); $testPart2 = new TestPart('T2', new AssessmentSectionCollection([$assessmentSection2])); $assessmentTest = new AssessmentTest('Test1', 'Test 1', new TestPartCollection([$testPart1, $testPart2])); $route->addRouteItem($assessmentItemRef1, $assessmentSection1, $testPart1, $assessmentTest); - $route->addRouteItem($assessmentItemRef2, $assessmentSection2, $testPart2, $assessmentTest); - - $this->expectException(OutOfBoundsException::class); - $this->expectExceptionMessage('Branchings to assessmentSections outside of the current testPart is forbidden by the QTI 2.1 specification.'); + $route->addRouteItem($assessmentItemRef2, $assessmentSection1, $testPart1, $assessmentTest); + $route->addRouteItem($assessmentItemRef3, $assessmentSection2, $testPart2, $assessmentTest); $route->branch('S2'); + $currentRoute = $route->current(); + + $this->assertEquals('Q2', $currentRoute->getAssessmentItemRef()->getIdentifier()); + $this->assertEquals('S1', $currentRoute->getAssessmentSection()->getIdentifier()); } public function testGetRouteItemPositionUnknownRouteItem(): void diff --git a/test/samples/custom/runtime/branchings/branching_rules.xml b/test/samples/custom/runtime/branchings/branching_rules.xml new file mode 100644 index 000000000..cf9e3557e --- /dev/null +++ b/test/samples/custom/runtime/branchings/branching_rules.xml @@ -0,0 +1,103 @@ + + + + + true + + + + + true + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/samples/custom/runtime/branchings/branchings_testparts.xml b/test/samples/custom/runtime/branchings/branchings_testparts.xml new file mode 100644 index 000000000..881cf54d1 --- /dev/null +++ b/test/samples/custom/runtime/branchings/branchings_testparts.xml @@ -0,0 +1,37 @@ + + + + + + + + GotoP02 + + + + + + + GotoP03 + + + + + + + + + + + + + + + + + + + diff --git a/test/samples/custom/runtime/preconditions/preconditions_on_test_part_section_item_combined_linear.xml b/test/samples/custom/runtime/preconditions/preconditions_on_test_part_section_item_combined_linear.xml new file mode 100644 index 000000000..d18d736b8 --- /dev/null +++ b/test/samples/custom/runtime/preconditions/preconditions_on_test_part_section_item_combined_linear.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + false + + + + + + + + + + false + + + + + + + + + true + + + + true + + + + false + + + + + true + + + + + + + + true + + + + + + + + + + true + + + + + + + + + + true + + + + + + + + false + + + + + + + + + + + true + + + + +