220 lines
9.4 KiB
PHP
220 lines
9.4 KiB
PHP
|
<?php
|
||
|
|
||
|
/**
|
||
|
* This program is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU General Public License
|
||
|
* as published by the Free Software Foundation; under version 2
|
||
|
* of the License (non-upgradable).
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
*
|
||
|
* Copyright (c) 2013 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
|
||
|
*
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
namespace oat\taoQtiItem\test\integration;
|
||
|
|
||
|
use oat\tao\test\TaoPhpUnitTestRunner;
|
||
|
use oat\taoQtiItem\model\qti\Item;
|
||
|
use oat\taoQtiItem\model\qti\interaction\ChoiceInteraction;
|
||
|
use oat\taoQtiItem\model\qti\ResponseDeclaration;
|
||
|
use oat\taoQtiItem\model\qti\response\Template;
|
||
|
use oat\taoQtiItem\model\qti\OutcomeDeclaration;
|
||
|
use oat\taoQtiItem\model\qti\feedback\ModalFeedback;
|
||
|
use oat\taoQtiItem\model\qti\response\SimpleFeedbackRule;
|
||
|
use oat\taoQtiItem\model\qti\Parser;
|
||
|
use oat\taoQtiItem\model\qti\interaction\MatchInteraction;
|
||
|
|
||
|
//include_once dirname(__FILE__) . '/../../includes/raw_start.php';
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @author Bertrand Chevrier, <taosupport@tudor.lu>
|
||
|
* @package taoQTI
|
||
|
|
||
|
*/
|
||
|
class QtiModelTest extends TaoPhpUnitTestRunner
|
||
|
{
|
||
|
|
||
|
/**
|
||
|
* tests initialization
|
||
|
* load qti service
|
||
|
*/
|
||
|
public function setUp(): void
|
||
|
{
|
||
|
TaoPhpUnitTestRunner::initTest();
|
||
|
}
|
||
|
|
||
|
public function testModel()
|
||
|
{
|
||
|
|
||
|
$myItem = new Item();
|
||
|
$myItem->setAttribute('title', 'My Coolest Item');
|
||
|
$myItem->getBody()->edit('sth');
|
||
|
|
||
|
$myInteraction = new ChoiceInteraction();
|
||
|
$myInteraction->getPrompt()->edit('Prompt you');
|
||
|
$myChoice1 = $myInteraction->createChoice(['fixed' => true], 'This is correct');
|
||
|
$myChoice2 = $myInteraction->createChoice(['fixed' => true], 'This is not correct');
|
||
|
$this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\choice\\SimpleChoice', $myChoice2);
|
||
|
$this->assertEquals(count($myInteraction->getChoices()), 2);
|
||
|
$myChoice1->setContent('answer #1');
|
||
|
$myChoice2->setContent('answer #2');
|
||
|
|
||
|
$myInteraction->removeChoice($myChoice1);
|
||
|
$this->assertEquals(count($myInteraction->getChoices()), 1);
|
||
|
|
||
|
$myItem->addInteraction($myInteraction, "Adding my interaction here {$myInteraction->getPlaceholder()}. And not there.");
|
||
|
$this->assertNotNull($myInteraction->getRelatedItem());
|
||
|
$this->assertEquals($myInteraction->getRelatedItem()->getSerial(), $myItem->getSerial());
|
||
|
|
||
|
$myResponse = new ResponseDeclaration();
|
||
|
$myItem->addResponse($myResponse);
|
||
|
$this->assertNotNull($myResponse->getRelatedItem());
|
||
|
$this->assertEquals($myResponse->getRelatedItem()->getSerial(), $myItem->getSerial());
|
||
|
|
||
|
$myItem->removeResponse($myResponse);
|
||
|
$responses = $myItem->getResponses();
|
||
|
$this->assertTrue(empty($responses));
|
||
|
}
|
||
|
|
||
|
public function testSimpleFeedback()
|
||
|
{
|
||
|
|
||
|
$response = new ResponseDeclaration(['identifier' => 'RESPONSE']);
|
||
|
$response->setHowMatch(Template::MAP_RESPONSE);
|
||
|
$outcomeFeedback = new OutcomeDeclaration(['identifier' => 'FEEDBACK']);
|
||
|
$modalFeedback1 = new ModalFeedback(['identifier' => 'feedbackOne']);
|
||
|
$feebackRuleA = new SimpleFeedbackRule($outcomeFeedback, $modalFeedback1);
|
||
|
$feebackRuleA->setCondition($response, 'gte', 2.1);
|
||
|
$output1 = $feebackRuleA->toQTI();
|
||
|
|
||
|
$modalFeedback2 = new ModalFeedback(['identifier' => 'feedbackTwo']);
|
||
|
$feebackRuleA->setFeedbackElse($modalFeedback2);
|
||
|
$output2 = $feebackRuleA->toQTI();
|
||
|
|
||
|
$doc = new \DOMDocument();
|
||
|
$doc->loadXML($output2);
|
||
|
|
||
|
$data = simplexml_import_dom($doc);
|
||
|
|
||
|
$subPatternFeedbackOperatorIf = '[name(./*[1]) = "responseIf" ] [count(./responseIf/*) = 2 ] [contains(name(./responseIf/*[1]/*[1]), "map")] [name(./responseIf/*[1]/*[2]) = "baseValue" ] [name(./responseIf/*[2]) = "setOutcomeValue" ] [name(./responseIf/setOutcomeValue/*[1]) = "baseValue" ]';
|
||
|
$subPatternFeedbackElse = '[name(./*[2]) = "responseElseIf"] [count(./responseElseIf/*) = 1 ] [name(./responseElseIf/*[1]) = "setOutcomeValue"] [name(./responseElseIf/setOutcomeValue/*[1]) = "baseValue"]';
|
||
|
$patternFeedbackOperator = '/responseCondition [count(./*) = 1 ]' . $subPatternFeedbackOperatorIf;
|
||
|
$patternFeedbackOperatorWithElse = '/responseCondition [count(./*) = 2 ]' . $subPatternFeedbackOperatorIf . $subPatternFeedbackElse;
|
||
|
$match = $data->xpath($patternFeedbackOperatorWithElse);
|
||
|
|
||
|
$operator = '';
|
||
|
$responseIdentifier = '';
|
||
|
$value = '';
|
||
|
foreach ($data->responseIf->children() as $child) {
|
||
|
$operator = $child->getName();
|
||
|
$map = null;
|
||
|
foreach ($child->children() as $granChild) {
|
||
|
$map = $granChild->getName();
|
||
|
$responseIdentifier = (string) $granChild['identifier'];
|
||
|
break;
|
||
|
}
|
||
|
$value = (string) $child->baseValue;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
$feedbackOutcomeIdentifier = (string) $data->responseIf->setOutcomeValue['identifier'];
|
||
|
$feedbackIdentifier = (string) $data->responseIf->setOutcomeValue->baseValue;
|
||
|
$feedbackIdentifierElse = (string) $data->responseElse->setOutcomeValue->baseValue;
|
||
|
|
||
|
$this->assertEquals($feedbackOutcomeIdentifier, 'FEEDBACK');
|
||
|
$this->assertEquals($feedbackIdentifier, 'feedbackOne');
|
||
|
$this->assertEquals($map, 'mapResponse');
|
||
|
$this->assertEquals($responseIdentifier, 'RESPONSE');
|
||
|
$this->assertEquals($operator, 'gte');
|
||
|
$this->assertEquals($value, '2.1');
|
||
|
$this->assertEquals($feedbackIdentifierElse, 'feedbackTwo');
|
||
|
}
|
||
|
|
||
|
public function testSimpleFeedbackCorrect()
|
||
|
{
|
||
|
|
||
|
$outcomeFeedback = new OutcomeDeclaration(['identifier' => 'FEEDBACK']);
|
||
|
$response2 = new ResponseDeclaration(['identifier' => 'RESPONSE2']);
|
||
|
$response2->setHowMatch(Template::MATCH_CORRECT);
|
||
|
$modalFeedback3 = new ModalFeedback(['identifier' => 'feedbackThree']);
|
||
|
$feebackRuleB = new SimpleFeedbackRule($outcomeFeedback, $modalFeedback3);
|
||
|
$feebackRuleB->setCondition($response2, 'correct');
|
||
|
$output3 = $feebackRuleB->toQTI();
|
||
|
|
||
|
$doc = new \DOMDocument();
|
||
|
$doc->loadXML($output3);
|
||
|
|
||
|
$data = simplexml_import_dom($doc);
|
||
|
$patternFeedbackCorrect = '/responseCondition [count(./*) = 1 ] [name(./*[1]) = "responseIf" ] [count(./responseIf/*) = 2 ] [name(./responseIf/*[1]) = "match" ] [name(./responseIf/*[1]/*[1]) = "variable" ] [name(./responseIf/*[1]/*[2]) = "correct" ] [name(./responseIf/*[2]) = "setOutcomeValue" ] [name(./responseIf/setOutcomeValue/*[1]) = "baseValue" ]';
|
||
|
$match = $data->xpath($patternFeedbackCorrect);
|
||
|
|
||
|
$responseIdentifier = (string) $data->responseIf->match->variable['identifier'];
|
||
|
$feedbackOutcomeIdentifier = (string) $data->responseIf->setOutcomeValue['identifier'];
|
||
|
$feedbackIdentifier = (string) $data->responseIf->setOutcomeValue->baseValue;
|
||
|
|
||
|
$this->assertEquals($responseIdentifier, 'RESPONSE2');
|
||
|
$this->assertEquals($feedbackOutcomeIdentifier, 'FEEDBACK');
|
||
|
$this->assertEquals($feedbackIdentifier, 'feedbackThree');
|
||
|
}
|
||
|
|
||
|
public function testGetComposingElements()
|
||
|
{
|
||
|
|
||
|
\common_ext_ExtensionsManager::singleton()->getExtensionById('tao');
|
||
|
|
||
|
$qtiParser = new Parser(dirname(__FILE__) . '/samples/xml/qtiv2p1/xinclude/embeded_stimulus.xml');
|
||
|
$item = $qtiParser->load();
|
||
|
|
||
|
$stimulus = $item->getComposingElements('oat\taoQtiItem\model\qti\Xinclude');
|
||
|
$this->assertCount(1, $stimulus);
|
||
|
$stim = array_shift($stimulus);
|
||
|
$this->assertEquals('stimulus.xml', $stim->attr('href'));
|
||
|
|
||
|
$elements = $item->getComposingElements();
|
||
|
$this->assertCount(21, $elements);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* test the building of item from all the samples
|
||
|
*/
|
||
|
public function _testSamples()
|
||
|
{
|
||
|
|
||
|
//check if samples are loaded
|
||
|
foreach (glob(dirname(__FILE__) . '/samples/xml/qtiv2p1/*.xml') as $file) {
|
||
|
$qtiParser = new Parser($file);
|
||
|
|
||
|
$item = $qtiParser->load();
|
||
|
$this->assertTrue($qtiParser->isValid());
|
||
|
$this->assertNotNull($item);
|
||
|
$this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\Item', $item);
|
||
|
|
||
|
foreach ($item->getInteractions() as $interaction) {
|
||
|
$this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\interaction\\Interaction', $interaction);
|
||
|
if ($interaction instanceof MatchInteraction) {
|
||
|
foreach ($interaction->getChoices(0) as $choice) {
|
||
|
$this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\choice\\Choice', $choice);
|
||
|
}
|
||
|
foreach ($interaction->getChoices(1) as $choice) {
|
||
|
$this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\choice\\Choice', $choice);
|
||
|
}
|
||
|
} else {
|
||
|
foreach ($interaction->getChoices() as $choice) {
|
||
|
$this->assertInstanceOf('\\\oat\\taoQtiItem\\model\\qti\\choice\\Choice', $choice);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|