Skip to content

Commit

Permalink
ItemSessionControl->showFeedback now considered correctly.
Browse files Browse the repository at this point in the history
  • Loading branch information
= committed Jan 17, 2016
1 parent 87e9604 commit 150dd39
Show file tree
Hide file tree
Showing 3 changed files with 285 additions and 32 deletions.
47 changes: 33 additions & 14 deletions src/qtism/runtime/tests/AssessmentItemSession.php
Original file line number Diff line number Diff line change
Expand Up @@ -897,24 +897,23 @@ public function suspend()
$msg = "Cannot switch from state " . strtoupper(AssessmentItemSessionState::getNameByConstant($state)) . " to state SUSPENDED.";
$code = AssessmentItemSessionException::STATE_VIOLATION;
throw new AssessmentItemSessionException($msg, $this, $code);
} else {
} elseif ($state == AssessmentItemSessionState::MODAL_FEEDBACK) {
// Let's play the suspension ritual...
$maxAttempts = $this->getItemSessionControl()->getMaxAttempts();

if ($state == AssessmentItemSessionState::MODAL_FEEDBACK) {
// Let's play the suspension ritual...
$maxAttempts = $this->getItemSessionControl()->getMaxAttempts();

if ($this->getAssessmentItem()->isAdaptive() === true && $this->getSubmissionMode() === SubmissionMode::INDIVIDUAL && $this['completionStatus']->getValue() === self::COMPLETION_STATUS_COMPLETED) {
// -- Adaptive item.
if ($this->getAssessmentItem()->isAdaptive() === true && $this->getSubmissionMode() === SubmissionMode::INDIVIDUAL && $this['completionStatus']->getValue() === self::COMPLETION_STATUS_COMPLETED) {
$this->endItemSession();
}
$this->endItemSession();
} elseif ($this->getAssessmentItem()->isAdaptive() === false && $this['numAttempts']->getValue() >= $maxAttempts && $maxAttempts !== 0 && $this->getSubmissionMode() !== SubmissionMode::SIMULTANEOUS) {
// -- Non-adaptive item + maxAttempts reached.
elseif ($this->getAssessmentItem()->isAdaptive() === false && $this['numAttempts']->getValue() >= $maxAttempts && $maxAttempts !== 0 && $this->getSubmissionMode() !== SubmissionMode::SIMULTANEOUS) {
$this->endItemSession();
}
$this->endItemSession();
} else {
$this->setState(AssessmentItemSessionState::SUSPENDED);
$this->setAttempting(false);
}
} else {
$this->setState(AssessmentItemSessionState::SUSPENDED);
$this->setAttempting(false);
}
}

Expand Down Expand Up @@ -1285,11 +1284,31 @@ protected function createResponseProcessingEngine(ResponseProcessing $responsePr
*/
private function mustModalFeedback()
{
// From IMS QTI 2.1:
// A value of maxAttempts greater than 1, by definition, indicates that any applicable feedback must be shown.
// This applies to both Modal Feedback and Integrated Feedback where applicable. However, once the maximum number
// of allowed attempts have been used (or for adaptive items, completionStatus has been set to completed) whether
// or not feedback is shown is controlled by the showFeedback constraint.
//
// This [showFeedback] constraint affects the visibility of feedback after the end of the last attempt. If it
// is false then feedback is not shown. This includes both Modal Feedback and Integrated Feedback even if the
// candidate has access to the review state. The default is false.

$mustModalFeedback = false;
$itemSessionControl = $this->getItemSessionControl();

if ($this->getRemainingAttempts() === 0 && $itemSessionControl->mustShowFeedback() === false) {
return $mustModalFeedback;
}

// Feedback is never shown in SIMULTANEOUS submission mode, nor if showFeedback is disabled.
if ($this->getSubmissionMode() === SubmissionMode::INDIVIDUAL && $this->getItemSessionControl()->mustShowFeedback() === true) {

$maxAttempts = $itemSessionControl->getMaxAttempts();
if ($this->getAssessmentItem()->isAdaptive() === true) {
$maxAttempts = 0;
}

if (($maxAttempts === 0 || $maxAttempts > 1) && $this->getSubmissionMode() === SubmissionMode::INDIVIDUAL) {

foreach ($this->getAssessmentItem()->getModalFeedbackRules() as $rule) {

$outcomeValue = $this[$rule->getOutcomeIdentifier()];
Expand All @@ -1308,7 +1327,7 @@ private function mustModalFeedback()
}
}
}

return $mustModalFeedback;
}

Expand Down
104 changes: 89 additions & 15 deletions test/qtismtest/runtime/tests/AssessmentTestSessionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1386,39 +1386,113 @@ public function testItemModalFeedbacks() {
$session = $manager->createAssessmentTestSession($doc->getDocumentComponent());
$session->beginTestSession();

// -- Q01.
// -- Q01 nonAdaptive, maxAttempts = 1, showFeedback = true.
$session->beginAttempt();
$responses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('true'))));
$session->endAttempt($responses);
$this->assertEquals(AssessmentItemSessionState::MODAL_FEEDBACK, $session->getCurrentAssessmentItemSession()->getState());
// The ModalFeedback must not be shown because the number of attempts is not > 1.
$this->assertEquals(AssessmentItemSessionState::CLOSED, $session->getCurrentAssessmentItemSession()->getState());

// -- Move from Q01 to Q02.
$session->moveNext();
// Check that the item session for Q01 is correctly CLOSED by moving next,
// even if it was in a modal feedback state. Why closed and not suspended?
// Because maxAttempts = 1.
$itemSessions = $session->getAssessmentItemSessions('Q01');
$this->assertEquals(AssessmentItemSessionState::CLOSED, $itemSessions[0]->getState());

// -- Q02.
// Here, the maxAttempts is 0 i.e. no limit. Moreover, feedback is shown only if the answer
// is wrong.

// -- Q02 nonAdaptive, maxAttempts = 0, showFeedback = false.
// Here, the maxAttempts is 0 i.e. no limit. Moreover, feedback is shown only if the answer is wrong.
$session->beginAttempt();
$responses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('false'))));
$session->endAttempt($responses);
$this->assertEquals(AssessmentItemSessionState::MODAL_FEEDBACK, $session->getCurrentAssessmentItemSession()->getState());

// Brutal new attempt!
// Brutal new attempt, without suspending explicitely the item session!
$session->beginAttempt();
$responses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('true'))));
$session->endAttempt($responses);
$this->assertEquals(AssessmentItemSessionState::SUSPENDED, $session->getCurrentAssessmentItemSession()->getState());

$session->endTestSession();

$session->beginAttempt();
$responses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('false'))));
$session->endAttempt($responses);
$this->assertEquals(AssessmentItemSessionState::MODAL_FEEDBACK, $session->getCurrentAssessmentItemSession()->getState());

// -- Move from Q02 to Q03.
$session->moveNext();

// Make sure that Q02's session get's closed by moving next.
$itemSessions = $session->getAssessmentItemSessions('Q02');
$this->assertEquals(AssessmentItemSessionState::SUSPENDED, $itemSessions[0]->getState());

// -- Q03 nonAdaptive, maxAttempts = 2, showFeedback = false.
$session->beginAttempt();
$responses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('false'))));
$session->endAttempt($responses);
$this->assertEquals(AssessmentItemSessionState::MODAL_FEEDBACK, $session->getCurrentAssessmentItemSession()->getState());

// itemSessionControl->showFeedback = false. It means that the last attempt will have no ModalFeedback shown.
$session->beginAttempt();
$responses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('false'))));
$session->endAttempt($responses);
$this->assertEquals(AssessmentItemSessionState::CLOSED, $session->getCurrentAssessmentItemSession()->getState());

// -- Move from Q03 to Q04.
$session->moveNext();

// -- Q04 nonAdaptive, maxAttempts = 2, showFeedback = true
$session->beginAttempt();
$responses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('false'))));
$session->endAttempt($responses);
$this->assertEquals(AssessmentItemSessionState::MODAL_FEEDBACK, $session->getCurrentAssessmentItemSession()->getState());

// itemSessionControl->showFeedback = true. It means that the last attempt will have a ModalFeedback shown.
$session->beginAttempt();
$responses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('false'))));
$session->endAttempt($responses);
$this->assertEquals(AssessmentItemSessionState::MODAL_FEEDBACK, $session->getCurrentAssessmentItemSession()->getState());

// -- Move from Q04 to Q05.
$session->moveNext();
// Check that Q04's session went to CLOSE state by moving next, because max number of attempts reached.
$itemSessions = $session->getAssessmentItemSessions('Q04');
$this->assertEquals(AssessmentItemSessionState::CLOSED, $itemSessions[0]->getState());

// -- Q05 adaptive, showFeedback = true
$session->beginAttempt();
$responses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('false'))));
$session->endAttempt($responses);
$this->assertEquals(AssessmentItemSessionState::MODAL_FEEDBACK, $session->getCurrentAssessmentItemSession()->getState());

// $itemSessionControl->showFeedback = true, so the final "correct!" feedback is shown.
$session->beginAttempt();
$responses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('true'))));
$session->endAttempt($responses);
$this->assertEquals(AssessmentItemSessionState::MODAL_FEEDBACK, $session->getCurrentAssessmentItemSession()->getState());

// -- Move from Q05 to Q06.
$session->moveNext();
// Check that Q05 went to CLOSE state.
$itemSessions = $session->getAssessmentItemSessions('Q05');
$this->assertEquals(AssessmentItemSessionState::CLOSED, $itemSessions[0]->getState());

// -- Q06 adaptive, showFeedback = false
$session->beginAttempt();
$responses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('false'))));
$session->endAttempt($responses);
$this->assertEquals(AssessmentItemSessionState::MODAL_FEEDBACK, $session->getCurrentAssessmentItemSession()->getState());

// $itemSessionControl->showFeedback = false, so the "correct!" feedback is not shown.
$session->beginAttempt();
$responses = new State(array(new ResponseVariable('RESPONSE', Cardinality::SINGLE, BaseType::IDENTIFIER, new QtiIdentifier('true'))));
$session->endAttempt($responses);
$this->assertEquals(AssessmentItemSessionState::CLOSED, $session->getCurrentAssessmentItemSession()->getState());

// Ends the test session.
$session->moveNext();

$itemSessions = $session->getAssessmentItemSessionStore()->getAllAssessmentItemSessions();
foreach ($itemSessions as $itemSession) {
$this->assertEquals(AssessmentItemSessionState::CLOSED, $itemSession->getState());
}

$this->assertEquals(AssessmentTestSessionState::CLOSED, $session->getState());
}

public function testIsTimeout() {
Expand Down Expand Up @@ -1473,4 +1547,4 @@ public function testIsTimeout() {
$this->assertEquals(AssessmentTestSessionState::CLOSED, $session->getState());
$this->assertFalse($session->isTimeout());
}
}
}
Loading

0 comments on commit 150dd39

Please sign in to comment.