mirror of
https://github.com/moodle/moodle.git
synced 2025-08-05 00:46:50 +02:00
MDL-27505 Remove the ou-specific question types from the main branch.
The OU question types are now available from https://github.com/timhunt.
This commit is contained in:
parent
9c197f4445
commit
8f9145bb52
73 changed files with 0 additions and 10874 deletions
|
@ -1,196 +0,0 @@
|
|||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This behaviour that is used when the actual qim was not
|
||||
* available.
|
||||
*
|
||||
* @package qbehaviour
|
||||
* @subpackage opaque
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* This behaviour is specifically for use with the Opaque question type.
|
||||
*
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qbehaviour_opaque extends question_behaviour {
|
||||
/** @var string */
|
||||
protected $preferredbehaviour;
|
||||
/** @var string */
|
||||
protected $questionsummary;
|
||||
|
||||
public function __construct(question_attempt $qa, $preferredbehaviour) {
|
||||
parent::__construct($qa, $preferredbehaviour);
|
||||
$this->preferredbehaviour = $preferredbehaviour;
|
||||
}
|
||||
|
||||
public function required_question_definition_type() {
|
||||
return 'qtype_opaque_question';
|
||||
}
|
||||
|
||||
public function get_state_string($showcorrectness) {
|
||||
$state = $this->qa->get_state();
|
||||
$omstate = $this->qa->get_last_behaviour_var('_statestring');
|
||||
if ($state->is_finished()) {
|
||||
return $state->default_string($showcorrectness);
|
||||
} else if ($omstate) {
|
||||
return $omstate;
|
||||
} else {
|
||||
return get_string('notcomplete', 'qbehaviour_opaque');
|
||||
}
|
||||
}
|
||||
|
||||
public function init_first_step(question_attempt_step $step) {
|
||||
global $USER;
|
||||
|
||||
// Set up the random seed to be the current time in milliseconds.
|
||||
list($micros, $sec) = explode(' ', microtime());
|
||||
$step->set_behaviour_var('_randomseed', $sec . floor($micros * 1000));
|
||||
$step->set_behaviour_var('_userid', $USER->id);
|
||||
$step->set_behaviour_var('_language', current_language());
|
||||
$step->set_behaviour_var('_preferredbehaviour', $this->preferredbehaviour);
|
||||
$opaquestate = qtype_opaque_update_state($this->qa, $step);
|
||||
$step->set_behaviour_var('_statestring', $opaquestate->progressinfo);
|
||||
|
||||
// Remember the question summary.
|
||||
$this->questionsummary = html_to_text($opaquestate->xhtml, 0, false);
|
||||
}
|
||||
|
||||
public function get_question_summary() {
|
||||
return $this->questionsummary;
|
||||
}
|
||||
|
||||
protected function is_same_response(question_attempt_step $pendingstep) {
|
||||
$newdata = $pendingstep->get_submitted_data();
|
||||
|
||||
foreach ($newdata as $key => $ignored) {
|
||||
// If an omact_ button has been clicked, never treat this as a duplicate submission.
|
||||
if (strpos($key, 'omact_') === 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$olddata = $this->qa->get_last_step()->get_submitted_data();
|
||||
return question_utils::arrays_have_same_keys_and_values($newdata, $olddata);
|
||||
}
|
||||
|
||||
public function summarise_action(question_attempt_step $step) {
|
||||
if ($step->has_behaviour_var('finish')) {
|
||||
return $this->summarise_finish($step);
|
||||
} else if ($step->has_behaviour_var('comment')) {
|
||||
return $this->summarise_manual_comment($step);
|
||||
} else {
|
||||
$data = qtype_opaque_get_submitted_data($step);
|
||||
$formatteddata = array();
|
||||
foreach ($data as $name => $value) {
|
||||
$formatteddata[] = $name . ' => ' . s($value);
|
||||
}
|
||||
if ($formatteddata) {
|
||||
return get_string('submitted', 'question', implode(', ', $formatteddata));
|
||||
} else {
|
||||
return $this->summarise_start($step);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function process_action(question_attempt_pending_step $pendingstep) {
|
||||
if ($pendingstep->has_behaviour_var('finish')) {
|
||||
return $this->process_finish($pendingstep);
|
||||
}
|
||||
if ($pendingstep->has_behaviour_var('comment')) {
|
||||
return $this->process_comment($pendingstep);
|
||||
} else if ($this->is_same_response($pendingstep) ||
|
||||
$this->qa->get_state()->is_finished()) {
|
||||
return question_attempt::DISCARD;
|
||||
} else {
|
||||
return $this->process_remote_action($pendingstep);
|
||||
}
|
||||
}
|
||||
|
||||
public function process_finish(question_attempt_pending_step $pendingstep) {
|
||||
if ($this->qa->get_state()->is_finished()) {
|
||||
return question_attempt::DISCARD;
|
||||
}
|
||||
|
||||
// Try to get the question to stop.
|
||||
$result = $this->process_remote_action($pendingstep);
|
||||
|
||||
if ($result == question_attempt::KEEP && !$this->qa->get_state()->is_finished()) {
|
||||
// They tried to finish but the question is not finished, so all we
|
||||
// can do is to set the state to gave up. This lets the renderer
|
||||
// handle the review page appropriately.
|
||||
$pendingstep->set_state(question_state::$gaveup);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function process_remote_action(question_attempt_pending_step $pendingstep) {
|
||||
try {
|
||||
$opaquestate = qtype_opaque_update_state($this->qa, $pendingstep);
|
||||
} catch (SoapFault $sf) {
|
||||
print_object($sf);
|
||||
return question_attempt::DISCARD; // TODO better Opaque error handling.
|
||||
}
|
||||
|
||||
if ($opaquestate->resultssequencenumber != $this->qa->get_num_steps()) {
|
||||
$pendingstep->set_state(question_state::$todo);
|
||||
$pendingstep->set_behaviour_var('_statestring', $opaquestate->progressinfo);
|
||||
|
||||
} else {
|
||||
// Look for a score on the default axis.
|
||||
$pendingstep->set_fraction(0);
|
||||
foreach ($opaquestate->results->scores as $score) {
|
||||
if ($score->axis == '') {
|
||||
$pendingstep->set_fraction($score->marks / $this->question->defaultmark);
|
||||
}
|
||||
}
|
||||
|
||||
if ($opaquestate->results->attempts > 0) {
|
||||
$pendingstep->set_state(question_state::$gradedright);
|
||||
} else {
|
||||
$pendingstep->set_state(
|
||||
question_state::graded_state_for_fraction($pendingstep->get_fraction()));
|
||||
}
|
||||
|
||||
if (!empty($opaquestate->results->questionLine)) {
|
||||
$this->qa->set_question_summary(
|
||||
$this->cleanup_results($opaquestate->results->questionLine));
|
||||
}
|
||||
if (!empty($opaquestate->results->answerLine)) {
|
||||
$pendingstep->set_new_response_summary(
|
||||
$this->cleanup_results($opaquestate->results->answerLine));
|
||||
}
|
||||
if (!empty($opaquestate->results->actionSummary)) {
|
||||
$pendingstep->set_behaviour_var('_actionsummary',
|
||||
$this->cleanup_results($opaquestate->results->actionSummary));
|
||||
}
|
||||
}
|
||||
|
||||
return question_attempt::KEEP;
|
||||
}
|
||||
|
||||
protected function cleanup_results($line) {
|
||||
return preg_replace('/\\s+/', ' ', $line);
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'qbehaviour_opaque', language 'en'.
|
||||
*
|
||||
* @package qbehaviour
|
||||
* @subpackage opaque
|
||||
* @copyright 2009 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['notcomplete'] = 'Not complete';
|
||||
$string['pluginname'] = 'Question managed by a remote engine';
|
|
@ -1,77 +0,0 @@
|
|||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Defines the renderer for the Opaque behaviour.
|
||||
*
|
||||
* @package qbehaviour
|
||||
* @subpackage opaque
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Renderer for outputting parts of a question when the actual behaviour
|
||||
* used is not available.
|
||||
*
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qbehaviour_opaque_renderer extends qbehaviour_renderer {
|
||||
public function controls(question_attempt $qa, question_display_options $options) {
|
||||
if ($qa->get_state()->is_gave_up()) {
|
||||
return html_writer::tag('div', get_string('notcompletedmessage', 'qtype_opaque'),
|
||||
array('class' => 'question_aborted'));
|
||||
}
|
||||
|
||||
try {
|
||||
$opaquestate = qtype_opaque_update_state($qa);
|
||||
} catch (SoapFault $sf) {
|
||||
return html_writer::tag('div', get_string('errorconnecting', 'qtype_opaque') .
|
||||
html_writer::tag('pre', get_string('soapfault', 'qtype_opaque', $sf),
|
||||
array('class' => 'notifytiny')),
|
||||
array('class' => 'opaqueerror'));
|
||||
}
|
||||
|
||||
return html_writer::tag('div', $opaquestate->xhtml,
|
||||
array('class' => qtype_opaque_browser_type()));
|
||||
}
|
||||
|
||||
public function head_code(question_attempt $qa) {
|
||||
$output = '';
|
||||
try {
|
||||
$opaquestate = qtype_opaque_update_state($qa);
|
||||
} catch (SoapFault $sf) {
|
||||
// Errors are reported properly elsewhere.
|
||||
return '';
|
||||
}
|
||||
|
||||
$question = $qa->get_question();
|
||||
$resourcecache = new qtype_opaque_resource_cache($question->engineid,
|
||||
$question->remoteid, $question->remoteversion);
|
||||
|
||||
if (!empty($opaquestate->cssfilename) &&
|
||||
$resourcecache->file_in_cache($opaquestate->cssfilename)) {
|
||||
$this->page->requires->css($resourcecache->file_url($opaquestate->cssfilename));
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
|
@ -1,244 +0,0 @@
|
|||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This file contains tests for the Opaque behaviour.
|
||||
*
|
||||
* @package qbehaviour
|
||||
* @subpackage opaque
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../../engine/lib.php');
|
||||
require_once(dirname(__FILE__) . '/../../../engine/simpletest/helpers.php');
|
||||
require_once(dirname(__FILE__) . '/../behaviour.php');
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for the Opaque behaviour.
|
||||
*
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qbehaviour_opaque_test extends qbehaviour_walkthrough_test_base {
|
||||
/**
|
||||
* Makes an Opaque question that refers to one of the sample questions
|
||||
* supplied by OpenMark.
|
||||
* @return unknown_type
|
||||
*/
|
||||
protected function make_standard_om_question() {
|
||||
global $DB;
|
||||
$engineid = $DB->get_field('question_opaque_engines', 'MIN(id)', array());
|
||||
if (empty($engineid)) {
|
||||
throw new coding_exception('Cannot test Opaque. No question engines configured.');
|
||||
}
|
||||
|
||||
question_bank::load_question_definition_classes('opaque');
|
||||
$q = new qtype_opaque_question();
|
||||
test_question_maker::initialise_a_question($q);
|
||||
|
||||
$q->name = 'samples.mu120.module5.question01';
|
||||
$q->qtype = question_bank::get_qtype('opaque');
|
||||
$q->defaultmark = 3;
|
||||
|
||||
$q->engineid = $engineid;
|
||||
$q->remoteid = 'samples.mu120.module5.question01';
|
||||
$q->remoteversion = '1.0';
|
||||
|
||||
return $q;
|
||||
}
|
||||
|
||||
public function test_wrong_three_times() {
|
||||
$q = $this->make_standard_om_question();
|
||||
$this->start_attempt_at_question($q, 'interactive');
|
||||
$qa = $this->quba->get_question_attempt($this->slot);
|
||||
|
||||
// Check the initial state.
|
||||
$this->check_current_state(question_state::$todo);
|
||||
$this->check_current_mark(null);
|
||||
$this->check_current_output(
|
||||
new PatternExpectation('/Below is a plan of a proposed garden/'),
|
||||
new PatternExpectation('/You have 3 attempts/'),
|
||||
$this->get_contains_button_expectation(
|
||||
$qa->get_qt_field_name('omact_gen_14'), 'Check'));
|
||||
$this->assertPattern('/^\s*Below is a plan of a proposed garden./',
|
||||
$qa->get_question_summary());
|
||||
$this->assertNull($qa->get_right_answer_summary());
|
||||
|
||||
// Submit a wrong answer.
|
||||
$this->process_submission(array('omval_response1' => 1, 'omval_response2' => 666,
|
||||
'omact_gen_14' => 'Check'));
|
||||
|
||||
// Verify.
|
||||
$this->check_current_state(question_state::$todo);
|
||||
$this->check_current_mark(null);
|
||||
$this->check_current_output(
|
||||
new PatternExpectation('/Below is a plan of a proposed garden/'),
|
||||
new PatternExpectation('/incorrect/'),
|
||||
new PatternExpectation('/' .
|
||||
preg_quote(get_string('notcomplete', 'qbehaviour_opaque')) . '/'),
|
||||
$this->get_contains_button_expectation(
|
||||
$qa->get_qt_field_name('omact_ok'), 'Try again'));
|
||||
|
||||
// Try again.
|
||||
$this->process_submission(array('omact_ok' => 'Try again'));
|
||||
|
||||
// Verify.
|
||||
$this->check_current_state(question_state::$todo);
|
||||
$this->check_current_mark(null);
|
||||
$this->check_current_output(
|
||||
new PatternExpectation('/You have 2 attempts/'));
|
||||
|
||||
// Submit a wrong answer again.
|
||||
$this->process_submission(array('omval_response1' => 1, 'omval_response2' => 666,
|
||||
'omact_gen_14' => 'Check'));
|
||||
|
||||
// Verify.
|
||||
$this->check_current_state(question_state::$todo);
|
||||
$this->check_current_mark(null);
|
||||
$this->check_current_output(
|
||||
new PatternExpectation('/Below is a plan of a proposed garden/'),
|
||||
new PatternExpectation('/still incorrect/'),
|
||||
new PatternExpectation('/' .
|
||||
preg_quote(get_string('notcomplete', 'qbehaviour_opaque')) . '/'));
|
||||
|
||||
// Try again.
|
||||
$this->process_submission(array('omact_ok' => 'Try again'));
|
||||
|
||||
// Verify.
|
||||
$this->check_current_state(question_state::$todo);
|
||||
$this->check_current_mark(null);
|
||||
$this->check_current_output(
|
||||
new PatternExpectation('/This is your last attempt/'));
|
||||
|
||||
// Submit a wrong answer third time.
|
||||
$this->process_submission(array('omval_response1' => 1, 'omval_response2' => 666,
|
||||
'omact_gen_14' => 'Check'));
|
||||
|
||||
// Verify.
|
||||
$this->check_current_state(question_state::$gradedwrong);
|
||||
$this->check_current_mark(0);
|
||||
$this->check_current_output(
|
||||
new PatternExpectation(
|
||||
'/Please see MU120 Preparatory Resource Book B section 5.1/'),
|
||||
new PatternExpectation('/still incorrect/'));
|
||||
$this->assertTrue(preg_match(
|
||||
'/What is \(X\*W\) (\d+\.\d+)\*(\d+), \(X\*L\)(\d+\.\d+)\*(\d+)\?/',
|
||||
$qa->get_question_summary(), $matches));
|
||||
$this->assertNull($qa->get_right_answer_summary());
|
||||
$this->assertPattern('/' . $matches[1]*$matches[2] . '.*, ' . $matches[3]*$matches[4] . '/',
|
||||
$qa->get_response_summary());
|
||||
}
|
||||
|
||||
public function test_right_first_time() {
|
||||
$q = $this->make_standard_om_question();
|
||||
$this->start_attempt_at_question($q, 'interactive');
|
||||
$qa = $this->quba->get_question_attempt($this->slot);
|
||||
|
||||
// Work out right answer (yuck!)
|
||||
$html = $this->quba->render_question($this->slot, $this->displayoptions);
|
||||
preg_match('/(0\.5|2\.0|3\.0) metres/', $html, $matches);
|
||||
$scale = $matches[1];
|
||||
preg_match('/Patio|Summer House|Flowerbed|Vegetable Plot|Pond/', $html, $matches);
|
||||
$feature = $matches[0];
|
||||
$sizes = array(
|
||||
'Patio' => array(4, 7),
|
||||
'Summer House' => array(3, 5),
|
||||
'Flowerbed' => array(2, 7),
|
||||
'Vegetable Plot' => array(3, 10),
|
||||
'Pond' => array(2, 3),
|
||||
);
|
||||
$size = $sizes[$feature];
|
||||
|
||||
// Check the initial state.
|
||||
$this->check_current_state(question_state::$todo);
|
||||
$this->check_current_mark(null);
|
||||
$this->check_current_output(
|
||||
new PatternExpectation('/Below is a plan of a proposed garden/'),
|
||||
new PatternExpectation('/You have 3 attempts/'),
|
||||
$this->get_contains_button_expectation(
|
||||
$qa->get_qt_field_name('omact_gen_14'), 'Check'));
|
||||
|
||||
// Submit the right answer.
|
||||
$this->process_submission(array('omval_response1' => $size[0] * $scale,
|
||||
'omval_response2' => $size[1] * $scale, 'omact_gen_14' => 'Check'));
|
||||
|
||||
// Verify.
|
||||
$this->check_current_state(question_state::$gradedright);
|
||||
$this->check_current_mark(3);
|
||||
$this->check_current_output(
|
||||
new PatternExpectation('/Below is a plan of a proposed garden/'),
|
||||
new PatternExpectation('/correct/'));
|
||||
}
|
||||
|
||||
public function test_different_max() {
|
||||
$q = $this->make_standard_om_question();
|
||||
$this->start_attempt_at_question($q, 'interactive', 6.0);
|
||||
$qa = $this->quba->get_question_attempt($this->slot);
|
||||
|
||||
// Work out right answer (yuck!)
|
||||
$html = $this->quba->render_question($this->slot, $this->displayoptions);
|
||||
preg_match('/(0\.5|2\.0|3\.0) metres/', $html, $matches);
|
||||
$scale = $matches[1];
|
||||
preg_match('/Patio|Summer House|Flowerbed|Vegetable Plot|Pond/', $html, $matches);
|
||||
$feature = $matches[0];
|
||||
$sizes = array(
|
||||
'Patio' => array(4, 7),
|
||||
'Summer House' => array(3, 5),
|
||||
'Flowerbed' => array(2, 7),
|
||||
'Vegetable Plot' => array(3, 10),
|
||||
'Pond' => array(2, 3),
|
||||
);
|
||||
$size = $sizes[$feature];
|
||||
|
||||
// Check the initial state.
|
||||
$this->check_current_state(question_state::$todo);
|
||||
$this->check_current_mark(null);
|
||||
$this->check_current_output(
|
||||
new PatternExpectation('/Below is a plan of a proposed garden/'),
|
||||
new PatternExpectation('/You have 3 attempts/'),
|
||||
$this->get_contains_button_expectation(
|
||||
$qa->get_qt_field_name('omact_gen_14'), 'Check'));
|
||||
|
||||
// Submit the right answer.
|
||||
$this->process_submission(array('omval_response1' => $size[0] * $scale,
|
||||
'omval_response2' => $size[1] * $scale, 'omact_gen_14' => 'Check'));
|
||||
|
||||
// Verify.
|
||||
$this->check_current_state(question_state::$gradedright);
|
||||
$this->check_current_mark(6);
|
||||
$this->check_current_output(
|
||||
new PatternExpectation('/Below is a plan of a proposed garden/'),
|
||||
new PatternExpectation('/correct/'));
|
||||
}
|
||||
|
||||
public function test_gave_up() {
|
||||
$q = $this->make_standard_om_question();
|
||||
$this->start_attempt_at_question($q, 'interactive');
|
||||
|
||||
$this->quba->finish_all_questions();
|
||||
|
||||
$this->check_current_state(question_state::$gaveup);
|
||||
$this->check_current_mark(null);
|
||||
$this->check_current_output(
|
||||
new PatternExpectation('/' .
|
||||
preg_quote(get_string('notcompletedmessage', 'qtype_opaque')) . '/'));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue