protected static function instantiate($url)
 {
     $doc = new XmlCompactDocument();
     $doc->load($url);
     $manager = new SessionManager();
     return $manager->createAssessmentTestSession($doc->getDocumentComponent());
 }
 public function setUp()
 {
     parent::setUp();
     $test = new XmlCompactDocument();
     $test->load(self::samplesDir() . 'custom/runtime/linear_5_items.xml');
     $this->setTest($test->getDocumentComponent());
 }
Exemple #3
0
 public function testSimpleSave()
 {
     $doc = new XmlCompactDocument();
     $doc->load(self::samplesDir() . 'custom/php/php_storage_simple.xml');
     $phpDoc = new PhpDocument('2.1', $doc->getDocumentComponent());
     $file = tempnam('/tmp', 'qsm');
     $phpDoc->save($file);
     unlink($file);
 }
 public function setUp()
 {
     parent::setUp();
     $testFilePath = self::samplesDir() . 'custom/runtime/itemsubset.xml';
     $doc = new XmlCompactDocument();
     $doc->load($testFilePath);
     $sessionManager = new SessionManager();
     $testSession = $sessionManager->createAssessmentTestSession($doc->getDocumentComponent());
     $testSession->beginTestSession();
     $this->setTestSession($testSession);
 }
 public function testClassSelection()
 {
     $doc = new XmlCompactDocument();
     $doc->load(self::samplesDir() . 'custom/runtime/itemsubset.xml');
     $iterator = new QtiComponentIterator($doc->getDocumentComponent(), array('responseProcessing'));
     $i = 0;
     foreach ($iterator as $responseProcessing) {
         $this->assertEquals($iterator->key(), 'responseProcessing');
         $i++;
     }
     $this->assertEquals(7, $i);
 }
 public function testTestResultsSubmissionNonLinearEnd()
 {
     // This test focuses on test results submission at outcome processing time.
     $file = self::samplesDir() . 'custom/runtime/results_linear.xml';
     $doc = new XmlCompactDocument();
     $doc->load($file);
     $factory = new SimpleResultsSubmittableTestSessionFactory();
     $testSession = $factory->createAssessmentTestSession($doc->getDocumentComponent());
     $testSession->setTestResultsSubmission(TestResultsSubmission::END);
     $this->assertEquals($testSession->getState(), AssessmentTestSessionState::INITIAL);
     $testSession->beginTestSession();
     $this->assertEquals($testSession->getState(), AssessmentTestSessionState::INTERACTING);
     // Q01 - Failure
     $testSession->beginAttempt();
     $testSession->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new Identifier('ChoiceB')))));
     $this->assertSame(0.0, $testSession['Q01.SCORE']->getValue());
     $testSession->moveNext();
     // Q02 - Success
     $testSession->beginAttempt();
     $testSession->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new Identifier('ChoiceB')))));
     $this->assertSame(1.0, $testSession['Q02.SCORE']->getValue());
     $testSession->moveNext();
     // Q03 - Success
     $testSession->beginAttempt();
     $testSession->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new Identifier('ChoiceC')))));
     $this->assertSame(1.0, $testSession['Q03.SCORE']->getValue());
     $testSession->moveNext();
     $this->assertEquals(AssessmentTestSessionState::CLOSED, $testSession->getState());
     // -- Let's test the submitted results.
     $submittedTestResults = $testSession->getSubmittedTestResults();
     $submittedItemResults = $testSession->getSubmittedItemResults();
     // Test Item Q01.
     $this->assertSame(0.0, $submittedItemResults['Q01.0.SCORE'][0]->getValue());
     // Test Item Q02.
     $this->assertSame(1.0, $submittedItemResults['Q02.0.SCORE'][0]->getValue());
     // Test Item Q03.
     $this->assertSame(1.0, $submittedItemResults['Q03.0.SCORE'][0]->getValue());
     // Test Results (submitted once).
     $this->assertSame(round(0.66666, 3), round($submittedTestResults['TEST_SCORE'][0]->getValue(), 3));
     $this->assertEquals(1, count($submittedTestResults['TEST_SCORE']));
 }
 public function testSeekPosition()
 {
     $doc = new XmlCompactDocument();
     $doc->load(self::samplesDir() . 'custom/runtime/itemsubset.xml');
     $seeker = new AssessmentTestSeeker($doc->getDocumentComponent(), array('assessmentItemRef', 'assessmentSection'));
     $this->assertEquals(1, $seeker->seekPosition($doc->getDocumentComponent()->getComponentByIdentifier('Q02')));
     $this->assertEquals(0, $seeker->seekPosition($doc->getDocumentComponent()->getComponentByIdentifier('Q01')));
     $this->assertEquals(0, $seeker->seekPosition($doc->getDocumentComponent()->getComponentByIdentifier('S01')));
     $this->assertEquals(2, $seeker->seekPosition($doc->getDocumentComponent()->getComponentByIdentifier('S03')));
     $this->assertEquals(2, $seeker->seekPosition($doc->getDocumentComponent()->getComponentByIdentifier('Q03')));
     $this->assertEquals(1, $seeker->seekPosition($doc->getDocumentComponent()->getComponentByIdentifier('S02')));
     try {
         $pos = $seeker->seekPosition(new AssessmentItemRef('Q05', 'Q05.xml'));
         $this->assertFalse(true, "Nothing should be found for Q05.");
     } catch (OutOfBoundsException $e) {
         $this->assertTrue(true);
     }
     try {
         $pos = $seeker->seekPosition(new Correct('Q01.SCORE'));
         $this->assertFalse(true, "The 'correct' QTI class is not registered with the AssessmentTestSeeker object.");
     } catch (OutOfBoundsException $e) {
         $this->assertTrue(true);
     }
 }
 /**
  * Get the route (the way items are delivered into a test).
  * This method will compute the shuffling and other predefined conditions to take the test.
  *
  * @param string $testFilePath - the path of the QTI Test definition
  * @return array the test structure as it should be delivered.
  */
 private function getRoute($testFilePath)
 {
     $route = array();
     // Load the test definition.
     $testDefinition = new XmlDocument();
     $testDefinition->load($testFilePath);
     // Make the test definition a compact one. Compact tests combine all needed
     // information to run a test instance.
     $resolver = new taoQtiTest_helpers_ItemResolver();
     $compactTestDef = XmlCompactDocument::createFromXmlAssessmentTestDocument($testDefinition, $resolver);
     $sessionManager = new SessionManager();
     $testSession = $sessionManager->createAssessmentTestSession($compactTestDef->getDocumentComponent());
     $assessmentTest = $testSession->getAssessmentTest();
     $renderingEngine = new XhtmlRenderingEngine();
     $testPartId = null;
     $sectionId = null;
     //We are getting items with their respective test part and sections, so we need to restructure it
     foreach ($testSession->getRoute() as $routeItem) {
         $item = array('id' => $routeItem->getAssessmentItemRef()->getIdentifier(), 'href' => $routeItem->getAssessmentItemRef()->getHref());
         $routeSections = $routeItem->getAssessmentSections()->getArrayCopy();
         $lastSection = $routeSections[count($routeSections) - 1];
         if ($sectionId != $lastSection->getIdentifier() || $testPartId != $routeItem->getTestPart()->getIdentifier()) {
             $sectionId = $lastSection->getIdentifier();
             $rubricBlocks = array();
             foreach ($routeItem->getAssessmentSections() as $section) {
                 foreach ($section->getRubricBlocks() as $rubricBlock) {
                     $xmlRendering = $renderingEngine->render($rubricBlock);
                     $strRendering = $xmlRendering->saveXML($xmlRendering->documentElement);
                     $finalRendering = '';
                     // No formatting at all :) !
                     foreach (preg_split('/\\n|\\r/u', $strRendering, -1, PREG_SPLIT_NO_EMPTY) as $line) {
                         $finalRendering .= trim($line);
                     }
                     $rubricBlocks[] = $finalRendering;
                 }
             }
             $section = array('id' => $section->getIdentifier(), 'title' => $section->getTitle(), 'rubricBlock' => $rubricBlocks, 'items' => array($item));
             if ($testPartId != $routeItem->getTestPart()->getIdentifier()) {
                 $testPartId = $routeItem->getTestPart()->getIdentifier();
                 $route[] = array('id' => $testPartId, 'sections' => array($section));
             } else {
                 $route = $this->addSectionToRoute($route, $testPartId, $section);
             }
         } else {
             $route = $this->addItemToRoute($route, $testPartId, $sectionId, $item);
         }
     }
     return array('id' => $assessmentTest->getIdentifier(), 'title' => $assessmentTest->getTitle(), 'testParts' => $route);
 }
 /**
  * @dataProvider branchingMultipleOccurencesProvider
  */
 public function testBranchingMultipleOccurences($response, $expectedTarget, $occurence)
 {
     // This test aims at testing the possibility to jump
     // on a particular item ref occurence.
     $doc = new XmlCompactDocument('1.0');
     $doc->load(self::samplesDir() . 'custom/runtime/branchings/branchings_multiple_occurences.xml');
     $manager = new SessionManager();
     $testSession = $manager->createAssessmentTestSession($doc->getDocumentComponent());
     $testSession->beginTestSession();
     $testSession->beginAttempt();
     if (empty($response) === true) {
         $testSession->skip();
         $testSession->moveNext();
     } else {
         $testSession->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, $response))));
         $testSession->moveNext();
     }
     $this->assertEquals($expectedTarget, $testSession->getCurrentAssessmentItemRef()->getIdentifier());
     $this->assertEquals($occurence, $testSession->getCurrentAssessmentItemRefOccurence());
 }
 public function testWritePendingResponses()
 {
     $doc = new XmlCompactDocument();
     $doc->load(self::samplesDir() . 'custom/runtime/itemsubset_simultaneous.xml');
     $seeker = new AssessmentTestSeeker($doc->getDocumentComponent(), array('assessmentItemRef', 'assessmentSection', 'testPart', 'outcomeDeclaration', 'responseDeclaration', 'branchRule', 'preCondition'));
     $stream = new MemoryStream();
     $stream->open();
     $access = new QtiBinaryStreamAccess($stream, new FileSystemFileManager());
     $factory = new SessionManager();
     $session = $factory->createAssessmentTestSession($doc->getDocumentComponent());
     $session->beginTestSession();
     $session->beginAttempt();
     $session->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('ChoiceB')))));
     $store = $session->getPendingResponseStore();
     $pendingResponses = $store->getPendingResponses($doc->getDocumentComponent()->getComponentByIdentifier('Q01'));
     $access->writePendingResponses($seeker, $pendingResponses);
     $stream->rewind();
     $pendingResponses = $access->readPendingResponses($seeker);
     $state = $pendingResponses->getState();
     $this->assertEquals('ChoiceB', $state['RESPONSE']->getValue());
     $this->assertEquals('Q01', $pendingResponses->getAssessmentItemRef()->getIdentifier());
     $this->assertEquals(0, $pendingResponses->getOccurence());
     $this->assertInternalType('integer', $pendingResponses->getOccurence());
 }
 /**
  * Explode the rubric blocks of the test definition into separate QTI-XML files and
  * remove the compact XML document from the file system (useless for
  * the rest of the compilation process).
  * 
  * @param XmlCompactDocument $compiledDoc
  */
 protected function explodeRubricBlocks(XmlCompactDocument $compiledDoc)
 {
     $privateDir = $this->getPrivateDirectory();
     $explodedRubricBlocks = $compiledDoc->explodeRubricBlocks();
     foreach ($explodedRubricBlocks as $href => $rubricBlock) {
         $doc = new XmlDocument();
         $doc->setDocumentComponent($rubricBlock);
         $data = $doc->saveToString();
         $privateDir->write($href, $data);
     }
 }
 public function testFiles()
 {
     $doc = new XmlCompactDocument();
     $doc->load(self::samplesDir() . 'custom/runtime/files/files.xml');
     $test = $doc->getDocumentComponent();
     $sessionManager = new SessionManager($doc->getDocumentComponent());
     $storage = new TemporaryQtiBinaryStorage($sessionManager, new BinaryAssessmentTestSeeker($test));
     $session = $storage->instantiate($test);
     $session->beginTestSession();
     $sessionId = $session->getSessionId();
     // --- Q01 - files_1.txt = ('text.txt', 'text/plain', 'Some text...')
     $session->beginAttempt();
     $filepath = self::samplesDir() . 'datatypes/file/files_1.txt';
     $session->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::FILE, FileSystemFile::retrieveFile($filepath)))));
     $session->moveNext();
     $this->assertInstanceOf('qtism\\common\\datatypes\\File', $session['Q01.RESPONSE']);
     $this->assertEquals('text.txt', $session['Q01.RESPONSE']->getFilename());
     $this->assertEquals('text/plain', $session['Q01.RESPONSE']->getMimeType());
     $this->assertEquals('Some text...', $session['Q01.RESPONSE']->getData());
     // Let's persist and retrieve and look if we have the same value in Q01.RESPONSE.
     $storage->persist($session);
     unset($session);
     $session = $storage->retrieve($test, $sessionId);
     $this->assertInstanceOf('qtism\\common\\datatypes\\File', $session['Q01.RESPONSE']);
     $this->assertEquals('text.txt', $session['Q01.RESPONSE']->getFilename());
     $this->assertEquals('text/plain', $session['Q01.RESPONSE']->getMimeType());
     $this->assertEquals('Some text...', $session['Q01.RESPONSE']->getData());
     // --- Q02 - files_2.txt = ('', 'text/html', '<img src="/qtism/img.png"/>')
     $session->beginAttempt();
     $filepath = self::samplesDir() . 'datatypes/file/files_2.txt';
     $session->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::FILE, FileSystemFile::retrieveFile($filepath)))));
     $session->moveNext();
     $this->assertInstanceOf('qtism\\common\\datatypes\\File', $session['Q02.RESPONSE']);
     $this->assertEquals('', $session['Q02.RESPONSE']->getFilename());
     $this->assertEquals('text/html', $session['Q02.RESPONSE']->getMimeType());
     $this->assertEquals('<img src="/qtism/img.png"/>', $session['Q02.RESPONSE']->getData());
     // Again, we persist and retrieve.
     $storage->persist($session);
     unset($session);
     $session = $storage->retrieve($test, $sessionId);
     // We now test all the collected variables.
     $this->assertInstanceOf('qtism\\common\\datatypes\\File', $session['Q01.RESPONSE']);
     $this->assertEquals('text.txt', $session['Q01.RESPONSE']->getFilename());
     $this->assertEquals('text/plain', $session['Q01.RESPONSE']->getMimeType());
     $this->assertEquals('Some text...', $session['Q01.RESPONSE']->getData());
     $this->assertInstanceOf('qtism\\common\\datatypes\\File', $session['Q02.RESPONSE']);
     $this->assertEquals('', $session['Q02.RESPONSE']->getFilename());
     $this->assertEquals('text/html', $session['Q02.RESPONSE']->getMimeType());
     $this->assertEquals('<img src="/qtism/img.png"/>', $session['Q02.RESPONSE']->getData());
     // --- Q03 - files_3.txt ('empty.txt', 'text/plain', '')
     $session->beginAttempt();
     $filepath = self::samplesDir() . 'datatypes/file/files_3.txt';
     $session->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::FILE, FileSystemFile::retrieveFile($filepath)))));
     $session->moveNext();
     $this->assertFalse($session->isRunning());
     $this->assertInstanceOf('qtism\\common\\datatypes\\File', $session['Q02.RESPONSE']);
     $this->assertEquals('empty.txt', $session['Q03.RESPONSE']->getFilename());
     $this->assertEquals('text/plain', $session['Q03.RESPONSE']->getMimeType());
     $this->assertEquals('', $session['Q03.RESPONSE']->getData());
     $storage->persist($session);
     unset($session);
     $session = $storage->retrieve($test, $sessionId);
     // Final big check.
     $this->assertInstanceOf('qtism\\common\\datatypes\\File', $session['Q01.RESPONSE']);
     $this->assertEquals('text.txt', $session['Q01.RESPONSE']->getFilename());
     $this->assertEquals('text/plain', $session['Q01.RESPONSE']->getMimeType());
     $this->assertEquals('Some text...', $session['Q01.RESPONSE']->getData());
     $this->assertInstanceOf('qtism\\common\\datatypes\\File', $session['Q02.RESPONSE']);
     $this->assertEquals('', $session['Q02.RESPONSE']->getFilename());
     $this->assertEquals('text/html', $session['Q02.RESPONSE']->getMimeType());
     $this->assertEquals('<img src="/qtism/img.png"/>', $session['Q02.RESPONSE']->getData());
     $this->assertInstanceOf('qtism\\common\\datatypes\\File', $session['Q02.RESPONSE']);
     $this->assertEquals('empty.txt', $session['Q03.RESPONSE']->getFilename());
     $this->assertEquals('text/plain', $session['Q03.RESPONSE']->getMimeType());
     $this->assertEquals('', $session['Q03.RESPONSE']->getData());
 }
 public function testCreateFromAssessmentTestEndAttemptIdentifiers()
 {
     $doc = new XmlDocument('2.1');
     $file = self::samplesDir() . 'custom/test_contains_endattemptinteractions.xml';
     $doc->load($file);
     $compactDoc = XmlCompactDocument::createFromXmlAssessmentTestDocument($doc, new LocalFileResolver());
     // ExtendedAssessmentItemRefs!
     $assessmentItemRefs = $compactDoc->getDocumentComponent()->getComponentsByClassName('assessmentItemRef');
     $this->assertEquals(2, count($assessmentItemRefs));
     $assessmentItemRef = $assessmentItemRefs[0];
     $endAttemptIdentifiers = $assessmentItemRef->getEndAttemptIdentifiers();
     $this->assertEquals(1, count($endAttemptIdentifiers));
     $this->assertEquals('HINT', $endAttemptIdentifiers[0]);
     $assessmentItemRef = $assessmentItemRefs[1];
     $endAttemptIdentifiers = $assessmentItemRef->getEndAttemptIdentifiers();
     $this->assertEquals(2, count($endAttemptIdentifiers));
     $this->assertEquals('LOST', $endAttemptIdentifiers[0]);
     $this->assertEquals('LOST2', $endAttemptIdentifiers[1]);
 }
 public function testEmptySection()
 {
     // Aims at testing that even a section of the test is empty,
     // it is simply ignored at runtime.
     $doc = new XmlCompactDocument();
     $doc->load(self::samplesDir() . 'custom/runtime/empty_section.xml');
     $manager = new SessionManager();
     $session = $manager->createAssessmentTestSession($doc->getDocumentComponent());
     $session->beginTestSession();
     // First section contains a single item.
     $this->assertEquals('Q01', $session->getCurrentAssessmentItemRef()->getIdentifier());
     $session->beginAttempt();
     $session->skip();
     $session->moveNext();
     // The second section is empty, moveNext() goes to the end of the current route,
     // and the session is then closed.
     $this->assertEquals(AssessmentTestSessionState::CLOSED, $session->getState());
 }
 public function testIsTimeout()
 {
     $doc = new XmlCompactDocument();
     $doc->load(self::samplesDir() . 'custom/runtime/linear_5_items.xml');
     $manager = new SessionManager();
     $session = $manager->createAssessmentTestSession($doc->getDocumentComponent());
     // If the session has not begun, the method systematically returns false.
     $this->assertFalse($session->isTimeout());
     // If no time limits in force, the test session is never considered timeout while running.
     $session->beginTestSession();
     $this->assertSame(0, $session->isTimeout());
     // Q01.
     $session->beginAttempt();
     $this->assertSame(0, $session->isTimeout());
     $session->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new Identifier('ChoiceA')))));
     $this->assertSame(0, $session->isTimeout());
     $session->moveNext();
     // Q02.
     $session->beginAttempt();
     $this->assertSame(0, $session->isTimeout());
     $session->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new Identifier('ChoiceB')))));
     $this->assertSame(0, $session->isTimeout());
     $session->moveNext();
     // Q03.
     $session->beginAttempt();
     $this->assertSame(0, $session->isTimeout());
     $session->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new Identifier('ChoiceC')))));
     $this->assertSame(0, $session->isTimeout());
     $session->moveNext();
     // Q04.
     $session->beginAttempt();
     $this->assertSame(0, $session->isTimeout());
     $session->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new Identifier('ChoiceD')))));
     $this->assertSame(0, $session->isTimeout());
     $session->moveNext();
     // Q05.
     $session->beginAttempt();
     $this->assertSame(0, $session->isTimeout());
     $session->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new Identifier('ChoiceE')))));
     $this->assertSame(0, $session->isTimeout());
     $session->moveNext();
     // If the session is closed, the method systematically returns false.
     $this->assertEquals(AssessmentTestSessionState::CLOSED, $session->getState());
     $this->assertFalse($session->isTimeout());
 }
 /**
  * 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;
                             }
                         }
                     }
                 }
             }
         }
     }
 }
 public function testMultipleOccurences()
 {
     $doc = new XmlCompactDocument();
     $doc->load(self::samplesDir() . 'custom/runtime/scenario_basic_nonadaptive_linear_singlesection_withreplacement.xml');
     $sessionManager = new SessionManager();
     $session = $sessionManager->createAssessmentTestSession($doc->getDocumentComponent());
     $variableExpr = $this->createComponentFromXml('<variable identifier="Q01.SCORE"/>');
     $occurenceVariableExpression = $this->createComponentFromXml('<variable identifier="Q01.1.SCORE"/>');
     $variableProcessor = new VariableProcessor($variableExpr);
     $variableProcessor->setState($session);
     // non begun test session.
     $this->assertSame(null, $variableProcessor->process());
     $variableProcessor->setExpression($occurenceVariableExpression);
     $this->assertSame(null, $variableProcessor->process());
     // begun test session.
     $variableProcessor->setExpression($variableExpr);
     $session->beginTestSession();
     // Why not 0.0? Because when using a non sequenced variable identifier
     // for an item with multiple occurence, the very last instance submitted becomes
     // the item where the values will be pulled out. No instances were submitted yet
     // and NULL is returned.
     $this->assertSame(null, $variableProcessor->process());
     $variableProcessor->setExpression($occurenceVariableExpression);
     // Why not NULL? Because we are in a linear test and Q01 is eligible for selection.
     // The item session is then instantiated. Outcome variables are set to their default
     // when the item session instantiation occurs.
     $this->assertSame(0.0, $variableProcessor->process()->getValue());
     // Q01.1
     $session->beginAttempt();
     $session->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new Identifier('ChoiceA')))));
     $variableProcessor->setExpression($variableExpr);
     $result = $variableProcessor->process();
     // Null because submission mode is individual...
     $this->assertSame(null, $result);
     $variableProcessor->setExpression($occurenceVariableExpression);
     $result = $variableProcessor->process();
     $this->assertInstanceOf('qtism\\common\\datatypes\\Float', $result);
     $this->assertEquals(1.0, $result->getValue());
     $session->moveNext();
     // Q01.2
     $session->beginAttempt();
     $session->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new Identifier('ChoiceB')))));
     $variableProcessor->setExpression($variableExpr);
     $result = $variableProcessor->process();
     $this->assertSame(null, $result);
     // $occurenceVariableExpression still targets Q01.1
     $variableProcessor->setExpression($occurenceVariableExpression);
     $result = $variableProcessor->process();
     $this->assertInstanceOf('qtism\\common\\datatypes\\Float', $result);
     $this->assertEquals(1.0, $result->getValue());
     // $occurenceVariableExpression now targets Q01.2
     $occurenceVariableExpression->setIdentifier('Q01.2.SCORE');
     $result = $variableProcessor->process();
     $this->assertInstanceOf('qtism\\common\\datatypes\\Float', $result);
     $this->assertEquals(0.0, $result->getValue());
 }
 public function testMultipleOccurences()
 {
     $doc = new XmlCompactDocument();
     $doc->load(self::samplesDir() . 'custom/runtime/scenario_basic_nonadaptive_linear_singlesection_withreplacement.xml');
     $sessionManager = new SessionManager();
     $session = $sessionManager->createAssessmentTestSession($doc->getDocumentComponent());
     $variableExpr = $this->createComponentFromXml('<variable identifier="Q01.SCORE"/>');
     $occurenceVariableExpression = $this->createComponentFromXml('<variable identifier="Q01.1.SCORE"/>');
     $variableProcessor = new VariableProcessor($variableExpr);
     $variableProcessor->setState($session);
     // non begun test session.
     $this->assertSame(null, $variableProcessor->process());
     $variableProcessor->setExpression($occurenceVariableExpression);
     $this->assertSame(null, $variableProcessor->process());
     // begun test session.
     $variableProcessor->setExpression($variableExpr);
     $session->beginTestSession();
     // Why not 0.0? Because we are in individual mode.
     $variableProcessor->setExpression($occurenceVariableExpression);
     // Why not NULL? Because we are in a linear test and Q01 is eligible for selection.
     // The item session is then instantiated. Outcome variables are set to their default
     // when the item session instantiation occurs.
     $this->assertSame(0.0, $variableProcessor->process()->getValue());
     // Q01.1
     $session->beginAttempt();
     $session->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('ChoiceA')))));
     $variableProcessor->setExpression($variableExpr);
     $result = $variableProcessor->process();
     // Null because submission mode is individual...
     // From IMS QTI:
     // The value of an item variable taken from an item instantiated multiple times from the same
     // assessmentItemRef (through the use of selection withReplacement) is taken from the last instance
     // submitted if submission is simultaneous, otherwise it is undefined.
     $this->assertSame(null, $result);
     $variableProcessor->setExpression($occurenceVariableExpression);
     $result = $variableProcessor->process();
     $this->assertInstanceOf('qtism\\common\\datatypes\\QtiFloat', $result);
     $this->assertEquals(1.0, $result->getValue());
     $session->moveNext();
     // Q01.2
     $session->beginAttempt();
     $session->endAttempt(new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('ChoiceB')))));
     $variableProcessor->setExpression($variableExpr);
     $result = $variableProcessor->process();
     $this->assertSame(null, $result);
     // $occurenceVariableExpression still targets Q01.1
     $variableProcessor->setExpression($occurenceVariableExpression);
     $result = $variableProcessor->process();
     $this->assertInstanceOf('qtism\\common\\datatypes\\QtiFloat', $result);
     $this->assertEquals(1.0, $result->getValue());
     // $occurenceVariableExpression now targets Q01.2
     $occurenceVariableExpression->setIdentifier('Q01.2.SCORE');
     $result = $variableProcessor->process();
     $this->assertInstanceOf('qtism\\common\\datatypes\\QtiFloat', $result);
     $this->assertEquals(0.0, $result->getValue());
 }
 public function testTemplateDefault1()
 {
     $doc = new XmlCompactDocument();
     $doc->load(self::samplesDir() . 'custom/runtime/templates/template_test_simple.xml');
     $test = $doc->getDocumentComponent();
     $sessionManager = new SessionManager($doc->getDocumentComponent());
     $storage = new TemporaryQtiBinaryStorage($sessionManager, new BinaryAssessmentTestSeeker($test));
     $session = $storage->instantiate($test);
     $sessionId = $session->getSessionId();
     // Let's try to persist a not begun session.
     $storage->persist($session);
     unset($session);
     $session = $storage->retrieve($test, $sessionId);
     // The session is instantiated, but not yet begun.
     $this->assertEquals(AssessmentTestSessionState::INITIAL, $session->getState());
     // The session begins...
     $session->beginTestSession();
     $this->assertEquals(AssessmentTestSessionState::INTERACTING, $session->getState());
     // We are in linear, non adaptive test. In this context, all item sessions
     // should be already begun.
     $QTPL1Sessions = $session->getAssessmentItemSessions('QTPL1');
     $QTPL1Session = $QTPL1Sessions[0];
     // The the session is correctly instantiated, with the <templateDefault>s in force.
     $this->assertEquals(AssessmentItemSessionState::INITIAL, $QTPL1Session->getState());
     $this->assertEquals(1.0, $QTPL1Session->getVariable('GOODSCORE')->getDefaultValue()->getValue());
     $this->assertEquals(0.0, $QTPL1Session->getVariable('WRONGSCORE')->getDefaultValue()->getValue());
     $this->assertEquals(1.0, $session['QTPL1.GOODSCORE']->getValue());
     $this->assertEquals(1.0, $QTPL1Session['GOODSCORE']->getValue());
     $this->assertEquals(0.0, $session['QTPL1.WRONGSCORE']->getValue());
     $this->assertEquals(0.0, $QTPL1Session['WRONGSCORE']->getValue());
     $QTPL2Sessions = $session->getAssessmentItemSessions('QTPL2');
     $QTPL2Session = $QTPL2Sessions[0];
     $this->assertEquals(AssessmentItemSessionState::INITIAL, $QTPL2Session->getState());
     $this->assertEquals(2.0, $QTPL2Session->getVariable('GOODSCORE')->getDefaultValue()->getValue());
     $this->assertEquals(-1.0, $QTPL2Session->getVariable('WRONGSCORE')->getDefaultValue()->getValue());
     $this->assertEquals(2.0, $session['QTPL2.GOODSCORE']->getValue());
     $this->assertEquals(2.0, $QTPL2Session['GOODSCORE']->getValue());
     $this->assertEquals(-1.0, $session['QTPL2.WRONGSCORE']->getValue());
     $this->assertEquals(-1.0, $QTPL2Session['WRONGSCORE']->getValue());
     // Now let's make sure the persistence works correctly when <templateDefault>s are in force...
     // We do this by testing again that default values are correctly initialized within their respective
     // item sessions...
     $storage->persist($session);
     unset($session);
     $session = $storage->retrieve($test, $sessionId);
     $this->assertEquals(AssessmentItemSessionState::INITIAL, $QTPL1Session->getState());
     $this->assertEquals(1.0, $QTPL1Session->getVariable('GOODSCORE')->getDefaultValue()->getValue());
     $this->assertEquals(0.0, $QTPL1Session->getVariable('WRONGSCORE')->getDefaultValue()->getValue());
     $this->assertEquals(1.0, $session['QTPL1.GOODSCORE']->getValue());
     $this->assertEquals(1.0, $QTPL1Session['GOODSCORE']->getValue());
     $this->assertEquals(0.0, $session['QTPL1.WRONGSCORE']->getValue());
     $this->assertEquals(0.0, $QTPL1Session['WRONGSCORE']->getValue());
     $QTPL2Sessions = $session->getAssessmentItemSessions('QTPL2');
     $QTPL2Session = $QTPL2Sessions[0];
     $this->assertEquals(AssessmentItemSessionState::INITIAL, $QTPL2Session->getState());
     $this->assertEquals(2.0, $QTPL2Session->getVariable('GOODSCORE')->getDefaultValue()->getValue());
     $this->assertEquals(-1.0, $QTPL2Session->getVariable('WRONGSCORE')->getDefaultValue()->getValue());
     $this->assertEquals(2.0, $session['QTPL2.GOODSCORE']->getValue());
     $this->assertEquals(2.0, $QTPL2Session['GOODSCORE']->getValue());
     $this->assertEquals(-1.0, $session['QTPL2.WRONGSCORE']->getValue());
     $this->assertEquals(-1.0, $QTPL2Session['WRONGSCORE']->getValue());
     // It seems to be ok! Let's take the test!
     $session->beginAttempt();
     // TPL1's responses should be applied their default values if any at the
     // beginning of the first attempt.
     $this->assertEquals(null, $session['QTPL1.RESPONSE']);
     // Noisy persistence ...
     $storage->persist($session);
     unset($session);
     $session = $storage->retrieve($test, $sessionId);
     // TPL1's response should still be at their default.
     $this->assertEquals(null, $session['QTPL1.RESPONSE']);
     // -- TPL1 - Correct response.
     $candidateResponses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new Identifier('ChoiceA'))));
     $session->endAttempt($candidateResponses);
     $this->assertEquals(1.0, $session['QTPL1.SCORE']->getValue());
     // Noisy persistence...
     $storage->persist($session);
     unset($session);
     $session = $storage->retrieve($test, $sessionId);
     $this->assertEquals('ChoiceA', $session['QTPL1.RESPONSE']->getValue());
     $this->assertEquals(1.0, $session['QTPL1.SCORE']->getValue());
     $session->moveNext();
     // Noisy persistence...
     $storage->persist($session);
     unset($session);
     $session = $storage->retrieve($test, $sessionId);
     // -- TPL2 - Correct response.
     $session->beginAttempt();
     // TPL2's responses should be at their default values if any at
     // the beginning of the first attempt.
     $this->assertEquals(null, $session['QTPL2.RESPONSE']);
     // Noisy persistence ...
     $storage->persist($session);
     unset($session);
     $session = $storage->retrieve($test, $sessionId);
     // TPL2's response should still be at their default.
     $this->assertEquals(null, $session['QTPL2.RESPONSE']);
     // -- TPL2 - Incorrect response.
     $candidateResponses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new Identifier('ChoiceC'))));
     $session->endAttempt($candidateResponses);
     $this->assertEquals(-1.0, $session['QTPL2.SCORE']->getValue());
     // Noisy persistence...
     $storage->persist($session);
     unset($session);
     $session = $storage->retrieve($test, $sessionId);
     $this->assertEquals('ChoiceC', $session['QTPL2.RESPONSE']->getValue());
     $this->assertEquals(-1.0, $session['QTPL2.SCORE']->getValue());
     // -- Go to the end of test.
     $session->moveNext();
     // Check states...
     $QTPL1Sessions = $session->getAssessmentItemSessions('QTPL1');
     $QTPL1Session = $QTPL1Sessions[0];
     $QTPL2Sessions = $session->getAssessmentItemSessions('QTPL2');
     $QTPL2Session = $QTPL2Sessions[0];
     $this->assertEquals(AssessmentTestSessionState::CLOSED, $session->getState());
     $this->assertEquals(AssessmentItemSessionState::CLOSED, $QTPL1Session->getState());
     $this->assertEquals(AssessmentItemSessionState::CLOSED, $QTPL2Session->getState());
 }
Exemple #20
0
<?php

require_once dirname(__FILE__) . '/../../../../vendor/autoload.php';
use qtism\data\storage\php\PhpDocument;
use qtism\data\storage\xml\XmlCompactDocument;
$test = $argv[1];
$xmlFile = dirname(__FILE__) . "/../runtime/{$test}.xml";
$xmlDoc = new XmlCompactDocument();
$xmlDoc->load($xmlFile);
$phpDoc = new PhpDocument();
$phpDoc->setDocumentComponent($xmlDoc->getDocumentComponent());
$phpDoc->save("{$test}.php");
 public function testExplodeRubricBlocks()
 {
     $src = self::samplesDir() . 'custom/runtime/rubricblockrefs_explosion.xml';
     $doc = new XmlCompactDocument();
     $doc->load($src, true);
     $doc->setExplodeRubricBlocks(true);
     $file = tempnam('/tmp', 'qsm');
     $doc->save($file);
     // Are external rubricBlocks set?
     $pathinfo = pathinfo($file);
     $path = $pathinfo['dirname'] . DIRECTORY_SEPARATOR . 'rubricBlock_RB_S01_1.xml';
     $this->assertTrue(file_exists($path));
     unlink($path);
     $this->assertFalse(file_exists($path));
     $path = $pathinfo['dirname'] . DIRECTORY_SEPARATOR . 'rubricBlock_RB_S01_2.xml';
     $this->assertTrue(file_exists($path));
     unlink($path);
     $this->assertFalse(file_exists($path));
     unlink($file);
 }
 /**
  * Explode the rubric blocks of the test definition into separate QTI-XML files and
  * remove the compact XML document from the file system (useless for
  * the rest of the compilation process).
  * 
  * @param XmlCompactDocument $compiledDoc
  */
 protected function explodeRubricBlocks(XmlCompactDocument $compiledDoc)
 {
     $savePath = $this->getPrivateDirectory()->getPath() . 'compact-test.xml';
     $compiledDoc->setExplodeRubricBlocks(true);
     $compiledDoc->save($savePath);
     unlink($savePath);
 }