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.
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

<
/**
< * Unit tests for the numerical question definition class.
> * Unit tests for the numerical questions answers processor.
*
< * @package moodlecore < * @subpackage questiontypes
> * @package qtype_numerical > * @category test
* @copyright 2008 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */
> namespace qtype_numerical; global $CFG; > require_once($CFG->dirroot . '/question/type/numerical/questiontype.php'); > use qtype_numerical_answer_processor; > class testable_qtype_numerical_answer_processor extends qtype_numerical_answer_processor { > /** public function parse_response($response) { > * Unit test for the numerical questions answers processor. return parent::parse_response($response); > * } > * @package qtype_numerical } > * @category test > * @copyright 2008 The Open University class qtype_numerical_answer_processor_test extends advanced_testcase { > * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later public function test_parse_response() { > * @covers \qtype_numerical_answer_processor $ap = new testable_qtype_numerical_answer_processor( > */ array('m' => 1, 'cm' => 100), false, '.', ','); > class answerprocessor_test extends \advanced_testcase { > /** $this->assertEquals(array('3', '142', '', ''), $ap->parse_response('3.142')); > * Test setup. $this->assertEquals(array('', '2', '', ''), $ap->parse_response('.2')); > */ $this->assertEquals(array('1', '', '', ''), $ap->parse_response('1.')); > public function setUp(): void {
< require_once($CFG->dirroot . '/question/type/numerical/questiontype.php');
< class testable_qtype_numerical_answer_processor extends qtype_numerical_answer_processor { < public function parse_response($response) { < return parent::parse_response($response);
> require_once("{$CFG->dirroot}/question/type/numerical/questiontype.php");
$this->assertEquals(array('1', '', '4', ''), $ap->parse_response('1e4'));
> $this->assertEquals(array('3', '142', '-4', ''), $ap->parse_response('3.142E-4')); > /** $this->assertEquals(array('', '2', '+2', ''), $ap->parse_response('.2e+2')); > * Test the parse_response function. $this->assertEquals(array('1', '', '-1', ''), $ap->parse_response('1.e-1')); > * $this->assertEquals(array('1', '0', '0', ''), $ap->parse_response('1.0e0')); > * @covers ::parse_response > * @dataProvider parse_response_provider $this->assertEquals(array('3', '', '8', ''), $ap->parse_response('3x10^8')); > * @param array $expected $this->assertEquals(array('3', '', '8', ''), $ap->parse_response('3×10^8')); > * @param mixed $args $this->assertEquals(array('3', '0', '8', ''), $ap->parse_response('3.0*10^8')); > */ $this->assertEquals(array('3', '00', '-8', ''), $ap->parse_response('3.00x10**-8')); > public function test_parse_response(array $expected, $args): void { $this->assertEquals(array('0', '001', '7', ''), $ap->parse_response('0.001×10**7')); > $ap = new qtype_numerical_answer_processor([ > 'm' => 1, $this->assertEquals(array('1', '', '', 'm'), $ap->parse_response('1m')); > 'cm' => 100, $this->assertEquals(array('3', '142', '', 'm'), $ap->parse_response('3.142 m')); > ], false, '.', ','); $this->assertEquals(array('', '2', '', 'm'), $ap->parse_response('.2m')); > $this->assertEquals(array('1', '', '', 'cm'), $ap->parse_response('1.cm')); > $rc = new \ReflectionClass($ap); $this->assertEquals(array('1', '0', '', 'cm'), $ap->parse_response('1.0 cm')); > $rcm = $rc->getMethod('parse_response'); $this->assertEquals(array('-1', '', '', 'm'), $ap->parse_response('-1.m')); > $rcm->setAccessible(true); $this->assertEquals(array('+1', '0', '', 'cm'), $ap->parse_response('+1.0cm')); > > $this->assertEquals($expected, $rcm->invoke($ap, $args));
< class qtype_numerical_answer_processor_test extends advanced_testcase { < public function test_parse_response() { < $ap = new testable_qtype_numerical_answer_processor( < array('m' => 1, 'cm' => 100), false, '.', ','); < < $this->assertEquals(array('3', '142', '', ''), $ap->parse_response('3.142')); < $this->assertEquals(array('', '2', '', ''), $ap->parse_response('.2')); < $this->assertEquals(array('1', '', '', ''), $ap->parse_response('1.')); < $this->assertEquals(array('1', '0', '', ''), $ap->parse_response('1.0')); < $this->assertEquals(array('-1', '', '', ''), $ap->parse_response('-1.')); < $this->assertEquals(array('+1', '0', '', ''), $ap->parse_response('+1.0')); < < $this->assertEquals(array('1', '', '4', ''), $ap->parse_response('1e4')); < $this->assertEquals(array('3', '142', '-4', ''), $ap->parse_response('3.142E-4')); < $this->assertEquals(array('', '2', '+2', ''), $ap->parse_response('.2e+2')); < $this->assertEquals(array('1', '', '-1', ''), $ap->parse_response('1.e-1')); < $this->assertEquals(array('1', '0', '0', ''), $ap->parse_response('1.0e0')); < < $this->assertEquals(array('3', '', '8', ''), $ap->parse_response('3x10^8')); < $this->assertEquals(array('3', '', '8', ''), $ap->parse_response('3×10^8')); < $this->assertEquals(array('3', '0', '8', ''), $ap->parse_response('3.0*10^8')); < $this->assertEquals(array('3', '00', '-8', ''), $ap->parse_response('3.00x10**-8')); < $this->assertEquals(array('0', '001', '7', ''), $ap->parse_response('0.001×10**7')); < < $this->assertEquals(array('1', '', '', 'm'), $ap->parse_response('1m')); < $this->assertEquals(array('3', '142', '', 'm'), $ap->parse_response('3.142 m')); < $this->assertEquals(array('', '2', '', 'm'), $ap->parse_response('.2m')); < $this->assertEquals(array('1', '', '', 'cm'), $ap->parse_response('1.cm')); < $this->assertEquals(array('1', '0', '', 'cm'), $ap->parse_response('1.0 cm')); < $this->assertEquals(array('-1', '', '', 'm'), $ap->parse_response('-1.m')); < $this->assertEquals(array('+1', '0', '', 'cm'), $ap->parse_response('+1.0cm')); < < $this->assertEquals(array('1', '', '4', 'm'), $ap->parse_response('1e4 m')); < $this->assertEquals(array('3', '142', '-4', 'cm'), $ap->parse_response('3.142E-4 cm')); < $this->assertEquals(array('', '2', '+2', 'm'), $ap->parse_response('.2e+2m')); < $this->assertEquals(array('1', '', '-1', 'm'), $ap->parse_response('1.e-1 m')); < $this->assertEquals(array('1', '0', '0', 'cm'), $ap->parse_response('1.0e0cm')); < < $this->assertEquals(array('1000000', '', '', ''), < $ap->parse_response('1,000,000')); < $this->assertEquals(array('1000', '00', '', 'm'), < $ap->parse_response('1,000.00 m')); < < $this->assertEquals(array(null, null, null, null), $ap->parse_response('frog')); < $this->assertEquals(array('3', '', '', 'frogs'), $ap->parse_response('3 frogs')); < $this->assertEquals(array(null, null, null, null), $ap->parse_response('. m')); < $this->assertEquals(array(null, null, null, null), $ap->parse_response('.e8 m')); < $this->assertEquals(array(null, null, null, null), $ap->parse_response(',')); < } < < protected function verify_value_and_unit($exectedval, $expectedunit, $expectedmultiplier, < qtype_numerical_answer_processor $ap, $input, $separateunit = null) { < list($val, $unit, $multiplier) = $ap->apply_units($input, $separateunit);
> /** > * Data provider for the parse_response function. > * > * @return array > */ > public function parse_response_provider(): array { > return [ > [['3', '142', '', ''], '3.142'], > [['', '2', '', ''], '.2'], > [['1', '', '', ''], '1.'], > [['1', '0', '', ''], '1.0'], > [['-1', '', '', ''], '-1.'], > [['+1', '0', '', ''], '+1.0'], > > [['1', '', '4', ''], '1e4'], > [['3', '142', '-4', ''], '3.142E-4'], > [['', '2', '+2', ''], '.2e+2'], > [['1', '', '-1', ''], '1.e-1'], > [['1', '0', '0', ''], '1.0e0'], > > [['3', '', '8', ''], '3x10^8'], > [['3', '', '8', ''], '3×10^8'], > [['3', '0', '8', ''], '3.0*10^8'], > [['3', '00', '-8', ''], '3.00x10**-8'], > [['0', '001', '7', ''], '0.001×10**7'], > > [['1', '', '', 'm'], '1m'], > [['3', '142', '', 'm'], '3.142 m'], > [['', '2', '', 'm'], '.2m'], > [['1', '', '', 'cm'], '1.cm'], > [['1', '0', '', 'cm'], '1.0 cm'], > [['-1', '', '', 'm'], '-1.m'], > [['+1', '0', '', 'cm'], '+1.0cm'], > > [['1', '', '4', 'm'], '1e4 m'], > [['3', '142', '-4', 'cm'], '3.142E-4 cm'], > [['', '2', '+2', 'm'], '.2e+2m'], > [['1', '', '-1', 'm'], '1.e-1 m'], > [['1', '0', '0', 'cm'], '1.0e0cm'], > > [['1000000', '', '', ''], '1,000,000'], > [['1000', '00', '', 'm'], '1,000.00 m'], > > [[null, null, null, null], 'frog'], > [['3', '', '', 'frogs'], '3 frogs'], > [[null, null, null, null], '. m'], > [[null, null, null, null], '.e8 m'], > [[null, null, null, null], ','], > ]; > } > > /** > * Call apply_units and verify the value and units returned. > * > * @param int|float $exectedval > * @param null|string $expectedunit > * @param int|float $expectedmultiplier > * @param qtype_numerical_answer_processor $ap > * @param null|int|float $input > * @param null|string $separateunit > */ > protected function verify_value_and_unit( > $exectedval, > $expectedunit, > $expectedmultiplier, > qtype_numerical_answer_processor $ap, > $input, > $separateunit = null > ): void { > [$val, $unit, $multiplier] = $ap->apply_units($input, $separateunit);
< public function test_apply_units() {
> /** > * Test the apply_units function with various parameters. > * > * @covers \qtype_numerical_answer_processor::apply_units > * @dataProvider apply_units_provider > * @param mixed $expectedvalue > * @param string|null $expectedunit > * @param float|int|null $expectedmultiplier > * @param string|null $input > */ > public function test_apply_units( > $expectedvalue, > $expectedunit, > $expectedmultiplier, > $input > ): void {
< array('m/s' => 1, 'c' => 3.3356409519815E-9, < 'mph' => 2.2369362920544), false, '.', ','); < < $this->verify_value_and_unit(3e8, 'm/s', 1, $ap, '3x10^8 m/s'); < $this->verify_value_and_unit(3e8, '', null, $ap, '3x10^8'); < $this->verify_value_and_unit(1, 'c', 299792458, $ap, '1c'); < $this->verify_value_and_unit(1, 'mph', 0.44704, $ap, '0001.000 mph');
> [ > 'm/s' => 1, > 'c' => 3.3356409519815E-9, > 'mph' => 2.2369362920544 > ], > false, > '.', > ',' > ); > > $this->verify_value_and_unit( > $expectedvalue, > $expectedunit, > $expectedmultiplier, > $ap, > $input > ); > }
< $this->verify_value_and_unit(1, 'frogs', null, $ap, '1 frogs'); < $this->verify_value_and_unit(null, null, null, $ap, '. m/s');
> /** > * Data provider for apply_units tests. > * > * @return array > */ > public function apply_units_provider(): array { > return [ > [3e8, 'm/s', 1, '3x10^8 m/s'], > [3e8, '', null, '3x10^8'], > [1, 'c', 299792458, '1c'], > [1, 'mph', 0.44704, '0001.000 mph'], > > [1, 'frogs', null, '1 frogs'], > [null, null, null, '. m/s'], > [null, null, null, null], > [null, null, null, ''], > [null, null, null, ' '], > ];
< public function test_apply_units_separate_unit() {
> /** > * Test the apply_units function with various parameters and different units. > * > * @covers \qtype_numerical_answer_processor::apply_units > * @dataProvider apply_units_provider_with_units > * @param mixed $expectedvalue > * @param string|null $expectedunit > * @param float|int|null $expectedmultiplier > * @param string|null $input > * @param string $units > */ > public function test_apply_units_with_unit( > $expectedvalue, > $expectedunit, > $expectedmultiplier, > $input, > $units > ): void {
< array('m/s' => 1, 'c' => 3.3356409519815E-9, < 'mph' => 2.2369362920544), false, '.', ','); < < $this->verify_value_and_unit(3e8, 'm/s', 1, $ap, '3x10^8', 'm/s'); < $this->verify_value_and_unit(3e8, '', null, $ap, '3x10^8', ''); < $this->verify_value_and_unit(1, 'c', 299792458, $ap, '1', 'c'); < $this->verify_value_and_unit(1, 'mph', 0.44704, $ap, '0001.000', 'mph'); < < $this->verify_value_and_unit(1, 'frogs', null, $ap, '1', 'frogs'); < $this->verify_value_and_unit(null, null, null, $ap, '.', 'm/s');
> [ > 'm/s' => 1, > 'c' => 3.3356409519815E-9, > 'mph' => 2.2369362920544 > ], > false, > '.', > ',' > ); > > $this->verify_value_and_unit( > $expectedvalue, > $expectedunit, > $expectedmultiplier, > $ap, > $input, > $units > );
< public function test_euro_style() { < $ap = new qtype_numerical_answer_processor(array(), false, ',', ' ');
> /** > * Data provider for apply_units with different units. > * > * @return array > */ > public function apply_units_provider_with_units(): array { > return [ > [3e8, 'm/s', 1, '3x10^8', 'm/s'], > [3e8, '', null, '3x10^8', ''], > [1, 'c', 299792458, '1', 'c'], > [1, 'mph', 0.44704, '0001.000', 'mph'], > > [1, 'frogs', null, '1', 'frogs'], > [null, null, null, '.', 'm/s'], > ]; > }
< $this->assertEquals(array(-1000, '', null), $ap->apply_units('-1 000')); < $this->assertEquals(array(3.14159, '', null), $ap->apply_units('3,14159'));
> /** > * Test apply_units with a comma float unit. > * > * @covers \qtype_numerical_answer_processor::apply_units > * @dataProvider euro_provider > * @param array $expected > * @param string $params > */ > public function test_euro_style(array $expected, string $params): void { > $ap = new qtype_numerical_answer_processor([], false, ',', ' '); > $this->assertEquals($expected, $ap->apply_units($params));
< public function test_percent() { < $ap = new qtype_numerical_answer_processor(array('%' => 100), false, '.', ',');
> /** > * Data provider for apply_units with euro float separators. > * > * return array > */ > public function euro_provider(): array { > return [ > [[-1000, '', null], '-1 000'], > [[3.14159, '', null], '3,14159'], > ]; > }
< $this->assertEquals(array('3', '%', 0.01), $ap->apply_units('3%')); < $this->assertEquals(array('1e-6', '%', 0.01), $ap->apply_units('1e-6 %')); < $this->assertEquals(array('100', '', null), $ap->apply_units('100'));
> /** > * Test apply_units with percentage values. > * > * @covers \qtype_numerical_answer_processor::apply_units > * @dataProvider percent_provider > * @param array $expected > * @param string $params > */ > public function test_percent(array $expected, string $params): void { > $ap = new qtype_numerical_answer_processor(['%' => 100], false, '.', ','); > $this->assertEquals($expected, $ap->apply_units($params));
$this->assertEquals(array('100', '$', 1), $ap->apply_units('$100.'));
> /** $this->assertEquals(array('100.00', '$', 1), $ap->apply_units('$100.00')); > * Data provider for apply_units with percentages. $this->assertEquals(array('100', '', null), $ap->apply_units('100')); > * $this->assertEquals(array('100', 'frog', null), $ap->apply_units('frog 100')); > * @return array } > */ } > public function percent_provider(): array { > return [ > [['3', '%', 0.01], '3%'], > [['1e-6', '%', 0.01], '1e-6 %'], > [['100', '', null], '100'], > ]; > }
< public function test_currency() { < $ap = new qtype_numerical_answer_processor(array('$' => 1, '£' => 1), true, '.', ',');
> /** > * Test apply_units with currency values. > * > * @covers \qtype_numerical_answer_processor::apply_units > * @dataProvider currency_provider > * @param array $expected > * @param string $params > */ > public function test_currency(array $expected, string $params): void { > $ap = new qtype_numerical_answer_processor([ > '$' => 1, > '£' => 1, > ], true, '.', ','); > $this->assertEquals($expected, $ap->apply_units($params)); > }
< $this->assertEquals(array('1234.56', '£', 1), $ap->apply_units('£1,234.56')); < $this->assertEquals(array('100', '$', 1), $ap->apply_units('$100')); < $this->assertEquals(array('100', '$', 1), $ap->apply_units('$100.')); < $this->assertEquals(array('100.00', '$', 1), $ap->apply_units('$100.00')); < $this->assertEquals(array('100', '', null), $ap->apply_units('100')); < $this->assertEquals(array('100', 'frog', null), $ap->apply_units('frog 100'));
> /** > * Data provider for apply_units with currency values. > * > * @return array > */ > public function currency_provider(): array { > return [ > [['1234.56', '£', 1], '£1,234.56'], > [['100', '$', 1], '$100'], > [['100', '$', 1], '$100.'], > [['100.00', '$', 1], '$100.00'], > [['100', '', null], '100'], > [['100', 'frog', null], 'frog 100'], > ];