Projet

Général

Profil

Paste
Télécharger (11,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ctools / tests / math_expression.test @ 6e3ce7c2

1
<?php
2

    
3
/**
4
 * Tests the MathExpression library of ctools.
5
 */
6
class CtoolsMathExpressionTestCase extends DrupalWebTestCase {
7

    
8
  /**
9
   * {@inheritdoc}
10
   */
11
  public static function getInfo() {
12
    return array(
13
      'name' => 'Math expressions',
14
      'description' => 'Test the math expression library of ctools.',
15
      'group' => 'ctools',
16
      'dependencies' => array('ctools'),
17
    );
18
  }
19

    
20
  /**
21
   * {@inheritdoc}
22
   */
23
  public function setUp(array $modules = array()) {
24
    $modules[] = 'ctools';
25
    $modules[] = 'ctools_plugin_test';
26
    parent::setUp($modules);
27
  }
28

    
29
  /**
30
   * Return the sign of the numeric arg $n as an integer -1, 0, 1.
31
   *
32
   * Note: Not defined when $n is Infinity or NaN (or NULL or ...)!
33
   *
34
   * @param int|float $n
35
   *   The number to test.
36
   *
37
   * @return int
38
   *   -1 if the $n is negative, 0 if $n is zero or 1 if $n is positive.
39
   *
40
   * @see gmp_sign()
41
   */
42
  protected static function sign($n) {
43
    return ($n > 0) - ($n < 0);
44
  }
45

    
46
  /**
47
   * Returns a random number between 0 and 1.
48
   *
49
   * @return float
50
   *   A random number between 0 and 1 inclusive.
51
   */
52
  protected function rand01() {
53
    return mt_rand(0, PHP_INT_MAX) / PHP_INT_MAX;
54
  }
55

    
56
  /**
57
   * A custom assertion with checks the values in a certain range.
58
   *
59
   * @param float $first
60
   *   A value to check for equality.
61
   * @param float $second
62
   *   A value to check for equality.
63
   * @param string $message
64
   *   The message describing the correct behaviour, eg. "2/4 equals 1/2". The
65
   *   default message is used if this value is empty.
66
   * @param float $delta
67
   *   The precision with which values must match. This accounts for rounding
68
   *   errors and imprecise representation errors in the floating point format.
69
   *   The value passed in should ideally be proportional to the values being
70
   *   compared.
71
   * @param string $group
72
   *   Which group this assert belongs to.
73
   *
74
   * @return bool
75
   *   TRUE if the assertion was correct (that is, $first == $second within the
76
   *   given limits), FALSE otherwise.
77
   */
78
  protected function assertFloat($first, $second, $message = '', $delta = 0.00000001, $group = 'Other') {
79
    // Check for NaN and Inf because the abs() and sign() code won't like those.
80
    $equal = FALSE
81
      // Equal if both an infinity.
82
      || (is_infinite($first) && is_infinite($second))
83

    
84
      // Equal if both NaN.
85
      || (is_nan($first) && is_nan($second))
86

    
87
      // Equal if same absolute value (within limits) and same sign.
88
      || ((abs($first - $second) <= $delta) && (self::sign($first) === self::sign($second)));
89

    
90
    if (empty($message)) {
91
      $default = t('Value !first is equal to value !second.',
92
        array(
93
          '!first' => var_export($first, TRUE),
94
          '!second' => var_export($second, TRUE),
95
        ));
96
      $message = $default;
97
    }
98

    
99
    return $this->assert($equal, $message, $group);
100
  }
101

    
102
  /**
103
   * Test some arithmetic handling.
104
   */
105
  public function testArithmetic() {
106
    $math_expr = new ctools_math_expr();
107

    
108
    $this->assertEqual($math_expr->evaluate('2'), 2, 'Check Literal 2');
109

    
110
    $this->assertEqual($math_expr->e('2+1'), $math_expr->evaluate('2+1'), 'Check that e() and evaluate() are equivalent.');
111

    
112
    foreach (range(1, 4) as $n) {
113
      // Test constant expressions.
114
      $random_number = mt_rand(0, 20);
115
      $this->assertEqual($random_number, $math_expr->evaluate((string) $random_number), "Literal $random_number");
116

    
117
      // Test simple arithmetic.
118
      $number_a = mt_rand(-55, 777);
119
      $number_b = mt_rand(-555, 77);
120
      $this->assertEqual(
121
        $number_a + $number_b,
122
        $math_expr->evaluate("$number_a + $number_b"),
123
        "Addition: $number_a + $number_b");
124
      $this->assertEqual(
125
        $number_a - $number_b,
126
        $math_expr->evaluate("$number_a - $number_b"),
127
        "Subtraction: $number_a + $number_b");
128
      $this->assertFloat(
129
        ($number_a * $number_b),
130
        $math_expr->evaluate("$number_a * $number_b"),
131
        "Multiplication: $number_a * $number_b = " . ($number_a * $number_b));
132
      $this->assertFloat(
133
        ($number_a / $number_b),
134
        $math_expr->evaluate("$number_a / $number_b"),
135
        "Division: $number_a / $number_b = " . ($number_a / $number_b));
136

    
137
      // Test Associative property.
138
      $number_c = mt_rand(-99, 77);
139
      $this->assertEqual(
140
        $math_expr->evaluate("$number_a + ($number_b + $number_c)"),
141
        $math_expr->evaluate("($number_a + $number_b) + $number_c"),
142
        "Associative: $number_a + ($number_b + $number_c)");
143
      $this->assertEqual(
144
        $math_expr->evaluate("$number_a * ($number_b * $number_c)"),
145
        $math_expr->evaluate("($number_a * $number_b) * $number_c"),
146
        "Associative: $number_a * ($number_b * $number_c)");
147

    
148
      // Test Commutative property.
149
      $this->assertEqual(
150
        $math_expr->evaluate("$number_a + $number_b"),
151
        $math_expr->evaluate("$number_b + $number_a"),
152
        "Commutative: $number_a + $number_b");
153
      $this->assertEqual(
154
        $math_expr->evaluate("$number_a * $number_b"),
155
        $math_expr->evaluate("$number_b * $number_a"),
156
        "Commutative: $number_a * $number_b");
157

    
158
      // Test Distributive property.
159
      $this->assertEqual(
160
        $math_expr->evaluate("($number_a + $number_b) * $number_c"),
161
        $math_expr->evaluate("($number_a * $number_c + $number_b * $number_c)"),
162
        "Distributive: ($number_a + $number_b) * $number_c");
163

    
164
      // @todo: Doesn't work with zero or negative powers when number is zero or negative, e.g. 0^0, 0^-2, -2^0, -2^-2.
165
      $random_number = mt_rand(1, 15);
166
      $random_power = mt_rand(-15, 15);
167

    
168
      $this->assertFloat(
169
        pow($random_number, $random_power),
170
        $math_expr->evaluate("$random_number ^ $random_power"),
171
        "$random_number ^ $random_power");
172

    
173
      $this->assertFloat(
174
        pow($random_number, $random_power),
175
        $math_expr->evaluate("pow($random_number, $random_power)"),
176
        "pow($random_number, $random_power)");
177
    }
178
  }
179

    
180
  /**
181
   * Test various built-in transcendental and extended functions.
182
   */
183
  public function testBuildInFunctions() {
184
    $math_expr = new ctools_math_expr();
185

    
186
    foreach (range(1, 4) as $n) {
187
      $random_double = $this->rand01();
188
      $random_int = mt_rand(-65535, 65535);
189
      $this->assertFloat(sin($random_double), $math_expr->evaluate("sin($random_double)"), "sin($random_double)");
190
      $this->assertFloat(cos($random_double), $math_expr->evaluate("cos($random_double)"), "cos($random_double)");
191
      $this->assertFloat(tan($random_double), $math_expr->evaluate("tan($random_double)"), "tan($random_double)");
192
      $this->assertFloat(exp($random_double), $math_expr->evaluate("exp($random_double)"), "exp($random_double)");
193
      $this->assertFloat(sqrt($random_double), $math_expr->evaluate("sqrt($random_double)"), "sqrt($random_double)");
194
      $this->assertFloat(log($random_double), $math_expr->evaluate("ln($random_double)"), "ln($random_double)");
195
      $this->assertFloat(round($random_double), $math_expr->evaluate("round($random_double)"), "round($random_double)");
196

    
197
      $random_real = $random_double + $random_int;
198
      $this->assertFloat(abs($random_real), $math_expr->evaluate('abs(' . $random_real . ')'), "abs($random_real)");
199
      $this->assertEqual(round($random_real), $math_expr->evaluate('round(' . $random_real . ')'), "round($random_real)");
200
      $this->assertEqual(ceil($random_real), $math_expr->evaluate('ceil(' . $random_real . ')'), "ceil($random_real)");
201
      $this->assertEqual(floor($random_real), $math_expr->evaluate('floor(' . $random_real . ')'), "floor($random_real)");
202
    }
203

    
204
    $this->assertFloat(time(), $math_expr->evaluate('time()'), "time()");
205

    
206
    $random_double_a = $this->rand01();
207
    $random_double_b = $this->rand01();
208
    $this->assertFloat(
209
      max($random_double_a, $random_double_b),
210
      $math_expr->evaluate("max($random_double_a, $random_double_b)"),
211
      "max($random_double_a, $random_double_b)");
212
    $this->assertFloat(
213
      min($random_double_a, $random_double_b),
214
      $math_expr->evaluate("min($random_double_a, $random_double_b)"),
215
      "min($random_double_a, $random_double_b)");
216
  }
217

    
218
  /**
219
   * Test variable handling.
220
   */
221
  public function testVariables() {
222
    $math_expr = new ctools_math_expr();
223

    
224
    // We should have a definition of pi:
225
    $this->assertFloat(pi(), $math_expr->evaluate('pi'));
226

    
227
    // And a definition of e:
228
    $this->assertFloat(exp(1), $math_expr->evaluate('e'));
229

    
230
    $number_a = 5;
231
    $number_b = 10;
232

    
233
    // Store the first number and use it on a calculation.
234
    $math_expr->evaluate("var = $number_a");
235
    $this->assertEqual($number_a + $number_b, $math_expr->evaluate("var + $number_b"));
236

    
237
    // Change the value and check the new value is used.
238
    $math_expr->evaluate("var = $number_b");
239
    $this->assertEqual(
240
      $number_b + $number_b,
241
      $math_expr->evaluate("var + $number_b"),
242
      "var + $number_b");
243

    
244
    // Store another number and use it on a calculation.
245
    $math_expr->evaluate("var = $number_a");
246
    $math_expr->evaluate("newvar = $number_a");
247

    
248
    $this->assertEqual(
249
      $number_a + $number_a,
250
      $math_expr->evaluate('var + newvar'),
251
      'var + newvar');
252

    
253
    $this->assertFloat(
254
      $number_a / $number_b,
255
      $math_expr->evaluate("var / $number_b"),
256
      "var / $number_b");
257
  }
258

    
259
  /**
260
   * Test custom function handling.
261
   */
262
  public function testCustomFunctions() {
263
    $math_expr = new ctools_math_expr();
264

    
265
    $number_a = mt_rand(5, 10);
266
    $number_b = mt_rand(5, 10);
267

    
268
    // Create a one-argument function.
269
    $math_expr->evaluate("f(x) = 2 * x");
270
    $this->assertEqual($number_a * 2, $math_expr->evaluate("f($number_a)"));
271
    $this->assertEqual($number_b * 2, $math_expr->evaluate("f($number_b)"));
272

    
273
    // Create a two-argument function.
274
    $math_expr->evaluate("g(x, y) = 2 * x + y");
275
    $this->assertEqual(
276
      $number_a * 2 + $number_b,
277
      $math_expr->evaluate("g($number_a, $number_b)"),
278
      "g($number_a, $number_b)");
279

    
280
    // Use a custom function in another function.
281
    $this->assertEqual(
282
      ($number_a * 2 + $number_b) * 2,
283
      $math_expr->evaluate("f(g($number_a, $number_b))"),
284
      "f(g($number_a, $number_b))");
285
  }
286

    
287
  /**
288
   * Test conditional handling.
289
   */
290
  public function testIf() {
291
    $math_expr = new ctools_math_expr();
292

    
293
    $number_a = mt_rand(1, 10);
294
    $number_b = mt_rand(11, 20);
295

    
296
    foreach (range(1, 4) as $n) {
297
      // @todo: Doesn't work with negative numbers.
298
      if ($n == 2 || $n == 4) {
299
        //$number_a = -$number_a;
300
      }
301

    
302
      if ($n == 3 || $n == 4) {
303
        //$number_b = -$number_b;
304
      }
305

    
306
      $this->assertEqual(
307
        $number_a,
308
        $math_expr->evaluate("if(1, $number_a, $number_b)"),
309
        "if(1, $number_a, $number_b)");
310

    
311
      $this->assertEqual(
312
        $number_a,
313
        $math_expr->evaluate("if(1, $number_a)",
314
          "if(1, $number_a)"));
315

    
316
      $this->assertEqual(
317
        $number_b,
318
        $math_expr->evaluate("if(0, $number_a, $number_b)"),
319
        "if(0, $number_a, $number_b)");
320

    
321
      // Also add an expression so ensure it's evaluated.
322
      $this->assertEqual(
323
        $number_b,
324
        $math_expr->evaluate("if($number_a > $number_b, $number_a, $number_b)"),
325
        "if($number_a > $number_b, $number_a, $number_b)");
326

    
327
      $this->assertEqual(
328
        $number_b,
329
        $math_expr->evaluate("if($number_a < $number_b, $number_b, $number_a)"),
330
        "if($number_a < $number_b, $number_b, $number_a)");
331
    }
332
  }
333

    
334
}