1: <?php
2: /**
3: * CakeTestCase file
4: *
5: * PHP 5
6: *
7: * CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
8: * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
9: *
10: * Licensed under The MIT License
11: * Redistributions of files must retain the above copyright notice
12: *
13: * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
14: * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
15: * @package Cake.TestSuite
16: * @since CakePHP(tm) v 1.2.0.4667
17: * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
18: */
19: App::uses('CakeFixtureManager', 'TestSuite/Fixture');
20: App::uses('CakeTestFixture', 'TestSuite/Fixture');
21:
22: /**
23: * CakeTestCase class
24: *
25: * @package Cake.TestSuite
26: */
27: abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
28:
29: /**
30: * The class responsible for managing the creation, loading and removing of fixtures
31: *
32: * @var CakeFixtureManager
33: */
34: public $fixtureManager = null;
35:
36: /**
37: * By default, all fixtures attached to this class will be truncated and reloaded after each test.
38: * Set this to false to handle manually
39: *
40: * @var array
41: */
42: public $autoFixtures = true;
43:
44: /**
45: * Set this to false to avoid tables to be dropped if they already exist
46: *
47: * @var boolean
48: */
49: public $dropTables = true;
50:
51: /**
52: * Configure values to restore at end of test.
53: *
54: * @var array
55: */
56: protected $_configure = array();
57:
58: /**
59: * Path settings to restore at the end of the test.
60: *
61: * @var array
62: */
63: protected $_pathRestore = array();
64:
65: /**
66: * Runs the test case and collects the results in a TestResult object.
67: * If no TestResult object is passed a new one will be created.
68: * This method is run for each test method in this class
69: *
70: * @param PHPUnit_Framework_TestResult $result
71: * @return PHPUnit_Framework_TestResult
72: * @throws InvalidArgumentException
73: */
74: public function run(PHPUnit_Framework_TestResult $result = null) {
75: if (!empty($this->fixtureManager)) {
76: $this->fixtureManager->load($this);
77: }
78: $result = parent::run($result);
79: if (!empty($this->fixtureManager)) {
80: $this->fixtureManager->unload($this);
81: }
82: return $result;
83: }
84:
85: /**
86: * Called when a test case method is about to start (to be overridden when needed.)
87: *
88: * @param string $method Test method about to get executed.
89: * @return void
90: */
91: public function startTest($method) {
92: }
93:
94: /**
95: * Called when a test case method has been executed (to be overridden when needed.)
96: *
97: * @param string $method Test method about that was executed.
98: * @return void
99: */
100: public function endTest($method) {
101: }
102:
103: /**
104: * Overrides SimpleTestCase::skipIf to provide a boolean return value
105: *
106: * @param boolean $shouldSkip
107: * @param string $message
108: * @return boolean
109: */
110: public function skipIf($shouldSkip, $message = '') {
111: if ($shouldSkip) {
112: $this->markTestSkipped($message);
113: }
114: return $shouldSkip;
115: }
116:
117: /**
118: * Setup the test case, backup the static object values so they can be restored.
119: * Specifically backs up the contents of Configure and paths in App if they have
120: * not already been backed up.
121: *
122: * @return void
123: */
124: public function setUp() {
125: parent::setUp();
126:
127: if (empty($this->_configure)) {
128: $this->_configure = Configure::read();
129: }
130: if (empty($this->_pathRestore)) {
131: $this->_pathRestore = App::paths();
132: }
133: if (class_exists('Router', false)) {
134: Router::reload();
135: }
136: }
137:
138: /**
139: * teardown any static object changes and restore them.
140: *
141: * @return void
142: */
143: public function tearDown() {
144: parent::tearDown();
145: App::build($this->_pathRestore, App::RESET);
146: if (class_exists('ClassRegistry', false)) {
147: ClassRegistry::flush();
148: }
149: if (!empty($this->_configure)) {
150: Configure::clear();
151: Configure::write($this->_configure);
152: }
153: if (isset($_GET['debug']) && $_GET['debug']) {
154: ob_flush();
155: }
156: }
157:
158: /**
159: * See CakeTestSuiteDispatcher::date()
160: *
161: * @param string $format format to be used.
162: * @return string
163: */
164: public static function date($format = 'Y-m-d H:i:s') {
165: return CakeTestSuiteDispatcher::date($format);
166: }
167:
168: // @codingStandardsIgnoreStart PHPUnit overrides don't match CakePHP
169:
170: /**
171: * Announces the start of a test.
172: *
173: * @param string $method Test method just started.
174: * @return void
175: */
176: protected function assertPreConditions() {
177: parent::assertPreConditions();
178: $this->startTest($this->getName());
179: }
180:
181: /**
182: * Announces the end of a test.
183: *
184: * @param string $method Test method just finished.
185: * @return void
186: */
187: protected function assertPostConditions() {
188: parent::assertPostConditions();
189: $this->endTest($this->getName());
190: }
191:
192: // @codingStandardsIgnoreEnd
193:
194: /**
195: * Chooses which fixtures to load for a given test
196: *
197: * @param string $fixture Each parameter is a model name that corresponds to a
198: * fixture, i.e. 'Post', 'Author', etc.
199: * @return void
200: * @see CakeTestCase::$autoFixtures
201: * @throws Exception when no fixture manager is available.
202: */
203: public function loadFixtures() {
204: if (empty($this->fixtureManager)) {
205: throw new Exception(__d('cake_dev', 'No fixture manager to load the test fixture'));
206: }
207: $args = func_get_args();
208: foreach ($args as $class) {
209: $this->fixtureManager->loadSingle($class);
210: }
211: }
212:
213: /**
214: * Assert text equality, ignoring differences in newlines.
215: * Helpful for doing cross platform tests of blocks of text.
216: *
217: * @param string $expected The expected value.
218: * @param string $result The actual value.
219: * @param message The message to use for failure.
220: * @return boolean
221: */
222: public function assertTextNotEquals($expected, $result, $message = '') {
223: $expected = str_replace(array("\r\n", "\r"), "\n", $expected);
224: $result = str_replace(array("\r\n", "\r"), "\n", $result);
225: return $this->assertNotEquals($expected, $result, $message);
226: }
227:
228: /**
229: * Assert text equality, ignoring differences in newlines.
230: * Helpful for doing cross platform tests of blocks of text.
231: *
232: * @param string $expected The expected value.
233: * @param string $result The actual value.
234: * @param message The message to use for failure.
235: * @return boolean
236: */
237: public function assertTextEquals($expected, $result, $message = '') {
238: $expected = str_replace(array("\r\n", "\r"), "\n", $expected);
239: $result = str_replace(array("\r\n", "\r"), "\n", $result);
240: return $this->assertEquals($expected, $result, $message);
241: }
242:
243: /**
244: * Asserts that a string starts with a given prefix, ignoring differences in newlines.
245: * Helpful for doing cross platform tests of blocks of text.
246: *
247: * @param string $prefix
248: * @param string $string
249: * @param string $message
250: * @return boolean
251: */
252: public function assertTextStartsWith($prefix, $string, $message = '') {
253: $prefix = str_replace(array("\r\n", "\r"), "\n", $prefix);
254: $string = str_replace(array("\r\n", "\r"), "\n", $string);
255: return $this->assertStringStartsWith($prefix, $string, $message);
256: }
257:
258: /**
259: * Asserts that a string starts not with a given prefix, ignoring differences in newlines.
260: * Helpful for doing cross platform tests of blocks of text.
261: *
262: * @param string $prefix
263: * @param string $string
264: * @param string $message
265: * @return boolean
266: */
267: public function assertTextStartsNotWith($prefix, $string, $message = '') {
268: $prefix = str_replace(array("\r\n", "\r"), "\n", $prefix);
269: $string = str_replace(array("\r\n", "\r"), "\n", $string);
270: return $this->assertStringStartsNotWith($prefix, $string, $message);
271: }
272:
273: /**
274: * Asserts that a string ends with a given prefix, ignoring differences in newlines.
275: * Helpful for doing cross platform tests of blocks of text.
276: *
277: * @param string $suffix
278: * @param string $string
279: * @param string $message
280: * @return boolean
281: */
282: public function assertTextEndsWith($suffix, $string, $message = '') {
283: $suffix = str_replace(array("\r\n", "\r"), "\n", $suffix);
284: $string = str_replace(array("\r\n", "\r"), "\n", $string);
285: return $this->assertStringEndsWith($suffix, $string, $message);
286: }
287:
288: /**
289: * Asserts that a string ends not with a given prefix, ignoring differences in newlines.
290: * Helpful for doing cross platform tests of blocks of text.
291: *
292: * @param string $suffix
293: * @param string $string
294: * @param string $message
295: * @return boolean
296: */
297: public function assertTextEndsNotWith($suffix, $string, $message = '') {
298: $suffix = str_replace(array("\r\n", "\r"), "\n", $suffix);
299: $string = str_replace(array("\r\n", "\r"), "\n", $string);
300: return $this->assertStringEndsNotWith($suffix, $string, $message);
301: }
302:
303: /**
304: * Assert that a string contains another string, ignoring differences in newlines.
305: * Helpful for doing cross platform tests of blocks of text.
306: *
307: * @param string $needle
308: * @param string $haystack
309: * @param string $message
310: * @param boolean $ignoreCase
311: * @return boolean
312: */
313: public function assertTextContains($needle, $haystack, $message = '', $ignoreCase = false) {
314: $needle = str_replace(array("\r\n", "\r"), "\n", $needle);
315: $haystack = str_replace(array("\r\n", "\r"), "\n", $haystack);
316: return $this->assertContains($needle, $haystack, $message, $ignoreCase);
317: }
318:
319: /**
320: * Assert that a text doesn't contain another text, ignoring differences in newlines.
321: * Helpful for doing cross platform tests of blocks of text.
322: *
323: * @param string $needle
324: * @param string $haystack
325: * @param string $message
326: * @param boolean $ignoreCase
327: * @return boolean
328: */
329: public function assertTextNotContains($needle, $haystack, $message = '', $ignoreCase = false) {
330: $needle = str_replace(array("\r\n", "\r"), "\n", $needle);
331: $haystack = str_replace(array("\r\n", "\r"), "\n", $haystack);
332: return $this->assertNotContains($needle, $haystack, $message, $ignoreCase);
333: }
334:
335: /**
336: * Takes an array $expected and generates a regex from it to match the provided $string.
337: * Samples for $expected:
338: *
339: * Checks for an input tag with a name attribute (contains any non-empty value) and an id
340: * attribute that contains 'my-input':
341: * array('input' => array('name', 'id' => 'my-input'))
342: *
343: * Checks for two p elements with some text in them:
344: * array(
345: * array('p' => true),
346: * 'textA',
347: * '/p',
348: * array('p' => true),
349: * 'textB',
350: * '/p'
351: * )
352: *
353: * You can also specify a pattern expression as part of the attribute values, or the tag
354: * being defined, if you prepend the value with preg: and enclose it with slashes, like so:
355: * array(
356: * array('input' => array('name', 'id' => 'preg:/FieldName\d+/')),
357: * 'preg:/My\s+field/'
358: * )
359: *
360: * Important: This function is very forgiving about whitespace and also accepts any
361: * permutation of attribute order. It will also allow whitespace between specified tags.
362: *
363: * @param string $string An HTML/XHTML/XML string
364: * @param array $expected An array, see above
365: * @param string $message SimpleTest failure output string
366: * @return boolean
367: */
368: public function assertTags($string, $expected, $fullDebug = false) {
369: $regex = array();
370: $normalized = array();
371: foreach ((array)$expected as $key => $val) {
372: if (!is_numeric($key)) {
373: $normalized[] = array($key => $val);
374: } else {
375: $normalized[] = $val;
376: }
377: }
378: $i = 0;
379: foreach ($normalized as $tags) {
380: if (!is_array($tags)) {
381: $tags = (string)$tags;
382: }
383: $i++;
384: if (is_string($tags) && $tags{0} == '<') {
385: $tags = array(substr($tags, 1) => array());
386: } elseif (is_string($tags)) {
387: $tagsTrimmed = preg_replace('/\s+/m', '', $tags);
388:
389: if (preg_match('/^\*?\//', $tags, $match) && $tagsTrimmed !== '//') {
390: $prefix = array(null, null);
391:
392: if ($match[0] == '*/') {
393: $prefix = array('Anything, ', '.*?');
394: }
395: $regex[] = array(
396: sprintf('%sClose %s tag', $prefix[0], substr($tags, strlen($match[0]))),
397: sprintf('%s<[\s]*\/[\s]*%s[\s]*>[\n\r]*', $prefix[1], substr($tags, strlen($match[0]))),
398: $i,
399: );
400: continue;
401: }
402: if (!empty($tags) && preg_match('/^preg\:\/(.+)\/$/i', $tags, $matches)) {
403: $tags = $matches[1];
404: $type = 'Regex matches';
405: } else {
406: $tags = preg_quote($tags, '/');
407: $type = 'Text equals';
408: }
409: $regex[] = array(
410: sprintf('%s "%s"', $type, $tags),
411: $tags,
412: $i,
413: );
414: continue;
415: }
416: foreach ($tags as $tag => $attributes) {
417: $regex[] = array(
418: sprintf('Open %s tag', $tag),
419: sprintf('[\s]*<%s', preg_quote($tag, '/')),
420: $i,
421: );
422: if ($attributes === true) {
423: $attributes = array();
424: }
425: $attrs = array();
426: $explanations = array();
427: $i = 1;
428: foreach ($attributes as $attr => $val) {
429: if (is_numeric($attr) && preg_match('/^preg\:\/(.+)\/$/i', $val, $matches)) {
430: $attrs[] = $matches[1];
431: $explanations[] = sprintf('Regex "%s" matches', $matches[1]);
432: continue;
433: } else {
434: $quotes = '["\']';
435: if (is_numeric($attr)) {
436: $attr = $val;
437: $val = '.+?';
438: $explanations[] = sprintf('Attribute "%s" present', $attr);
439: } elseif (!empty($val) && preg_match('/^preg\:\/(.+)\/$/i', $val, $matches)) {
440: $quotes = '["\']?';
441: $val = $matches[1];
442: $explanations[] = sprintf('Attribute "%s" matches "%s"', $attr, $val);
443: } else {
444: $explanations[] = sprintf('Attribute "%s" == "%s"', $attr, $val);
445: $val = preg_quote($val, '/');
446: }
447: $attrs[] = '[\s]+' . preg_quote($attr, '/') . '=' . $quotes . $val . $quotes;
448: }
449: $i++;
450: }
451: if ($attrs) {
452: $permutations = $this->_arrayPermute($attrs);
453:
454: $permutationTokens = array();
455: foreach ($permutations as $permutation) {
456: $permutationTokens[] = implode('', $permutation);
457: }
458: $regex[] = array(
459: sprintf('%s', implode(', ', $explanations)),
460: $permutationTokens,
461: $i,
462: );
463: }
464: $regex[] = array(
465: sprintf('End %s tag', $tag),
466: '[\s]*\/?[\s]*>[\n\r]*',
467: $i,
468: );
469: }
470: }
471: foreach ($regex as $i => $assertation) {
472: list($description, $expressions, $itemNum) = $assertation;
473: $matches = false;
474: foreach ((array)$expressions as $expression) {
475: if (preg_match(sprintf('/^%s/s', $expression), $string, $match)) {
476: $matches = true;
477: $string = substr($string, strlen($match[0]));
478: break;
479: }
480: }
481: if (!$matches) {
482: $this->assertTrue(false, sprintf('Item #%d / regex #%d failed: %s', $itemNum, $i, $description));
483: if ($fullDebug) {
484: debug($string, true);
485: debug($regex, true);
486: }
487: return false;
488: }
489: }
490:
491: $this->assertTrue(true, '%s');
492: return true;
493: }
494:
495: /**
496: * Generates all permutation of an array $items and returns them in a new array.
497: *
498: * @param array $items An array of items
499: * @return array
500: */
501: protected function _arrayPermute($items, $perms = array()) {
502: static $permuted;
503: if (empty($perms)) {
504: $permuted = array();
505: }
506:
507: if (empty($items)) {
508: $permuted[] = $perms;
509: } else {
510: $numItems = count($items) - 1;
511: for ($i = $numItems; $i >= 0; --$i) {
512: $newItems = $items;
513: $newPerms = $perms;
514: list($tmp) = array_splice($newItems, $i, 1);
515: array_unshift($newPerms, $tmp);
516: $this->_arrayPermute($newItems, $newPerms);
517: }
518: return $permuted;
519: }
520: }
521:
522: // @codingStandardsIgnoreStart
523:
524: /**
525: * Compatibility wrapper function for assertEquals
526: *
527: *
528: * @param mixed $result
529: * @param mixed $expected
530: * @param string $message the text to display if the assertion is not correct
531: * @return void
532: */
533: protected static function assertEqual($result, $expected, $message = '') {
534: return self::assertEquals($expected, $result, $message);
535: }
536:
537: /**
538: * Compatibility wrapper function for assertNotEquals
539: *
540: * @param mixed $result
541: * @param mixed $expected
542: * @param string $message the text to display if the assertion is not correct
543: * @return void
544: */
545: protected static function assertNotEqual($result, $expected, $message = '') {
546: return self::assertNotEquals($expected, $result, $message);
547: }
548:
549: /**
550: * Compatibility wrapper function for assertRegexp
551: *
552: * @param mixed $pattern a regular expression
553: * @param string $string the text to be matched
554: * @param string $message the text to display if the assertion is not correct
555: * @return void
556: */
557: protected static function assertPattern($pattern, $string, $message = '') {
558: return self::assertRegExp($pattern, $string, $message);
559: }
560:
561: /**
562: * Compatibility wrapper function for assertEquals
563: *
564: * @param mixed $actual
565: * @param mixed $expected
566: * @param string $message the text to display if the assertion is not correct
567: * @return void
568: */
569: protected static function assertIdentical($actual, $expected, $message = '') {
570: return self::assertSame($expected, $actual, $message);
571: }
572:
573: /**
574: * Compatibility wrapper function for assertNotEquals
575: *
576: * @param mixed $actual
577: * @param mixed $expected
578: * @param string $message the text to display if the assertion is not correct
579: * @return void
580: */
581: protected static function assertNotIdentical($actual, $expected, $message = '') {
582: return self::assertNotSame($expected, $actual, $message);
583: }
584:
585: /**
586: * Compatibility wrapper function for assertNotRegExp
587: *
588: * @param mixed $pattern a regular expression
589: * @param string $string the text to be matched
590: * @param string $message the text to display if the assertion is not correct
591: * @return void
592: */
593: protected static function assertNoPattern($pattern, $string, $message = '') {
594: return self::assertNotRegExp($pattern, $string, $message);
595: }
596:
597: protected function assertNoErrors() {
598: }
599:
600: /**
601: * Compatibility wrapper function for setExpectedException
602: *
603: * @param mixed $expected the name of the Exception or error
604: * @param string $message the text to display if the assertion is not correct
605: * @return void
606: */
607: protected function expectError($expected = false, $message = '') {
608: if (!$expected) {
609: $expected = 'Exception';
610: }
611: $this->setExpectedException($expected, $message);
612: }
613:
614: /**
615: * Compatibility wrapper function for setExpectedException
616: *
617: * @param mixed $expected the name of the Exception
618: * @param string $message the text to display if the assertion is not correct
619: * @return void
620: */
621: protected function expectException($name = 'Exception', $message = '') {
622: $this->setExpectedException($name, $message);
623: }
624:
625: /**
626: * Compatibility wrapper function for assertSame
627: *
628: * @param mixed $first
629: * @param mixed $second
630: * @param string $message the text to display if the assertion is not correct
631: * @return void
632: */
633: protected static function assertReference(&$first, &$second, $message = '') {
634: return self::assertSame($first, $second, $message);
635: }
636:
637: /**
638: * Compatibility wrapper for assertIsA
639: *
640: * @param string $object
641: * @param string $type
642: * @param string $message
643: * @return void
644: */
645: protected static function assertIsA($object, $type, $message = '') {
646: return self::assertInstanceOf($type, $object, $message);
647: }
648:
649: /**
650: * Compatibility function to test if value is between an acceptable range
651: *
652: * @param mixed $result
653: * @param mixed $expected
654: * @param mixed $margin the rage of acceptation
655: * @param string $message the text to display if the assertion is not correct
656: * @return void
657: */
658: protected static function assertWithinMargin($result, $expected, $margin, $message = '') {
659: $upper = $result + $margin;
660: $lower = $result - $margin;
661: return self::assertTrue((($expected <= $upper) && ($expected >= $lower)), $message);
662: }
663:
664: /**
665: * Compatibility function for skipping.
666: *
667: * @param boolean $condition Condition to trigger skipping
668: * @param string $message Message for skip
669: * @return boolean
670: */
671: protected function skipUnless($condition, $message = '') {
672: if (!$condition) {
673: $this->markTestSkipped($message);
674: }
675: return $condition;
676: }
677: // @codingStandardsIgnoreEnd
678:
679: }
680: