Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 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 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   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 of mathslib wrapper and underlying EvalMath library.
  19   *
  20   * @package    core
  21   * @category   phpunit
  22   * @copyright  2007 Petr Skoda {@link http://skodak.org}
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  global $CFG;
  29  require_once($CFG->libdir . '/mathslib.php');
  30  
  31  
  32  class core_mathslib_testcase extends basic_testcase {
  33  
  34      /**
  35       * Tests the basic formula evaluation.
  36       */
  37      public function test__basic() {
  38          $formula = new calc_formula('=1+2');
  39          $res = $formula->evaluate();
  40          $this->assertSame($res, 3, '3+1 is: %s');
  41      }
  42  
  43      /**
  44       * Tests the formula params.
  45       */
  46      public function test__params() {
  47          $formula = new calc_formula('=a+b+c', array('a'=>10, 'b'=>20, 'c'=>30));
  48          $res = $formula->evaluate();
  49          $this->assertSame(60, $res, '10+20+30 is: %s');
  50      }
  51  
  52      /**
  53       * Tests the changed params.
  54       */
  55      public function test__changing_params() {
  56          $formula = new calc_formula('=a+b+c', array('a'=>10, 'b'=>20, 'c'=>30));
  57          $res = $formula->evaluate();
  58          $this->assertSame(60, $res, '10+20+30 is: %s');
  59          $formula->set_params(array('a'=>1, 'b'=>2, 'c'=>3));
  60          $res = $formula->evaluate();
  61          $this->assertSame(6, $res, 'changed params 1+2+3 is: %s');
  62      }
  63  
  64      /**
  65       * Tests the spreadsheet emulation function in formula.
  66       */
  67      public function test__calc_function() {
  68          $formula = new calc_formula('=sum(a, b, c)', array('a'=>10, 'b'=>20, 'c'=>30));
  69          $res = $formula->evaluate();
  70          $this->assertSame(60, $res, 'sum(a, b, c) is: %s');
  71      }
  72  
  73      public function test_other_functions() {
  74          $formula = new calc_formula('=average(1,2,3)');
  75          $this->assertSame(2, $formula->evaluate());
  76  
  77          $formula = new calc_formula('=mod(10,3)');
  78          $this->assertSame(1, $formula->evaluate());
  79  
  80          $formula = new calc_formula('=power(2,3)');
  81          $this->assertSame(8, $formula->evaluate());
  82      }
  83  
  84      public function test_conditional_functions() {
  85          // Test ifthenelse.
  86          $formula = new calc_formula('=ifthenelse(1,2,3)');
  87          $this->assertSame(2, (int)$formula->evaluate());
  88  
  89          $formula = new calc_formula('=ifthenelse(0,2,3)');
  90          $this->assertSame(3, (int) $formula->evaluate());
  91  
  92          $formula = new calc_formula('=ifthenelse(2<3,2,3)');
  93          $this->assertSame(2, (int) $formula->evaluate());
  94  
  95          // Test synonym if.
  96          $formula = new calc_formula('=if(1,2,3)');
  97          $this->assertSame(2, (int)$formula->evaluate());
  98  
  99          $formula = new calc_formula('=if(0,2,3)');
 100          $this->assertSame(3, (int) $formula->evaluate());
 101  
 102          $formula = new calc_formula('=if(2<3,2,3)');
 103          $this->assertSame(2, (int) $formula->evaluate());
 104  
 105          // Test cond_and.
 106          $formula = new calc_formula('=cond_and(1,1,1)');
 107          $this->assertSame(1, (int)$formula->evaluate());
 108  
 109          $formula = new calc_formula('=cond_and(1,1,0)');
 110          $this->assertSame(0, (int) $formula->evaluate());
 111  
 112          $formula = new calc_formula('=cond_and(0,0,0)');
 113          $this->assertSame(0, (int) $formula->evaluate());
 114  
 115          // Test synonym and.
 116          $formula = new calc_formula('=and(1,1,1)');
 117          $this->assertSame(1, (int)$formula->evaluate());
 118  
 119          $formula = new calc_formula('=and(1,1,0)');
 120          $this->assertSame(0, (int) $formula->evaluate());
 121  
 122          $formula = new calc_formula('=and(0,0,0)');
 123          $this->assertSame(0, (int) $formula->evaluate());
 124  
 125          // Test cond_or.
 126          $formula = new calc_formula('=cond_or(1,1,1)');
 127          $this->assertSame(1, (int)$formula->evaluate());
 128  
 129          $formula = new calc_formula('=cond_or(1,1,0)');
 130          $this->assertSame(1, (int) $formula->evaluate());
 131  
 132          $formula = new calc_formula('=cond_or(0,0,0)');
 133          $this->assertSame(0, (int) $formula->evaluate());
 134  
 135          // Test synonym or.
 136          $formula = new calc_formula('=or(1,1,1)');
 137          $this->assertSame(1, (int)$formula->evaluate());
 138  
 139          $formula = new calc_formula('=or(1,1,0)');
 140          $this->assertSame(1, (int) $formula->evaluate());
 141  
 142          $formula = new calc_formula('=or(0,0,0)');
 143          $this->assertSame(0, (int) $formula->evaluate());
 144      }
 145  
 146      public function test_conditional_operators() {
 147          $formula = new calc_formula('=2==2');
 148          $this->assertSame(1, $formula->evaluate());
 149  
 150          $formula = new calc_formula('=2>3');
 151          $this->assertSame(0, $formula->evaluate());
 152          $formula = new calc_formula('=2<3');
 153          $this->assertSame(1, $formula->evaluate());
 154  
 155          $formula = new calc_formula('=(2<=3)');
 156          $this->assertSame(1, $formula->evaluate());
 157  
 158          $formula = new calc_formula('=(2<=3)*10');
 159          $this->assertSame(10, $formula->evaluate());
 160  
 161          $formula = new calc_formula('=(2>=3)*10');
 162          $this->assertSame(0, $formula->evaluate());
 163          $formula = new calc_formula('=2<3*10');
 164          $this->assertSame(10, $formula->evaluate());
 165      }
 166      /**
 167       * Tests the min and max functions.
 168       */
 169      public function test__minmax_function() {
 170          $formula = new calc_formula('=min(a, b, c)', array('a'=>10, 'b'=>20, 'c'=>30));
 171          $res = $formula->evaluate();
 172          $this->assertSame(10, $res, 'minimum is: %s');
 173          $formula = new calc_formula('=max(a, b, c)', array('a'=>10, 'b'=>20, 'c'=>30));
 174          $res = $formula->evaluate();
 175          $this->assertSame(30, $res, 'maximum is: %s');
 176      }
 177  
 178      /**
 179       * Tests special chars.
 180       */
 181      public function test__specialchars() {
 182          $formula = new calc_formula('=gi1 + gi2 + gi11', array('gi1'=>10, 'gi2'=>20, 'gi11'=>30));
 183          $res = $formula->evaluate();
 184          $this->assertSame(60, $res, 'sum is: %s');
 185      }
 186  
 187      /**
 188       * Tests some slightly more complex expressions.
 189       */
 190      public function test__more_complex_expressions() {
 191          $formula = new calc_formula('=pi() + a', array('a'=>10));
 192          $res = $formula->evaluate();
 193          $this->assertSame(pi()+10, $res);
 194          $formula = new calc_formula('=pi()^a', array('a'=>10));
 195          $res = $formula->evaluate();
 196          $this->assertSame(pow(pi(), 10), $res);
 197          $formula = new calc_formula('=-8*(5/2)^2*(1-sqrt(4))-8');
 198          $res = $formula->evaluate();
 199          $this->assertSame(-8*pow((5/2), 2)*(1-sqrt(4))-8, $res);
 200      }
 201  
 202      /**
 203       * Tests some slightly more complex expressions.
 204       */
 205      public function test__error_handling() {
 206          $formula = new calc_formula('=pi( + a', array('a'=>10));
 207          $res = $formula->evaluate();
 208          $this->assertFalse($res);
 209          $this->assertSame(get_string('unexpectedoperator', 'mathslib', '+'), $formula->get_error());
 210  
 211          $formula = new calc_formula('=pi(');
 212          $res = $formula->evaluate();
 213          $this->assertSame($res, false);
 214          $this->assertSame(get_string('expectingaclosingbracket', 'mathslib'), $formula->get_error());
 215  
 216          $formula = new calc_formula('=pi()^');
 217          $res = $formula->evaluate();
 218          $this->assertSame($res, false);
 219          $this->assertSame(get_string('operatorlacksoperand', 'mathslib', '^'), $formula->get_error());
 220  
 221      }
 222  
 223      public function test_rounding_function() {
 224          // Rounding to the default number of decimal places.
 225          // The default == 0.
 226  
 227          $formula = new calc_formula('=round(2.5)');
 228          $this->assertSame(3.0, $formula->evaluate());
 229  
 230          $formula = new calc_formula('=round(1.5)');
 231          $this->assertSame(2.0, $formula->evaluate());
 232  
 233          $formula = new calc_formula('=round(-1.49)');
 234          $this->assertSame(-1.0, $formula->evaluate());
 235  
 236          $formula = new calc_formula('=round(-2.49)');
 237          $this->assertSame(-2.0, $formula->evaluate());
 238  
 239          $formula = new calc_formula('=round(-1.5)');
 240          $this->assertSame(-2.0, $formula->evaluate());
 241  
 242          $formula = new calc_formula('=round(-2.5)');
 243          $this->assertSame(-3.0, $formula->evaluate());
 244  
 245          $formula = new calc_formula('=ceil(2.5)');
 246          $this->assertSame(3.0, $formula->evaluate());
 247  
 248          $formula = new calc_formula('=ceil(1.5)');
 249          $this->assertSame(2.0, $formula->evaluate());
 250  
 251          $formula = new calc_formula('=ceil(-1.49)');
 252          $this->assertSame(-1.0, $formula->evaluate());
 253  
 254          $formula = new calc_formula('=ceil(-2.49)');
 255          $this->assertSame(-2.0, $formula->evaluate());
 256  
 257          $formula = new calc_formula('=ceil(-1.5)');
 258          $this->assertSame(-1.0, $formula->evaluate());
 259  
 260          $formula = new calc_formula('=ceil(-2.5)');
 261          $this->assertSame(-2.0, $formula->evaluate());
 262  
 263          $formula = new calc_formula('=floor(2.5)');
 264          $this->assertSame(2.0, $formula->evaluate());
 265  
 266          $formula = new calc_formula('=floor(1.5)');
 267          $this->assertSame(1.0, $formula->evaluate());
 268  
 269          $formula = new calc_formula('=floor(-1.49)');
 270          $this->assertSame(-2.0, $formula->evaluate());
 271  
 272          $formula = new calc_formula('=floor(-2.49)');
 273          $this->assertSame(-3.0, $formula->evaluate());
 274  
 275          $formula = new calc_formula('=floor(-1.5)');
 276          $this->assertSame(-2.0, $formula->evaluate());
 277  
 278          $formula = new calc_formula('=floor(-2.5)');
 279          $this->assertSame(-3.0, $formula->evaluate());
 280  
 281          // Rounding to an explicit number of decimal places.
 282  
 283          $formula = new calc_formula('=round(2.5, 1)');
 284          $this->assertSame(2.5, $formula->evaluate());
 285  
 286          $formula = new calc_formula('=round(2.5, 0)');
 287          $this->assertSame(3.0, $formula->evaluate());
 288  
 289          $formula = new calc_formula('=round(1.2345, 2)');
 290          $this->assertSame(1.23, $formula->evaluate());
 291  
 292          $formula = new calc_formula('=round(123.456, -1)');
 293          $this->assertSame(120.0, $formula->evaluate());
 294      }
 295  
 296      public function test_scientific_notation() {
 297          $formula = new calc_formula('=10e10');
 298          $this->assertEquals(1e11, $formula->evaluate(), '', 1e11*1e-15);
 299  
 300          $formula = new calc_formula('=10e-10');
 301          $this->assertEquals(1e-9, $formula->evaluate(), '', 1e11*1e-15);
 302  
 303          $formula = new calc_formula('=10e+10');
 304          $this->assertEquals(1e11, $formula->evaluate(), '', 1e11*1e-15);
 305  
 306          $formula = new calc_formula('=10e10*5');
 307          $this->assertEquals(5e11, $formula->evaluate(), '', 1e11*1e-15);
 308  
 309          $formula = new calc_formula('=10e10^2');
 310          $this->assertEquals(1e22, $formula->evaluate(), '', 1e22*1e-15);
 311      }
 312  
 313      public function test_rand_float() {
 314          $formula = new calc_formula('=rand_float()');
 315          $result = $formula->evaluate();
 316          $this->assertTrue(is_float($result));
 317      }
 318  }