MDL-46148 qtype_calculated: unit tests + fixes for validation
authorTim Hunt <T.J.Hunt@open.ac.uk>
Thu, 26 Jun 2014 09:48:02 +0000 (10:48 +0100)
committerDan Poltawski <dan@moodle.com>
Mon, 7 Jul 2014 13:33:20 +0000 (14:33 +0100)
question/type/calculated/questiontype.php
question/type/calculated/tests/formula_validation_test.php [new file with mode: 0644]

index b2e3b2a..3bfa25b 100644 (file)
@@ -1890,6 +1890,11 @@ function qtype_calculated_calculate_answer($formula, $individualdata,
 }
 
 
+/**
+ * Validate a forumula.
+ * @param string $formula the formula to validate.
+ * @return string|boolean false if there are no problems. Otherwise a string error message.
+ */
 function qtype_calculated_find_formula_errors($formula) {
     // Validates the formula submitted from the question edit page.
     // Returns false if everything is alright
@@ -1918,7 +1923,7 @@ function qtype_calculated_find_formula_errors($formula) {
 
                 // Zero argument functions.
             case 'pi':
-                if ($regs[3]) {
+                if (array_key_exists(3, $regs)) {
                     return get_string('functiontakesnoargs', 'qtype_calculated', $regs[2]);
                 }
                 break;
diff --git a/question/type/calculated/tests/formula_validation_test.php b/question/type/calculated/tests/formula_validation_test.php
new file mode 100644 (file)
index 0000000..e9f52e1
--- /dev/null
@@ -0,0 +1,86 @@
+<?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 formula validation code.
+ *
+ * @package    qtype_calculated
+ * @copyright  2014 The Open University
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/question/type/calculated/questiontype.php');
+
+
+/**
+ * Unit tests for formula validation code.
+ *
+ * @copyright  2014 The Open University
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class qtype_calculated_formula_validation_testcase extends basic_testcase {
+    protected function assert_nonempty_string($actual) {
+        $this->assertInternalType('string', $actual);
+        $this->assertNotEquals('', $actual);
+    }
+
+    public function test_simple_equations_ok() {
+        $this->assertFalse(qtype_calculated_find_formula_errors(1));
+        $this->assertFalse(qtype_calculated_find_formula_errors('1 + 1'));
+        $this->assertFalse(qtype_calculated_find_formula_errors('{x} + {y}'));
+        $this->assertFalse(qtype_calculated_find_formula_errors('{x}*{y}'));
+    }
+
+    public function test_safe_functions_ok() {
+        $this->assertFalse(qtype_calculated_find_formula_errors('abs(-1)'));
+        $this->assertFalse(qtype_calculated_find_formula_errors('tan(pi())'));
+        $this->assertFalse(qtype_calculated_find_formula_errors('log(10)'));
+        $this->assertFalse(qtype_calculated_find_formula_errors('log(64, 2)'));
+        $this->assertFalse(qtype_calculated_find_formula_errors('atan2(1.0, 1.0)'));
+        $this->assertFalse(qtype_calculated_find_formula_errors('max(1.0, 1.0)'));
+        $this->assertFalse(qtype_calculated_find_formula_errors('max(1.0, 1.0, 2.0)'));
+        $this->assertFalse(qtype_calculated_find_formula_errors('max(1.0, 1.0, 2, 3)'));
+    }
+
+    public function test_dangerous_functions_blocked() {
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('eval(1)'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('system(1)'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('base64_decode(1)'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('unserialize(1)'));
+
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('cos(tan(1) + abs(cos(eval)) * pi())'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('eval (CONSTANTREADASSTRING)'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors("eval \t ()"));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('"eval"()'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('?><?php()'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('?><?php+1'));
+    }
+
+    public function test_functions_with_wrong_num_args_caught() {
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('abs(-1, 1)'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('abs()'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('pi(1)'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('log()'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('log(64, 2, 3)'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('atan2(1.0)'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('atan2(1.0, 1.0, 2.0)'));
+        $this->assert_nonempty_string(qtype_calculated_find_formula_errors('max(1.0)'));
+    }
+}