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: Configure::write($this->_configure);
150: if (isset($_GET['debug']) && $_GET['debug']) {
151: ob_flush();
152: }
153: }
154:
155: /**
156: * See CakeTestSuiteDispatcher::date()
157: *
158: * @param string $format format to be used.
159: * @return string
160: */
161: public static function date($format = 'Y-m-d H:i:s') {
162: return CakeTestSuiteDispatcher::date($format);
163: }
164:
165: // @codingStandardsIgnoreStart PHPUnit overrides don't match CakePHP
166:
167: /**
168: * Announces the start of a test.
169: *
170: * @param string $method Test method just started.
171: * @return void
172: */
173: protected function assertPreConditions() {
174: parent::assertPreConditions();
175: $this->startTest($this->getName());
176: }
177:
178: /**
179: * Announces the end of a test.
180: *
181: * @param string $method Test method just finished.
182: * @return void
183: */
184: protected function assertPostConditions() {
185: parent::assertPostConditions();
186: $this->endTest($this->getName());
187: }
188:
189: // @codingStandardsIgnoreEnd
190:
191: /**
192: * Chooses which fixtures to load for a given test
193: *
194: * @param string $fixture Each parameter is a model name that corresponds to a
195: * fixture, i.e. 'Post', 'Author', etc.
196: * @return void
197: * @see CakeTestCase::$autoFixtures
198: * @throws Exception when no fixture manager is available.
199: */
200: public function loadFixtures() {
201: if (empty($this->fixtureManager)) {
202: throw new Exception(__d('cake_dev', 'No fixture manager to load the test fixture'));
203: }
204: $args = func_get_args();
205: foreach ($args as $class) {
206: $this->fixtureManager->loadSingle($class);
207: }
208: }
209:
210: /**
211: * Assert text equality, ignoring differences in newlines.
212: * Helpful for doing cross platform tests of blocks of text.
213: *
214: * @param string $expected The expected value.
215: * @param string $result The actual value.
216: * @param message The message to use for failure.
217: * @return boolean
218: */
219: public function assertTextNotEquals($expected, $result, $message = '') {
220: $expected = str_replace(array("\r\n", "\r"), "\n", $expected);
221: $result = str_replace(array("\r\n", "\r"), "\n", $result);
222: return $this->assertNotEquals($expected, $result, $message);
223: }
224:
225: /**
226: * Assert text equality, ignoring differences in newlines.
227: * Helpful for doing cross platform tests of blocks of text.
228: *
229: * @param string $expected The expected value.
230: * @param string $result The actual value.
231: * @param message The message to use for failure.
232: * @return boolean
233: */
234: public function assertTextEquals($expected, $result, $message = '') {
235: $expected = str_replace(array("\r\n", "\r"), "\n", $expected);
236: $result = str_replace(array("\r\n", "\r"), "\n", $result);
237: return $this->assertEquals($expected, $result, $message);
238: }
239:
240: /**
241: * Asserts that a string starts with a given prefix, ignoring differences in newlines.
242: * Helpful for doing cross platform tests of blocks of text.
243: *
244: * @param string $prefix
245: * @param string $string
246: * @param string $message
247: * @return boolean
248: */
249: public function assertTextStartsWith($prefix, $string, $message = '') {
250: $prefix = str_replace(array("\r\n", "\r"), "\n", $prefix);
251: $string = str_replace(array("\r\n", "\r"), "\n", $string);
252: return $this->assertStringStartsWith($prefix, $string, $message);
253: }
254:
255: /**
256: * Asserts that a string starts not with a given prefix, ignoring differences in newlines.
257: * Helpful for doing cross platform tests of blocks of text.
258: *
259: * @param string $prefix
260: * @param string $string
261: * @param string $message
262: * @return boolean
263: */
264: public function assertTextStartsNotWith($prefix, $string, $message = '') {
265: $prefix = str_replace(array("\r\n", "\r"), "\n", $prefix);
266: $string = str_replace(array("\r\n", "\r"), "\n", $string);
267: return $this->assertStringStartsNotWith($prefix, $string, $message);
268: }
269:
270: /**
271: * Asserts that a string ends with a given prefix, ignoring differences in newlines.
272: * Helpful for doing cross platform tests of blocks of text.
273: *
274: * @param string $suffix
275: * @param string $string
276: * @param string $message
277: * @return boolean
278: */
279: public function assertTextEndsWith($suffix, $string, $message = '') {
280: $suffix = str_replace(array("\r\n", "\r"), "\n", $suffix);
281: $string = str_replace(array("\r\n", "\r"), "\n", $string);
282: return $this->assertStringEndsWith($suffix, $string, $message);
283: }
284:
285: /**
286: * Asserts that a string ends not with a given prefix, ignoring differences in newlines.
287: * Helpful for doing cross platform tests of blocks of text.
288: *
289: * @param string $suffix
290: * @param string $string
291: * @param string $message
292: * @return boolean
293: */
294: public function assertTextEndsNotWith($suffix, $string, $message = '') {
295: $suffix = str_replace(array("\r\n", "\r"), "\n", $suffix);
296: $string = str_replace(array("\r\n", "\r"), "\n", $string);
297: return $this->assertStringEndsNotWith($suffix, $string, $message);
298: }
299:
300: /**
301: * Assert that a string contains another string, ignoring differences in newlines.
302: * Helpful for doing cross platform tests of blocks of text.
303: *
304: * @param string $needle
305: * @param string $haystack
306: * @param string $message
307: * @param boolean $ignoreCase
308: * @return boolean
309: */
310: public function assertTextContains($needle, $haystack, $message = '', $ignoreCase = false) {
311: $needle = str_replace(array("\r\n", "\r"), "\n", $needle);
312: $haystack = str_replace(array("\r\n", "\r"), "\n", $haystack);
313: return $this->assertContains($needle, $haystack, $message, $ignoreCase);
314: }
315:
316: /**
317: * Assert that a text doesn't contain another text, ignoring differences in newlines.
318: * Helpful for doing cross platform tests of blocks of text.
319: *
320: * @param string $needle
321: * @param string $haystack
322: * @param string $message
323: * @param boolean $ignoreCase
324: * @return boolean
325: */
326: public function assertTextNotContains($needle, $haystack, $message = '', $ignoreCase = false) {
327: $needle = str_replace(array("\r\n", "\r"), "\n", $needle);
328: $haystack = str_replace(array("\r\n", "\r"), "\n", $haystack);
329: return $this->assertNotContains($needle, $haystack, $message, $ignoreCase);
330: }
331:
332: /**
333: * Takes an array $expected and generates a regex from it to match the provided $string.
334: * Samples for $expected:
335: *
336: * Checks for an input tag with a name attribute (contains any non-empty value) and an id
337: * attribute that contains 'my-input':
338: * array('input' => array('name', 'id' => 'my-input'))
339: *
340: * Checks for two p elements with some text in them:
341: * array(
342: * array('p' => true),
343: * 'textA',
344: * '/p',
345: * array('p' => true),
346: * 'textB',
347: * '/p'
348: * )
349: *
350: * You can also specify a pattern expression as part of the attribute values, or the tag
351: * being defined, if you prepend the value with preg: and enclose it with slashes, like so:
352: * array(
353: * array('input' => array('name', 'id' => 'preg:/FieldName\d+/')),
354: * 'preg:/My\s+field/'
355: * )
356: *
357: * Important: This function is very forgiving about whitespace and also accepts any
358: * permutation of attribute order. It will also allow whitespace between specified tags.
359: *
360: * @param string $string An HTML/XHTML/XML string
361: * @param array $expected An array, see above
362: * @param string $message SimpleTest failure output string
363: * @return boolean
364: */
365: public function assertTags($string, $expected, $fullDebug = false) {
366: $regex = array();
367: $normalized = array();
368: foreach ((array)$expected as $key => $val) {
369: if (!is_numeric($key)) {
370: $normalized[] = array($key => $val);
371: } else {
372: $normalized[] = $val;
373: }
374: }
375: $i = 0;
376: foreach ($normalized as $tags) {
377: if (!is_array($tags)) {
378: $tags = (string)$tags;
379: }
380: $i++;
381: if (is_string($tags) && $tags{0} == '<') {
382: $tags = array(substr($tags, 1) => array());
383: } elseif (is_string($tags)) {
384: $tagsTrimmed = preg_replace('/\s+/m', '', $tags);
385:
386: if (preg_match('/^\*?\//', $tags, $match) && $tagsTrimmed !== '//') {
387: $prefix = array(null, null);
388:
389: if ($match[0] == '*/') {
390: $prefix = array('Anything, ', '.*?');
391: }
392: $regex[] = array(
393: sprintf('%sClose %s tag', $prefix[0], substr($tags, strlen($match[0]))),
394: sprintf('%s<[\s]*\/[\s]*%s[\s]*>[\n\r]*', $prefix[1], substr($tags, strlen($match[0]))),
395: $i,
396: );
397: continue;
398: }
399: if (!empty($tags) && preg_match('/^preg\:\/(.+)\/$/i', $tags, $matches)) {
400: $tags = $matches[1];
401: $type = 'Regex matches';
402: } else {
403: $tags = preg_quote($tags, '/');
404: $type = 'Text equals';
405: }
406: $regex[] = array(
407: sprintf('%s "%s"', $type, $tags),
408: $tags,
409: $i,
410: );
411: continue;
412: }
413: foreach ($tags as $tag => $attributes) {
414: $regex[] = array(
415: sprintf('Open %s tag', $tag),
416: sprintf('[\s]*<%s', preg_quote($tag, '/')),
417: $i,
418: );
419: if ($attributes === true) {
420: $attributes = array();
421: }
422: $attrs = array();
423: $explanations = array();
424: $i = 1;
425: foreach ($attributes as $attr => $val) {
426: if (is_numeric($attr) && preg_match('/^preg\:\/(.+)\/$/i', $val, $matches)) {
427: $attrs[] = $matches[1];
428: $explanations[] = sprintf('Regex "%s" matches', $matches[1]);
429: continue;
430: } else {
431: $quotes = '["\']';
432: if (is_numeric($attr)) {
433: $attr = $val;
434: $val = '.+?';
435: $explanations[] = sprintf('Attribute "%s" present', $attr);
436: } elseif (!empty($val) && preg_match('/^preg\:\/(.+)\/$/i', $val, $matches)) {
437: $quotes = '["\']?';
438: $val = $matches[1];
439: $explanations[] = sprintf('Attribute "%s" matches "%s"', $attr, $val);
440: } else {
441: $explanations[] = sprintf('Attribute "%s" == "%s"', $attr, $val);
442: $val = preg_quote($val, '/');
443: }
444: $attrs[] = '[\s]+' . preg_quote($attr, '/') . '=' . $quotes . $val . $quotes;
445: }
446: $i++;
447: }
448: if ($attrs) {
449: $permutations = $this->_arrayPermute($attrs);
450:
451: $permutationTokens = array();
452: foreach ($permutations as $permutation) {
453: $permutationTokens[] = implode('', $permutation);
454: }
455: $regex[] = array(
456: sprintf('%s', implode(', ', $explanations)),
457: $permutationTokens,
458: $i,
459: );
460: }
461: $regex[] = array(
462: sprintf('End %s tag', $tag),
463: '[\s]*\/?[\s]*>[\n\r]*',
464: $i,
465: );
466: }
467: }
468: foreach ($regex as $i => $assertation) {
469: list($description, $expressions, $itemNum) = $assertation;
470: $matches = false;
471: foreach ((array)$expressions as $expression) {
472: if (preg_match(sprintf('/^%s/s', $expression), $string, $match)) {
473: $matches = true;
474: $string = substr($string, strlen($match[0]));
475: break;
476: }
477: }
478: if (!$matches) {
479: $this->assertTrue(false, sprintf('Item #%d / regex #%d failed: %s', $itemNum, $i, $description));
480: if ($fullDebug) {
481: debug($string, true);
482: debug($regex, true);
483: }
484: return false;
485: }
486: }
487:
488: $this->assertTrue(true, '%s');
489: return true;
490: }
491:
492: /**
493: * Generates all permutation of an array $items and returns them in a new array.
494: *
495: * @param array $items An array of items
496: * @return array
497: */
498: protected function _arrayPermute($items, $perms = array()) {
499: static $permuted;
500: if (empty($perms)) {
501: $permuted = array();
502: }
503:
504: if (empty($items)) {
505: $permuted[] = $perms;
506: } else {
507: $numItems = count($items) - 1;
508: for ($i = $numItems; $i >= 0; --$i) {
509: $newItems = $items;
510: $newPerms = $perms;
511: list($tmp) = array_splice($newItems, $i, 1);
512: array_unshift($newPerms, $tmp);
513: $this->_arrayPermute($newItems, $newPerms);
514: }
515: return $permuted;
516: }
517: }
518:
519: // @codingStandardsIgnoreStart
520:
521: /**
522: * Compatibility wrapper function for assertEquals
523: *
524: *
525: * @param mixed $result
526: * @param mixed $expected
527: * @param string $message the text to display if the assertion is not correct
528: * @return void
529: */
530: protected static function assertEqual($result, $expected, $message = '') {
531: return self::assertEquals($expected, $result, $message);
532: }
533:
534: /**
535: * Compatibility wrapper function for assertNotEquals
536: *
537: * @param mixed $result
538: * @param mixed $expected
539: * @param string $message the text to display if the assertion is not correct
540: * @return void
541: */
542: protected static function assertNotEqual($result, $expected, $message = '') {
543: return self::assertNotEquals($expected, $result, $message);
544: }
545:
546: /**
547: * Compatibility wrapper function for assertRegexp
548: *
549: * @param mixed $pattern a regular expression
550: * @param string $string the text to be matched
551: * @param string $message the text to display if the assertion is not correct
552: * @return void
553: */
554: protected static function assertPattern($pattern, $string, $message = '') {
555: return self::assertRegExp($pattern, $string, $message);
556: }
557:
558: /**
559: * Compatibility wrapper function for assertEquals
560: *
561: * @param mixed $actual
562: * @param mixed $expected
563: * @param string $message the text to display if the assertion is not correct
564: * @return void
565: */
566: protected static function assertIdentical($actual, $expected, $message = '') {
567: return self::assertSame($expected, $actual, $message);
568: }
569:
570: /**
571: * Compatibility wrapper function for assertNotEquals
572: *
573: * @param mixed $actual
574: * @param mixed $expected
575: * @param string $message the text to display if the assertion is not correct
576: * @return void
577: */
578: protected static function assertNotIdentical($actual, $expected, $message = '') {
579: return self::assertNotSame($expected, $actual, $message);
580: }
581:
582: /**
583: * Compatibility wrapper function for assertNotRegExp
584: *
585: * @param mixed $pattern a regular expression
586: * @param string $string the text to be matched
587: * @param string $message the text to display if the assertion is not correct
588: * @return void
589: */
590: protected static function assertNoPattern($pattern, $string, $message = '') {
591: return self::assertNotRegExp($pattern, $string, $message);
592: }
593:
594: protected function assertNoErrors() {
595: }
596:
597: /**
598: * Compatibility wrapper function for setExpectedException
599: *
600: * @param mixed $expected the name of the Exception or error
601: * @param string $message the text to display if the assertion is not correct
602: * @return void
603: */
604: protected function expectError($expected = false, $message = '') {
605: if (!$expected) {
606: $expected = 'Exception';
607: }
608: $this->setExpectedException($expected, $message);
609: }
610:
611: /**
612: * Compatibility wrapper function for setExpectedException
613: *
614: * @param mixed $expected the name of the Exception
615: * @param string $message the text to display if the assertion is not correct
616: * @return void
617: */
618: protected function expectException($name = 'Exception', $message = '') {
619: $this->setExpectedException($name, $message);
620: }
621:
622: /**
623: * Compatibility wrapper function for assertSame
624: *
625: * @param mixed $first
626: * @param mixed $second
627: * @param string $message the text to display if the assertion is not correct
628: * @return void
629: */
630: protected static function assertReference(&$first, &$second, $message = '') {
631: return self::assertSame($first, $second, $message);
632: }
633:
634: /**
635: * Compatibility wrapper for assertIsA
636: *
637: * @param string $object
638: * @param string $type
639: * @param string $message
640: * @return void
641: */
642: protected static function assertIsA($object, $type, $message = '') {
643: return self::assertInstanceOf($type, $object, $message);
644: }
645:
646: /**
647: * Compatibility function to test if value is between an acceptable range
648: *
649: * @param mixed $result
650: * @param mixed $expected
651: * @param mixed $margin the rage of acceptation
652: * @param string $message the text to display if the assertion is not correct
653: * @return void
654: */
655: protected static function assertWithinMargin($result, $expected, $margin, $message = '') {
656: $upper = $result + $margin;
657: $lower = $result - $margin;
658: return self::assertTrue((($expected <= $upper) && ($expected >= $lower)), $message);
659: }
660:
661: /**
662: * Compatibility function for skipping.
663: *
664: * @param boolean $condition Condition to trigger skipping
665: * @param string $message Message for skip
666: * @return boolean
667: */
668: protected function skipUnless($condition, $message = '') {
669: if (!$condition) {
670: $this->markTestSkipped($message);
671: }
672: return $condition;
673: }
674: // @codingStandardsIgnoreStop
675:
676: }
677: