MDL-79863 qtype_ordering: Coding style improvements part 1

Co-authored by: Ilya Tregubov <ilya@moodle.com>
Co-authored by: Mihail Geshoski <mihail@moodle.com>
Co-authored by: Shamim Rezaie <shamim@moodle.com>
This commit is contained in:
Shamim Rezaie 2023-11-12 23:30:39 +11:00 committed by Mathew May
parent 18182c30e6
commit 31fc5161c9
9 changed files with 620 additions and 347 deletions

View File

@ -33,8 +33,10 @@
* @param bool $forcedownload whether or not force download
* @param array $options additional options affecting the file serving
*/
function qtype_ordering_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
function qtype_ordering_pluginfile(stdClass $course, stdClass $cm, stdClass $context, string $filearea, array $args,
bool $forcedownload, array $options = []) {
global $CFG;
require_once($CFG->dirroot.'/lib/questionlib.php');
require_once($CFG->dirroot . '/lib/questionlib.php');
question_pluginfile($course, $context, 'qtype_ordering', $filearea, $args, $forcedownload);
}

View File

@ -104,10 +104,10 @@ class qtype_ordering_question extends question_graded_automatically {
* Any information about how the question has been set up for this attempt
* should be stored in the $step, by calling $step->set_qt_var(...).
*
* @param question_attempt_step $step The first step of the {@link question_attempt}
* @param question_attempt_step $step The first step of the {@see question_attempt}
* being started. Can be used to store state.
* @param int $variant which variant of this question to start. Will be between
* 1 and {@link get_num_variants()} inclusive.
* 1 and {@see get_num_variants()} inclusive.
*/
public function start_attempt(question_attempt_step $step, $variant) {
$countanswers = count($this->answers);
@ -158,7 +158,7 @@ class qtype_ordering_question extends question_graded_automatically {
}
/**
* When an in-progress {@link question_attempt} is re-loaded from the
* When an in-progress {@see question_attempt} is re-loaded from the
* database, this method is called so that the question can re-initialise
* its internal state as needed by this attempt.
*
@ -167,7 +167,7 @@ class qtype_ordering_question extends question_graded_automatically {
* originally. All the information required to do this should be in the
* $step object, which is the first step of the question_attempt being loaded.
*
* @param question_attempt_step $step The first step of the {@link question_attempt}
* @param question_attempt_step $step The first step of the {@see question_attempt}
* being loaded.
*/
public function apply_attempt_state(question_attempt_step $step) {
@ -207,9 +207,9 @@ class qtype_ordering_question extends question_graded_automatically {
}
return [
'_currentresponse' => implode(',', $neworder),
'_correctresponse' => implode(',', $newcorrect),
];
'_currentresponse' => implode(',', $neworder),
'_correctresponse' => implode(',', $newcorrect),
];
}
/**
@ -217,7 +217,7 @@ class qtype_ordering_question extends question_graded_automatically {
* this question in its current state?
*
* This information is used in calls to optional_param. The parameter name
* has {@link question_attempt::get_field_prefix()} automatically prepended.
* has {@see question_attempt::get_field_prefix()} automatically prepended.
*
* @return array|string variable name => PARAM_... constant, or, as a special case
* that should only be used in unavoidable, the constant question_attempt::USE_RAW_DATA
@ -225,7 +225,7 @@ class qtype_ordering_question extends question_graded_automatically {
*/
public function get_expected_data() {
$name = $this->get_response_fieldname();
return array($name => PARAM_TEXT);
return [$name => PARAM_TEXT];
}
/**
@ -243,13 +243,13 @@ class qtype_ordering_question extends question_graded_automatically {
$correctresponse[$position] = $answer->md5key;
}
$name = $this->get_response_fieldname();
return array($name => implode(',', $correctresponse));
return [$name => implode(',', $correctresponse)];
}
/**
* Produce a plain text summary of a response.
*
* @param array $response a response, as might be passed to {@link grade_response()}.
* @param array $response a response, as might be passed to {@see grade_response()}.
* @return string a plain text summary of that response, that could be used in reports.
*/
public function summarise_response(array $response) {
@ -257,9 +257,9 @@ class qtype_ordering_question extends question_graded_automatically {
if (array_key_exists($name, $response)) {
$items = explode(',', $response[$name]);
} else {
$items = array(); // Shouldn't happen !!
$items = []; // Shouldn't happen!
}
$answerids = array();
$answerids = [];
foreach ($this->answers as $answer) {
$answerids[$answer->md5key] = $answer->id;
}
@ -270,7 +270,7 @@ class qtype_ordering_question extends question_graded_automatically {
$item = shorten_text($item, 10, true); // Force truncate at 10 chars.
$items[$i] = $item;
} else {
$items[$i] = ''; // Shouldn't happen !!
$items[$i] = ''; // Shouldn't happen!
}
}
return implode('; ', array_filter($items));
@ -280,15 +280,15 @@ class qtype_ordering_question extends question_graded_automatically {
* Categorise the student's response according to the categories defined by
* get_possible_responses.
*
* @param array $response a response, as might be passed to {@link grade_response()}.
* @return array subpartid => {@link question_classified_response} objects.
* @param array $response a response, as might be passed to {@see grade_response()}.
* @return array subpartid => {@see question_classified_response} objects.
* returns an empty array if no analysis is possible.
*/
public function classify_response(array $response) {
$this->update_current_response($response);
$fraction = 1 / count($this->correctresponse);
$classifiedresponse = array();
$classifiedresponse = [];
foreach ($this->correctresponse as $position => $answerid) {
if (in_array($answerid, $this->currentresponse)) {
$currentposition = array_search($answerid, $this->currentresponse);
@ -298,7 +298,7 @@ class qtype_ordering_question extends question_graded_automatically {
$subqid = question_utils::to_plain_text($answer->answer, $answer->answerformat);
// Truncate responses longer than 100 bytes because they cannot be stored in the database.
// CAUTION: This will mess up answers which are not unique within the first 100 chars !!
// CAUTION: This will mess up answers which are not unique within the first 100 chars!
$maxbytes = 100;
if (strlen($subqid) > $maxbytes) {
// If the truncation point is in the middle of a multi-byte unicode char,
@ -325,7 +325,7 @@ class qtype_ordering_question extends question_graded_automatically {
* should move to the COMPLETE or INCOMPLETE state.
*
* @param array $response responses, as returned by
* {@link question_attempt_step::get_qt_data()}.
* {@see question_attempt_step::get_qt_data()}.
* @return bool whether this response is a complete answer to this question.
*/
public function is_complete_response(array $response) {
@ -338,7 +338,7 @@ class qtype_ordering_question extends question_graded_automatically {
* or whether it must be considered aborted.
*
* @param array $response responses, as returned by
* {@link question_attempt_step::get_qt_data()}.
* {@see question_attempt_step::get_qt_data()}.
* @return bool whether this response can be graded.
*/
public function is_gradable_response(array $response) {
@ -348,6 +348,7 @@ class qtype_ordering_question extends question_graded_automatically {
/**
* In situations where is_gradable_response() returns false, this method
* should generate a description of what the problem is.
*
* @param array $response
* @return string the message
*/
@ -361,7 +362,7 @@ class qtype_ordering_question extends question_graded_automatically {
* of responses can safely be discarded.
*
* @param array $old the responses previously recorded for this question,
* as returned by {@link question_attempt_step::get_qt_data()}
* as returned by {@see question_attempt_step::get_qt_data()}
* @param array $new the new responses, in the same format.
* @return bool whether the two sets of responses are the same - that is
* whether the new set of responses can safely be discarded.
@ -373,11 +374,11 @@ class qtype_ordering_question extends question_graded_automatically {
/**
* Grade a response to the question, returning a fraction between
* get_min_fraction() and get_max_fraction(), and the corresponding {@link question_state}
* get_min_fraction() and get_max_fraction(), and the corresponding {@see question_state}
* right, partial or wrong.
*
* @param array $response responses, as returned by
* {@link question_attempt_step::get_qt_data()}.
* {@see question_attempt_step::get_qt_data()}.
* @return array (float, integer) the fraction, and the state.
*/
public function grade_response(array $response) {
@ -469,7 +470,10 @@ class qtype_ordering_question extends question_graded_automatically {
} else {
$fraction = ($countcorrect / $countanswers);
}
return array($fraction, question_state::graded_state_for_fraction($fraction));
return [
$fraction,
question_state::graded_state_for_fraction($fraction),
];
}
/**
@ -537,17 +541,16 @@ class qtype_ordering_question extends question_graded_automatically {
*
* @return string
*/
public function get_response_fieldname() {
return 'response_'.$this->id;
public function get_response_fieldname(): string {
return 'response_' . $this->id;
}
/**
* Convert response data from mform into array
*
* @param array $response Form data
* @return array
*/
public function update_current_response($response) {
public function update_current_response(array $response) {
$name = $this->get_response_fieldname();
if (array_key_exists($name, $response)) {
$ids = explode(',', $response[$name]);
@ -568,14 +571,14 @@ class qtype_ordering_question extends question_graded_automatically {
*
* @return string
*/
public function get_ordering_layoutclass() {
public function get_ordering_layoutclass(): string {
switch ($this->options->layouttype) {
case self::LAYOUT_VERTICAL:
return 'vertical';
case self::LAYOUT_HORIZONTAL:
return 'horizontal';
default:
return ''; // Shouldn't happen !!
return ''; // Shouldn't happen!
}
}
@ -586,8 +589,8 @@ class qtype_ordering_question extends question_graded_automatically {
* @param bool $lastitem Include last item?
* @return array of id of next answer
*/
public function get_next_answerids($answerids, $lastitem = false) {
$nextanswerids = array();
public function get_next_answerids(array $answerids, bool $lastitem = false): array {
$nextanswerids = [];
$imax = count($answerids);
$imax--;
if ($lastitem) {
@ -611,21 +614,21 @@ class qtype_ordering_question extends question_graded_automatically {
* @param bool $all include all answers
* @return array of array('prev' => previd, 'next' => nextid)
*/
public function get_previous_and_next_answerids($answerids, $all = false) {
$prevnextanswerids = array();
public function get_previous_and_next_answerids(array $answerids, bool $all = false): array {
$prevnextanswerids = [];
$next = $answerids;
$prev = array();
$prev = [];
while ($answerid = array_shift($next)) {
if ($all) {
$prevnextanswerids[$answerid] = (object)array(
$prevnextanswerids[$answerid] = (object) [
'prev' => $prev,
'next' => $next
);
'next' => $next,
];
} else {
$prevnextanswerids[$answerid] = (object)array(
'prev' => array(empty($prev) ? 0 : $prev[0]),
'next' => array(empty($next) ? 0 : $next[0])
);
$prevnextanswerids[$answerid] = (object) [
'prev' => [empty($prev) ? 0 : $prev[0]],
'next' => [empty($next) ? 0 : $next[0]],
];
}
array_unshift($prev, $answerid);
}
@ -635,17 +638,16 @@ class qtype_ordering_question extends question_graded_automatically {
/**
* Search for best ordered subset
*
* @param bool $contiguous
* @param bool $contiguous A flag indicating whether only contiguous values should be considered for inclusion in the subset.
* @return array
*/
public function get_ordered_subset($contiguous) {
public function get_ordered_subset(bool $contiguous): array {
$positions = $this->get_ordered_positions($this->correctresponse,
$this->currentresponse);
$positions = $this->get_ordered_positions($this->correctresponse, $this->currentresponse);
$subsets = $this->get_ordered_subsets($positions, $contiguous);
// The best subset (longest and leftmost).
$bestsubset = array();
$bestsubset = [];
// The length of the best subset
// initializing this to 1 means
@ -669,8 +671,8 @@ class qtype_ordering_question extends question_graded_automatically {
* @param array $currentresponse
* @return array
*/
public function get_ordered_positions($correctresponse, $currentresponse) {
$positions = array();
public function get_ordered_positions(array $correctresponse, array $currentresponse): array {
$positions = [];
foreach ($currentresponse as $answerid) {
$positions[] = array_search($answerid, $correctresponse);
}
@ -680,15 +682,14 @@ class qtype_ordering_question extends question_graded_automatically {
/**
* Get all ordered subsets in the positions array
*
* @param array $positions maps an item's current position to its correct position
* @param boolean $contiguous TRUE if searching only for contiguous subsets; otherwise FALSE
*
* @param array $positions maps an item's current position to its correct position
* @param bool $contiguous TRUE if searching only for contiguous subsets; otherwise FALSE
* @return array of ordered subsets from within the $positions array
*/
public function get_ordered_subsets($positions, $contiguous) {
public function get_ordered_subsets(array $positions, bool $contiguous): array {
// Var $subsets is the collection of all subsets within $positions.
$subsets = array();
$subsets = [];
// Loop through the values at each position.
foreach ($positions as $p => $value) {
@ -697,7 +698,7 @@ class qtype_ordering_question extends question_graded_automatically {
$isnew = true;
// An array of new and saved subsets to be added to $subsets.
$new = array();
$new = [];
// Append the current value to any subsets to which it belongs
// i.e. any subset whose end value is less than the current value.
@ -731,7 +732,7 @@ class qtype_ordering_question extends question_graded_automatically {
// If this is a "new" value, add it as a new subset.
if ($isnew) {
$new[] = array($p);
$new[] = [$p];
}
// Append any "new" subsets that were found during this iteration.
@ -749,85 +750,92 @@ class qtype_ordering_question extends question_graded_automatically {
* @param array $types
* @param int $type
* @return array|string array if $type is not specified and single string if $type is specified
* @throws coding_exception
*/
public static function get_types($types, $type) {
public static function get_types(array $types, $type): array|string {
if ($type === null) {
return $types; // Return all $types.
}
if (array_key_exists($type, $types)) {
return $types[$type]; // One $type.
}
return $type; // Shouldn't happen !!
throw new coding_exception('Invalid type: ' . $type);
}
/**
* Returns available values and descriptions for field "selecttype"
*
* @param int $type
* @param int|null $type
* @return array|string array if $type is not specified and single string if $type is specified
*/
public static function get_select_types($type=null) {
public static function get_select_types(int $type = null): array|string {
$plugin = 'qtype_ordering';
$types = array(
self::SELECT_ALL => get_string('selectall', $plugin),
self::SELECT_RANDOM => get_string('selectrandom', $plugin),
self::SELECT_CONTIGUOUS => get_string('selectcontiguous', $plugin)
);
$types = [
self::SELECT_ALL => get_string('selectall', $plugin),
self::SELECT_RANDOM => get_string('selectrandom', $plugin),
self::SELECT_CONTIGUOUS => get_string('selectcontiguous', $plugin),
];
return self::get_types($types, $type);
}
/**
* Returns available values and descriptions for field "layouttype"
*
* @param int $type
* @param int|null $type
* @return array|string array if $type is not specified and single string if $type is specified
*/
public static function get_layout_types($type=null) {
public static function get_layout_types(int $type = null): array|string {
$plugin = 'qtype_ordering';
$types = array(
$types = [
self::LAYOUT_VERTICAL => get_string('vertical', $plugin),
self::LAYOUT_HORIZONTAL => get_string('horizontal', $plugin)
);
self::LAYOUT_HORIZONTAL => get_string('horizontal', $plugin),
];
return self::get_types($types, $type);
}
/**
* Returns available values and descriptions for field "gradingtype"
*
* @param int $type
* @param int|null $type
* @return array|string array if $type is not specified and single string if $type is specified
*/
public static function get_grading_types($type=null) {
public static function get_grading_types(int $type = null): array|string {
$plugin = 'qtype_ordering';
$types = array(
self::GRADING_ALL_OR_NOTHING => get_string('allornothing', $plugin),
self::GRADING_ABSOLUTE_POSITION => get_string('absoluteposition', $plugin),
self::GRADING_RELATIVE_TO_CORRECT => get_string('relativetocorrect', $plugin),
self::GRADING_RELATIVE_NEXT_EXCLUDE_LAST => get_string('relativenextexcludelast', $plugin),
self::GRADING_RELATIVE_NEXT_INCLUDE_LAST => get_string('relativenextincludelast', $plugin),
$types = [
self::GRADING_ALL_OR_NOTHING => get_string('allornothing', $plugin),
self::GRADING_ABSOLUTE_POSITION => get_string('absoluteposition', $plugin),
self::GRADING_RELATIVE_TO_CORRECT => get_string('relativetocorrect', $plugin),
self::GRADING_RELATIVE_NEXT_EXCLUDE_LAST => get_string('relativenextexcludelast', $plugin),
self::GRADING_RELATIVE_NEXT_INCLUDE_LAST => get_string('relativenextincludelast', $plugin),
self::GRADING_RELATIVE_ONE_PREVIOUS_AND_NEXT => get_string('relativeonepreviousandnext', $plugin),
self::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT => get_string('relativeallpreviousandnext', $plugin),
self::GRADING_LONGEST_ORDERED_SUBSET => get_string('longestorderedsubset', $plugin),
self::GRADING_LONGEST_CONTIGUOUS_SUBSET => get_string('longestcontiguoussubset', $plugin)
);
self::GRADING_LONGEST_ORDERED_SUBSET => get_string('longestorderedsubset', $plugin),
self::GRADING_LONGEST_CONTIGUOUS_SUBSET => get_string('longestcontiguoussubset', $plugin),
];
return self::get_types($types, $type);
}
/**
* @param string $style
* @return array of the numbering styles supported. For each one, there
* should be a lang string numberingstylexxx in the qtype_ordering
* language file, and a case in the switch statement in number_in_style,
* and it should be listed in the definition of this column in install.xml.
* Get the numbering styles supported.
*
* For each style, there should be a corresponding lang string 'numberingstylexxx' in the qtype_ordering language file,
* a case in the switch statement in number_in_style, and it should be listed in the definition of this column in install.xml.
*
* @param string|null $style The specific numbering style to retrieve.
* @return array|string Numbering style(s).
* The keys are style identifiers, and the values are the corresponding language strings.
*/
public static function get_numbering_styles($style=null) {
public static function get_numbering_styles(string $style = null): array|string {
$plugin = 'qtype_ordering';
$styles = array('none' => get_string('numberingstylenone', $plugin),
'abc' => get_string('numberingstyleabc', $plugin),
'ABCD' => get_string('numberingstyleABCD', $plugin),
'123' => get_string('numberingstyle123', $plugin),
'iii' => get_string('numberingstyleiii', $plugin),
'IIII' => get_string('numberingstyleIIII', $plugin));
$styles = [
'none' => get_string('numberingstylenone', $plugin),
'abc' => get_string('numberingstyleabc', $plugin),
'ABCD' => get_string('numberingstyleABCD', $plugin),
'123' => get_string('numberingstyle123', $plugin),
'iii' => get_string('numberingstyleiii', $plugin),
'IIII' => get_string('numberingstyleIIII', $plugin),
];
return self::get_types($styles, $style);
}
@ -838,7 +846,7 @@ class qtype_ordering_question extends question_graded_automatically {
* @return array Array of three elements: the number of correct subparts,
* the number of partial correct subparts and the number of incorrect subparts.
*/
public function get_num_parts_right(array $response) {
public function get_num_parts_right(array $response): array {
$this->update_current_response($response);
$gradingtype = $this->options->gradingtype;
@ -874,7 +882,12 @@ class qtype_ordering_question extends question_graded_automatically {
* @param array $currentresponse The current response list base on grading type.
* @return float|null Float if the grade, base on the fraction scale and null if the item is not in the correct response.
*/
protected function get_fraction_of_item(int $position, int $answerid, array $correctresponse, array $currentresponse) {
protected function get_fraction_of_item(
int $position,
int $answerid,
array $correctresponse,
array $currentresponse
): float|null {
$gradingtype = $this->options->gradingtype;
$score = 0;

View File

@ -26,5 +26,5 @@ defined('MOODLE_INTERNAL') || die;
if ($ADMIN->fulltree) {
$settings->add(new admin_setting_configselect('qtype_ordering/defaultanswerformat',
get_string('defaultanswerformat', 'qtype_ordering'), '', FORMAT_MOODLE, format_text_menu()));
get_string('defaultanswerformat', 'qtype_ordering'), '', FORMAT_MOODLE, format_text_menu()));
}

View File

@ -34,13 +34,12 @@ require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_qtype_ordering extends behat_base {
/**
* Get the xpath for a given item by label.
* @param string $label the text of the item to drag.
* @return string the xpath expression.
*/
protected function item_xpath_by_lable($label) {
protected function item_xpath_by_label(string $label): string {
return '//li[@class = "sortableitem" and contains(normalize-space(.), "' . $this->escape($label) . '")]';
}
@ -49,7 +48,7 @@ class behat_qtype_ordering extends behat_base {
* @param string $position the number of place to drop it.
* @return string the xpath expression.
*/
protected function item_xpath_by_position($position) {
protected function item_xpath_by_position(string $position): string {
return '//li[@class = "sortableitem"][' . $position . ']';
}
@ -67,14 +66,22 @@ class behat_qtype_ordering extends behat_base {
*
* @Given /^I drag "(?P<label>[^"]*)" to space "(?P<position>\d+)" in the ordering question$/
*/
public function i_drag_to_space_in_the_drag_and_drop_into_text_question($label, $position) {
public function i_drag_to_space_in_the_drag_and_drop_into_text_question(string $label, int $position): void {
$generalcontext = behat_context_helper::get('behat_general');
// There was a weird issue where drag-drop was not reliable if an item was being
// dragged to the same place it already was. So, first drag below the bottom to reliably
// move it to the last place.
$generalcontext->i_drag_and_i_drop_it_in($this->item_xpath_by_lable($label),
'xpath_element', get_string('check', 'question'), 'button');
$generalcontext->i_drag_and_i_drop_it_in($this->item_xpath_by_lable($label),
'xpath_element', $this->item_xpath_by_position($position), 'xpath_element');
$generalcontext->i_drag_and_i_drop_it_in(
$this->item_xpath_by_label($label),
'xpath_element',
get_string('check', 'question'),
'button'
);
$generalcontext->i_drag_and_i_drop_it_in(
$this->item_xpath_by_label($label),
'xpath_element',
$this->item_xpath_by_position($position),
'xpath_element'
);
}
}

View File

@ -36,8 +36,8 @@ 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 {
public function get_test_questions() {
return array('moodle');
public function get_test_questions(): array {
return ['moodle'];
}
/**
@ -45,10 +45,9 @@ class qtype_ordering_test_helper extends question_test_helper {
*
* @return qtype_ordering_question the question instance.
*/
public function make_ordering_question_moodle() {
public function make_ordering_question_moodle(): qtype_ordering_question {
question_bank::load_question_definition_classes('ordering');
$q = new qtype_ordering_question();
$q->questionid = $q->id;
test_question_maker::initialise_a_question($q);
$q->qtype = question_bank::get_qtype('ordering');
$q->name = 'Moodle';
@ -80,12 +79,12 @@ class qtype_ordering_test_helper extends question_test_helper {
*
* @param int $id the id to set.
* @param string $text
* @param int $textformat one of the FORMAT_... constanst.
* @param int $textformat one of the FORMAT_... constants.
* @param int $order the position in order, numbered from 1.
* @param bool $addmd5 whether to add the md5key property.
* @return stdClass the answer.
*/
public function make_answer($id, $text, $textformat, $order, $addmd5 = false) {
public function make_answer(int $id, string $text, int $textformat, int $order, bool $addmd5 = false): stdClass {
global $CFG;
$answer = new stdClass();
@ -116,14 +115,14 @@ class qtype_ordering_test_helper extends question_test_helper {
*
* @return stdClass simulated question form data.
*/
public function get_ordering_question_form_data_moodle() {
public function get_ordering_question_form_data_moodle(): stdClass {
$form = new stdClass();
$form->name = 'Moodle';
$form->questiontext = ['text' => 'Put these words in order.', 'format' => FORMAT_HTML];
$form->defaultmark = 1;
$form->generalfeedback = [
'text' => 'The correct answer is "Modular Object Oriented Dynamic Learning Environment".',
'format' => FORMAT_HTML
'format' => FORMAT_HTML,
];
$form->layouttype = qtype_ordering_question::LAYOUT_HORIZONTAL;
@ -160,7 +159,7 @@ class qtype_ordering_test_helper extends question_test_helper {
*
* @return stdClass simulated question form data.
*/
public function get_ordering_question_data_moodle() {
public function get_ordering_question_data_moodle(): stdClass {
$questiondata = new stdClass();
test_question_maker::initialise_question_data($questiondata);
$questiondata->qtype = 'ordering';

View File

@ -35,7 +35,6 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
* @covers \qtype_ordering\output\correct_response
*/
class correct_response_test extends advanced_testcase {
/**
* Test the exported data for the template that renders the correct response to a given question attempt.
*
@ -56,13 +55,13 @@ class correct_response_test extends advanced_testcase {
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 attemp.
// Create a question attempt step and add it to the question attempt.
$step = new \question_attempt_step();
$qa->add_step($step);
$question->start_attempt($qa->get_last_step(), 1);
// Get the grading state based on the correct response and the current response, and later set it in the question
// attempt step.
list($fraction, $state) = $question->grade_response(qtype_ordering_test_helper::get_response($question, $currentresponse));
[$fraction, $state] = $question->grade_response(qtype_ordering_test_helper::get_response($question, $currentresponse));
$qa->get_last_step()->set_state($state);
$renderer = $PAGE->get_renderer('core');
@ -85,7 +84,7 @@ class correct_response_test extends advanced_testcase {
[
'hascorrectresponse' => true,
'showcorrect' => false,
]
],
],
'Partially correct question attempt (horizontal layout).' => [
['Modular', 'Object', 'Dynamic', 'Learning', 'Oriented', 'Environment'],
@ -102,7 +101,7 @@ class correct_response_test extends advanced_testcase {
['answertext' => 'Learning'],
['answertext' => 'Environment'],
],
]
],
],
'Incorrect question attempt (horizontal layout).' => [
['Object', 'Dynamic', 'Modular', 'Learning', 'Environment', 'Oriented'],
@ -119,7 +118,7 @@ class correct_response_test extends advanced_testcase {
['answertext' => 'Learning'],
['answertext' => 'Environment'],
],
]
],
],
'Incorrect question attempt (vertical layout).' => [
['Object', 'Dynamic', 'Modular', 'Learning', 'Environment', 'Oriented'],
@ -136,7 +135,7 @@ class correct_response_test extends advanced_testcase {
['answertext' => 'Learning'],
['answertext' => 'Environment'],
],
]
],
],
];
}

View File

@ -56,25 +56,43 @@ class question_test extends \advanced_testcase {
*/
const REVERSEORDER = ['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular'];
public function test_grading_all_or_nothing () {
public function test_grading_all_or_nothing(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
// Zero grade on any error (no partial scroe at all, it is either 1 or 0).
// Zero grade on any error (no partial score at all, it is either 1 or 0).
$question->options->gradingtype = qtype_ordering_question::GRADING_ALL_OR_NOTHING;
$question->start_attempt(new question_attempt_pending_step(), 1);
$this->assertEquals([1, question_state::$gradedright],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment'])));
$this->assertEquals([0., question_state::$gradedwrong],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular'])));
$this->assertEquals([0, question_state::$gradedwrong],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertEquals(
[1, question_state::$gradedright],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']
)
)
);
$this->assertEquals(
[0., question_state::$gradedwrong],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular']
)
)
);
$this->assertEquals(
[0, question_state::$gradedwrong],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
}
public function test_grading_absolute_position () {
public function test_grading_absolute_position(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
@ -82,29 +100,65 @@ class question_test extends \advanced_testcase {
$question->options->gradingtype = qtype_ordering_question::GRADING_ABSOLUTE_POSITION;
$question->start_attempt(new question_attempt_pending_step(), 1);
// Every item is in the correct position.
$this->assertEquals([1, question_state::$gradedright],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment'])));
$this->assertEquals(
[1, question_state::$gradedright],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']
)
)
);
// None of the items are in the correct position.
$this->assertEquals([0., question_state::$gradedwrong],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular'])));
$this->assertEquals(
[0., question_state::$gradedwrong],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular']
)
)
);
// 4 out of 6 items are in the correct position.
$this->assertLessThan([0.67, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Modular'])));
$this->assertGreaterThan([0.66, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Modular'])));
$this->assertLessThan(
[0.67, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Modular']
)
)
);
$this->assertGreaterThan(
[0.66, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Modular']
)
)
);
// 1 out of 6 item is in the correct position.
$this->assertLessThan([0.17, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertGreaterThan([0.16, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertLessThan(
[0.17, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
$this->assertGreaterThan(
[0.16, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
}
public function test_grading_relative_next_exclude_last () {
public function test_grading_relative_next_exclude_last(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
@ -113,24 +167,47 @@ class question_test extends \advanced_testcase {
$question->start_attempt(new question_attempt_pending_step(), 1);
// Every item is in the correct position.
$this->assertEquals([1, question_state::$gradedright],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment'])));
$this->assertEquals(
[1, question_state::$gradedright],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']
)
)
);
// None of the items are in the correct position and there is not relative next.
$this->assertEquals([0., question_state::$gradedwrong],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular'])));
$this->assertEquals(
[0., question_state::$gradedwrong],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular']
)
)
);
// 4 out of 6 items are in the correct position with relative next.
$this->assertEquals([0.6, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Modular'])));
$this->assertEquals(
[0.6, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Modular']
)
)
);
// 2 out of 6 item are in the correct position with relative next.
$this->assertEquals([0.4, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertEquals(
[0.4, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
}
public function test_grading_relative_next_include_last () {
public function test_grading_relative_next_include_last(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
@ -138,20 +215,37 @@ class question_test extends \advanced_testcase {
$question->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_NEXT_INCLUDE_LAST;
$question->start_attempt(new question_attempt_pending_step(), 1);
// Every item is in the correct position.
$this->assertEquals([1, question_state::$gradedright],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment'])));
// None of the items are in the correct position and there is not relative next.
$this->assertEquals([0., question_state::$gradedwrong],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular'])));
$this->assertEquals(
[1, question_state::$gradedright],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']
)
)
);
// None of the items are in the correct position and there is no relative next.
$this->assertEquals(
[0., question_state::$gradedwrong],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular']
)
)
);
// 3 out of 6 items are in the correct position with relative next.
$this->assertEquals([0.5, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Modular'])));
$this->assertEquals(
[0.5, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Modular']
)
)
);
}
public function test_grading_relative_one_previous_and_next () {
public function test_grading_relative_one_previous_and_next(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
@ -159,22 +253,46 @@ class question_test extends \advanced_testcase {
$question->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_ONE_PREVIOUS_AND_NEXT;
$question->start_attempt(new question_attempt_pending_step(), 1);
// All items are in the correct position.
$this->assertEquals([1, question_state::$gradedright],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment'])));
$this->assertEquals(
[1, question_state::$gradedright],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']
)
)
);
// None of the items are in the correct position.
$this->assertEquals([0., question_state::$gradedwrong],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular'])));
$this->assertEquals(
[0., question_state::$gradedwrong],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular']
)
)
);
// Partically correct.
$this->assertGreaterThan([0.33, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertLessThan([0.34, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertGreaterThan(
[0.33, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
$this->assertLessThan(
[0.34, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
}
public function test_grading_relative_all_previous_and_next () {
public function test_grading_relative_all_previous_and_next(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
@ -182,26 +300,55 @@ class question_test extends \advanced_testcase {
$question->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT;
$question->start_attempt(new question_attempt_pending_step(), 1);
// All items are in the correct position.
$this->assertEquals([1, question_state::$gradedright],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment'])));
$this->assertEquals(
[1, question_state::$gradedright],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']
)
)
);
// None of the items are in the correct position.
$this->assertEquals([0., question_state::$gradedwrong],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular'])));
$this->assertEquals(
[0., question_state::$gradedwrong],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular']
)
)
);
// Partially correct.
$this->assertEquals([0.6, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertLessThan([0.7, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertGreaterThan([0.6, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertEquals(
[0.6, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Oriented', 'Object', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
$this->assertLessThan(
[0.7, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
$this->assertGreaterThan(
[0.6, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
}
public function test_grading_longest_ordered_subset () {
public function test_grading_longest_ordered_subset(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
@ -209,22 +356,46 @@ class question_test extends \advanced_testcase {
$question->options->gradingtype = qtype_ordering_question::GRADING_LONGEST_ORDERED_SUBSET;
$question->start_attempt(new question_attempt_pending_step(), 1);
// All items are in the correct position.
$this->assertEquals([1, question_state::$gradedright],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment'])));
$this->assertEquals(
[1, question_state::$gradedright],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']
)
)
);
// None of the items are in the correct position.
$this->assertEquals([0., question_state::$gradedwrong],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular'])));
$this->assertEquals(
[0., question_state::$gradedwrong],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular']
)
)
);
// 5 items make the longest ordered subset and the result is 5 out of 5 (0.8333333333....)
$this->assertLessThan([0.84, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertGreaterThan([0.8, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertLessThan(
[0.84, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
$this->assertGreaterThan(
[0.8, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
}
public function test_grading_longest_contiguous_subset () {
public function test_grading_longest_contiguous_subset(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
@ -232,22 +403,46 @@ class question_test extends \advanced_testcase {
$question->options->gradingtype = qtype_ordering_question::GRADING_LONGEST_CONTIGUOUS_SUBSET;
$question->start_attempt(new question_attempt_pending_step(), 1);
// All items are in the correct position.
$this->assertEquals([1, question_state::$gradedright],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment'])));
$this->assertEquals(
[1, question_state::$gradedright],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']
)
)
);
// None of the items are in the correct position.
$this->assertEquals([0., question_state::$gradedwrong],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular'])));
$this->assertEquals(
[0., question_state::$gradedwrong],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular']
)
)
);
// 5 items make the longest ordered subset and the result is 5 out of 6 (0.8333333333....)
$this->assertLessThan([0.84, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertGreaterThan([0.8, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertLessThan(
[0.84, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
$this->assertGreaterThan(
[0.8, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
}
public function test_grading_relative_to_correct () {
public function test_grading_relative_to_correct(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
@ -255,31 +450,55 @@ class question_test extends \advanced_testcase {
$question->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_TO_CORRECT;
$question->start_attempt(new question_attempt_pending_step(), 1);
// All items are in the correct position.
$this->assertEquals([1, question_state::$gradedright],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment'])));
$this->assertEquals(
[1, question_state::$gradedright],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']
)
)
);
// None of the items are in the correct position.
// TODO: This grading method is very generous. It has to be chnaged.
$this->assertEquals([0.4, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular'])));
$this->assertEquals(
[0.4, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Learning', 'Dynamic', 'Oriented', 'Object', 'Modular']
)
)
);
$this->assertLessThan([0.7, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertGreaterThan([0.6, question_state::$gradedpartial],
$question->grade_response(qtype_ordering_test_helper::get_response($question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular'])));
$this->assertLessThan(
[0.7, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
$this->assertGreaterThan(
[0.6, question_state::$gradedpartial],
$question->grade_response(
qtype_ordering_test_helper::get_response(
$question,
['Object', 'Oriented', 'Dynamic', 'Learning', 'Environment', 'Modular']
)
)
);
}
public function test_get_expected_data() {
public function test_get_expected_data(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
$this->assertArrayHasKey('response_' . $question->id, $question->get_expected_data());
}
public function test_get_correct_response() {
public function test_get_correct_response(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
@ -288,43 +507,57 @@ class question_test extends \advanced_testcase {
// The assertEquals() is used to replace the deprecated assertArraySubset(), because in this one case
// they are equals. For more info see https://thephp.cc/articles/migrating-to-phpunit-9
// and https://github.com/rdohms/phpunit-arraysubset-asserts.
$this->assertEquals(qtype_ordering_test_helper::get_response($question, self::CORRECTORDER),
$question->get_correct_response());
$this->assertEquals(
qtype_ordering_test_helper::get_response($question, self::CORRECTORDER),
$question->get_correct_response()
);
}
public function test_is_same_response() {
public function test_is_same_response(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
$question->start_attempt(new question_attempt_pending_step(), 1);
$old = qtype_ordering_test_helper::get_response($question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']);
$old = qtype_ordering_test_helper::get_response(
$question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']
);
$new = $old;
$this->assertTrue($question->is_same_response($old, $new));
$new = qtype_ordering_test_helper::get_response($question,
['Environment', 'Modular', 'Object', 'Oriented', 'Dynamic', 'Learning']);
$new = qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Modular', 'Object', 'Oriented', 'Dynamic', 'Learning']
);
$this->assertFalse($question->is_same_response($old, $new));
}
public function test_summarise_response() {
public function test_summarise_response(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
$question->start_attempt(new question_attempt_pending_step(), 1);
$expected = 'Modular; Object; Oriented; Dynamic; Learning; Environ...';
$actual = $question->summarise_response(qtype_ordering_test_helper::get_response($question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']));
$actual = $question->summarise_response(
qtype_ordering_test_helper::get_response(
$question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']
)
);
$this->assertEquals($expected, $actual);
$expected = 'Environ...; Modular; Object; Oriented; Dynamic; Learning';
$actual = $question->summarise_response(qtype_ordering_test_helper::get_response($question,
['Environment', 'Modular', 'Object', 'Oriented', 'Dynamic', 'Learning']));
$actual = $question->summarise_response(
qtype_ordering_test_helper::get_response(
$question,
['Environment', 'Modular', 'Object', 'Oriented', 'Dynamic', 'Learning']
)
);
$this->assertEquals($expected, $actual);
}
public function test_initialise_question_instance() {
public function test_initialise_question_instance(): void {
// Create an Ordering question.
$questiondata = test_question_maker::get_question_data('ordering');
/** @var qtype_ordering_question $question */
@ -332,7 +565,7 @@ class question_test extends \advanced_testcase {
$this->assertStringContainsString('ordering_item_', reset($question->answers)->md5key);
}
public function test_get_ordering_layoutclass() {
public function test_get_ordering_layoutclass(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
@ -344,7 +577,7 @@ class question_test extends \advanced_testcase {
}
}
public function test_get_next_answerids() {
public function test_get_next_answerids(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
@ -373,7 +606,7 @@ class question_test extends \advanced_testcase {
}
}
public function test_get_previous_and_next_answerids() {
public function test_get_previous_and_next_answerids(): void {
// Create an Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
@ -397,13 +630,15 @@ class question_test extends \advanced_testcase {
}
}
public function test_classify_response_correct() {
public function test_classify_response_correct(): void {
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
$question->start_attempt(new question_attempt_step(), 1);
$response = qtype_ordering_test_helper::get_response($question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']);
$response = qtype_ordering_test_helper::get_response(
$question,
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']
);
$classifiedresponse = $question->classify_response($response);
$expected = [
@ -418,13 +653,15 @@ class question_test extends \advanced_testcase {
$this->assertEqualsWithDelta($expected, $classifiedresponse, 0.0000005);
}
public function test_classify_response_partially_correct() {
public function test_classify_response_partially_correct(): void {
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
$question->start_attempt(new question_attempt_step(), 1);
$response = qtype_ordering_test_helper::get_response($question,
['Dynamic', 'Modular', 'Object', 'Oriented', 'Learning', 'Environment']);
$response = qtype_ordering_test_helper::get_response(
$question,
['Dynamic', 'Modular', 'Object', 'Oriented', 'Learning', 'Environment']
);
$classifiedresponse = $question->classify_response($response);
$expected = [
@ -442,7 +679,7 @@ class question_test extends \advanced_testcase {
/**
* Test get number of correct|partial|incorrect on response.
*/
public function test_get_num_parts_right() {
public function test_get_num_parts_right(): void {
// Create a Ordering question.
/** @var qtype_ordering_question $question */
$question = test_question_maker::make_question('ordering');
@ -450,14 +687,16 @@ class question_test extends \advanced_testcase {
$question->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_TO_CORRECT;
$question->start_attempt(new question_attempt_pending_step(), 1);
$response = qtype_ordering_test_helper::get_response($question,
['Dynamic', 'Modular', 'Object', 'Oriented', 'Learning', 'Environment']);
$response = qtype_ordering_test_helper::get_response(
$question,
['Dynamic', 'Modular', 'Object', 'Oriented', 'Learning', 'Environment']
);
$numparts = $question->get_num_parts_right($response);
$this->assertEquals([2, 4, 0], $numparts);
}
public function test_validate_can_regrade_with_other_version_bad() {
public function test_validate_can_regrade_with_other_version_bad(): void {
if (!method_exists('question_definition', 'validate_can_regrade_with_other_version')) {
$this->markTestSkipped('This test only applies to Moodle 4.x');
}
@ -475,11 +714,13 @@ class question_test extends \advanced_testcase {
27 => $helper->make_answer(27, 'Learning', FORMAT_HTML, 5, true),
];
$this->assertEquals(get_string('regradeissuenumitemschanged', 'qtype_ordering'),
$newq->validate_can_regrade_with_other_version($question));
$this->assertEquals(
get_string('regradeissuenumitemschanged', 'qtype_ordering'),
$newq->validate_can_regrade_with_other_version($question)
);
}
public function test_validate_can_regrade_with_other_version_ok() {
public function test_validate_can_regrade_with_other_version_ok(): void {
if (!method_exists('question_definition', 'validate_can_regrade_with_other_version')) {
$this->markTestSkipped('This test only applies to Moodle 4.x');
}
@ -501,7 +742,7 @@ class question_test extends \advanced_testcase {
$this->assertNull($newq->validate_can_regrade_with_other_version($question));
}
public function test_update_attempt_state_date_from_old_version_bad() {
public function test_update_attempt_state_date_from_old_version_bad(): void {
if (!method_exists('question_definition', 'update_attempt_state_data_for_new_version')) {
$this->markTestSkipped('This test only applies to Moodle 4.x');
}
@ -526,7 +767,7 @@ class question_test extends \advanced_testcase {
$newq->update_attempt_state_data_for_new_version($oldstep, $question);
}
public function test_update_attempt_state_date_from_old_version_ok() {
public function test_update_attempt_state_date_from_old_version_ok(): void {
if (!method_exists('question_definition', 'update_attempt_state_data_for_new_version')) {
$this->markTestSkipped('This test only applies to Moodle 4.x');
}
@ -549,7 +790,9 @@ class question_test extends \advanced_testcase {
$oldstep->set_qt_var('_currentresponse', '15,13,17,16,18,14');
$oldstep->set_qt_var('_correctresponse', '13,14,15,16,17,18');
$this->assertEquals(['_currentresponse' => '25,23,27,26,28,24', '_correctresponse' => '23,24,25,26,27,28'],
$newq->update_attempt_state_data_for_new_version($oldstep, $question));
$this->assertEquals(
['_currentresponse' => '25,23,27,26,28,24', '_correctresponse' => '23,24,25,26,27,28'],
$newq->update_attempt_state_data_for_new_version($oldstep, $question)
);
}
}

View File

@ -60,15 +60,15 @@ class questiontype_test extends \advanced_testcase {
$this->qtype = null;
}
public function test_name() {
$this->assertEquals($this->qtype->name(), 'ordering');
public function test_name(): void {
$this->assertEquals('ordering', $this->qtype->name());
}
public function test_can_analyse_responses() {
public function test_can_analyse_responses(): void {
$this->assertTrue($this->qtype->can_analyse_responses());
}
public function test_question_saving() {
public function test_question_saving(): void {
$this->resetAfterTest();
$this->setAdminUser();
@ -92,7 +92,7 @@ class questiontype_test extends \advanced_testcase {
$actualquestiondata = question_bank::load_question_data($returnedfromsave->id);
foreach ($questiondata as $property => $value) {
if (!in_array($property, array('id', 'version', 'timemodified', 'timecreated', 'options', 'stamp'))) {
if (!in_array($property, ['id', 'version', 'timemodified', 'timecreated', 'options', 'stamp'])) {
$this->assertContainsEquals($value, (array)$actualquestiondata);
$this->assertContainsEquals($property, array_keys((array)$actualquestiondata));
}
@ -119,63 +119,63 @@ class questiontype_test extends \advanced_testcase {
}
}
public function test_get_possible_responses() {
public function test_get_possible_responses(): void {
$questiondata = test_question_maker::get_question_data('ordering');
$possibleresponses = $this->qtype->get_possible_responses($questiondata);
$expectedresponseclasses = array(
'Modular' => array(
$expectedresponseclasses = [
'Modular' => [
1 => new question_possible_response('Position 1', 0.1666667),
2 => new question_possible_response('Position 2', 0),
3 => new question_possible_response('Position 3', 0),
4 => new question_possible_response('Position 4', 0),
5 => new question_possible_response('Position 5', 0),
6 => new question_possible_response('Position 6', 0),
),
'Object' => array(
],
'Object' => [
1 => new question_possible_response('Position 1', 0),
2 => new question_possible_response('Position 2', 0.1666667),
3 => new question_possible_response('Position 3', 0),
4 => new question_possible_response('Position 4', 0),
5 => new question_possible_response('Position 5', 0),
6 => new question_possible_response('Position 6', 0),
),
'Oriented' => array(
],
'Oriented' => [
1 => new question_possible_response('Position 1', 0),
2 => new question_possible_response('Position 2', 0),
3 => new question_possible_response('Position 3', 0.1666667),
4 => new question_possible_response('Position 4', 0),
5 => new question_possible_response('Position 5', 0),
6 => new question_possible_response('Position 6', 0),
),
'Dynamic' => array(
],
'Dynamic' => [
1 => new question_possible_response('Position 1', 0),
2 => new question_possible_response('Position 2', 0),
3 => new question_possible_response('Position 3', 0),
4 => new question_possible_response('Position 4', 0.1666667),
5 => new question_possible_response('Position 5', 0),
6 => new question_possible_response('Position 6', 0),
),
'Learning' => array(
],
'Learning' => [
1 => new question_possible_response('Position 1', 0),
2 => new question_possible_response('Position 2', 0),
3 => new question_possible_response('Position 3', 0),
4 => new question_possible_response('Position 4', 0),
5 => new question_possible_response('Position 5', 0.1666667),
6 => new question_possible_response('Position 6', 0),
),
'Environment' => array(
],
'Environment' => [
1 => new question_possible_response('Position 1', 0),
2 => new question_possible_response('Position 2', 0),
3 => new question_possible_response('Position 3', 0),
4 => new question_possible_response('Position 4', 0),
5 => new question_possible_response('Position 5', 0),
6 => new question_possible_response('Position 6', 0.1666667),
),
);
$this->assertEqualsWithDelta($expectedresponseclasses, $possibleresponses, 0.0000005, '');
],
];
$this->assertEqualsWithDelta($expectedresponseclasses, $possibleresponses, 0.0000005);
}
public function test_get_possible_responses_very_long() {
public function test_get_possible_responses_very_long(): void {
$questiondata = test_question_maker::get_question_data('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.
@ -184,7 +184,7 @@ class questiontype_test extends \advanced_testcase {
$this->assertArrayHasKey($onehundredchars, $possibleresponses);
}
public function test_get_numberingstyle() {
public function test_get_numberingstyle(): void {
$questiondata = test_question_maker::get_question_data('ordering');
$expected = qtype_ordering_question::NUMBERING_STYLE_DEFAULT;
$actual = $this->qtype->get_numberingstyle($questiondata);
@ -215,5 +215,4 @@ class questiontype_test extends \advanced_testcase {
$actual = $this->qtype->get_numberingstyle($questiondata);
$this->assertEquals($expected, $actual);
}
}

View File

@ -24,7 +24,6 @@
namespace qtype_ordering;
use qtype_ordering\question_hint_ordering;
use test_question_maker;
use question_state;
use question_pattern_expectation;
@ -47,20 +46,19 @@ require_once($CFG->dirroot . '/question/type/ddwtos/tests/helper.php');
* @covers \qtype_ordering
*/
class walkthrough_test extends \qbehaviour_walkthrough_test_base {
/**
* Get the array of post data that will .
*
* @param array Representation of the response we want to submit. The answers in order.
* @param array $items Representation of the response we want to submit. The answers in order.
* @return array simulated POST data.
*/
protected function get_response($items) {
protected function get_response(array $items): array {
$question = $this->quba->get_question($this->slot);
return qtype_ordering_test_helper::get_response($question, $items);
}
public function test_deferred_feedback() {
public function test_deferred_feedback(): void {
// Create an ordering question.
$question = test_question_maker::make_question('ordering');
@ -70,9 +68,11 @@ class walkthrough_test extends \qbehaviour_walkthrough_test_base {
$this->check_current_state(question_state::$todo);
$this->check_current_mark(null);
$this->check_current_output(
$this->get_contains_hidden_expectation(
$this->quba->get_field_prefix($this->slot) . 'response_' . $question->id),
$this->get_does_not_contain_feedback_expectation());
$this->get_contains_hidden_expectation(
$this->quba->get_field_prefix($this->slot) . 'response_' . $question->id
),
$this->get_does_not_contain_feedback_expectation()
);
// Save the right answer.
$rightresponse = $this->get_response(['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']);
@ -82,8 +82,9 @@ class walkthrough_test extends \qbehaviour_walkthrough_test_base {
$this->check_current_state(question_state::$complete);
$this->check_current_mark(null);
$this->check_current_output(
$this->get_does_not_contain_correctness_expectation(),
$this->get_does_not_contain_feedback_expectation());
$this->get_does_not_contain_correctness_expectation(),
$this->get_does_not_contain_feedback_expectation()
);
// If the same answer is saved again, we should not generate another step.
$stepcount = $this->get_step_count();
@ -99,73 +100,79 @@ class walkthrough_test extends \qbehaviour_walkthrough_test_base {
$this->check_current_state(question_state::$gradedright);
$this->check_current_mark(15);
$this->check_current_output(
$this->get_contains_correct_expectation(),
$this->get_contains_general_feedback_expectation($question));
$this->get_contains_correct_expectation(),
$this->get_contains_general_feedback_expectation($question)
);
}
public function test_interactive_behaviour() {
public function test_interactive_behaviour(): void {
// Create a drag-and-drop question.
$question = test_question_maker::make_question('ordering');
$question->hints = array(
$question->hints = [
new question_hint_ordering(13, 'This is the first hint.', FORMAT_HTML, true, false, true),
new question_hint_ordering(14, 'This is the second hint.', FORMAT_HTML, false, false, false),
);
];
$this->start_attempt_at_question($question, 'interactive', 3);
// Check the initial state.
$this->check_current_state(question_state::$todo);
$this->check_current_mark(null);
$this->check_current_output(
$this->get_contains_hidden_expectation(
$this->quba->get_field_prefix($this->slot) . 'response_' . $question->id),
$this->get_contains_submit_button_expectation(true),
$this->get_does_not_contain_feedback_expectation(),
$this->get_tries_remaining_expectation(3),
$this->get_does_not_contain_num_parts_correct(),
$this->get_no_hint_visible_expectation());
$this->get_contains_hidden_expectation(
$this->quba->get_field_prefix($this->slot) . 'response_' . $question->id
),
$this->get_contains_submit_button_expectation(true),
$this->get_does_not_contain_feedback_expectation(),
$this->get_tries_remaining_expectation(3),
$this->get_does_not_contain_num_parts_correct(),
$this->get_no_hint_visible_expectation()
);
// Submit the wrong answer.
$this->process_submission(['-submit' => 1] +
$this->get_response(['Environment', 'Modular', 'Object', 'Oriented', 'Dynamic', 'Learning']));
$this->get_response(['Environment', 'Modular', 'Object', 'Oriented', 'Dynamic', 'Learning']));
// Verify.
$this->check_current_state(question_state::$todo);
$this->check_current_mark(null);
$this->check_current_output(
$this->get_does_not_contain_submit_button_expectation(),
$this->get_contains_try_again_button_expectation(true),
$this->get_does_not_contain_correctness_expectation(),
$this->get_contains_num_parts_correct_ordering(0, 5, 1),
$this->get_contains_hint_expectation('This is the first hint'));
$this->get_does_not_contain_submit_button_expectation(),
$this->get_contains_try_again_button_expectation(true),
$this->get_does_not_contain_correctness_expectation(),
$this->get_contains_num_parts_correct_ordering(0, 5, 1),
$this->get_contains_hint_expectation('This is the first hint')
);
// Do try again.
$this->process_submission(array('-tryagain' => 1));
$this->process_submission(['-tryagain' => 1]);
// Verify.
$this->check_current_state(question_state::$todo);
$this->check_current_mark(null);
$this->check_current_output(
$this->get_contains_submit_button_expectation(true),
$this->get_does_not_contain_correctness_expectation(),
$this->get_does_not_contain_feedback_expectation(),
$this->get_tries_remaining_expectation(2),
$this->get_no_hint_visible_expectation());
$this->get_contains_submit_button_expectation(true),
$this->get_does_not_contain_correctness_expectation(),
$this->get_does_not_contain_feedback_expectation(),
$this->get_tries_remaining_expectation(2),
$this->get_no_hint_visible_expectation()
);
// Submit the right answer.
$this->process_submission(['-submit' => 1] +
$this->get_response(['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']));
$this->get_response(['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment']));
// Verify.
$this->check_current_state(question_state::$gradedright);
// Note, this may not be the 'best possible' grade. Perhaps there should
// partial credit for things that were right on the first try.
// partially credit for things that were right on the first try.
$this->check_current_mark(2);
$this->check_current_output(
$this->get_does_not_contain_submit_button_expectation(),
$this->get_contains_correct_expectation(),
$this->get_does_not_contain_num_parts_correct(),
$this->get_no_hint_visible_expectation());
$this->get_does_not_contain_submit_button_expectation(),
$this->get_contains_correct_expectation(),
$this->get_does_not_contain_num_parts_correct(),
$this->get_no_hint_visible_expectation()
);
// Check regrading does not mess anything up.
$this->quba->regrade_all_questions();
@ -183,7 +190,11 @@ class walkthrough_test extends \qbehaviour_walkthrough_test_base {
* @param int $numincorrect The number of incorrect item.
* @return question_pattern_expectation
*/
protected function get_contains_num_parts_correct_ordering($numright, $numpartial, $numincorrect) {
protected function get_contains_num_parts_correct_ordering(
int $numright,
int $numpartial,
int $numincorrect
): question_pattern_expectation {
$a = new stdClass();
$a->numright = $numright;
$a->numpartial = $numpartial;