public function testMarshall()
 {
     $identifier = 'myAssessmentTest';
     $title = 'My Assessment Test';
     $toolName = 'QTIStateMachine';
     $toolVersion = '1.0b';
     $assessmentSections = new AssessmentSectionCollection();
     $assessmentSections[] = new AssessmentSection('myAssessmentSection', 'My Assessment Section', true);
     $testParts = new TestPartCollection();
     $testParts[] = new TestPart('myTestPart', $assessmentSections);
     $div = new Div();
     $div->setContent(new FlowCollection(array(new TextRun('Feedback!'))));
     $testFeedBacks = new TestFeedbackCollection();
     $testFeedBacks[] = new TestFeedback('myFeedback', 'myOutcome', new FlowStaticCollection(array($div)), 'A Feedback');
     $outcomeRules = new OutcomeRuleCollection();
     $outcomeRules[] = new SetOutcomeValue('myOutcome', new BaseValue(BaseType::BOOLEAN, true));
     $outcomeProcessing = new OutcomeProcessing($outcomeRules);
     $outcomeDeclarations = new OutcomeDeclarationCollection();
     $outcomeDeclarations[] = new OutcomeDeclaration('myOutcome', BaseType::BOOLEAN);
     $component = new AssessmentTest($identifier, $title, $testParts);
     $component->setToolName($toolName);
     $component->setToolVersion($toolVersion);
     $component->setTestFeedbacks($testFeedBacks);
     $component->setOutcomeProcessing($outcomeProcessing);
     $component->setOutcomeDeclarations($outcomeDeclarations);
     $marshaller = $this->getMarshallerFactory('2.1.0')->createMarshaller($component);
     $element = $marshaller->marshall($component);
     $this->assertInstanceOf('\\DOMElement', $element);
     $this->assertEquals('assessmentTest', $element->nodeName);
     $this->assertEquals($identifier, $element->getAttribute('identifier'));
     $this->assertEquals($title, $element->getAttribute('title'));
     $this->assertEquals($toolName, $element->getAttribute('toolName'));
     $this->assertEquals($toolVersion, $element->getAttribute('toolVersion'));
     // testParts
     $this->assertEquals(1, $element->getElementsByTagName('testPart')->length);
     $this->assertTrue($element === $element->getElementsByTagName('testPart')->item(0)->parentNode);
     // assessmentSections
     $testPart = $element->getElementsByTagName('testPart')->item(0);
     $this->assertEquals(1, $element->getElementsByTagName('assessmentSection')->length);
     $this->assertTrue($testPart === $element->getElementsByTagName('assessmentSection')->item(0)->parentNode);
     // outcomeDeclarations
     $this->assertEquals(1, $element->getElementsByTagName('outcomeDeclaration')->length);
     $this->assertTrue($element === $element->getElementsByTagName('outcomeDeclaration')->item(0)->parentNode);
     // testFeedbacks
     $this->assertEquals(1, $element->getElementsByTagName('testFeedback')->length);
     $this->assertTrue($element === $element->getElementsByTagName('testFeedback')->item(0)->parentNode);
     // outcomeProcessing
     $this->assertEquals(1, $element->getElementsByTagName('outcomeProcessing')->length);
     $this->assertTrue($element === $element->getElementsByTagName('outcomeProcessing')->item(0)->parentNode);
 }
 /**
  * Append a QTI-SDK OutcomeRule object in an AssessmentTest's OutcomeProcessing.
  * 
  * In case of no OutcomeProcessing is set yet for the AssessmentTest $test object,
  * it will be automatically created, with the OutcomeRule $rule as its first
  * rule. Otherwise, the OutcomeRule $rule is simply appended to the existing
  * OutcomeProcessing object.
  * 
  * @param qtism\data\AssessmentTest $test A QTI-SDK AssessmentTest object.
  * @param qtism\data\rules\OutcomeRule A QTI-SDK OutcomeRule object.
  */
 private static function appendOutcomeRule(AssessmentTest $test, OutcomeRule $rule)
 {
     $outcomeProcessing = $test->getOutcomeProcessing();
     if ($outcomeProcessing === null) {
         $test->setOutcomeProcessing(new OutcomeProcessing(new OutcomeRuleCollection(array($rule))));
     } else {
         $outcomeProcessing->getOutcomeRules()[] = $rule;
     }
 }
 /**
  * Create a new instance of XmlCompactDocument from an XmlAssessmentTestDocument.
  *
  * @param XmlDocument $xmlAssessmentTestDocument An XmlAssessmentTestDocument object you want to store as a compact XML file.
  * @return XmlCompactDocument An XmlCompactAssessmentTestDocument object.
  * @throws XmlStorageException If an error occurs while transforming the XmlAssessmentTestDocument object into an XmlCompactAssessmentTestDocument object.
  */
 public static function createFromXmlAssessmentTestDocument(XmlDocument $xmlAssessmentTestDocument, FileResolver $itemResolver = null)
 {
     $compactAssessmentTest = new XmlCompactDocument();
     $identifier = $xmlAssessmentTestDocument->getDocumentComponent()->getIdentifier();
     $title = $xmlAssessmentTestDocument->getDocumentComponent()->getTitle();
     $assessmentTest = new AssessmentTest($identifier, $title);
     $assessmentTest->setOutcomeDeclarations($xmlAssessmentTestDocument->getDocumentComponent()->getOutcomeDeclarations());
     $assessmentTest->setOutcomeProcessing($xmlAssessmentTestDocument->getDocumentComponent()->getOutcomeProcessing());
     $assessmentTest->setTestFeedbacks($xmlAssessmentTestDocument->getDocumentComponent()->getTestFeedbacks());
     $assessmentTest->setTestParts($xmlAssessmentTestDocument->getDocumentComponent()->getTestParts());
     $assessmentTest->setTimeLimits($xmlAssessmentTestDocument->getDocumentComponent()->getTimeLimits());
     $assessmentTest->setToolName($xmlAssessmentTestDocument->getDocumentComponent()->getToolName());
     $assessmentTest->setToolVersion($xmlAssessmentTestDocument->getDocumentComponent()->getToolVersion());
     // File resolution.
     $sectionResolver = new LocalFileResolver($xmlAssessmentTestDocument->getUrl());
     if (is_null($itemResolver) === true) {
         $itemResolver = new LocalFileResolver($xmlAssessmentTestDocument->getUrl());
     } else {
         $itemResolver->setBasePath($xmlAssessmentTestDocument->getUrl());
     }
     // It simply consists of replacing assessmentItemRef and assessmentSectionRef elements.
     $trail = array();
     // trailEntry[0] = a component, trailEntry[1] = from where we are coming (parent).
     $mark = array();
     $root = $xmlAssessmentTestDocument->getDocumentComponent();
     array_push($trail, array($root, $root));
     while (count($trail > 0)) {
         $trailer = array_pop($trail);
         $component = $trailer[0];
         $previous = $trailer[1];
         if (!in_array($component, $mark) && count($component->getComponents()) > 0) {
             // First pass on a hierarchical node... go deeper in the n-ary tree.
             array_push($mark, $component);
             // We want to go back on this component.
             array_push($trail, $trailer);
             // Prepare further exploration.
             foreach ($component->getComponents()->getArrayCopy() as $comp) {
                 array_push($trail, array($comp, $component));
             }
         } else {
             if (in_array($component, $mark) || count($component->getComponents()) === 0) {
                 // Second pass on a hierarchical node (we are bubbling up accross the n-ary tree)
                 // OR
                 // Leaf node
                 if ($component instanceof AssessmentItemRef) {
                     // Transform the ref in an compact extended ref.
                     $compactRef = ExtendedAssessmentItemRef::createFromAssessmentItemRef($component);
                     // find the old one and replace it.
                     $previousParts = $previous->getSectionParts();
                     foreach ($previousParts as $k => $previousPart) {
                         if ($previousParts[$k] === $component) {
                             // If the previous processed component is an XmlAssessmentSectionDocument,
                             // it means that the given baseUri must be adapted.
                             $baseUri = $xmlAssessmentTestDocument->getUrl();
                             if ($component instanceof XmlDocument && $component->getDocumentComponent() instanceof AssessmentSection) {
                                 $baseUri = $component->getUrl();
                             }
                             $itemResolver->setBasePath($baseUri);
                             self::resolveAssessmentItemRef($compactRef, $itemResolver);
                             $previousParts->replace($component, $compactRef);
                             break;
                         }
                     }
                 } else {
                     if ($component instanceof AssessmentSectionRef) {
                         // We follow the unreferenced AssessmentSection as if it was
                         // the 1st pass.
                         $assessmentSection = self::resolveAssessmentSectionRef($component, $sectionResolver);
                         $previousParts = $previous->getSectionParts();
                         foreach ($previousParts as $k => $previousPart) {
                             if ($previousParts[$k] === $component) {
                                 $previousParts->replace($component, $assessmentSection);
                                 break;
                             }
                         }
                         array_push($trail, array($assessmentSection, $previous));
                     } else {
                         if ($component instanceof AssessmentSection) {
                             $assessmentSection = ExtendedAssessmentSection::createFromAssessmentSection($component);
                             $previousParts = $previous instanceof TestPart ? $previous->getAssessmentSections() : $previous->getSectionParts();
                             foreach ($previousParts as $k => $previousPart) {
                                 if ($previousParts[$k] === $component) {
                                     $previousParts->replace($component, $assessmentSection);
                                     break;
                                 }
                             }
                         } else {
                             if ($component === $root) {
                                 // 2nd pass on the root, we have to stop.
                                 $compactAssessmentTest->setDocumentComponent($assessmentTest);
                                 return $compactAssessmentTest;
                             }
                         }
                     }
                 }
             }
         }
     }
 }