From 5f412b33019189be3ece29625b3b124cbf3feabc Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Fri, 6 Jan 2023 22:09:56 +0800 Subject: [PATCH] MDL-76362 qtype_numeric: Refactor answer tests --- .../type/numerical/tests/answerprocessor_test.php | 512 ++++++++++++++------- question/type/numerical/tests/coverage.php | 31 ++ 2 files changed, 375 insertions(+), 168 deletions(-) rewrite question/type/numerical/tests/answerprocessor_test.php (77%) create mode 100644 question/type/numerical/tests/coverage.php diff --git a/question/type/numerical/tests/answerprocessor_test.php b/question/type/numerical/tests/answerprocessor_test.php dissimilarity index 77% index e50bfc56829..db80069a563 100644 --- a/question/type/numerical/tests/answerprocessor_test.php +++ b/question/type/numerical/tests/answerprocessor_test.php @@ -1,168 +1,344 @@ -. - -/** - * Unit tests for the numerical questions answers processor. - * - * @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; - -use qtype_numerical_answer_processor; - -defined('MOODLE_INTERNAL') || die(); - -global $CFG; -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); - } -} - -/** - * Unit test for the numerical questions answers processor. - * - * @package qtype_numerical - * @category test - * @copyright 2008 The Open University - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class answerprocessor_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); - if (is_null($exectedval)) { - $this->assertNull($val); - } else { - $this->assertEqualsWithDelta($exectedval, $val, 0.0001); - } - $this->assertEquals($expectedunit, $unit); - if (is_null($expectedmultiplier)) { - $this->assertNull($multiplier); - } else { - $this->assertEqualsWithDelta($expectedmultiplier, $multiplier, 0.0001); - } - } - - public function test_apply_units() { - $ap = new qtype_numerical_answer_processor( - 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'); - - $this->verify_value_and_unit(1, 'frogs', null, $ap, '1 frogs'); - $this->verify_value_and_unit(null, null, null, $ap, '. m/s'); - } - - public function test_apply_units_separate_unit() { - $ap = new qtype_numerical_answer_processor( - 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'); - } - - public function test_euro_style() { - $ap = new qtype_numerical_answer_processor(array(), false, ',', ' '); - - $this->assertEquals(array(-1000, '', null), $ap->apply_units('-1 000')); - $this->assertEquals(array(3.14159, '', null), $ap->apply_units('3,14159')); - } - - public function test_percent() { - $ap = new qtype_numerical_answer_processor(array('%' => 100), false, '.', ','); - - $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')); - } - - public function test_currency() { - $ap = new qtype_numerical_answer_processor(array('$' => 1, '£' => 1), true, '.', ','); - - $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')); - } -} +. + +/** + * Unit tests for the numerical questions answers processor. + * + * @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; + +use qtype_numerical_answer_processor; + +/** + * Unit test for the numerical questions answers processor. + * + * @package qtype_numerical + * @category test + * @copyright 2008 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @covers \qtype_numerical_answer_processor + */ +class answerprocessor_test extends \advanced_testcase { + /** + * Test setup. + */ + public function setUp(): void { + global $CFG; + + require_once("{$CFG->dirroot}/question/type/numerical/questiontype.php"); + } + + /** + * Test the parse_response function. + * + * @covers ::parse_response + * @dataProvider parse_response_provider + * @param array $expected + * @param mixed $args + */ + public function test_parse_response(array $expected, $args): void { + $ap = new qtype_numerical_answer_processor([ + 'm' => 1, + 'cm' => 100, + ], false, '.', ','); + + $rc = new \ReflectionClass($ap); + $rcm = $rc->getMethod('parse_response'); + $rcm->setAccessible(True); + + $this->assertEquals($expected, $rcm->invoke($ap, $args)); + } + + /** + * 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); + if (is_null($exectedval)) { + $this->assertNull($val); + } else { + $this->assertEqualsWithDelta($exectedval, $val, 0.0001); + } + $this->assertEquals($expectedunit, $unit); + if (is_null($expectedmultiplier)) { + $this->assertNull($multiplier); + } else { + $this->assertEqualsWithDelta($expectedmultiplier, $multiplier, 0.0001); + } + } + + /** + * 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 { + $ap = new qtype_numerical_answer_processor( + [ + 'm/s' => 1, + 'c' => 3.3356409519815E-9, + 'mph' => 2.2369362920544 + ], + false, + '.', + ',' + ); + + $this->verify_value_and_unit( + $expectedvalue, + $expectedunit, + $expectedmultiplier, + $ap, + $input + ); + } + + /** + * 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'], + ]; + } + + /** + * 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 { + $ap = new qtype_numerical_answer_processor( + [ + 'm/s' => 1, + 'c' => 3.3356409519815E-9, + 'mph' => 2.2369362920544 + ], + false, + '.', + ',' + ); + + $this->verify_value_and_unit( + $expectedvalue, + $expectedunit, + $expectedmultiplier, + $ap, + $input, + $units + ); + } + + /** + * 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'], + ]; + } + + /** + * 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)); + } + + /** + * 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'], + ]; + } + + /** + * 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)); + } + + /** + * Data provider for apply_units with percentages. + * + * @return array + */ + public function percent_provider(): array { + return [ + [['3', '%', 0.01], '3%'], + [['1e-6', '%', 0.01], '1e-6 %'], + [['100', '', null], '100'], + ]; + } + + /** + * 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)); + } + + /** + * 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'], + ]; + } +} diff --git a/question/type/numerical/tests/coverage.php b/question/type/numerical/tests/coverage.php new file mode 100644 index 00000000000..8d8e9355908 --- /dev/null +++ b/question/type/numerical/tests/coverage.php @@ -0,0 +1,31 @@ +. + +defined('MOODLE_INTERNAL') || die(); + +/** + * Coverage information for the qtype_numerical. + * + * @copyright 2022 Andrew Nicols + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +return new class extends phpunit_coverage_info { + /** @var array The list of files relative to the plugin root to include in coverage generation. */ + protected $includelistfiles = [ + 'question.php', + 'questiontype.php', + ]; +}; -- 2.11.4.GIT