Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  
  18  /**
  19   * Unit tests for the numerical question definition class.
  20   *
  21   * @package    qtype
  22   * @subpackage numerical
  23   * @copyright  2008 The Open University
  24   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  
  27  
  28  global $CFG;
  29  require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
  30  
  31  
  32  /**
  33   * Unit tests for the numerical question definition class.
  34   *
  35   * @copyright 2008 The Open University
  36   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class qtype_numerical_question_test extends advanced_testcase {
  39      public function test_is_complete_response() {
  40          $question = test_question_maker::make_question('numerical');
  41  
  42          $this->assertFalse($question->is_complete_response(array()));
  43          $this->assertTrue($question->is_complete_response(array('answer' => '0')));
  44          $this->assertTrue($question->is_complete_response(array('answer' => 0)));
  45          $this->assertFalse($question->is_complete_response(array('answer' => 'test')));
  46      }
  47  
  48      public function test_is_gradable_response() {
  49          $question = test_question_maker::make_question('numerical');
  50  
  51          $this->assertFalse($question->is_gradable_response(array()));
  52          $this->assertTrue($question->is_gradable_response(array('answer' => '0')));
  53          $this->assertTrue($question->is_gradable_response(array('answer' => 0)));
  54          $this->assertTrue($question->is_gradable_response(array('answer' => 'test')));
  55      }
  56  
  57      public function test_grading() {
  58          $question = test_question_maker::make_question('numerical');
  59  
  60          $this->assertEquals(array(0, question_state::$gradedwrong),
  61                  $question->grade_response(array('answer' => '1.0')));
  62          $this->assertEquals(array(1, question_state::$gradedright),
  63                  $question->grade_response(array('answer' => '3.14')));
  64      }
  65  
  66      public function test_grading_with_units() {
  67          $question = test_question_maker::make_question('numerical');
  68          $question->unitgradingtype = qtype_numerical::UNITOPTIONAL;
  69          $question->ap = new qtype_numerical_answer_processor(
  70                  array('m' => 1, 'cm' => 100), false, '.', ',');
  71  
  72          $this->assertEquals(array(1, question_state::$gradedright),
  73                  $question->grade_response(array('answer' => '3.14 frogs')));
  74          $this->assertEquals(array(1, question_state::$gradedright),
  75                  $question->grade_response(array('answer' => '3.14')));
  76          $this->assertEquals(array(1, question_state::$gradedright),
  77                  $question->grade_response(array('answer' => '3.14 m')));
  78          $this->assertEquals(array(1, question_state::$gradedright),
  79                  $question->grade_response(array('answer' => '314cm')));
  80          $this->assertEquals(array(1, question_state::$gradedright),
  81                  $question->grade_response(array('answer' => '314000000x10^-8m')));
  82      }
  83  
  84      public function test_grading_with_units_graded() {
  85          $question = test_question_maker::make_question('numerical');
  86          $question->unitgradingtype = qtype_numerical::UNITGRADED;
  87          $question->ap = new qtype_numerical_answer_processor(
  88                  array('m' => 1, 'cm' => 100), false, '.', ',');
  89  
  90          $this->assertEquals(array(0.8, question_state::$gradedpartial),
  91                  $question->grade_response(array('answer' => '3.14 frogs')));
  92          $this->assertEquals(array(0.8, question_state::$gradedpartial),
  93                  $question->grade_response(array('answer' => '3.14')));
  94          $this->assertEquals(array(1, question_state::$gradedright),
  95                  $question->grade_response(array('answer' => '3.14 m')));
  96          $this->assertEquals(array(1, question_state::$gradedright),
  97                  $question->grade_response(array('answer' => '314cm')));
  98          $this->assertEquals(array(1, question_state::$gradedright),
  99                  $question->grade_response(array('answer' => '314000000x10^-8m')));
 100          $this->assertEquals(array(0.8, question_state::$gradedpartial),
 101                  $question->grade_response(array('answer' => '3.14 cm')));
 102          $this->assertEquals(array(0, question_state::$gradedwrong),
 103                  $question->grade_response(array('answer' => '314 m')));
 104      }
 105  
 106      public function test_grading_unit() {
 107          $question = test_question_maker::make_question('numerical', 'unit');
 108  
 109          $this->assertEquals(array(0, question_state::$gradedwrong),
 110                  $question->grade_response(array('answer' => '2', 'unit' => 'm')));
 111          $this->assertEquals(array(0, question_state::$gradedwrong),
 112                  $question->grade_response(array('answer' => '2', 'unit' => 'cm')));
 113          $this->assertEquals(array(0, question_state::$gradedwrong),
 114                  $question->grade_response(array('answer' => '2', 'unit' => '')));
 115  
 116          $this->assertEquals(array(1, question_state::$gradedright),
 117                  $question->grade_response(array('answer' => '1.25', 'unit' => 'm')));
 118          $this->assertEquals(array(1, question_state::$gradedright),
 119                  $question->grade_response(array('answer' => '125', 'unit' => 'cm')));
 120          $this->assertEquals(array(0.5, question_state::$gradedpartial),
 121                  $question->grade_response(array('answer' => '1.25', 'unit' => '')));
 122  
 123          $this->assertEquals(array(0.5, question_state::$gradedpartial),
 124                  $question->grade_response(array('answer' => '1.23', 'unit' => 'm')));
 125          $this->assertEquals(array(0.5, question_state::$gradedpartial),
 126                  $question->grade_response(array('answer' => '123', 'unit' => 'cm')));
 127          $this->assertEquals(array(0.25, question_state::$gradedpartial),
 128                  $question->grade_response(array('answer' => '1.23', 'unit' => '')));
 129      }
 130  
 131      public function test_grading_currency() {
 132          $question = test_question_maker::make_question('numerical', 'currency');
 133  
 134          $this->assertEquals(array(1, question_state::$gradedright),
 135                  $question->grade_response(array('answer' => '$1332')));
 136          $this->assertEquals(array(1, question_state::$gradedright),
 137                  $question->grade_response(array('answer' => '$ 1332')));
 138          $this->assertEquals(array(0.8, question_state::$gradedpartial),
 139                  $question->grade_response(array('answer' => 'frog 1332')));
 140          $this->assertEquals(array(0.8, question_state::$gradedpartial),
 141                  $question->grade_response(array('answer' => '1332')));
 142          $this->assertEquals(array(0.8, question_state::$gradedpartial),
 143                  $question->grade_response(array('answer' => ' 1332')));
 144          $this->assertEquals(array(0, question_state::$gradedwrong),
 145                  $question->grade_response(array('answer' => '1332 $')));
 146          $this->assertEquals(array(0, question_state::$gradedwrong),
 147                  $question->grade_response(array('answer' => '1332 frogs')));
 148          $this->assertEquals(array(0, question_state::$gradedwrong),
 149                  $question->grade_response(array('answer' => '$1')));
 150      }
 151  
 152      public function test_get_correct_response() {
 153          $question = test_question_maker::make_question('numerical');
 154  
 155          $this->assertEquals(array('answer' => '3.14'),
 156                  $question->get_correct_response());
 157      }
 158  
 159      public function test_get_correct_response_units() {
 160          $question = test_question_maker::make_question('numerical', 'unit');
 161  
 162          $this->assertEquals(array('answer' => '1.25', 'unit' => 'm'),
 163                  $question->get_correct_response());
 164      }
 165  
 166      public function test_get_correct_response_currency() {
 167          $question = test_question_maker::make_question('numerical', 'currency');
 168  
 169          $this->assertEquals(array('answer' => '$ 1332'),
 170                  $question->get_correct_response());
 171      }
 172  
 173      public function test_get_question_summary() {
 174          $num = test_question_maker::make_question('numerical');
 175          $qsummary = $num->get_question_summary();
 176          $this->assertEquals('What is pi to two d.p.?', $qsummary);
 177      }
 178  
 179      public function test_summarise_response() {
 180          $num = test_question_maker::make_question('numerical');
 181          $this->assertEquals('3.1', $num->summarise_response(array('answer' => '3.1')));
 182      }
 183  
 184      public function test_summarise_response_zero() {
 185          $num = test_question_maker::make_question('numerical');
 186          $this->assertEquals('0', $num->summarise_response(array('answer' => '0')));
 187      }
 188  
 189      public function test_summarise_response_unit() {
 190          $num = test_question_maker::make_question('numerical', 'unit');
 191          $this->assertEquals('3.1', $num->summarise_response(array('answer' => '3.1')));
 192          $this->assertEquals('3.1m', $num->summarise_response(array('answer' => '3.1m')));
 193          $this->assertEquals('3.1 cm', $num->summarise_response(array('answer' => '3.1 cm')));
 194      }
 195  
 196      public function test_summarise_response_currency() {
 197          $num = test_question_maker::make_question('numerical', 'currency');
 198          $this->assertEquals('100', $num->summarise_response(array('answer' => '100')));
 199          $this->assertEquals('$100', $num->summarise_response(array('answer' => '$100')));
 200          $this->assertEquals('$ 100', $num->summarise_response(array('answer' => '$ 100')));
 201          $this->assertEquals('100 frogs', $num->summarise_response(array('answer' => '100 frogs')));
 202      }
 203  
 204      public function test_classify_response() {
 205          $num = test_question_maker::make_question('numerical');
 206          $num->start_attempt(new question_attempt_step(), 1);
 207  
 208          $this->assertEquals(array(
 209                  new question_classified_response(15, '3.1', 0.0)),
 210                  $num->classify_response(array('answer' => '3.1')));
 211          $this->assertEquals(array(
 212                  new question_classified_response(17, '42', 0.0)),
 213                  $num->classify_response(array('answer' => '42')));
 214          $this->assertEquals(array(
 215                  new question_classified_response(13, '3.14', 1.0)),
 216                  $num->classify_response(array('answer' => '3.14')));
 217          // Invalid response.
 218          $this->assertEquals(array(
 219                  new question_classified_response(null, 'abc', 0.0)),
 220                  $num->classify_response(array('answer' => 'abc')));
 221      }
 222  
 223      public function test_classify_response_no_star() {
 224          $num = test_question_maker::make_question('numerical');
 225          unset($num->answers[17]);
 226          $num->start_attempt(new question_attempt_step(), 1);
 227  
 228          $this->assertEquals(array(
 229                  new question_classified_response(15, '3.1', 0.0)),
 230                  $num->classify_response(array('answer' => '3.1')));
 231          $this->assertEquals(array(
 232                  new question_classified_response(0, '42', 0.0)),
 233                  $num->classify_response(array('answer' => '42')));
 234          // Invalid response.
 235          $this->assertEquals(array(
 236                  new question_classified_response(null, 'abc', 0.0)),
 237                  $num->classify_response(array('answer' => 'abc')));
 238      }
 239  
 240      public function test_classify_response_unit() {
 241          $num = test_question_maker::make_question('numerical', 'unit');
 242          $num->start_attempt(new question_attempt_step(), 1);
 243  
 244          $this->assertEquals(array(
 245                  new question_classified_response(13, '1.25', 0.5)),
 246                  $num->classify_response(array('answer' => '1.25', 'unit' => '')));
 247          $this->assertEquals(array(
 248                  new question_classified_response(13, '1.25 m', 1.0)),
 249                  $num->classify_response(array('answer' => '1.25', 'unit' => 'm')));
 250          $this->assertEquals(array(
 251                  new question_classified_response(13, '125 cm', 1.0)),
 252                  $num->classify_response(array('answer' => '125', 'unit' => 'cm')));
 253          $this->assertEquals(array(
 254                  new question_classified_response(14, '123 cm', 0.5)),
 255                  $num->classify_response(array('answer' => '123', 'unit' => 'cm')));
 256          $this->assertEquals(array(
 257                  new question_classified_response(14, '1.27 m', 0.5)),
 258                  $num->classify_response(array('answer' => '1.27', 'unit' => 'm')));
 259          $this->assertEquals(array(
 260                  new question_classified_response(17, '3.0 m', 0)),
 261                  $num->classify_response(array('answer' => '3.0', 'unit' => 'm')));
 262          $this->assertEquals(array(
 263                  question_classified_response::no_response()),
 264                  $num->classify_response(array('answer' => '')));
 265          // Invalid response.
 266          $this->assertEquals(array(
 267                  new question_classified_response(null, 'abc m', 0.0)),
 268                  $num->classify_response(array('answer' => 'abc', 'unit' => 'm')));
 269      }
 270  
 271      public function test_classify_response_unit_no_star() {
 272          $num = test_question_maker::make_question('numerical', 'unit');
 273          unset($num->answers[17]);
 274          $num->start_attempt(new question_attempt_step(), 1);
 275  
 276          $this->assertEquals(array(
 277                  new question_classified_response(0, '42 cm', 0)),
 278                  $num->classify_response(array('answer' => '42', 'unit' => 'cm')));
 279          $this->assertEquals(array(
 280                  new question_classified_response(0, '3.0', 0)),
 281                  $num->classify_response(array('answer' => '3.0', 'unit' => '')));
 282          $this->assertEquals(array(
 283                  new question_classified_response(0, '3.0 m', 0)),
 284                  $num->classify_response(array('answer' => '3.0', 'unit' => 'm')));
 285          $this->assertEquals(array(
 286                  question_classified_response::no_response()),
 287                  $num->classify_response(array('answer' => '', 'unit' => '')));
 288          // Invalid response.
 289          $this->assertEquals(array(
 290                              new question_classified_response(null, 'abc m', 0.0)),
 291                              $num->classify_response(array('answer' => 'abc', 'unit' => 'm')));
 292      }
 293  
 294      public function test_classify_response_currency() {
 295          $num = test_question_maker::make_question('numerical', 'currency');
 296          $num->start_attempt(new question_attempt_step(), 1);
 297  
 298          $this->assertEquals(array(
 299                  new question_classified_response(14, '$100', 0)),
 300                  $num->classify_response(array('answer' => '$100')));
 301          $this->assertEquals(array(
 302                  new question_classified_response(13, '1 332', 0.8)),
 303                  $num->classify_response(array('answer' => '1 332')));
 304          // Invalid response.
 305          $this->assertEquals(array(
 306                  new question_classified_response(null, '$abc', 0.0)),
 307                  $num->classify_response(array('answer' => '$abc')));
 308      }
 309  
 310      /**
 311       * test_get_question_definition_for_external_rendering
 312       */
 313      public function test_get_question_definition_for_external_rendering() {
 314          $this->resetAfterTest();
 315  
 316          $question = test_question_maker::make_question('numerical', 'unit');
 317          $question->start_attempt(new question_attempt_step(), 1);
 318          $qa = test_question_maker::get_a_qa($question);
 319          $displayoptions = new question_display_options();
 320  
 321          $options = $question->get_question_definition_for_external_rendering($qa, $displayoptions);
 322          $this->assertNotEmpty($options);
 323          $this->assertEquals(1, $options['unitgradingtype']);
 324          $this->assertEquals(0.5, $options['unitpenalty']);
 325          $this->assertEquals(qtype_numerical::UNITSELECT, $options['unitdisplay']);
 326          $this->assertEmpty($options['unitsleft']);
 327      }
 328  }