PageRenderTime 50ms CodeModel.GetById 13ms app.highlight 27ms RepoModel.GetById 2ms app.codeStats 0ms

/Test/Case.php

https://github.com/toshibr/hashmark
PHP | 426 lines | 190 code | 57 blank | 179 comment | 26 complexity | 36876459b8b71c4199e3f8ae715e55b0 MD5 | raw file
  1<?php
  2// vim: fenc=utf-8:ft=php:ai:si:ts=4:sw=4:et:
  3
  4/**
  5 * Hashmark_TestCase
  6 *
  7 * @filesource
  8 * @link        http://code.google.com/p/hashmark/
  9 * @link        http://framework.zend.com/manual/en/coding-standard.html
 10 * @link        http://phpdoc.org/tutorial.php
 11 * @copyright   Copyright (c) 2008-2009, Code Actual LLC
 12 * @license     http://www.opensource.org/licenses/bsd-license.php New BSD License
 13 * @package     Hashmark-Test
 14 * @subpackage  Base
 15 * @version     $Id: Case.php 294 2009-02-13 03:48:59Z david $
 16*/
 17
 18/**
 19 * Base class for all module test classes.
 20 *
 21 * @abstract
 22 * @package     Hashmark-Test
 23 * @subpackage  Base
 24 */
 25abstract class Hashmark_TestCase extends PHPUnit_Framework_TestCase
 26{
 27    /**
 28     * @access protected
 29     * @var boolean     If true, PHPUnit lets globals persist between tests.
 30     * @link http://sebastian-bergmann.de/archives/797-Global-Variables-and-PHPUnit.html
 31     */
 32    protected $backupGlobals = false;
 33
 34    /**
 35     * @access protected
 36     * @var mixed   Database connection object/resource.
 37     * @see setUp()
 38     */
 39    protected $_db;
 40    
 41    /**
 42     * @access protected
 43     * @var Hashmark_DbHelper_*    Instance created in setUp().
 44     */
 45    protected $_dbHelper;
 46
 47    /**
 48     * @access protected
 49     * @var string  Test case type, ex. 'Mysql'.
 50     * @see setUp()
 51     */
 52    protected $_type;
 53
 54    /**
 55     * Set up the test case fixtures.
 56     * 
 57     * @access protected
 58     * @return void
 59     */
 60    protected function setUp()
 61    {
 62        // Extract suffix (ex. 'Mysql') from class (ex. 'Hashmark_TestCase_Client_Mysql'). 
 63        $className = get_class($this);
 64
 65        $this->_type = substr($className, strrpos($className, '_') + 1);
 66
 67        // Auto-load a DbHelper instance for DB dependent modules.
 68        $matchingDbHelperFile = dirname(__FILE__) . '/../DbHelper/' . HASHMARK_DBHELPER_DEFAULT_TYPE . '.php';
 69        if (is_readable($matchingDbHelperFile)) {
 70            $this->_dbHelper = Hashmark::getModule('DbHelper', HASHMARK_DBHELPER_DEFAULT_TYPE);
 71            $this->_db = $this->_dbHelper->openDb('unittest');
 72        }
 73    }
 74    
 75    /**
 76     * @access protected
 77     * @return void
 78     */
 79    protected function tearDown()
 80    {
 81        if ($this->_dbHelper) {
 82            $this->_dbHelper->closeDb($this->_db);
 83        }
 84    }
 85
 86    /**
 87     * Return a @dataProvider-compat argument set without the array()
 88     * wrapping around each value.
 89     *
 90     * @static
 91     * @access public
 92     * @return Array
 93     */
 94    public static function unwrapProviderData($providerData)
 95    {
 96        array_walk($providerData, create_function('&$v,$k', '$v = $v[0];'));
 97        return $providerData;
 98    }
 99
100
101    /**
102     * Provide valid increment values (initial, delta, expected result).
103     *
104     * @static
105     * @access public
106     * @return Array    Test method argument sets.
107     * @see Loaded data file for return value format.
108     */
109    public static function provideIncrementValues()
110    {
111        static $data;
112
113        require_once dirname(__FILE__) . '/Core/Data/' . __FUNCTION__ . '.php';
114
115        return $data;
116    }
117
118    /**
119     * Provide valid decrement values (initial, delta, expected result).
120     *
121     * @static
122     * @access public
123     * @return Array    Test method argument sets.
124     * @see Loaded data file for return value format.
125     */
126    public static function provideDecrementValues()
127    {
128        static $data;
129
130        require_once dirname(__FILE__) . '/Core/Data/' . __FUNCTION__ . '.php';
131
132        return $data;
133    }
134
135    /**
136     * Provide valid string values.
137     *
138     * @static
139     * @access public
140     * @return Array    Test method argument sets.
141     */
142    public static function provideStringValues()
143    {
144        static $data;
145
146        if (!$data) {
147            $data = array(array(''),
148                          array(' '),
149                          array('87a46c25bc0723ada70db470198e887d'));
150        }
151
152        return $data;
153    }
154
155    /**
156     * Provide valid decimal values.
157     *
158     * @static
159     * @access public
160     * @return Array    Test method argument sets.
161     */
162    public static function provideDecimalValues()
163    {
164        static $data;
165
166        if (!$data) {
167            $data = array(array('0'),
168                          array('1'),
169                          array('-1'),
170                          array('1.0001'),
171                          array('-1.0001'),
172                          array('0.0001'),
173                          array('-0.0001'),
174                          array('1000000000000000.0001'),
175                          array('-1000000000000000.0001'));
176        }
177
178        return $data;
179    }
180
181    /**
182     * Provide names which should never identify a scalar.
183     *
184     * @static
185     * @access public
186     * @return Array    Test method argument sets.
187     */
188    public static function provideInvalidScalarNames()
189    {
190        static $data;
191
192        if (!$data) {
193            $data = array(array(''),
194                          array(' '),
195                          array(null),
196                          array(true),
197                          array(false),
198                          array(0),
199                          array(1),
200                          array(-1));
201        }
202
203        return $data;
204    }
205
206    /**
207     * Provide sets of scalar types and values.
208     *
209     * @static
210     * @access public
211     * @return Array    Test method argument sets.
212     * 
213     * Format:
214     *
215     *      array(array('decimal', 0),
216     *            ...
217     *            array('string', 'aef448733247db5be49ae8597aa94d59S'));
218     */
219    public static function provideScalarTypesAndValues()
220    {
221        static $data;
222
223        if (!$data) {
224            $strings = self::provideStringValues();
225            $numbers = self::provideDecimalValues();
226
227            $data = array();
228
229            foreach ($strings as $str) {
230                $data[] = array('string', $str[0]);
231            }
232
233            foreach ($numbers as $num) {
234                $data[] = array('decimal', $num[0]);
235            }
236        }
237
238        return $data;
239    }
240
241    /**
242     * Provide fields of scalars scheduled for sampling.
243     *
244     * @static
245     * @access public
246     * @return Array    Test method argument sets.
247     */
248    public static function provideScalarsWithScheduledSamplers()
249    {
250        static $data;
251
252        if (!$data) {
253            foreach (Hashmark_Core::getValidScalarTypes() as $type) {
254                $argSet = array();
255                $argSet['name'] = self::randomString();
256                $argSet['type'] = $type;
257                $argSet['description'] = self::randomString();
258                $argSet['sampler_status'] = 'Scheduled';
259                $argSet['sampler_handler'] = 'Test';
260                $argSet['sampler_start'] = gmdate(HASHMARK_DATETIME_FORMAT);
261            
262                // 0-minute frequencies will make them due to run immediately.
263                $argSet['sampler_frequency'] = 0;
264                
265                $data[] = $argSet;
266            }
267        }
268
269        return $data;
270    }
271
272    /**
273     * Return a random decimal string.
274     *
275     * @static
276     * @access public
277     * @return string
278     */
279    public static function randomDecimal()
280    {
281        // Random DECIMAL(M,D) numbers.
282        // @see DECIMAL type, http://dev.mysql.com/doc/refman/5.0/en/numeric-type-overview.html#id4944739
283
284        // Before decimal point:
285        $value = '';
286        $wholeDigits = mt_rand(1, HASHMARK_DECIMAL_TOTALWIDTH - HASHMARK_DECIMAL_RIGHTWIDTH);
287        for ($d = 0; $d < $wholeDigits; $d++) {
288            $value .= mt_rand(0, 9);
289        }
290
291        // After:
292        $value = preg_replace('/^0+/', '', $value) . '.';
293        $pointDigits = mt_rand(1, HASHMARK_DECIMAL_RIGHTWIDTH);
294        for ($d = 0; $d < $pointDigits; $d++) {
295            $value .= mt_rand(0, 9);
296        }
297        return $value;
298    }
299    
300    /**
301     * Return a random string.
302     *
303     * @static
304     * @access public
305     * @param int   $minLength  1 to 40.
306     * @param int   $maxLength  1 to 40.
307     * @return string
308     * @throws Exception If $minLength or $maxLength is greater than 40 or negative.
309     */
310    public static function randomString($minLength = 30, $maxLength = 30)
311    {
312        $str = Hashmark_Util::randomSha1();
313
314        if ($maxLength > 0 && $maxLength < 41 && $minLength > 0 && $minLength <= $maxLength) {
315            return substr($str, 0, mt_rand($minLength, $maxLength));
316        }
317
318        throw new Exception('Random string limits are invalid.', HASHMARK_EXCEPTION_VALIDATION);
319    }
320    
321    /**
322     * Testable logic for assertArrayContainsOnly().
323     *
324     * @static
325     * @access public
326     * @param mixed     $needle     Only expected element of $haystack.
327     * @param Array     $haystack
328     * @param boolean   $strict     If true, $a === $b logic is used; othewise in_array().
329     * @return boolean  True if $haystack only contains one $needle.
330     */
331    public static function checkArrayContainsOnly($needle, $haystack, $strict = false)
332    {
333        if (!is_array($haystack) || count($haystack) != 1) {
334            return false;
335        }
336
337        if ($strict) {
338            $values = array_values($haystack);
339            return $values[0] === $needle;
340        } else {
341            return in_array($needle, $haystack);
342        }
343    }
344
345    /**
346     * Assert $haystack contains only one element that is equal to $needle.
347     *
348     *      -   Uses assertTrue() internally to increment assertion count.
349     *
350     * @access public
351     * @param mixed     $needle     Only expected element of $haystack.
352     * @param Array     $haystack
353     * @param boolean   $strict     If true, $a === $b logic is used; othewise in_array().
354     * @return void
355     */
356    public function assertArrayContainsOnly($needle, $haystack, $message = '')
357    {
358        if (self::checkArrayContainsOnly($needle, $haystack, $message)) {
359            $this->assertTrue(true);
360        } else {
361            $needleType = gettype($needle);
362            $needle = str_replace("\n", '', print_r($needle, true));
363            $haystackType = gettype($haystack);
364            $haystack = str_replace("\n", '', print_r($haystack, true));
365
366            if ($message) {
367                $message .= "\n";
368            }
369
370            $message .= "Failed asserting that Array <{$haystackType}:{$haystack}> "
371                      . "contains only element <{$needleType}:{$needle}>.";
372
373            $this->assertTrue(false, $message);
374        }
375    }
376    
377    /**
378     * Testable logic for assertDecimalEquals().
379     *
380     * @static
381     * @access public
382     * @param string    $expected
383     * @param string    $actual
384     * @return boolean  True if equal.
385     */
386    public static function checkDecimalEquals($expected, $actual) 
387    {
388        if (!is_string($expected) || !is_string($actual)) {
389            return false;
390        }
391
392        bcscale(HASHMARK_DECIMAL_RIGHTWIDTH);
393
394        return 0 === bccomp($expected, $actual);
395    }
396    
397    /**
398     * Uses bccomp() to check equality of two strings representing decimal values.
399     *
400     *      -   Uses assertTrue() internally to increment assertion count.
401     *
402     * @access public
403     * @param string    $expected
404     * @param string    $actual
405     * @return void
406     */
407    public function assertDecimalEquals($expected, $actual, $message = '')
408    {
409
410        if (self::checkDecimalEquals($expected, $actual)) {
411            $this->assertTrue(true);
412        } else {
413            $actualType = gettype($actual);
414            $expectedType = gettype($expected);
415            
416            if ($message) {
417                $message .= "\n";
418            }
419
420            $message .= "Failed asserting that actual decimal string <{$actualType}:"
421                      . "{$actual}> equals expected <{$expectedType}:{$expected}>.";
422
423            $this->assertTrue(false, $message);
424        }
425    }
426}