CakeTestCase.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. <?php
  2. /**
  3. * CakeTestCase file
  4. *
  5. * PHP 5
  6. *
  7. * CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing>
  8. * Copyright 2005-2011, 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-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
  15. * @package cake.tests.libs
  16. * @since CakePHP(tm) v 1.2.0.4667
  17. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  18. */
  19. PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT');
  20. App::uses('CakeFixtureManager', 'TestSuite/Fixture');
  21. App::uses('CakeTestFixture', 'TestSuite/Fixture');
  22. /**
  23. * CakeTestCase class
  24. *
  25. * @package cake.tests.lib
  26. */
  27. abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
  28. /**
  29. * The class responsible for managing the creation, loading and removing of fixtures
  30. *
  31. * @var CakeFixtureManager
  32. * @access public
  33. */
  34. public $fixtureManager = null;
  35. /**
  36. * By default, all fixtures attached to this class will be truncated and reloaded after each test.
  37. * Set this to false to handle manually
  38. *
  39. * @var array
  40. * @access public
  41. */
  42. public $autoFixtures = true;
  43. /**
  44. * Set this to false to avoid tables to be dropped if they already exist
  45. *
  46. * @var boolean
  47. * @access public
  48. */
  49. public $dropTables = true;
  50. /**
  51. * The fixtures to be loaded in this test case. Fixtures are referenced using a dot notation:
  52. * - fixture_name : A fixtures that can be found in the main app folder and is named FixtureNameFixture
  53. * - core.fixture_name : A fixtures that can be found in the cake core folder and is named FixtureNameFixture
  54. * - plugin.plugin_name.fixture_name : A fixtures that can be found in the plugin "plugin_name" folder and is named FixtureNameFixture
  55. *
  56. * @var array
  57. * @access public
  58. */
  59. private $fixtures = array();
  60. /**
  61. * Configure values to restore at end of test.
  62. *
  63. * @var array
  64. */
  65. protected $_configure = array();
  66. /**
  67. * Runs the test case and collects the results in a TestResult object.
  68. * If no TestResult object is passed a new one will be created.
  69. * This method is run for each test method in this class
  70. *
  71. * @param PHPUnit_Framework_TestResult $result
  72. * @return PHPUnit_Framework_TestResult
  73. * @throws InvalidArgumentException
  74. */
  75. public function run(PHPUnit_Framework_TestResult $result = NULL) {
  76. if (!empty($this->fixtureManager)) {
  77. $this->fixtureManager->load($this);
  78. }
  79. $result = parent::run($result);
  80. if (!empty($this->fixtureManager)) {
  81. $this->fixtureManager->unload($this);
  82. }
  83. return $result;
  84. }
  85. /**
  86. * Called when a test case method is about to start (to be overriden 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. * Called when a test case method has been executed (to be overriden when needed.)
  95. *
  96. * @param string $method Test method about that was executed.
  97. * @return void
  98. */
  99. public function endTest($method) {
  100. }
  101. /**
  102. * Overrides SimpleTestCase::skipIf to provide a boolean return value
  103. *
  104. * @param boolean $shouldSkip
  105. * @param string $message
  106. * @return boolean
  107. */
  108. public function skipIf($shouldSkip, $message = '') {
  109. if ($shouldSkip) {
  110. $this->markTestSkipped($message);
  111. }
  112. return $shouldSkip;
  113. }
  114. /**
  115. * setup the test case, backup the static object values so they can be restored.
  116. *
  117. * @return void
  118. */
  119. public function setUp() {
  120. parent::setUp();
  121. $this->_configure = Configure::read();
  122. if (class_exists('Router', false)) {
  123. Router::reload();
  124. }
  125. }
  126. /**
  127. * teardown any static object changes and restore them.
  128. *
  129. * @return void
  130. */
  131. public function tearDown() {
  132. parent::tearDown();
  133. App::build();
  134. if (class_exists('ClassRegistry', false)) {
  135. ClassRegistry::flush();
  136. }
  137. Configure::write($this->_configure);
  138. }
  139. /**
  140. * Announces the start of a test.
  141. *
  142. * @param string $method Test method just started.
  143. * @return void
  144. */
  145. protected function assertPreConditions() {
  146. parent::assertPreConditions();
  147. $this->startTest($this->getName());
  148. }
  149. /**
  150. * Announces the end of a test.
  151. *
  152. * @param string $method Test method just finished.
  153. * @return void
  154. */
  155. protected function assertPostConditions() {
  156. parent::assertPostConditions();
  157. $this->endTest($this->getName());
  158. }
  159. /**
  160. * Chooses which fixtures to load for a given test
  161. *
  162. * @param string $fixture Each parameter is a model name that corresponds to a
  163. * fixture, i.e. 'Post', 'Author', etc.
  164. * @return void
  165. * @access public
  166. * @see CakeTestCase::$autoFixtures
  167. */
  168. public function loadFixtures() {
  169. if (empty($this->fixtureManager)) {
  170. throw new Exception(__d('cake_dev', 'No fixture manager to load the test fixture'));
  171. }
  172. $args = func_get_args();
  173. foreach ($args as $class) {
  174. $this->fixtureManager->loadSingle($class);
  175. }
  176. }
  177. /**
  178. * Takes an array $expected and generates a regex from it to match the provided $string.
  179. * Samples for $expected:
  180. *
  181. * Checks for an input tag with a name attribute (contains any non-empty value) and an id
  182. * attribute that contains 'my-input':
  183. * array('input' => array('name', 'id' => 'my-input'))
  184. *
  185. * Checks for two p elements with some text in them:
  186. * array(
  187. * array('p' => true),
  188. * 'textA',
  189. * '/p',
  190. * array('p' => true),
  191. * 'textB',
  192. * '/p'
  193. * )
  194. *
  195. * You can also specify a pattern expression as part of the attribute values, or the tag
  196. * being defined, if you prepend the value with preg: and enclose it with slashes, like so:
  197. * array(
  198. * array('input' => array('name', 'id' => 'preg:/FieldName\d+/')),
  199. * 'preg:/My\s+field/'
  200. * )
  201. *
  202. * Important: This function is very forgiving about whitespace and also accepts any
  203. * permutation of attribute order. It will also allow whitespaces between specified tags.
  204. *
  205. * @param string $string An HTML/XHTML/XML string
  206. * @param array $expected An array, see above
  207. * @param string $message SimpleTest failure output string
  208. * @return boolean
  209. */
  210. public function assertTags($string, $expected, $fullDebug = false) {
  211. $regex = array();
  212. $normalized = array();
  213. foreach ((array) $expected as $key => $val) {
  214. if (!is_numeric($key)) {
  215. $normalized[] = array($key => $val);
  216. } else {
  217. $normalized[] = $val;
  218. }
  219. }
  220. $i = 0;
  221. foreach ($normalized as $tags) {
  222. if (!is_array($tags)) {
  223. $tags = (string)$tags;
  224. }
  225. $i++;
  226. if (is_string($tags) && $tags{0} == '<') {
  227. $tags = array(substr($tags, 1) => array());
  228. } elseif (is_string($tags)) {
  229. $tagsTrimmed = preg_replace('/\s+/m', '', $tags);
  230. if (preg_match('/^\*?\//', $tags, $match) && $tagsTrimmed !== '//') {
  231. $prefix = array(null, null);
  232. if ($match[0] == '*/') {
  233. $prefix = array('Anything, ', '.*?');
  234. }
  235. $regex[] = array(
  236. sprintf('%sClose %s tag', $prefix[0], substr($tags, strlen($match[0]))),
  237. sprintf('%s<[\s]*\/[\s]*%s[\s]*>[\n\r]*', $prefix[1], substr($tags, strlen($match[0]))),
  238. $i,
  239. );
  240. continue;
  241. }
  242. if (!empty($tags) && preg_match('/^preg\:\/(.+)\/$/i', $tags, $matches)) {
  243. $tags = $matches[1];
  244. $type = 'Regex matches';
  245. } else {
  246. $tags = preg_quote($tags, '/');
  247. $type = 'Text equals';
  248. }
  249. $regex[] = array(
  250. sprintf('%s "%s"', $type, $tags),
  251. $tags,
  252. $i,
  253. );
  254. continue;
  255. }
  256. foreach ($tags as $tag => $attributes) {
  257. $regex[] = array(
  258. sprintf('Open %s tag', $tag),
  259. sprintf('[\s]*<%s', preg_quote($tag, '/')),
  260. $i,
  261. );
  262. if ($attributes === true) {
  263. $attributes = array();
  264. }
  265. $attrs = array();
  266. $explanations = array();
  267. $i = 1;
  268. foreach ($attributes as $attr => $val) {
  269. if (is_numeric($attr) && preg_match('/^preg\:\/(.+)\/$/i', $val, $matches)) {
  270. $attrs[] = $matches[1];
  271. $explanations[] = sprintf('Regex "%s" matches', $matches[1]);
  272. continue;
  273. } else {
  274. $quotes = '["\']';
  275. if (is_numeric($attr)) {
  276. $attr = $val;
  277. $val = '.+?';
  278. $explanations[] = sprintf('Attribute "%s" present', $attr);
  279. } elseif (!empty($val) && preg_match('/^preg\:\/(.+)\/$/i', $val, $matches)) {
  280. $quotes = '["\']?';
  281. $val = $matches[1];
  282. $explanations[] = sprintf('Attribute "%s" matches "%s"', $attr, $val);
  283. } else {
  284. $explanations[] = sprintf('Attribute "%s" == "%s"', $attr, $val);
  285. $val = preg_quote($val, '/');
  286. }
  287. $attrs[] = '[\s]+' . preg_quote($attr, '/') . '=' . $quotes . $val . $quotes;
  288. }
  289. $i++;
  290. }
  291. if ($attrs) {
  292. $permutations = $this->__array_permute($attrs);
  293. $permutationTokens = array();
  294. foreach ($permutations as $permutation) {
  295. $permutationTokens[] = implode('', $permutation);
  296. }
  297. $regex[] = array(
  298. sprintf('%s', implode(', ', $explanations)),
  299. $permutationTokens,
  300. $i,
  301. );
  302. }
  303. $regex[] = array(
  304. sprintf('End %s tag', $tag),
  305. '[\s]*\/?[\s]*>[\n\r]*',
  306. $i,
  307. );
  308. }
  309. }
  310. foreach ($regex as $i => $assertation) {
  311. list($description, $expressions, $itemNum) = $assertation;
  312. $matches = false;
  313. foreach ((array)$expressions as $expression) {
  314. if (preg_match(sprintf('/^%s/s', $expression), $string, $match)) {
  315. $matches = true;
  316. $string = substr($string, strlen($match[0]));
  317. break;
  318. }
  319. }
  320. if (!$matches) {
  321. $this->assertTrue(false, sprintf('Item #%d / regex #%d failed: %s', $itemNum, $i, $description));
  322. if ($fullDebug) {
  323. debug($string, true);
  324. debug($regex, true);
  325. }
  326. return false;
  327. }
  328. }
  329. $this->assertTrue(true, '%s');
  330. return true;
  331. }
  332. /**
  333. * Generates all permutation of an array $items and returns them in a new array.
  334. *
  335. * @param array $items An array of items
  336. * @return array
  337. * @access private
  338. */
  339. private function __array_permute($items, $perms = array()) {
  340. static $permuted;
  341. if (empty($perms)) {
  342. $permuted = array();
  343. }
  344. if (empty($items)) {
  345. $permuted[] = $perms;
  346. } else {
  347. $numItems = count($items) - 1;
  348. for ($i = $numItems; $i >= 0; --$i) {
  349. $newItems = $items;
  350. $newPerms = $perms;
  351. list($tmp) = array_splice($newItems, $i, 1);
  352. array_unshift($newPerms, $tmp);
  353. $this->__array_permute($newItems, $newPerms);
  354. }
  355. return $permuted;
  356. }
  357. }
  358. /**
  359. * Compatibility wrapper function for assertEquals
  360. * @param mixed $a
  361. * @param mixed $b
  362. * @param string $message the text to display if the assertion is not correct
  363. * @return void
  364. */
  365. protected function assertEqual($a, $b, $message = '') {
  366. return $this->assertEquals($a, $b, $message);
  367. }
  368. /**
  369. * Compatibility wrapper function for assertNotEquals
  370. * @param mixed $a
  371. * @param mixed $b
  372. * @param string $message the text to display if the assertion is not correct
  373. * @return void
  374. */
  375. protected function assertNotEqual($a, $b, $message = '') {
  376. return $this->assertNotEquals($a, $b, $message);
  377. }
  378. /**
  379. * Compatibility wrapper function for assertRegexp
  380. * @param mixed $pattern a regular expression
  381. * @param string $string the text to be matched
  382. * @param string $message the text to display if the assertion is not correct
  383. * @return void
  384. */
  385. protected function assertPattern($pattern, $string, $message = '') {
  386. return $this->assertRegExp($pattern, $string, $message);
  387. }
  388. /**
  389. * Compatibility wrapper function for assertEquals
  390. * @param mixed $expected
  391. * @param mixed $actual
  392. * @param string $message the text to display if the assertion is not correct
  393. * @return void
  394. */
  395. protected function assertIdentical($expected, $actual, $message = '') {
  396. return $this->assertSame($expected, $actual, $message);
  397. }
  398. /**
  399. * Compatibility wrapper function for assertNotEquals
  400. * @param mixed $expected
  401. * @param mixed $actual
  402. * @param string $message the text to display if the assertion is not correct
  403. * @return void
  404. */
  405. protected function assertNotIdentical($expected, $actual, $message = '') {
  406. return $this->assertNotSame($expected, $actual, $message);
  407. }
  408. /**
  409. * Compatibility wrapper function for assertNotRegExp
  410. * @param mixed $pattern a regular expression
  411. * @param string $string the text to be matched
  412. * @param string $message the text to display if the assertion is not correct
  413. * @return void
  414. */
  415. protected function assertNoPattern($pattern, $string, $message = '') {
  416. return $this->assertNotRegExp($pattern, $string, $message);
  417. }
  418. protected function assertNoErrors() {
  419. }
  420. /**
  421. * Compatibility wrapper function for setExpectedException
  422. * @param mixed $expected the name of the Exception or error
  423. * @param string $message the text to display if the assertion is not correct
  424. * @return void
  425. */
  426. protected function expectError($expected = false, $message = '') {
  427. if (!$expected) {
  428. $expected = 'Exception';
  429. }
  430. $this->setExpectedException($expected, $message);
  431. }
  432. /**
  433. * Compatibility wrapper function for setExpectedException
  434. * @param mixed $expected the name of the Exception
  435. * @param string $message the text to display if the assertion is not correct
  436. * @return void
  437. */
  438. protected function expectException($name = 'Exception', $message = '') {
  439. $this->setExpectedException($name, $message);
  440. }
  441. /**
  442. * Compatibility wrapper function for assertSame
  443. * @param mixed $expected
  444. * @param mixed $actual
  445. * @param string $message the text to display if the assertion is not correct
  446. * @return void
  447. */
  448. protected function assertReference(&$first, &$second, $message = '') {
  449. return $this->assertSame($first, $second, $message);
  450. }
  451. /**
  452. * Compatibility wrapper for assertIsA
  453. *
  454. * @param string $object
  455. * @param string $type
  456. * @param string $message
  457. * @return void
  458. */
  459. protected function assertIsA($object, $type, $message = '') {
  460. return $this->assertInstanceOf($type, $object, $message);
  461. }
  462. /**
  463. * Compatibility function to test if value is between an acceptable range
  464. * @param mixed $value
  465. * @param mixed $expected
  466. * @param mixed $margin the rage of acceptation
  467. * @param string $message the text to display if the assertion is not correct
  468. * @return void
  469. */
  470. protected function assertWithinMargin($value, $expected, $margin, $message = '') {
  471. $upper = $value + $margin;
  472. $lower = $value - $margin;
  473. $this->assertTrue((($expected <= $upper) && ($expected >= $lower)), $message);
  474. }
  475. /**
  476. * Compatibility function for skipping.
  477. *
  478. * @param boolean $condition Condition to trigger skipping
  479. * @param string $message Message for skip
  480. * @return boolean
  481. */
  482. protected function skipUnless($condition, $message = '') {
  483. if (!$condition) {
  484. $this->markTestSkipped($message);
  485. }
  486. return $condition;
  487. }
  488. }