Skip to content

Commit 44f726a

Browse files
timhuntdanpoltawski
authored andcommitted
MDL-46148 qtype_calculated: unit tests + fixes for validation
1 parent 595ef47 commit 44f726a

File tree

2 files changed

+92
-1
lines changed

2 files changed

+92
-1
lines changed

question/type/calculated/questiontype.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -1890,6 +1890,11 @@ function qtype_calculated_calculate_answer($formula, $individualdata,
18901890
}
18911891

18921892

1893+
/**
1894+
* Validate a forumula.
1895+
* @param string $formula the formula to validate.
1896+
* @return string|boolean false if there are no problems. Otherwise a string error message.
1897+
*/
18931898
function qtype_calculated_find_formula_errors($formula) {
18941899
// Validates the formula submitted from the question edit page.
18951900
// Returns false if everything is alright
@@ -1918,7 +1923,7 @@ function qtype_calculated_find_formula_errors($formula) {
19181923

19191924
// Zero argument functions.
19201925
case 'pi':
1921-
if ($regs[3]) {
1926+
if (array_key_exists(3, $regs)) {
19221927
return get_string('functiontakesnoargs', 'qtype_calculated', $regs[2]);
19231928
}
19241929
break;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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+
* Unit tests for formula validation code.
19+
*
20+
* @package qtype_calculated
21+
* @copyright 2014 The Open University
22+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23+
*/
24+
25+
26+
defined('MOODLE_INTERNAL') || die();
27+
28+
global $CFG;
29+
require_once($CFG->dirroot . '/question/type/calculated/questiontype.php');
30+
31+
32+
/**
33+
* Unit tests for formula validation code.
34+
*
35+
* @copyright 2014 The Open University
36+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37+
*/
38+
class qtype_calculated_formula_validation_testcase extends basic_testcase {
39+
protected function assert_nonempty_string($actual) {
40+
$this->assertInternalType('string', $actual);
41+
$this->assertNotEquals('', $actual);
42+
}
43+
44+
public function test_simple_equations_ok() {
45+
$this->assertFalse(qtype_calculated_find_formula_errors(1));
46+
$this->assertFalse(qtype_calculated_find_formula_errors('1 + 1'));
47+
$this->assertFalse(qtype_calculated_find_formula_errors('{x} + {y}'));
48+
$this->assertFalse(qtype_calculated_find_formula_errors('{x}*{y}'));
49+
}
50+
51+
public function test_safe_functions_ok() {
52+
$this->assertFalse(qtype_calculated_find_formula_errors('abs(-1)'));
53+
$this->assertFalse(qtype_calculated_find_formula_errors('tan(pi())'));
54+
$this->assertFalse(qtype_calculated_find_formula_errors('log(10)'));
55+
$this->assertFalse(qtype_calculated_find_formula_errors('log(64, 2)'));
56+
$this->assertFalse(qtype_calculated_find_formula_errors('atan2(1.0, 1.0)'));
57+
$this->assertFalse(qtype_calculated_find_formula_errors('max(1.0, 1.0)'));
58+
$this->assertFalse(qtype_calculated_find_formula_errors('max(1.0, 1.0, 2.0)'));
59+
$this->assertFalse(qtype_calculated_find_formula_errors('max(1.0, 1.0, 2, 3)'));
60+
}
61+
62+
public function test_dangerous_functions_blocked() {
63+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('eval(1)'));
64+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('system(1)'));
65+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('base64_decode(1)'));
66+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('unserialize(1)'));
67+
68+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('cos(tan(1) + abs(cos(eval)) * pi())'));
69+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('eval (CONSTANTREADASSTRING)'));
70+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors("eval \t ()"));
71+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('"eval"()'));
72+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('?><?php()'));
73+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('?><?php+1'));
74+
}
75+
76+
public function test_functions_with_wrong_num_args_caught() {
77+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('abs(-1, 1)'));
78+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('abs()'));
79+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('pi(1)'));
80+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('log()'));
81+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('log(64, 2, 3)'));
82+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('atan2(1.0)'));
83+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('atan2(1.0, 1.0, 2.0)'));
84+
$this->assert_nonempty_string(qtype_calculated_find_formula_errors('max(1.0)'));
85+
}
86+
}

0 commit comments

Comments
 (0)