diff --git a/question/type/calculated/questiontype.php b/question/type/calculated/questiontype.php index 988a17960069e..7bd48f6112019 100644 --- a/question/type/calculated/questiontype.php +++ b/question/type/calculated/questiontype.php @@ -39,17 +39,17 @@ */ class qtype_calculated extends question_type { /** - * @const string a placeholder is a letter, followed by almost any characters. (This should probably be restricted more.) + * @var string a placeholder is a letter, followed by almost any characters. (This should probably be restricted more.) */ const PLACEHOLDER_REGEX_PART = '[[:alpha:]][^>} <`{"\']*'; /** - * @const string REGEXP for a placeholder, wrapped in its {...} delimiters, with capturing brackets around the name. + * @var string REGEXP for a placeholder, wrapped in its {...} delimiters, with capturing brackets around the name. */ const PLACEHODLER_REGEX = '~\{(' . self::PLACEHOLDER_REGEX_PART . ')\}~'; /** - * @const string Regular expression that finds the formulas in content, with capturing brackets to get the forumlas. + * @var string Regular expression that finds the formulas in content, with capturing brackets to get the forumlas. */ const FORMULAS_IN_TEXT_REGEX = '~\{=([^{}]*(?:\{' . self::PLACEHOLDER_REGEX_PART . '\}[^{}]*)*)\}~'; @@ -63,7 +63,7 @@ public function get_question_options($question) { global $CFG, $DB, $OUTPUT; parent::get_question_options($question); if (!$question->options = $DB->get_record('question_calculated_options', - array('question' => $question->id))) { + ['question' => $question->id])) { $question->options = new stdClass(); $question->options->synchronize = 0; $question->options->single = 0; @@ -83,7 +83,7 @@ public function get_question_options($question) { {question_calculated} c WHERE a.question = ? AND a.id = c.answer - ORDER BY a.id ASC", array($question->id))) { + ORDER BY a.id ASC", [$question->id])) { return false; } @@ -93,7 +93,7 @@ public function get_question_options($question) { } $question->hints = $DB->get_records('question_hints', - array('questionid' => $question->id), 'id ASC'); + ['questionid' => $question->id], 'id ASC'); if (isset($question->export_process)&&$question->export_process) { $question->options->datasets = $this->get_datasets_for_export($question); @@ -103,12 +103,12 @@ public function get_question_options($question) { public function get_datasets_for_export($question) { global $DB, $CFG; - $datasetdefs = array(); + $datasetdefs = []; if (!empty($question->id)) { $sql = "SELECT i.* FROM {question_datasets} d, {question_dataset_definitions} i WHERE d.question = ? AND d.datasetdefinition = i.id"; - if ($records = $DB->get_records_sql($sql, array($question->id))) { + if ($records = $DB->get_records_sql($sql, [$question->id])) { foreach ($records as $r) { $def = $r; if ($def->category == '0') { @@ -124,7 +124,7 @@ public function get_datasets_for_export($question) { $def->decimals = $dec; if ($def->itemcount > 0) { // Get the datasetitems. - $def->items = array(); + $def->items = []; if ($items = $this->get_database_dataset_items($def->id)) { $n = 0; foreach ($items as $ii) { @@ -155,7 +155,7 @@ public function save_question_options($question) { // Calculated options. $update = true; $options = $DB->get_record('question_calculated_options', - array('question' => $question->id)); + ['question' => $question->id]); if (!$options) { $update = false; $options = new stdClass(); @@ -168,11 +168,11 @@ public function save_question_options($question) { $options->synchronize = 0; } $options->single = 0; - $options->answernumbering = $question->answernumbering; + $options->answernumbering = $question->answernumbering; $options->shuffleanswers = $question->shuffleanswers; - foreach (array('correctfeedback', 'partiallycorrectfeedback', - 'incorrectfeedback') as $feedbackname) { + foreach (['correctfeedback', 'partiallycorrectfeedback', + 'incorrectfeedback'] as $feedbackname) { $options->$feedbackname = ''; $feedbackformat = $feedbackname . 'format'; $options->$feedbackformat = 0; @@ -186,10 +186,10 @@ public function save_question_options($question) { // Get old versions of the objects. $oldanswers = $DB->get_records('question_answers', - array('question' => $question->id), 'id ASC'); + ['question' => $question->id], 'id ASC'); $oldoptions = $DB->get_records('question_calculated', - array('question' => $question->id), 'answer ASC'); + ['question' => $question->id], 'answer ASC'); // Save the units. $virtualqtype = $this->get_virtual_qtype(); @@ -248,14 +248,14 @@ public function save_question_options($question) { // Delete old answer records. if (!empty($oldanswers)) { foreach ($oldanswers as $oa) { - $DB->delete_records('question_answers', array('id' => $oa->id)); + $DB->delete_records('question_answers', ['id' => $oa->id]); } } // Delete old answer records. if (!empty($oldoptions)) { foreach ($oldoptions as $oo) { - $DB->delete_records('question_calculated', array('id' => $oo->id)); + $DB->delete_records('question_calculated', ['id' => $oo->id]); } } @@ -284,7 +284,7 @@ public function import_datasets($question) { $datasetdef = new stdClass(); $datasetdef->name = $dataset->name; $datasetdef->type = 1; - $datasetdef->options = $dataset->distribution . ':' . $dataset->min . ':' . + $datasetdef->options = $dataset->distribution . ':' . $dataset->min . ':' . $dataset->max . ':' . $dataset->length; $datasetdef->itemcount = $dataset->itemcount; if ($dataset->status == 'private') { @@ -296,10 +296,10 @@ public function import_datasets($question) { "type = '1' AND " . $DB->sql_equal('name', '?') . " AND category = ? - ORDER BY id DESC ", array($dataset->name, $question->category) + ORDER BY id DESC ", [$dataset->name, $question->category] )) { // So there is at least one. $sharedatasetdef = array_shift($sharedatasetdefs); - if ($sharedatasetdef->options == $datasetdef->options) {// Identical so use it. + if ($sharedatasetdef->options == $datasetdef->options) {// Identical so use it. $todo = 'useit'; $datasetdef = $sharedatasetdef; } else { // Different so create a private one. @@ -339,7 +339,7 @@ public function import_datasets($question) { * @param stdClass $questiondata The question data object. */ protected function initialise_calculated_answers(question_definition $question, stdClass $questiondata) { - $question->answers = array(); + $question->answers = []; if (empty($questiondata->options->answers)) { return; } @@ -541,7 +541,7 @@ public function preparedatasets($form, $questionfromid = '0') { // The dataset names present in the edit_question_form and edit_calculated_form // are retrieved. $possibledatasets = $this->find_dataset_names($form->questiontext); - $mandatorydatasets = array(); + $mandatorydatasets = []; foreach ($form->answer as $key => $answer) { $mandatorydatasets += $this->find_dataset_names($answer); } @@ -551,7 +551,7 @@ public function preparedatasets($form, $questionfromid = '0') { if ($questionfromid != '0') { $form->id = $questionfromid; } - $datasets = array(); + $datasets = []; $key = 0; // Always prepare the mandatorydatasets present in the answers. // The $options are not used here. @@ -590,7 +590,7 @@ public function addnamecategory(&$question) { AND a.type = '1' AND a.category != 0 AND b.question = ? - ORDER BY a.name ", array($question->id)); + ORDER BY a.name ", [$question->id]); $questionname = $this->clean_technical_prefix_from_question_name($question->name); if (!empty($categorydatasetdefs)) { @@ -603,7 +603,7 @@ public function addnamecategory(&$question) { } $questionname = '#' . $questionname; } - $DB->set_field('question', 'name', $questionname, array('id' => $question->id)); + $DB->set_field('question', 'name', $questionname, ['id' => $question->id]); } /** @@ -633,7 +633,7 @@ public function save_question($question, $form) { return $question; } - $wizardnow = optional_param('wizardnow', '', PARAM_ALPHA); + $wizardnow = optional_param('wizardnow', '', PARAM_ALPHA); $id = optional_param('id', 0, PARAM_INT); // Question id. // In case 'question': // For a new question $form->id is empty @@ -647,7 +647,7 @@ public function save_question($question, $form) { switch($wizardnow) { case '' : case 'question': // Coming from the first page, creating the second. - if (empty($form->id)) { // or a new question $form->id is empty. + if (empty($form->id)) { // Or a new question $form->id is empty. $question = parent::save_question($question, $form); // Prepare the datasets using default $questionfromid. $this->preparedatasets($form); @@ -657,7 +657,7 @@ public function save_question($question, $form) { $this->addnamecategory($question); } } else { - $questionfromid = $form->id; + $questionfromid = $form->id; $question = parent::save_question($question, $form); // Prepare the datasets. $this->preparedatasets($form, $questionfromid); @@ -679,7 +679,7 @@ public function save_question($question, $form) { $optionssynchronize = 0; } $DB->set_field('question_calculated_options', 'synchronize', $optionssynchronize, - array('question' => $question->id)); + ['question' => $question->id]); if (isset($form->synchronize) && $form->synchronize == 2) { $this->addnamecategory($question); } @@ -700,22 +700,22 @@ public function save_question($question, $form) { public function delete_question($questionid, $contextid) { global $DB; - $DB->delete_records('question_calculated', array('question' => $questionid)); - $DB->delete_records('question_calculated_options', array('question' => $questionid)); - $DB->delete_records('question_numerical_units', array('question' => $questionid)); - if ($datasets = $DB->get_records('question_datasets', array('question' => $questionid))) { + $DB->delete_records('question_calculated', ['question' => $questionid]); + $DB->delete_records('question_calculated_options', ['question' => $questionid]); + $DB->delete_records('question_numerical_units', ['question' => $questionid]); + if ($datasets = $DB->get_records('question_datasets', ['question' => $questionid])) { foreach ($datasets as $dataset) { if (!$DB->get_records_select('question_datasets', "question != ? AND datasetdefinition = ? ", - array($questionid, $dataset->datasetdefinition))) { + [$questionid, $dataset->datasetdefinition])) { $DB->delete_records('question_dataset_definitions', - array('id' => $dataset->datasetdefinition)); + ['id' => $dataset->datasetdefinition]); $DB->delete_records('question_dataset_items', - array('definition' => $dataset->datasetdefinition)); + ['definition' => $dataset->datasetdefinition]); } } } - $DB->delete_records('question_datasets', array('question' => $questionid)); + $DB->delete_records('question_datasets', ['question' => $questionid]); parent::delete_question($questionid, $contextid); } @@ -736,7 +736,7 @@ public function supports_dataset_item_generation() { public function custom_generator_tools_part($mform, $idx, $j) { - $minmaxgrp = array(); + $minmaxgrp = []; $minmaxgrp[] = $mform->createElement('float', "calcmin[{$idx}]", get_string('calcmin', 'qtype_calculated')); $minmaxgrp[] = $mform->createElement('float', "calcmax[{$idx}]", @@ -748,8 +748,8 @@ public function custom_generator_tools_part($mform, $idx, $j) { $mform->addElement('select', "calclength[{$idx}]", get_string('calclength', 'qtype_calculated'), $precisionoptions); - $distriboptions = array('uniform' => get_string('uniform', 'qtype_calculated'), - 'loguniform' => get_string('loguniform', 'qtype_calculated')); + $distriboptions = ['uniform' => get_string('uniform', 'qtype_calculated'), + 'loguniform' => get_string('loguniform', 'qtype_calculated')]; $mform->addElement('select', "calcdistribution[{$idx}]", get_string('calcdistribution', 'qtype_calculated'), $distriboptions); } @@ -774,20 +774,20 @@ public function custom_generator_tools($datasetdef) { if (preg_match('~^(uniform|loguniform):([^:]*):([^:]*):([0-9]*)$~', $datasetdef->options, $regs)) { $defid = "{$datasetdef->type}-{$datasetdef->category}-{$datasetdef->name}"; - for ($i = 0; $i<10; ++$i) { + for ($i = 0; $i < 10; ++$i) { $lengthoptions[$i] = get_string(($regs[1] == 'uniform' ? 'decimals' : 'significantfigures'), 'qtype_calculated', $i); } $menu1 = html_writer::label(get_string('lengthoption', 'qtype_calculated'), - 'menucalclength', false, array('class' => 'accesshide')); - $menu1 .= html_writer::select($lengthoptions, 'calclength[]', $regs[4], null, array('class' => 'custom-select')); + 'menucalclength', false, ['class' => 'accesshide']); + $menu1 .= html_writer::select($lengthoptions, 'calclength[]', $regs[4], null, ['class' => 'custom-select']); - $options = array('uniform' => get_string('uniformbit', 'qtype_calculated'), - 'loguniform' => get_string('loguniformbit', 'qtype_calculated')); + $options = ['uniform' => get_string('uniformbit', 'qtype_calculated'), + 'loguniform' => get_string('loguniformbit', 'qtype_calculated')]; $menu2 = html_writer::label(get_string('distributionoption', 'qtype_calculated'), - 'menucalcdistribution', false, array('class' => 'accesshide')); - $menu2 .= html_writer::select($options, 'calcdistribution[]', $regs[1], null, array('class' => 'custom-select')); + 'menucalcdistribution', false, ['class' => 'accesshide']); + $menu2 .= html_writer::select($options, 'calcdistribution[]', $regs[1], null, ['class' => 'custom-select']); return '
' @@ -815,20 +815,20 @@ public function update_dataset_options($datasetdefs, $form) { $uniquedefs = array_values(array_unique($form->definition)); foreach ($uniquedefs as $key => $defid) { if (isset($datasetdefs[$defid]) - && is_numeric($form->calcmin[$key+1]) - && is_numeric($form->calcmax[$key+1]) - && is_numeric($form->calclength[$key+1])) { - switch ($form->calcdistribution[$key+1]) { + && is_numeric($form->calcmin[$key + 1]) + && is_numeric($form->calcmax[$key + 1]) + && is_numeric($form->calclength[$key + 1])) { + switch ($form->calcdistribution[$key + 1]) { case 'uniform': case 'loguniform': - $datasetdefs[$defid]->options = - $form->calcdistribution[$key+1] . ':' - . $form->calcmin[$key+1] . ':' - . $form->calcmax[$key+1] . ':' - . $form->calclength[$key+1]; + $datasetdefs[$defid]->options = + $form->calcdistribution[$key + 1] . ':' + . $form->calcmin[$key + 1] . ':' + . $form->calcmax[$key + 1] . ':' + . $form->calclength[$key + 1]; break; default: echo $OUTPUT->notification( - "Unexpected distribution ".$form->calcdistribution[$key+1]); + "Unexpected distribution ".$form->calcdistribution[$key + 1]); } } } @@ -847,7 +847,7 @@ public function save_question_calculated($question, $fromform) { global $DB; foreach ($question->options->answers as $key => $answer) { - if ($options = $DB->get_record('question_calculated', array('answer' => $key))) { + if ($options = $DB->get_record('question_calculated', ['answer' => $key])) { $options->tolerance = trim($fromform->tolerance[$key]); $options->tolerancetype = trim($fromform->tolerancetype[$key]); $options->correctanswerlength = trim($fromform->correctanswerlength[$key]); @@ -866,11 +866,11 @@ public function save_question_calculated($question, $fromform) { */ public function get_database_dataset_items($definition) { global $CFG, $DB; - $databasedataitems = $DB->get_records_sql(// Use number as key!! + $databasedataitems = $DB->get_records_sql( // Hint: Use the number as a key. " SELECT id , itemnumber, definition, value FROM {question_dataset_items} - WHERE definition = $definition order by id DESC ", array($definition)); - $dataitems = Array(); + WHERE definition = $definition order by id DESC ", [$definition]); + $dataitems = []; foreach ($databasedataitems as $id => $dataitem) { if (!isset($dataitems[$dataitem->itemnumber])) { $dataitems[$dataitem->itemnumber] = $dataitem; @@ -896,7 +896,7 @@ public function save_dataset_items($question, $fromform) { } // Get the old datasets for this question. - $datasetdefs = $this->get_dataset_definitions($question->id, array()); + $datasetdefs = $this->get_dataset_definitions($question->id, []); // Handle generator options... $olddatasetdefs = fullclone($datasetdefs); $datasetdefs = $this->update_dataset_options($datasetdefs, $fromform); @@ -923,7 +923,7 @@ public function save_dataset_items($question, $fromform) { foreach ($fromform->definition as $key => $defid) { // If the delete button has not been pressed then skip the datasetitems // in the 'add item' part of the form. - if ($i > count($datasetdefs)*$maxnumber) { + if ($i > count($datasetdefs) * $maxnumber) { break; } $addeditem = new stdClass(); @@ -978,7 +978,7 @@ public function save_dataset_items($question, $fromform) { $datasetdefs[$defid]->items = $this->get_database_dataset_items($datasetdef->id); } - for ($numberadded = $maxnumber+1; $numberadded <= $maxnumber + $numbertoadd; $numberadded++) { + for ($numberadded = $maxnumber + 1; $numberadded <= $maxnumber + $numbertoadd; $numberadded++) { if (isset($datasetdefs[$defid]->items[$numberadded])) { // In case of regenerate it modifies the already existing record. if ($defregenerate) { @@ -1017,16 +1017,16 @@ public function save_dataset_items($question, $fromform) { if (isset($fromform->deletebutton)) { if (isset($fromform->selectdelete)) { - $newmaxnumber = $maxnumber-$fromform->selectdelete; + $newmaxnumber = $maxnumber - $fromform->selectdelete; } else { - $newmaxnumber = $maxnumber-1; + $newmaxnumber = $maxnumber - 1; } if ($newmaxnumber < 0) { $newmaxnumber = 0; } foreach ($datasetdefs as $datasetdef) { if ($datasetdef->itemcount == $maxnumber) { - $datasetdef->itemcount= $newmaxnumber; + $datasetdef->itemcount = $newmaxnumber; $DB->update_record('question_dataset_definitions', $datasetdef); } } @@ -1039,12 +1039,12 @@ public function generate_dataset_item($options) { return false; } if ($regs[1] == 'uniform') { - $nbr = $regs[2] + ($regs[3]-$regs[2])*mt_rand()/mt_getrandmax(); + $nbr = $regs[2] + ($regs[3] - $regs[2]) * mt_rand() / mt_getrandmax(); return sprintf("%.".$regs[4].'f', $nbr); } else if ($regs[1] == 'loguniform') { $log0 = log(abs($regs[2])); // It would have worked the other way to. - $nbr = exp($log0 + (log(abs($regs[3])) - $log0)*mt_rand()/mt_getrandmax()); + $nbr = exp($log0 + (log(abs($regs[3])) - $log0) * mt_rand() / mt_getrandmax()); return sprintf("%.".$regs[4].'f', $nbr); } else { @@ -1071,14 +1071,14 @@ public function comment_on_datasetitems($qtypeobj, $questionid, $questiontext, $answers, $data, $number) { global $DB; $comment = new stdClass(); - $comment->stranswers = array(); + $comment->stranswers = []; $comment->outsidelimit = false; - $comment->answers = array(); + $comment->answers = []; // Find a default unit. $unit = ''; if (!empty($questionid)) { $units = $DB->get_records('question_numerical_units', - array('question' => $questionid, 'multiplier' => 1.0), + ['question' => $questionid, 'multiplier' => 1.0], 'id ASC', '*', 0, 1); if ($units) { $unit = reset($units); @@ -1088,7 +1088,7 @@ public function comment_on_datasetitems($qtypeobj, $questionid, $questiontext, $answers = fullclone($answers); $delimiter = ': '; - $virtualqtype = $qtypeobj->get_virtual_qtype(); + $virtualqtype = $qtypeobj->get_virtual_qtype(); foreach ($answers as $key => $answer) { $error = qtype_calculated_find_formula_errors($answer->answer); if ($error) { @@ -1121,8 +1121,8 @@ public function comment_on_datasetitems($qtypeobj, $questionid, $questiontext, $correcttrue = new stdClass(); $correcttrue->correct = $formattedanswer->answer; $correcttrue->true = ''; - if ($formattedanswer->answer < $answer->min || - $formattedanswer->answer > $answer->max) { + if ((float) $formattedanswer->answer < $answer->min || + (float) $formattedanswer->answer > $answer->max) { $comment->outsidelimit = true; $comment->answers[$key] = $key; $comment->stranswers[$key] .= @@ -1142,11 +1142,11 @@ public function comment_on_datasetitems($qtypeobj, $questionid, $questiontext, } public function tolerance_types() { - return array( + return [ '1' => get_string('relative', 'qtype_numerical'), '2' => get_string('nominal', 'qtype_numerical'), - '3' => get_string('geometric', 'qtype_numerical') - ); + '3' => get_string('geometric', 'qtype_numerical'), + ]; } public function dataset_options($form, $name, $mandatory = true, @@ -1166,18 +1166,18 @@ public function dataset_options($form, $name, $mandatory = true, } if (!$selected) { if ($mandatory) { - $selected = "1-0-{$name}"; // Default. + $selected = "1-0-{$name}"; // Default. } else { $selected = '0'; // Default. } } - return array($options, $selected); + return [$options, $selected]; } public function construct_dataset_menus($form, $mandatorydatasets, $optionaldatasets) { global $OUTPUT; - $datasetmenus = array(); + $datasetmenus = []; foreach ($mandatorydatasets as $datasetname) { if (!isset($datasetmenus[$datasetname])) { list($options, $selected) = @@ -1249,14 +1249,14 @@ public function substitute_variables_and_eval($str, $dataset) { public function get_dataset_definitions($questionid, $newdatasets) { global $DB; // Get the existing datasets for this question. - $datasetdefs = array(); + $datasetdefs = []; if (!empty($questionid)) { global $CFG; $sql = "SELECT i.* FROM {question_datasets} d, {question_dataset_definitions} i WHERE d.question = ? AND d.datasetdefinition = i.id ORDER BY i.id"; - if ($records = $DB->get_records_sql($sql, array($questionid))) { + if ($records = $DB->get_records_sql($sql, [$questionid])) { foreach ($records as $r) { $datasetdefs["{$r->type}-{$r->category}-{$r->name}"] = $r; } @@ -1288,7 +1288,7 @@ public function save_dataset_definitions($form) { // Save synchronize. if (empty($form->dataset)) { - $form->dataset = array(); + $form->dataset = []; } // Save datasets. $datasetdefinitions = $this->get_dataset_definitions($form->id, $form->dataset); @@ -1300,13 +1300,13 @@ public function save_dataset_definitions($form) { if (!isset($tmpdatasets[$defid])) { // This dataset is not used any more, delete it. $DB->delete_records('question_datasets', - array('question' => $form->id, 'datasetdefinition' => $datasetdef->id)); + ['question' => $form->id, 'datasetdefinition' => $datasetdef->id]); if ($datasetdef->category == 0) { // Question local dataset. $DB->delete_records('question_dataset_definitions', - array('id' => $datasetdef->id)); + ['id' => $datasetdef->id]); $DB->delete_records('question_dataset_items', - array('definition' => $datasetdef->id)); + ['definition' => $datasetdef->id]); } } // This has already been saved or just got deleted. @@ -1324,12 +1324,12 @@ public function save_dataset_definitions($form) { if ($olderdatasetdefs = $DB->get_records_select('question_dataset_definitions', 'type = ? AND name = ? AND category = ? AND id < ? ORDER BY id DESC', - array($datasetdef->type, $datasetdef->name, - $datasetdef->category, $datasetdef->id))) { + [$datasetdef->type, $datasetdef->name, + $datasetdef->category, $datasetdef->id])) { while ($olderdatasetdef = array_shift($olderdatasetdefs)) { $DB->delete_records('question_dataset_definitions', - array('id' => $datasetdef->id)); + ['id' => $datasetdef->id]); $datasetdef = $olderdatasetdef; } } @@ -1348,13 +1348,13 @@ public function save_dataset_definitions($form) { if (!empty($datasetdefinitions)) { foreach ($datasetdefinitions as $def) { $DB->delete_records('question_datasets', - array('question' => $form->id, 'datasetdefinition' => $def->id)); + ['question' => $form->id, 'datasetdefinition' => $def->id]); if ($def->category == 0) { // Question local dataset. $DB->delete_records('question_dataset_definitions', - array('id' => $def->id)); + ['id' => $def->id]); $DB->delete_records('question_dataset_items', - array('definition' => $def->id)); + ['definition' => $def->id]); } } } @@ -1427,12 +1427,12 @@ public function save_as_new_dataset_definitions($form, $initialid) { if ($olderdatasetdefs = $DB->get_records_select('question_dataset_definitions', "type = ? AND " . $DB->sql_equal('name', '?') . " AND category = ? AND id < ? ORDER BY id DESC", - array($datasetdef->type, $datasetdef->name, - $datasetdef->category, $datasetdef->id))) { + [$datasetdef->type, $datasetdef->name, + $datasetdef->category, $datasetdef->id])) { while ($olderdatasetdef = array_shift($olderdatasetdefs)) { $DB->delete_records('question_dataset_definitions', - array('id' => $datasetdef->id)); + ['id' => $datasetdef->id]); $datasetdef = $olderdatasetdef; } } @@ -1451,13 +1451,13 @@ public function save_as_new_dataset_definitions($form, $initialid) { if (!empty($datasetdefinitions)) { foreach ($datasetdefinitions as $def) { $DB->delete_records('question_datasets', - array('question' => $form->id, 'datasetdefinition' => $def->id)); + ['question' => $form->id, 'datasetdefinition' => $def->id]); if ($def->category == 0) { // Question local dataset. $DB->delete_records('question_dataset_definitions', - array('id' => $def->id)); + ['id' => $def->id]); $DB->delete_records('question_dataset_items', - array('definition' => $def->id)); + ['definition' => $def->id]); } } } @@ -1478,13 +1478,13 @@ public function pick_question_dataset($question, $datasetitem) { AND q.datasetdefinition = d.id AND d.id = i.definition AND i.itemnumber = ? - ORDER BY i.id DESC ", array($question->id, $datasetitem))) { + ORDER BY i.id DESC ", [$question->id, $datasetitem])) { $a = new stdClass(); $a->id = $question->id; $a->item = $datasetitem; throw new \moodle_exception('cannotgetdsfordependent', 'question', '', $a); } - $dataset = Array(); + $dataset = []; foreach ($dataitems as $id => $dataitem) { if (!isset($dataset[$dataitem->name])) { $dataset[$dataitem->name] = $dataitem->value; @@ -1510,14 +1510,14 @@ public function dataset_options_from_database($form, $name, $prefix = '', $sql = "SELECT a.* FROM {question_dataset_definitions} a, {question_datasets} b WHERE a.id = b.datasetdefinition AND a.type = '1' AND b.question = ? AND " . $DB->sql_equal('a.name', '?'); - $currentdatasetdef = $DB->get_record_sql($sql, array($form->id, $name)); + $currentdatasetdef = $DB->get_record_sql($sql, [$form->id, $name]); if (!$currentdatasetdef) { $currentdatasetdef = new stdClass(); $currentdatasetdef->type = '0'; } $key = "{$type}-0-{$name}"; if ($currentdatasetdef->type == $type - and $currentdatasetdef->category == 0) { + && $currentdatasetdef->category == 0) { $options[$key] = get_string($prefix."keptlocal{$type}", $langfile); } else { $options[$key] = get_string($prefix."newlocal{$type}", $langfile); @@ -1531,7 +1531,7 @@ public function dataset_options_from_database($form, $name, $prefix = '', WHERE a.id = b.datasetdefinition AND a.type = '1' AND a.category = ? - AND " . $DB->sql_equal('a.name', '?'), array($form->category, $name)); + AND " . $DB->sql_equal('a.name', '?'), [$form->category, $name]); $type = 1; $key = "{$type}-{$form->category}-{$name}"; if (!empty($categorydatasetdefs)) { @@ -1546,9 +1546,9 @@ public function dataset_options_from_database($form, $name, $prefix = '', $options[$key] = get_string($prefix."newcategory{$type}", $langfile); } // All done! - return array($options, $currentdatasetdef->type + return [$options, $currentdatasetdef->type ? "{$currentdatasetdef->type}-{$currentdatasetdef->category}-{$name}" - : ''); + : '']; } /** @@ -1582,13 +1582,13 @@ public function find_formulas($text) { */ public function get_dataset_definitions_category($form) { global $CFG, $DB; - $datasetdefs = array(); + $datasetdefs = []; $lnamemax = 30; if (!empty($form->category)) { $sql = "SELECT i.*, d.* FROM {question_datasets} d, {question_dataset_definitions} i WHERE i.id = d.datasetdefinition AND i.category = ?"; - if ($records = $DB->get_records_sql($sql, array($form->category))) { + if ($records = $DB->get_records_sql($sql, [$form->category])) { foreach ($records as $r) { if (!isset ($datasetdefs["{$r->name}"])) { $datasetdefs["{$r->name}"] = $r->itemcount; @@ -1608,7 +1608,7 @@ public function get_dataset_definitions_category($form) { */ public function print_dataset_definitions_category($form) { global $CFG, $DB; - $datasetdefs = array(); + $datasetdefs = []; $lnamemax = 22; $namestr = get_string('name'); $rangeofvaluestr = get_string('minmax', 'qtype_calculated'); @@ -1622,7 +1622,7 @@ public function print_dataset_definitions_category($form) { {question_dataset_definitions} i WHERE i.id = d.datasetdefinition AND i.category = ?"; - if ($records = $DB->get_records_sql($sql, array($category))) { + if ($records = $DB->get_records_sql($sql, [$category])) { foreach ($records as $r) { $sql1 = "SELECT q.* FROM {question} q @@ -1630,12 +1630,12 @@ public function print_dataset_definitions_category($form) { if (!isset ($datasetdefs["{$r->type}-{$r->category}-{$r->name}"])) { $datasetdefs["{$r->type}-{$r->category}-{$r->name}"] = $r; } - if ($questionb = $DB->get_records_sql($sql1, array($r->question))) { + if ($questionb = $DB->get_records_sql($sql1, [$r->question])) { if (!isset ($datasetdefs["{$r->type}-{$r->category}-{$r->name}"]->questions[$r->question])) { $datasetdefs["{$r->type}-{$r->category}-{$r->name}"]->questions[$r->question] = new stdClass(); } - $datasetdefs["{$r->type}-{$r->category}-{$r->name}"]->questions[ - $r->question]->name = $questionb[$r->question]->name; + $datasetdefs["{$r->type}-{$r->category}-{$r->name}"]->questions[$r->question]->name = + $questionb[$r->question]->name; } } } @@ -1680,8 +1680,7 @@ public function print_dataset_definitions_category($form) { * @param int $characterlimit the character limit. * @return string */ - public function get_short_question_name($stringtoshorten, $characterlimit) - { + public function get_short_question_name($stringtoshorten, $characterlimit) { if (!empty($stringtoshorten)) { $returnstring = format_string($stringtoshorten); if (strlen($returnstring) > $characterlimit) { @@ -1703,7 +1702,7 @@ public function get_short_question_name($stringtoshorten, $characterlimit) public function print_dataset_definitions_category_shared($question, $datasetdefsq) { global $CFG, $DB; - $datasetdefs = array(); + $datasetdefs = []; $lnamemax = 22; $namestr = get_string('name', 'quiz'); $rangeofvaluestr = get_string('minmax', 'qtype_calculated'); @@ -1715,7 +1714,7 @@ public function print_dataset_definitions_category_shared($question, $datasetdef $sql = "SELECT i.*, d.* FROM {question_datasets} d, {question_dataset_definitions} i WHERE i.id = d.datasetdefinition AND i.category = ?"; - if ($records = $DB->get_records_sql($sql, array($category))) { + if ($records = $DB->get_records_sql($sql, [$category])) { foreach ($records as $r) { $key = "{$r->type}-{$r->category}-{$r->name}"; $sql1 = "SELECT q.* @@ -1724,7 +1723,7 @@ public function print_dataset_definitions_category_shared($question, $datasetdef if (!isset($datasetdefs[$key])) { $datasetdefs[$key] = $r; } - if ($questionb = $DB->get_records_sql($sql1, array($r->question))) { + if ($questionb = $DB->get_records_sql($sql1, [$r->question])) { $datasetdefs[$key]->questions[$r->question] = new stdClass(); $datasetdefs[$key]->questions[$r->question]->name = $questionb[$r->question]->name; @@ -1792,7 +1791,7 @@ public function get_virtual_qtype() { } public function get_possible_responses($questiondata) { - $responses = array(); + $responses = []; $virtualqtype = $this->get_virtual_qtype(); $unit = $virtualqtype->get_default_numerical_unit($questiondata); @@ -1825,7 +1824,7 @@ public function get_possible_responses($questiondata) { $responses[null] = question_possible_response::no_response(); - return array($questiondata->id => $responses); + return [$questiondata->id => $responses]; } public function move_files($questionid, $oldcontextid, $newcontextid) { @@ -1910,7 +1909,7 @@ function qtype_calculated_calculate_answer($formula, $individualdata, $answer .= (1 == strlen($answer) ? '.' : '') . '00000000000000000000000000000000000000000x'; $calculated->answer = $sign - .substr($answer, 0, $answerlength +1).$exponent; + .substr($answer, 0, $answerlength + 1).$exponent; } } else { // Stick to plain numeric format. @@ -1921,7 +1920,7 @@ function qtype_calculated_calculate_answer($formula, $individualdata, // Could be an idea to add some zeros here. $answer .= (preg_match('~^[0-9]*$~', $answer) ? '.' : '') . '00000000000000000000000000000000000000000x'; - $oklen = $answerlength + ($p10 < 1 ? 2-$p10 : 1); + $oklen = $answerlength + ($p10 < 1 ? 2 - $p10 : 1); $calculated->answer = $sign.substr($answer, 0, $oklen); } } @@ -1980,7 +1979,7 @@ function qtype_calculated_find_formula_errors($formula) { } break; - // Single argument functions (the most common case). + // Single argument functions (the most common case). case 'abs': case 'acos': case 'acosh': case 'asin': case 'asinh': case 'atan': case 'atanh': case 'bindec': case 'ceil': case 'cos': case 'cosh': case 'decbin': case 'decoct': case 'deg2rad': @@ -1995,23 +1994,23 @@ function qtype_calculated_find_formula_errors($formula) { // Functions that take one or two arguments. case 'log': case 'round': - if (!empty($regs[5]) || empty($regs[3])) { - return get_string('functiontakesoneortwoargs', 'qtype_calculated', $regs[2]); - } + if (!empty($regs[5]) || empty($regs[3])) { + return get_string('functiontakesoneortwoargs', 'qtype_calculated', $regs[2]); + } break; // Functions that must have two arguments. case 'atan2': case 'fmod': case 'pow': - if (!empty($regs[5]) || empty($regs[4])) { - return get_string('functiontakestwoargs', 'qtype_calculated', $regs[2]); - } + if (!empty($regs[5]) || empty($regs[4])) { + return get_string('functiontakestwoargs', 'qtype_calculated', $regs[2]); + } break; // Functions that take two or more arguments. case 'min': case 'max': - if (empty($regs[4])) { - return get_string('functiontakesatleasttwo', 'qtype_calculated', $regs[2]); - } + if (empty($regs[4])) { + return get_string('functiontakesatleasttwo', 'qtype_calculated', $regs[2]); + } break; default: @@ -2045,7 +2044,7 @@ function qtype_calculated_find_formula_errors($formula) { function qtype_calculated_find_formula_errors_in_text($text) { $formulas = question_bank::get_qtype('calculated')->find_formulas($text); - $errors = array(); + $errors = []; foreach ($formulas as $match) { $error = qtype_calculated_find_formula_errors($match); if ($error) { diff --git a/question/type/calculated/tests/helper.php b/question/type/calculated/tests/helper.php index 623ed446fd031..cbbe06180217b 100644 --- a/question/type/calculated/tests/helper.php +++ b/question/type/calculated/tests/helper.php @@ -41,7 +41,7 @@ */ class qtype_calculated_test_helper extends question_test_helper { public function get_test_questions() { - return array('sum'); + return ['sum', 'mult']; } /** @@ -70,15 +70,15 @@ public function make_calculated_question_sum() { $q->unitdisplay = qtype_numerical::UNITNONE; $q->unitgradingtype = 0; $q->unitpenalty = 0; - $q->ap = new qtype_numerical_answer_processor(array()); + $q->ap = new qtype_numerical_answer_processor([]); $q->synchronised = false; - $q->datasetloader = new qtype_calculated_test_dataset_loader(0, array( - array('a' => 1, 'b' => 5), - array('a' => 3, 'b' => 4), - array('a' => 3, 'b' => 0.01416), - array('a' => 31, 'b' => 0.01416), - )); + $q->datasetloader = new qtype_calculated_test_dataset_loader(0, [ + ['a' => 1, 'b' => 5], + ['a' => 3, 'b' => 4], + ['a' => 3, 'b' => 0.01416], + ['a' => 31, 'b' => 0.01416], + ]); return $q; } @@ -115,7 +115,7 @@ public function get_calculated_question_data_sum() { $answer->correctanswerformat = 1; } - $qdata->options->units = array(); + $qdata->options->units = []; return $qdata; } @@ -138,24 +138,24 @@ public function get_calculated_question_form_data_sum() { $fromform->unitgradingtypes = '1'; $fromform->unitsleft = '0'; $fromform->nounits = 1; - $fromform->multiplier = array(); + $fromform->multiplier = []; $fromform->multiplier[0] = '1.0'; $fromform->synchronize = 0; $fromform->answernumbering = 0; $fromform->shuffleanswers = 0; $fromform->noanswers = 6; - $fromform->answer = array(); + $fromform->answer = []; $fromform->answer[0] = '{a} + {b}'; $fromform->answer[1] = '{a} - {b}'; $fromform->answer[2] = '*'; - $fromform->fraction = array(); + $fromform->fraction = []; $fromform->fraction[0] = '1.0'; $fromform->fraction[1] = '0.0'; $fromform->fraction[2] = '0.0'; - $fromform->tolerance = array(); + $fromform->tolerance = []; $fromform->tolerance[0] = 0.001; $fromform->tolerance[1] = 0.001; $fromform->tolerance[2] = 0; @@ -172,16 +172,16 @@ public function get_calculated_question_form_data_sum() { $fromform->correctanswerformat[1] = 1; $fromform->correctanswerformat[2] = 1; - $fromform->feedback = array(); - $fromform->feedback[0] = array(); + $fromform->feedback = []; + $fromform->feedback[0] = []; $fromform->feedback[0]['format'] = FORMAT_HTML; $fromform->feedback[0]['text'] = 'Very good.'; - $fromform->feedback[1] = array(); + $fromform->feedback[1] = []; $fromform->feedback[1]['format'] = FORMAT_HTML; $fromform->feedback[1]['text'] = 'Add. not subtract!'; - $fromform->feedback[2] = array(); + $fromform->feedback[2] = []; $fromform->feedback[2]['format'] = FORMAT_HTML; $fromform->feedback[2]['text'] = 'Completely wrong.'; @@ -189,6 +189,149 @@ public function get_calculated_question_form_data_sum() { return $fromform; } + + /** + * Makes a calculated question about multiplying two numbers. + * + * @return qtype_calculated_question + * @throws coding_exception + */ + public function make_calculated_question_mult() { + question_bank::load_question_definition_classes('calculated'); + $q = new qtype_calculated_question(); + test_question_maker::initialise_a_question($q); + $q->name = 'Simple multiplication'; + $q->questiontext = 'What is {a} * {b}?'; + $q->generalfeedback = 'Generalfeedback: {={a} * {b}} is the right answer.'; + + $q->answers = [ + 13 => new \qtype_calculated\qtype_calculated_answer(13, '{a} * {b}', 1.0, 'Positive.', FORMAT_HTML, 0), + 14 => new \qtype_calculated\qtype_calculated_answer(14, '-{a} * {b}', 0.0, 'Negative.', FORMAT_HTML, 0), + ]; + foreach ($q->answers as $answer) { + $answer->correctanswerlength = 2; + $answer->correctanswerformat = 1; + } + + $q->qtype = question_bank::get_qtype('calculated'); + $q->unitdisplay = qtype_numerical::UNITOPTIONAL; + $q->unitgradingtype = 0; + $q->unitpenalty = 0; + $q->unit = 'cm'; + $q->ap = new qtype_numerical_answer_processor([]); + $q->synchronised = false; + + $q->datasetloader = new qtype_calculated_test_dataset_loader(0, [ + ['a' => 1, 'b' => 5], + ['a' => 3, 'b' => 4], + ['a' => 3, 'b' => 0.01416], + ['a' => 31, 'b' => 0.01416], + ]); + + return $q; + } + + /** + * Makes a calculated question about multiplying two numbers. + * + * @return qtype_calculated_question + * @throws coding_exception + */ + public function get_calculated_question_data_mult() { + question_bank::load_question_definition_classes('calculated'); + $qdata = new stdClass(); + test_question_maker::initialise_question_data($qdata); + + $qdata->qtype = 'calculated'; + $qdata->name = 'Simple multiplication'; + $qdata->questiontext = 'What is {a} * {b}?'; + $qdata->generalfeedback = 'Generalfeedback: {={a} * {b}} is the right answer.'; + $qdata->status = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY; + + $qdata->options = new stdClass(); + $qdata->options->unitgradingtype = 0; + $qdata->options->unitpenalty = 0.0; + $qdata->options->showunits = qtype_numerical::UNITOPTIONAL; + $qdata->unit = 'cm'; + $qdata->options->unitsleft = 0; + $qdata->options->synchronize = 0; + + $qdata->options->answers = [ + 13 => new \qtype_calculated\qtype_calculated_answer(13, '{a} * {b}', 1.0, 'Positive.', FORMAT_HTML, 0.001), + 14 => new \qtype_calculated\qtype_calculated_answer(14, '-{a} * {b}', 0.0, 'Negative.', FORMAT_HTML, 0.001), + ]; + foreach ($qdata->options->answers as $answer) { + $answer->correctanswerlength = 2; + $answer->correctanswerformat = 1; + } + + $qdata->options->units = []; + + return $qdata; + } + + /** + * Makes a calculated question about multiplying two numbers. + * + * @return qtype_calculated_question + * @throws coding_exception + */ + public function get_calculated_question_form_data_mult() { + question_bank::load_question_definition_classes('calculated'); + $fromform = new stdClass(); + + $fromform->name = 'Simple multiplication'; + $fromform->questiontext = 'What is {a} * {b}?'; + $fromform->defaultmark = 1.0; + $fromform->generalfeedback = 'Generalfeedback: {={a} * {b}} is the right answer.'; + + $fromform->unitrole = '0'; + $fromform->unitpenalty = 0.1; + $fromform->unitgradingtypes = '1'; + $fromform->unitsleft = '0'; + $fromform->nounits = 1; + $fromform->multiplier = []; + $fromform->multiplier[0] = '1.0'; + $fromform->synchronize = 0; + $fromform->answernumbering = 0; + $fromform->shuffleanswers = 0; + + $fromform->noanswers = 6; + $fromform->answer = []; + $fromform->answer[0] = '{a} * {b}'; + $fromform->answer[1] = '-{a} * {b}'; + + $fromform->fraction = []; + $fromform->fraction[0] = '1.0'; + $fromform->fraction[1] = '0.0'; + + $fromform->tolerance = []; + $fromform->tolerance[0] = 0.001; + $fromform->tolerance[1] = 0.001; + + $fromform->tolerancetype[0] = 1; + $fromform->tolerancetype[1] = 1; + + $fromform->correctanswerlength[0] = 2; + $fromform->correctanswerlength[1] = 2; + + $fromform->correctanswerformat[0] = 1; + $fromform->correctanswerformat[1] = 1; + + $fromform->feedback = []; + $fromform->feedback[0] = []; + $fromform->feedback[0]['format'] = FORMAT_HTML; + $fromform->feedback[0]['text'] = 'Positive.'; + + $fromform->feedback[1] = []; + $fromform->feedback[1]['format'] = FORMAT_HTML; + $fromform->feedback[1]['text'] = 'Negative.'; + + $fromform->status = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY; + + return $fromform; + } + } @@ -199,9 +342,9 @@ public function get_calculated_question_form_data_sum() { * @copyright 2011 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class qtype_calculated_test_dataset_loader extends qtype_calculated_dataset_loader{ +class qtype_calculated_test_dataset_loader extends qtype_calculated_dataset_loader { protected $valuesets; - protected $aresynchronised = array(); + protected $aresynchronised = []; public function __construct($questionid, array $valuesets) { parent::__construct($questionid); diff --git a/question/type/calculated/tests/question_test.php b/question/type/calculated/tests/question_test.php index 0d6db2f3c2854..44e73c8487f5a 100644 --- a/question/type/calculated/tests/question_test.php +++ b/question/type/calculated/tests/question_test.php @@ -16,7 +16,9 @@ namespace qtype_calculated; +use qtype_calculated; use question_attempt_step; +use question_bank; use question_classified_response; use question_display_options; use question_state; @@ -36,74 +38,99 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class question_test extends \advanced_testcase { - public function test_is_complete_response() { + /** + * Test is complete response + * + * @covers \qtype_calculated + */ + public function test_is_complete_response(): void { $question = \test_question_maker::make_question('calculated'); - $this->assertFalse($question->is_complete_response(array())); - $this->assertTrue($question->is_complete_response(array('answer' => '0'))); - $this->assertTrue($question->is_complete_response(array('answer' => 0))); - $this->assertFalse($question->is_complete_response(array('answer' => 'test'))); + $this->assertFalse($question->is_complete_response([])); + $this->assertTrue($question->is_complete_response(['answer' => '0'])); + $this->assertTrue($question->is_complete_response(['answer' => 0])); + $this->assertFalse($question->is_complete_response(['answer' => 'test'])); } - public function test_is_gradable_response() { + /** + * Test is gradable response + * + * @covers \qtype_calculated + */ + public function test_is_gradable_response(): void { $question = \test_question_maker::make_question('calculated'); - $this->assertFalse($question->is_gradable_response(array())); - $this->assertTrue($question->is_gradable_response(array('answer' => '0'))); - $this->assertTrue($question->is_gradable_response(array('answer' => 0))); - $this->assertTrue($question->is_gradable_response(array('answer' => 'test'))); + $this->assertFalse($question->is_gradable_response([])); + $this->assertTrue($question->is_gradable_response(['answer' => '0'])); + $this->assertTrue($question->is_gradable_response(['answer' => 0])); + $this->assertTrue($question->is_gradable_response(['answer' => 'test'])); } - public function test_grading() { + /** + * Test grading + * + * @covers \qtype_calculated + */ + public function test_grading(): void { $question = \test_question_maker::make_question('calculated'); $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); - $this->assertEquals(array(0, question_state::$gradedwrong), - $question->grade_response(array('answer' => $values['a'] - $values['b']))); - $this->assertEquals(array(1, question_state::$gradedright), - $question->grade_response(array('answer' => $values['a'] + $values['b']))); + $this->assertEquals([0, question_state::$gradedwrong], + $question->grade_response(['answer' => $values['a'] - $values['b']])); + $this->assertEquals([1, question_state::$gradedright], + $question->grade_response(['answer' => $values['a'] + $values['b']])); } - public function test_get_correct_response() { + /** + * Test get correct response + * + * @covers \qtype_calculated + */ + public function test_get_correct_response(): void { // Testing with 3.0 + 0.1416. $question = \test_question_maker::make_question('calculated'); $question->start_attempt(new question_attempt_step(), 3); $values = $question->vs->get_values(); - $this->assertSame(array('answer' => '3.01' ), $question->get_correct_response()); + $this->assertSame(['answer' => '3.01' ], $question->get_correct_response()); foreach ($question->answers as $answer) { $answer->correctanswerlength = 2; $answer->correctanswerformat = 2; } - $this->assertSame(array('answer' => '3.0' ), $question->get_correct_response()); + $this->assertSame(['answer' => '3.0' ], $question->get_correct_response()); // Testing with 1.0 + 5.0. $question = \test_question_maker::make_question('calculated'); $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); - $this->assertSame(array('answer' => '6.00' ), $question->get_correct_response()); + $this->assertSame(['answer' => '6.00' ], $question->get_correct_response()); foreach ($question->answers as $answer) { $answer->correctanswerlength = 2; $answer->correctanswerformat = 2; } - $this->assertSame(array('answer' => '6.0' ), + $this->assertSame(['answer' => '6.0' ], $question->get_correct_response()); // Testing with 31.0 + 0.01416 . $question = \test_question_maker::make_question('calculated'); $question->start_attempt(new question_attempt_step(), 4); $values = $question->vs->get_values(); - $this->assertSame(array('answer' => '31.01' ), $question->get_correct_response()); + $this->assertSame(['answer' => '31.01' ], $question->get_correct_response()); foreach ($question->answers as $answer) { $answer->correctanswerlength = 3; $answer->correctanswerformat = 2; } - $this->assertSame(array('answer' => '31.0' ), $question->get_correct_response()); + $this->assertSame(['answer' => '31.0' ], $question->get_correct_response()); } - public function test_get_question_summary() { + /** + * Test get question summary + * + * @covers \qtype_calculated + */ + public function test_get_question_summary(): void { $question = \test_question_maker::make_question('calculated'); $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); @@ -112,65 +139,95 @@ public function test_get_question_summary() { $this->assertEquals('What is ' . $values['a'] . ' + ' . $values['b'] . '?', $qsummary); } - public function test_summarise_response() { + /** + * Test summarise response + * + * @covers \qtype_calculated + */ + public function test_summarise_response(): void { $question = \test_question_maker::make_question('calculated'); $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); - $this->assertEquals('3.1', $question->summarise_response(array('answer' => '3.1'))); + $this->assertEquals('3.1', $question->summarise_response(['answer' => '3.1'])); } - public function test_classify_response() { + /** + * Test classify response + * + * @covers \qtype_calculated + */ + public function test_classify_response(): void { $question = \test_question_maker::make_question('calculated'); $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); - $this->assertEquals(array( - new question_classified_response(13, $values['a'] + $values['b'], 1.0)), - $question->classify_response(array('answer' => $values['a'] + $values['b']))); - $this->assertEquals(array( - new question_classified_response(14, $values['a'] - $values['b'], 0.0)), - $question->classify_response(array('answer' => $values['a'] - $values['b']))); - $this->assertEquals(array( - new question_classified_response(17, 7 * $values['a'], 0.0)), - $question->classify_response(array('answer' => 7 * $values['a']))); - $this->assertEquals(array( - question_classified_response::no_response()), - $question->classify_response(array('answer' => ''))); + $this->assertEquals([ + new question_classified_response(13, $values['a'] + $values['b'], 1.0)], + $question->classify_response(['answer' => $values['a'] + $values['b']])); + $this->assertEquals([ + new question_classified_response(14, $values['a'] - $values['b'], 0.0)], + $question->classify_response(['answer' => $values['a'] - $values['b']])); + $this->assertEquals([ + new question_classified_response(17, 7 * $values['a'], 0.0)], + $question->classify_response(['answer' => 7 * $values['a']])); + $this->assertEquals([ + question_classified_response::no_response()], + $question->classify_response(['answer' => ''])); } - public function test_classify_response_no_star() { + /** + * Test classify response no star + * + * @covers \qtype_calculated + */ + public function test_classify_response_no_star(): void { $question = \test_question_maker::make_question('calculated'); unset($question->answers[17]); $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); - $this->assertEquals(array( - new question_classified_response(13, $values['a'] + $values['b'], 1.0)), - $question->classify_response(array('answer' => $values['a'] + $values['b']))); - $this->assertEquals(array( - new question_classified_response(14, $values['a'] - $values['b'], 0.0)), - $question->classify_response(array('answer' => $values['a'] - $values['b']))); - $this->assertEquals(array( - new question_classified_response(0, 7 * $values['a'], 0.0)), - $question->classify_response(array('answer' => 7 * $values['a']))); - $this->assertEquals(array( - question_classified_response::no_response()), - $question->classify_response(array('answer' => ''))); + $this->assertEquals([ + new question_classified_response(13, $values['a'] + $values['b'], 1.0)], + $question->classify_response(['answer' => $values['a'] + $values['b']])); + $this->assertEquals([ + new question_classified_response(14, $values['a'] - $values['b'], 0.0)], + $question->classify_response(['answer' => $values['a'] - $values['b']])); + $this->assertEquals([ + new question_classified_response(0, 7 * $values['a'], 0.0)], + $question->classify_response(['answer' => 7 * $values['a']])); + $this->assertEquals([ + question_classified_response::no_response()], + $question->classify_response(['answer' => ''])); } - public function test_get_variants_selection_seed_q_not_synchronised() { + /** + * Test get variants selection seed q not synchronised + * + * @covers \qtype_calculated + */ + public function test_get_variants_selection_seed_q_not_synchronised(): void { $question = \test_question_maker::make_question('calculated'); $this->assertEquals($question->stamp, $question->get_variants_selection_seed()); } - public function test_get_variants_selection_seed_q_synchronised_datasets_not() { + /** + * Test get variants selection seed q synchronised datasets not + * + * @covers \qtype_calculated + */ + public function test_get_variants_selection_seed_q_synchronised_datasets_not(): void { $question = \test_question_maker::make_question('calculated'); $question->synchronised = true; $this->assertEquals($question->stamp, $question->get_variants_selection_seed()); } - public function test_get_variants_selection_seed_q_synchronised() { + /** + * Test get variants selection seed q synchronised + * + * @covers \qtype_calculated + */ + public function test_get_variants_selection_seed_q_synchronised(): void { $question = \test_question_maker::make_question('calculated'); $question->synchronised = true; $question->datasetloader->set_are_synchronised($question->category, true); @@ -179,9 +236,11 @@ public function test_get_variants_selection_seed_q_synchronised() { } /** - * test_get_question_definition_for_external_rendering + * Test get question definition for external rendering + * + * @covers \qtype_calculated */ - public function test_get_question_definition_for_external_rendering() { + public function test_get_question_definition_for_external_rendering(): void { $this->resetAfterTest(); $question = \test_question_maker::make_question('calculated'); @@ -196,4 +255,43 @@ public function test_get_question_definition_for_external_rendering() { $this->assertEquals(qtype_numerical::UNITNONE, $options['unitdisplay']); $this->assertEmpty($options['unitsleft']); } + + /** + * Test that the grading of negative responses does not show false ERROR. + * + * @return void + * @throws \coding_exception + * @throws \dml_exception + * @covers \qtype_calculated + */ + public function test_grading_of_negative_responses(): void { + global $DB; + + $this->resetAfterTest(); + + $qtype = new qtype_calculated(); + + // Create a question. + $q = \test_question_maker::get_question_data('calculated', 'mult'); + $q->id = 99; + + // Add units for the question. The issue to test only applies if the answer contains a unit string. + $units = []; + $unit = new \stdClass(); + $unit->question = $q->id; + $unit->multiplier = 1.0; + $unit->unit = "cm"; + $units[] = $unit; + $DB->insert_records("question_numerical_units", $units); + + $qtypeobj = question_bank::get_qtype($qtype->name()); + $fakedata = ["a" => "5.7", "b" => "3.3"]; + + $result = $qtype->comment_on_datasetitems($qtypeobj, $q->id, $q->questiontext, $q->options->answers, $fakedata, 1); + + // Make sure "ERROR" is not part of the answers. + foreach ($result->stranswers as $answer) { + $this->assertFalse(strstr($answer, "ERROR"), "Assert that 'ERROR' is not part of the answer!"); + } + } }