MDL-79863 qtype_ordering: Unit test updates

This commit is contained in:
Mathew May 2024-02-21 14:46:53 +08:00
parent fbfbb7272a
commit 881107a977
22 changed files with 386 additions and 241 deletions

View File

@ -99,7 +99,9 @@ class formulation_and_controls extends renderable_base {
foreach ($currentresponse as $position => $answerid) {
if (!array_key_exists($answerid, $question->answers) || !array_key_exists($position, $correctresponse)) {
continue; // Shouldn't happen !!
// @codeCoverageIgnoreStart
continue; // This shouldn't happen.
// @codeCoverageIgnoreEnd
}
// Format the answer text.

View File

@ -88,7 +88,7 @@ class specific_grade_detail_feedback extends renderable_base {
}
}
if ($totalmaxscore == 0) {
if ($question->gradingtype === qtype_ordering_question::GRADING_ALL_OR_NOTHING || $totalmaxscore == 0) {
unset($data['scoredetails']); // All or nothing.
} else {
// Format gradedetails, e.g. 4/6 = 67%.

View File

@ -14,14 +14,6 @@
// 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 editing form for the ordering question type.
*
* @package qtype_ordering
* @copyright 2013 Gordon Bateson (gordon.bateson@gmail.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// Prevent direct access to this script.
defined('MOODLE_INTERNAL') || die();
@ -31,8 +23,10 @@ require_once($CFG->dirroot.'/question/type/ordering/question.php');
/**
* Ordering editing form definition
*
* @package qtype_ordering
* @copyright 2013 Gordon Bateson (gordon.bateson@gmail.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @codeCoverageIgnore Edit form is covered via behat and mocked in units.
*/
class qtype_ordering_edit_form extends question_edit_form {

View File

@ -285,10 +285,9 @@ class qtype_ordering_question extends question_graded_automatically {
*/
public function summarise_response(array $response) {
$name = $this->get_response_fieldname();
$items = [];
if (array_key_exists($name, $response)) {
$items = explode(',', $response[$name]);
} else {
$items = []; // Shouldn't happen!
}
$answerids = [];
foreach ($this->answers as $answer) {
@ -782,6 +781,7 @@ class qtype_ordering_question extends question_graded_automatically {
* @param int $type
* @return array|string array if $type is not specified and single string if $type is specified
* @throws coding_exception
* @codeCoverageIgnore
*/
public static function get_types(array $types, $type): array|string {
if ($type === null) {

View File

@ -34,6 +34,7 @@ class qtype_ordering extends question_type {
/**
* @return bool whether the question_answers.answer field needs to have
* restore_decode_content_links_worker called on it.
* @CodeCoverageIgnore
*/
public function has_html_answers(): bool {
return true;
@ -787,11 +788,12 @@ class qtype_ordering extends question_type {
* Fix empty or long question name
*
* @param string $name The name of the question
* @param string $defaultname (optional, default='') The default name of the question
* @param integer $maxnamelength (optional, default=42) The maximum length of the name
* @param string|null $defaultname (optional, default='') The default name of the question
* @param int|null $maxnamelength (optional, default=42) The maximum length of the name
* @return string Fixed name
* @throws coding_exception
*/
public function fix_questionname(string $name, string $defaultname = '', int $maxnamelength = 42): string {
public function fix_questionname(string $name, ?string $defaultname = '', ?int $maxnamelength = 42): string {
if (trim($name) == '') {
if ($defaultname) {
$name = $defaultname;

View File

@ -17,7 +17,6 @@
namespace qtype_ordering;
use question_bank;
use test_question_maker;
defined('MOODLE_INTERNAL') || die();
@ -32,11 +31,10 @@ require_once($CFG->dirroot . '/course/externallib.php');
* @package qtype_ordering
* @copyright 2020 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
* @covers \backup_qtype_ordering_plugin
* @covers \restore_qtype_ordering_plugin
* @covers \backup_qtype_ordering_plugin
* @covers \restore_qtype_ordering_plugin
*/
class backup_test extends \advanced_testcase {
final class backup_test extends \advanced_testcase {
/**
* Duplicate quiz with a orderinging question, and check it worked.
*/
@ -54,7 +52,7 @@ class backup_test extends \advanced_testcase {
$quizcontext = \context_module::instance($quiz->cmid);
$cat = $questiongenerator->create_question_category(['contextid' => $quizcontext->id]);
$question = $questiongenerator->create_question('ordering', 'moodle', ['category' => $cat->id]);
$question = $questiongenerator->create_question('ordering', 'moodle', ['category' => $cat->id, 'shownumcorrect' => null]);
// Store some counts.
$numquizzes = count(get_fast_modinfo($course)->instances['quiz']);

View File

@ -14,22 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Behat steps definitions for the ordering question type.
*
* @package qtype_ordering
* @category test
* @copyright 2018 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
/**
* Steps definitions related with the ordering question type.
* Behat steps definitions for the ordering question type.
*
* @package qtype_ordering
* @category test
* @copyright 2018 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

View File

@ -31,7 +31,6 @@ return new class extends phpunit_coverage_info {
/** @var array The list of files relative to the plugin root to include in coverage generation. */
protected $includelistfiles = [
'edit_ordering_form.php',
'question.php',
'questiontype.php',
];

View File

@ -1,6 +1,6 @@
// question: 409000 name: Moodle
// question: 123 name: Moodle
// [id:myid]
::Moodle::[html]Put these words in order.{>0 none
::Moodle::[html]Put these words in order.{>2 none
Modular
Object
Oriented

View File

@ -1,4 +1,4 @@
<!-- question: 409000 -->
<!-- question: 123 -->
<question type="ordering">
<name>
<text>Moodle</text>
@ -65,4 +65,10 @@
<text>Environment is correct.</text>
</feedback>
</answer>
<hint format="html">
<text>Hint 1</text>
</hint>
<hint format="html">
<text>Hint 2</text>
</hint>
</question>

View File

@ -61,4 +61,10 @@
<text><![CDATA[Environment is correct.]]></text>
</feedback>
</answer>
<hint format="html">
<text>Hint 1</text>
</hint>
<hint format="html">
<text>Hint 2</text>
</hint>
</question>

View File

@ -1,64 +0,0 @@
<question type="ordering">
<name>
<text></text>
</name>
<questiontext format="html">
<text>Put these words in order.</text>
</questiontext>
<questiontext format="html">
<text><![CDATA[Put these words in order.]]></text>
</questiontext>
<generalfeedback format="html">
<text><![CDATA[The correct answer is "Modular Object Oriented Dynamic Learning Environment".]]></text>
</generalfeedback>
<defaultgrade>1</defaultgrade>
<penalty>0.3333333</penalty>
<hidden>0</hidden>
<idnumber>myid</idnumber>
<numberingstyle>none</numberingstyle>
<correctfeedback format="html">
<text><![CDATA[<p>Your answer is correct.</p>]]></text>
</correctfeedback>
<partiallycorrectfeedback format="html">
<text><![CDATA[<p>Your answer is partially correct.</p>]]></text>
</partiallycorrectfeedback>
<incorrectfeedback format="html">
<text><![CDATA[<p>Your answer is incorrect.</p>]]></text>
</incorrectfeedback>
<answer fraction="1.0000000" format="html">
<text>Modular</text>
<feedback format="html">
<text><![CDATA[Modular is correct.]]></text>
</feedback>
</answer>
<answer fraction="2.0000000" format="html">
<text>Object</text>
<feedback format="html">
<text><![CDATA[Object is correct.]]></text>
</feedback>
</answer>
<answer fraction="3.0000000" format="html">
<text>Oriented</text>
<feedback format="html">
<text><![CDATA[Oriented is correct.]]></text>
</feedback>
</answer>
<answer fraction="4.0000000" format="html">
<text>Dynamic</text>
<feedback format="html">
<text><![CDATA[Dynamic is correct.]]></text>
</feedback>
</answer>
<answer fraction="5.0000000" format="html">
<text>Learning</text>
<feedback format="html">
<text><![CDATA[Learning is correct.]]></text>
</feedback>
</answer>
<answer fraction="6.0000000" format="html">
<text>Environment</text>
<feedback format="html">
<text><![CDATA[Environment is correct.]]></text>
</feedback>
</answer>
</question>

View File

@ -17,9 +17,9 @@
/**
* Test helper for the ordering question type.
*
* @package qtype_ordering
* @copyright 2018 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @package qtype_ordering
* @copyright 2018 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
@ -36,6 +36,11 @@ require_once($CFG->dirroot . '/question/type/ordering/question.php');
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qtype_ordering_test_helper extends question_test_helper {
/**
* Get the question types that this helper can handle.
*
* @return array the question types.
*/
public function get_test_questions(): array {
return ['moodle'];
}
@ -48,6 +53,16 @@ class qtype_ordering_test_helper extends question_test_helper {
public function make_ordering_question_moodle(): qtype_ordering_question {
question_bank::load_question_definition_classes('ordering');
$q = new qtype_ordering_question();
$q->hints = [
[
'text' => 'Hint 1',
'format' => FORMAT_HTML,
],
[
'text' => 'Hint 2',
'format' => FORMAT_HTML,
],
];
test_question_maker::initialise_a_question($q);
$q->qtype = question_bank::get_qtype('ordering');
$q->name = 'Moodle';
@ -144,8 +159,18 @@ class qtype_ordering_test_helper extends question_test_helper {
test_question_maker::set_standard_combined_feedback_form_data($form);
$form->penalty = '0.3333333';
$form->numhints = 0;
$form->hint = [];
// Build the expected hint base.
$form->numhints = 2;
$form->hint = [
[
'text' => 'Hint 1',
'format' => FORMAT_HTML,
],
[
'text' => 'Hint 2',
'format' => FORMAT_HTML,
],
];;
$form->qtype = 'ordering';
return $form;

View File

@ -29,12 +29,13 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
/**
* A test class used to test correct_response.
*
* @package qtype_ordering
* @copyright 2023 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering\output\correct_response
* @package qtype_ordering
* @copyright 2023 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering\output\renderable_base
* @covers \qtype_ordering\output\correct_response
*/
class correct_response_test extends advanced_testcase {
final class correct_response_test extends advanced_testcase {
/**
* Test the exported data for the template that renders the correct response to a given question attempt.
*
@ -43,7 +44,6 @@ class correct_response_test extends advanced_testcase {
* @param string $layouttype The type of the layout.
* @param array $expected The expected exported data.
* @return void
* @covers ::export_for_template
*/
public function test_export_for_template(array $currentresponse, string $layouttype, array $expected): void {
global $PAGE;
@ -53,6 +53,7 @@ class correct_response_test extends advanced_testcase {
$question->gradingtype = qtype_ordering_question::GRADING_ABSOLUTE_POSITION;
$question->layouttype = $layouttype === 'horizontal' ? qtype_ordering_question::LAYOUT_HORIZONTAL :
qtype_ordering_question::LAYOUT_VERTICAL;
// Create a question attempt.
$qa = new \testable_question_attempt($question, 0);
// Create a question attempt step and add it to the question attempt.
@ -63,6 +64,9 @@ class correct_response_test extends advanced_testcase {
// attempt step.
[$fraction, $state] = $question->grade_response(qtype_ordering_test_helper::get_response($question, $currentresponse));
$qa->get_last_step()->set_state($state);
if ($expected['hascorrectresponse'] === false) {
$qa->get_question()->correctresponse = 0;
}
$renderer = $PAGE->get_renderer('core');
$correctresponse = new correct_response($qa);
@ -75,7 +79,7 @@ class correct_response_test extends advanced_testcase {
*
* @return array
*/
public function export_for_template_provider(): array {
public static function export_for_template_provider(): array {
return [
'Correct question attempt.' => [
@ -137,6 +141,13 @@ class correct_response_test extends advanced_testcase {
],
],
],
'Correct state not set somehow' => [
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment'],
'horizontal',
[
'hascorrectresponse' => false,
],
],
];
}
}

View File

@ -30,14 +30,15 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
/**
* Test the feedback exporter.
*
* @package qtype_ordering
* @copyright 2023 Mathew May <mathew.solutions>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @package qtype_ordering
* @copyright 2023 Mathew May <mathew.solutions>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering\output\renderable_base
* @covers \qtype_ordering\output\feedback
*/
class feedback_test extends qbehaviour_walkthrough_test_base {
/** @var array $correctanswers The correct answers for the question, added to quickly reference. */
private $correctanswers = [
final class feedback_test extends qbehaviour_walkthrough_test_base {
/** @var array $CORRECTANSWERS The correct answers for the question, added to quickly reference. */
const CORRECTANSWERS = [
0 => [
'answertext' => 'Modular',
],
@ -61,7 +62,6 @@ class feedback_test extends qbehaviour_walkthrough_test_base {
/**
* Test the exported data for the template that renders the feedback test to a given question attempt.
*
* @covers \qtype_ordering\output\feedback::export_for_template()
* @dataProvider export_for_template_provider
* @param array $answeritems The array of ordered answers.
* @param int $gradingtype Grading type.
@ -119,7 +119,7 @@ class feedback_test extends qbehaviour_walkthrough_test_base {
*
* @return array
*/
public function export_for_template_provider(): array {
public static function export_for_template_provider(): array {
global $CFG;
require_once($CFG->dirroot . '/question/type/ordering/question.php');
@ -201,7 +201,7 @@ class feedback_test extends qbehaviour_walkthrough_test_base {
'hascorrectresponse' => true,
'showcorrect' => true,
'orderinglayoutclass' => 'horizontal',
'correctanswers' => $this->correctanswers,
'correctanswers' => self::CORRECTANSWERS,
],
],
],
@ -233,7 +233,7 @@ class feedback_test extends qbehaviour_walkthrough_test_base {
'hascorrectresponse' => true,
'showcorrect' => true,
'orderinglayoutclass' => 'horizontal',
'correctanswers' => $this->correctanswers,
'correctanswers' => self::CORRECTANSWERS,
],
'numpartscorrect' => [
'numcorrect' => 4,
@ -298,7 +298,7 @@ class feedback_test extends qbehaviour_walkthrough_test_base {
'hascorrectresponse' => true,
'showcorrect' => true,
'orderinglayoutclass' => 'horizontal',
'correctanswers' => $this->correctanswers,
'correctanswers' => self::CORRECTANSWERS,
],
],
],
@ -358,7 +358,7 @@ class feedback_test extends qbehaviour_walkthrough_test_base {
'hascorrectresponse' => true,
'showcorrect' => true,
'orderinglayoutclass' => 'vertical',
'correctanswers' => $this->correctanswers,
'correctanswers' => self::CORRECTANSWERS,
],
],
],

View File

@ -30,13 +30,14 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
/**
* A test class used to test formulation_and_controls.
*
* @package qtype_ordering
* @copyright 2023 Ilya Tregubov <ilya.a.tregubov@gmail.com.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering\output\specific_grade_detail_feedback
* @package qtype_ordering
* @copyright 2023 Ilya Tregubov <ilya.a.tregubov@gmail.com.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering\output\renderable_base
* @covers \qtype_ordering\output\formulation_and_controls
* @covers \qtype_ordering_renderer::feedback_image
*/
class formulation_and_controls_test extends advanced_testcase {
final class formulation_and_controls_test extends advanced_testcase {
/**
* Test the exported data for the template that renders the formulation and controls for a given question.
*
@ -46,7 +47,6 @@ class formulation_and_controls_test extends advanced_testcase {
* @param string $layouttype The type of the layout.
* @param array $expected The expected exported data.
* @return void
* @covers ::export_for_template
*/
public function test_export_for_template(array $answeritems, int $gradingtype, string $layouttype, array $expected): void {
global $PAGE;
@ -74,6 +74,10 @@ class formulation_and_controls_test extends advanced_testcase {
$step->set_qt_var('_currentresponse', $keys);
[$fraction, $state] = $question->grade_response(qtype_ordering_test_helper::get_response($question, $values));
// Force the state to be complete if it is graded correct for testing purposes.
if ($state === \question_state::$gradedright) {
$state = \question_state::$complete;
}
$qa->get_last_step()->set_state($state);
$renderer = $PAGE->get_renderer('core');
@ -88,7 +92,7 @@ class formulation_and_controls_test extends advanced_testcase {
*
* @return array
*/
public function export_for_template_provider(): array {
public static function export_for_template_provider(): array {
global $CFG, $OUTPUT;
require_once($CFG->dirroot . '/question/type/ordering/question.php');
@ -217,6 +221,66 @@ class formulation_and_controls_test extends advanced_testcase {
],
],
],
'Horizontal, correct and complete' => [
[13 => 'Modular', 14 => 'Object', 15 => 'Oriented', 16 => 'Dynamic', 17 => 'Learning', 18 => 'Environment'],
qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT,
'horizontal',
[
'readonly' => false,
'questiontext' => 'Put these words in order',
'responsename' => 'q0:_response_0',
'responseid' => 'id_q0_response_0',
'value' => 'ordering_item_ac5fc041de63c8c5b34d0aabb96cf33d,' .
'ordering_item_497031794414a552435f90151ac3b54b,' .
'ordering_item_5a35edab0f2bf86dfa3901baa8c235dc,' .
'ordering_item_971fd8cc345d8bd9f92e9f7d88fdf20c,' .
'ordering_item_8af0f5c3edad8d8e158ff27b9f03afac,' .
'ordering_item_0ba29c6a1afacf586b03a26162c72274',
'ablockid' => 'id_ablock_0',
'layoutclass' => 'horizontal',
'numberingstyle' => 'none',
'active' => true,
'sortableid' => 'id_sortable_0',
'answers' => [
[
'scoreclass' => 'correct',
'id' => 'ordering_item_' . md5('Modular'),
'answertext' => "Modular",
'feedbackimage' => $correct,
],
[
'scoreclass' => 'correct',
'id' => 'ordering_item_' . md5('Object'),
'answertext' => "Object",
'feedbackimage' => $correct,
],
[
'scoreclass' => 'correct',
'id' => 'ordering_item_' . md5('Oriented'),
'answertext' => "Oriented",
'feedbackimage' => $correct,
],
[
'scoreclass' => 'correct',
'id' => 'ordering_item_' . md5('Dynamic'),
'answertext' => "Dynamic",
'feedbackimage' => $correct,
],
[
'scoreclass' => 'correct',
'id' => 'ordering_item_' . md5('Learning'),
'answertext' => "Learning",
'feedbackimage' => $correct,
],
[
'scoreclass' => 'correct',
'id' => 'ordering_item_' . md5('Environment'),
'answertext' => "Environment",
'feedbackimage' => $correct,
],
],
],
],
];
}
}

View File

@ -19,7 +19,6 @@ namespace qtype_ordering\output;
use advanced_testcase;
use test_question_maker;
use qtype_ordering_question;
use qtype_ordering_test_helper;
defined('MOODLE_INTERNAL') || die();
@ -29,13 +28,13 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
/**
* A test class used to test specific_grade_detail_feedback.
*
* @package qtype_ordering
* @copyright 2023 Ilya Tregubov <ilya.a.tregubov@gmail.com.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering\output\specific_grade_detail_feedback
* @package qtype_ordering
* @copyright 2023 Ilya Tregubov <ilya.a.tregubov@gmail.com.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering\output\renderable_base
* @covers \qtype_ordering\output\num_parts_correct
*/
class num_parts_correct_test extends advanced_testcase {
final class num_parts_correct_test extends advanced_testcase {
/**
* Test the exported data for the template that renders the specific grade detail feedback test to a given question attempt.
*
@ -44,7 +43,6 @@ class num_parts_correct_test extends advanced_testcase {
* @param int $gradingtype Grading type.
* @param array $expected The expected exported data.
* @return void
* @covers ::export_for_template
*/
public function test_export_for_template(array $answeritems, int $gradingtype, array $expected): void {
global $PAGE;
@ -71,7 +69,7 @@ class num_parts_correct_test extends advanced_testcase {
*
* @return array
*/
public function export_for_template_provider(): array {
public static function export_for_template_provider(): array {
global $CFG;
require_once($CFG->dirroot . '/question/type/ordering/question.php');

View File

@ -29,13 +29,13 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
/**
* A test class used to test specific_grade_detail_feedback.
*
* @package qtype_ordering
* @copyright 2023 Ilya Tregubov <ilya.a.tregubov@gmail.com.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering\output\specific_grade_detail_feedback
* @package qtype_ordering
* @copyright 2023 Ilya Tregubov <ilya.a.tregubov@gmail.com.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering\output\renderable_base
* @covers \qtype_ordering\output\specific_grade_detail_feedback
*/
class specific_grade_detail_feedback_test extends advanced_testcase {
final class specific_grade_detail_feedback_test extends advanced_testcase {
/**
* Test the exported data for the template that renders the specific grade detail feedback test to a given question attempt.
*
@ -46,7 +46,6 @@ class specific_grade_detail_feedback_test extends advanced_testcase {
* @param array $expected The expected exported data.
* @param int $selecttype The type of the select.
* @return void
* @covers ::export_for_template
*/
public function test_export_for_template(array $answeritems, int $gradingtype, string $layouttype, array $expected,
int $selecttype): void {
@ -82,8 +81,11 @@ class specific_grade_detail_feedback_test extends advanced_testcase {
$this->assertEquals($expected['showpartialwrong'], $actual['showpartialwrong']);
$this->assertEquals($expected['gradingtype'], $actual['gradingtype']);
$this->assertEquals($expected['orderinglayoutclass'], $actual['orderinglayoutclass']);
$this->assertEquals($expected['totalmaxscore'], $actual['totalmaxscore']);
$this->assertArrayHasKey('scoredetails', $actual);
// All or nothing grading type does not have score details.
if ($gradingtype !== qtype_ordering_question::GRADING_ALL_OR_NOTHING) {
$this->assertEquals($expected['totalmaxscore'], $actual['totalmaxscore']);
$this->assertArrayHasKey('scoredetails', $actual);
}
}
}
@ -92,7 +94,7 @@ class specific_grade_detail_feedback_test extends advanced_testcase {
*
* @return array
*/
public function export_for_template_provider(): array {
public static function export_for_template_provider(): array {
global $CFG;
require_once($CFG->dirroot . '/question/type/ordering/question.php');
@ -238,6 +240,28 @@ class specific_grade_detail_feedback_test extends advanced_testcase {
],
qtype_ordering_question::SELECT_CONTIGUOUS,
],
'Incorrect question attempt (SELECT_CONTIGUOUS). Grading type: GRADING_ALL_OR_NOTHING' => [
[14 => 'Object', 16 => 'Dynamic', 13 => 'Modular', 17 => 'Learning', 18 => 'Environment', 15 => 'Oriented'],
qtype_ordering_question::GRADING_ALL_OR_NOTHING,
'vertical',
[
'showpartialwrong' => 1,
'gradingtype' => 'Grading type: All or nothing',
'orderinglayoutclass' => 'vertical',
'gradedetails' => 0,
'totalscore' => 0,
'totalmaxscore' => 2,
'scoredetails' => [
['score' => 0, 'maxscore' => 1, 'percent' => 0],
['score' => 1, 'maxscore' => 1, 'percent' => 100.0],
['score' => 0, 'maxscore' => 1, 'percent' => 0],
['score' => 'No score', 'maxscore' => null, 'percent' => 0],
['score' => 'No score', 'maxscore' => null, 'percent' => 0],
['score' => 'No score', 'maxscore' => null, 'percent' => 0],
],
],
qtype_ordering_question::SELECT_CONTIGUOUS,
],
];
}
}

View File

@ -14,15 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for the ordering question definition class.
*
* @package qtype_ordering
* @copyright 2018 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace qtype_ordering;
use test_question_maker;
@ -41,11 +32,13 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
/**
* Unit tests for the ordering question definition class.
*
* @package qtype_ordering
* @copyright 2018 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering_question
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering
* @covers \qtype_ordering_question
*/
class question_test extends \advanced_testcase {
final class question_test extends \advanced_testcase {
/**
* Array of draggable items in correct order.
*/
@ -92,6 +85,7 @@ class question_test extends \advanced_testcase {
)
);
}
public function test_grading_absolute_position(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
@ -158,6 +152,7 @@ class question_test extends \advanced_testcase {
)
);
}
public function test_grading_relative_next_exclude_last(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
@ -207,6 +202,7 @@ class question_test extends \advanced_testcase {
)
);
}
public function test_grading_relative_next_include_last(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
@ -245,6 +241,7 @@ class question_test extends \advanced_testcase {
)
);
}
public function test_grading_relative_one_previous_and_next(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
@ -292,6 +289,7 @@ class question_test extends \advanced_testcase {
)
);
}
public function test_grading_relative_all_previous_and_next(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
@ -348,6 +346,7 @@ class question_test extends \advanced_testcase {
)
);
}
public function test_grading_longest_ordered_subset(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
@ -395,6 +394,7 @@ class question_test extends \advanced_testcase {
)
);
}
public function test_grading_longest_contiguous_subset(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
@ -442,6 +442,7 @@ class question_test extends \advanced_testcase {
)
);
}
public function test_grading_relative_to_correct(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
@ -512,6 +513,7 @@ class question_test extends \advanced_testcase {
$question->get_correct_response()
);
}
public function test_is_same_response(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
@ -579,11 +581,12 @@ class question_test extends \advanced_testcase {
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
if ($question->layouttype === 0) {
$this->assertEquals('vertical', $question->get_ordering_layoutclass());
} else if ($question->layouttype === 1) {
$this->assertEquals('horizontal', $question->get_ordering_layoutclass());
}
$question->layouttype = 0;
$this->assertEquals('vertical', $question->get_ordering_layoutclass());
$question->layouttype = 1;
$this->assertEquals('horizontal', $question->get_ordering_layoutclass());
// Confirm that if an invalid layouttype is set, an empty string is returned.
$question->layouttype = 3;
$error = $question->get_ordering_layoutclass();
@ -814,8 +817,5 @@ class question_test extends \advanced_testcase {
$this->assertEquals(true, $question->is_complete_response([]));
$this->assertEquals(true, $question->is_gradable_response([]));
$this->assertEquals('', $question->get_validation_error([]));
$this->expectException(\coding_exception::class);
qtype_ordering_question::get_types(['foo', 'bar', 'baz'], 'notexist');
}
}

View File

@ -0,0 +1,111 @@
<?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/>.
namespace qtype_ordering;
use advanced_testcase;
use qtype_ordering;
use question_bank;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
/**
* A test class used to test question_hint_ordering.
*
* @package qtype_ordering
* @copyright 2024 Mathew May <mathew.solutions>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering\question_hint_ordering
* @covers \qtype_ordering
*/
final class questionhint_test extends advanced_testcase {
/** @var qtype_ordering instance of the question type class to test. */
protected $qtype;
protected function setUp(): void {
$this->qtype = new qtype_ordering();
}
protected function tearDown(): void {
$this->qtype = null;
}
/**
* Test that hints can be fetched from the DB.
* @return void
*/
public function test_load_from_record(): void {
$this->resetAfterTest();
$obj = (object) [
'id' => 13,
'hint' => 'Hint 1',
'hintformat' => FORMAT_HTML,
'shownumcorrect' => 0,
'clearwrong' => 0,
'options' => null,
];
$hint = question_hint_ordering::load_from_record($obj);
$this->assertInstanceOf(question_hint_ordering::class, $hint);
}
public function test_make_hint(): void {
$this->resetAfterTest();
$syscontext = \context_system::instance();
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$category = $generator->create_question_category(['contextid' => $syscontext->id]);
$fromdata = \test_question_maker::get_question_form_data('ordering');
$fromdata->category = $category->id . ',' . $syscontext->id;
$question = new \stdClass();
$question->category = $category->id;
$question->qtype = 'ordering';
$question->createdby = 0;
$question = $this->qtype->save_question($question, $fromdata);
$questiondata = question_bank::load_question_data($question->id);
// Build the expected hint base.
$hintbase = [
'questionid' => $questiondata->id,
'shownumcorrect' => '0',
'clearwrong' => '0',
'options' => '0',
];
$expectedhints = [];
foreach ($fromdata->hint as $key => $value) {
$hint = $hintbase + [
'hint' => $value['text'],
'hintformat' => $value['format'],
];
$expectedhints[] = (object)$hint;
}
// Need to get rid of ids.
$gothints = array_map(function($hint) {
unset($hint->id);
return $hint;
}, $questiondata->hints);
// Compare hints.
$this->assertEquals($expectedhints, array_values($gothints));
}
}

View File

@ -14,14 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for the ordering question type class.
*
* @package qtype_ordering
* @copyright 2018 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace qtype_ordering;
use core_question_generator;
@ -32,7 +24,7 @@ use qtype_ordering_question;
use test_question_maker;
use question_bank;
use question_possible_response;
use qformat_xml;
use qformat_gift;
use question_check_specified_fields_expectation;
@ -52,20 +44,21 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
/**
* Unit tests for the ordering question type class.
*
* @copyright 20018 The Open University
* @package qtype_ordering
* @copyright 2018 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering
* @covers \qtype_ordering_question
*/
class questiontype_test extends \question_testcase {
/** @var qtype_ordering instance of the question type class to test. */
protected $qtype;
final class questiontype_test extends \question_testcase {
/** @var object Default import object to compare against. */
protected $expectedimportobj;
protected function setUp(): void {
$this->qtype = new qtype_ordering();
$this->expectedimportobj = (object) [
/**
* Define the import object to compare against.
*
* @return object The expected import object.
*/
private static function expectedimport(): object {
return (object) [
'qtype' => 'ordering',
'idnumber' => 'myid',
'name' => 'Moodle',
@ -79,11 +72,6 @@ class questiontype_test extends \question_testcase {
];
}
protected function tearDown(): void {
$this->qtype = null;
$this->expectedimportobj = null;
}
/**
* Asserts that two XML strings are the same, ignoring differences in line endings.
*
@ -96,11 +84,13 @@ class questiontype_test extends \question_testcase {
}
public function test_name(): void {
$this->assertEquals('ordering', $this->qtype->name());
$ordering = new qtype_ordering();
$this->assertEquals('ordering', $ordering->name());
}
public function test_can_analyse_responses(): void {
$this->assertTrue($this->qtype->can_analyse_responses());
$ordering = new qtype_ordering();
$this->assertTrue($ordering->can_analyse_responses());
}
public function test_question_saving(): void {
@ -122,8 +112,9 @@ class questiontype_test extends \question_testcase {
$this->assertTrue($form->is_validated());
$fromform = $form->get_data();
$ordering = new qtype_ordering();
$returnedfromsave = $this->qtype->save_question($questiondata, $fromform);
$returnedfromsave = $ordering->save_question($questiondata, $fromform);
$actualquestiondata = question_bank::load_question_data($returnedfromsave->id);
foreach ($questiondata as $property => $value) {
@ -156,7 +147,8 @@ class questiontype_test extends \question_testcase {
public function test_get_possible_responses(): void {
$questiondata = test_question_maker::get_question_data('ordering');
$possibleresponses = $this->qtype->get_possible_responses($questiondata);
$ordering = new qtype_ordering();
$possibleresponses = $ordering->get_possible_responses($questiondata);
$expectedresponseclasses = [
'Modular' => [
1 => new question_possible_response('Position 1', 0.1666667),
@ -212,42 +204,44 @@ class questiontype_test extends \question_testcase {
public function test_get_possible_responses_very_long(): void {
$questiondata = test_question_maker::get_question_data('ordering');
$ordering = new qtype_ordering();
$onehundredchars = str_repeat('1234567890', 9) . '123456789碁';
// Set one of the answers to over 100 chars, with a multi-byte UTF-8 character at position 100.
$questiondata->options->answers[13]->answer = $onehundredchars . 'and some more';
$possibleresponses = $this->qtype->get_possible_responses($questiondata);
$possibleresponses = $ordering->get_possible_responses($questiondata);
$this->assertArrayHasKey($onehundredchars, $possibleresponses);
}
public function test_get_numberingstyle(): void {
$questiondata = test_question_maker::get_question_data('ordering');
$ordering = new qtype_ordering();
$expected = qtype_ordering_question::NUMBERING_STYLE_DEFAULT;
$actual = $this->qtype->get_numberingstyle($questiondata);
$actual = $ordering->get_numberingstyle($questiondata);
$this->assertEquals($expected, $actual);
$questiondata->options->numberingstyle = 'abc';
$expected = 'abc';
$actual = $this->qtype->get_numberingstyle($questiondata);
$actual = $ordering->get_numberingstyle($questiondata);
$this->assertEquals($expected, $actual);
$questiondata->options->numberingstyle = 'ABCD';
$expected = 'ABCD';
$actual = $this->qtype->get_numberingstyle($questiondata);
$actual = $ordering->get_numberingstyle($questiondata);
$this->assertEquals($expected, $actual);
$questiondata->options->numberingstyle = '123';
$expected = '123';
$actual = $this->qtype->get_numberingstyle($questiondata);
$actual = $ordering->get_numberingstyle($questiondata);
$this->assertEquals($expected, $actual);
$questiondata->options->numberingstyle = 'iii';
$expected = 'iii';
$actual = $this->qtype->get_numberingstyle($questiondata);
$actual = $ordering->get_numberingstyle($questiondata);
$this->assertEquals($expected, $actual);
$questiondata->options->numberingstyle = 'III';
$expected = 'III';
$actual = $this->qtype->get_numberingstyle($questiondata);
$actual = $ordering->get_numberingstyle($questiondata);
$this->assertEquals($expected, $actual);
}
@ -256,25 +250,11 @@ class questiontype_test extends \question_testcase {
// Import a question from XML.
$xml = file_get_contents(__DIR__ . '/fixtures/testimport.moodle.xml');
$xmldata = xmlize($xml);
$format = new \qformat_xml();
$format = new qformat_xml();
$imported = $format->try_importing_using_qtypes(
$xmldata['question'], null, null, 'ordering');
$this->assert(new question_check_specified_fields_expectation($this->expectedimportobj), $imported);
}
public function test_xml_import_empty(): void {
$this->resetAfterTest();
// Import a question from XML.
$xml = file_get_contents(__DIR__ . '/fixtures/testimportempty.moodle.xml');
$xmldata = xmlize($xml);
$format = new \qformat_xml();
$imported = $format->try_importing_using_qtypes(
$xmldata['question'], null, null, 'ordering');
$this->expectedimportobj->name = 'Put these words in order.';
$this->assert(new question_check_specified_fields_expectation($this->expectedimportobj), $imported);
$this->assert(new question_check_specified_fields_expectation(self::expectedimport()), $imported);
}
public function test_xml_import_long(): void {
@ -282,13 +262,14 @@ class questiontype_test extends \question_testcase {
// Import a question from XML.
$xml = file_get_contents(__DIR__ . '/fixtures/testimportlong.moodle.xml');
$xmldata = xmlize($xml);
$format = new \qformat_xml();
$format = new qformat_xml();
$imported = $format->try_importing_using_qtypes(
$xmldata['question'], null, null, 'ordering');
$this->expectedimportobj->name = 'Moodle Moodle Moodle Moodle Moodle Moodle ...';
$expected = self::expectedimport();
$expected->name = 'Moodle Moodle Moodle Moodle Moodle Moodle Moodle';
$this->assert(new question_check_specified_fields_expectation($this->expectedimportobj), $imported);
$this->assert(new question_check_specified_fields_expectation($expected), $imported);
}
public function test_xml_export(): void {
@ -300,6 +281,9 @@ class questiontype_test extends \question_testcase {
// Export it.
$questiondata = question_bank::load_question_data($question->id);
// Force the question id to be 123, to ensure it comes through the export.
$questiondata->id = 123;
$questiondata->options->numberingstyle = null;
// Add some feedback to ensure it comes through the export.
foreach ($questiondata->options->answers as $answer) {
$answer->feedback = $answer->answer . ' is correct.';
@ -307,7 +291,7 @@ class questiontype_test extends \question_testcase {
$answer->feedbackfiles = 0;
}
$exporter = new \qformat_xml();
$exporter = new qformat_xml();
$xml = $exporter->writequestion($questiondata);
$expectedxml = file_get_contents(__DIR__ . '/fixtures/testexport.moodle.xml');
@ -323,8 +307,7 @@ class questiontype_test extends \question_testcase {
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$imported = $format->readquestion($lines);
// TODO - MDL-XXXXX format_gift: Set ID & tags from comment for third parties.
// $this->assert(new question_check_specified_fields_expectation($this->expectedimportobj), $imported);
$this->assert(new question_check_specified_fields_expectation(self::expectedimport()), $imported);
}
public function test_gift_export(): void {
@ -336,13 +319,14 @@ class questiontype_test extends \question_testcase {
// Export it.
$questiondata = question_bank::load_question_data($question->id);
// Force the question id to be 123, to ensure it comes through the export.
$questiondata->id = 123;
$exporter = new qformat_gift();
$gift = $exporter->writequestion($questiondata);
$expectedgift = file_get_contents(__DIR__ . '/fixtures/testexport.gift.txt');
// TODO - MDL-XXXXX format_gift: Set ID & tags from comment for third parties.
// $this->assertEquals($expectedgift, $gift);
$this->assertEquals($expectedgift, $gift);
}
}

View File

@ -14,20 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for the ordering question type.
*
* @package qtype_ordering
* @copyright 2018 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace qtype_ordering;
use test_question_maker;
use question_state;
use question_pattern_expectation;
use stdClass;
use qtype_ordering_test_helper;
defined('MOODLE_INTERNAL') || die();
@ -41,11 +31,13 @@ require_once($CFG->dirroot . '/question/type/ddwtos/tests/helper.php');
*
* These tests simulate a student's complete interaction with a question.
*
* @package qtype_ordering
* @copyright 2018 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering
* @covers \qtype_ordering_question
*/
class walkthrough_test extends \qbehaviour_walkthrough_test_base {
final class walkthrough_test extends \qbehaviour_walkthrough_test_base {
/**
* Get the array of post data that will .
*