PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/test/Unit.php

http://github.com/UnionOfRAD/lithium
PHP | 2020 lines | 1021 code | 125 blank | 874 comment | 122 complexity | a3fdb4860ea2cc3a0f934bac4c043cc7 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * li₃: the most RAD framework for PHP (http://li3.me)
  4. *
  5. * Copyright 2009, Union of RAD. All rights reserved. This source
  6. * code is distributed under the terms of the BSD 3-Clause License.
  7. * The full license text can be found in the LICENSE.txt file.
  8. */
  9. namespace lithium\test;
  10. use Error;
  11. use Exception;
  12. use ErrorException;
  13. use ReflectionClass;
  14. use InvalidArgumentException;
  15. use lithium\aop\Filters;
  16. use lithium\util\Text;
  17. use lithium\core\Libraries;
  18. use lithium\util\Validator;
  19. use lithium\analysis\Debugger;
  20. use lithium\analysis\Inspector;
  21. use RecursiveDirectoryIterator;
  22. use RecursiveIteratorIterator;
  23. /**
  24. * This is the base class for all test cases. Test are performed using an assertion method.
  25. * If the assertion is correct, the test passes, otherwise it fails. Most assertions take an
  26. * expected result, a received result, and a message (to describe the failure) as parameters.
  27. *
  28. * Unit tests are used to check a small unit of functionality, such as if a method returns an
  29. * expected result for a known input, or whether an adapter can successfully open a connection.
  30. *
  31. * Available assertions are (see `assert<assertion-name>` methods for details): Equal, False,
  32. * Identical, NoPattern, NotEqual, Null, Pattern, Tags, True.
  33. *
  34. * If an assertion is expected to produce an exception, `assertException()` should be used.
  35. *
  36. * @see lithium\test\Unit::assertException()
  37. */
  38. class Unit extends \lithium\core\ObjectDeprecated {
  39. /**
  40. * The Reference to a test reporter class.
  41. *
  42. * @var string
  43. */
  44. protected $_reporter = null;
  45. /**
  46. * The list of test results.
  47. *
  48. * @var string
  49. */
  50. protected $_results = [];
  51. /**
  52. * Internal types and how to test for them
  53. *
  54. * @var array
  55. */
  56. protected static $_internalTypes = [
  57. 'array' => 'is_array',
  58. 'bool' => 'is_bool',
  59. 'boolean' => 'is_bool',
  60. 'callable' => 'is_callable',
  61. 'double' => 'is_double',
  62. 'float' => 'is_float',
  63. 'int' => 'is_int',
  64. 'integer' => 'is_integer',
  65. 'long' => 'is_long',
  66. 'null' => 'is_null',
  67. 'numeric' => 'is_numeric',
  68. 'object' => 'is_object',
  69. 'real' => 'is_real',
  70. 'resource' => 'is_resource',
  71. 'scalar' => 'is_scalar',
  72. 'string' => 'is_string'
  73. ];
  74. /**
  75. * Finds the test case for the corresponding class name.
  76. *
  77. * @param string $class A fully-namespaced class reference for which to find a test case.
  78. * @return string Returns the class name of a test case for `$class`, or `null` if none exists.
  79. */
  80. public static function get($class) {
  81. $parts = explode('\\', $class);
  82. $library = array_shift($parts);
  83. $name = array_pop($parts);
  84. $type = 'tests.cases.' . implode('.', $parts);
  85. return Libraries::locate($type, $name, compact('library'));
  86. }
  87. /**
  88. * Setup method run before every test method. Override in subclasses.
  89. *
  90. * @return void
  91. */
  92. public function setUp() {}
  93. /**
  94. * Teardown method run after every test method. Override in subclasses.
  95. *
  96. * @return void
  97. */
  98. public function tearDown() {}
  99. /**
  100. * Subclasses should use this method to set conditions that, if failed, terminate further
  101. * testing.
  102. *
  103. * For example:
  104. * ```
  105. * public function skip() {
  106. * $connection = Connections::get('test', ['config' => true]);
  107. * $this->skipIf(!$connection, 'Test database is unavailable.');
  108. * }
  109. * ```
  110. */
  111. public function skip() {}
  112. /**
  113. * Skips test(s) if the condition is met.
  114. *
  115. * When used within a subclass' `skip` method, all tests are ignored if the condition is
  116. * met, otherwise processing continues as normal. For other methods, only the remainder of
  117. * the method is skipped, when the condition is met.
  118. *
  119. * @throws Exception
  120. * @param boolean $condition
  121. * @param string|boolean $message Message to pass if the condition is met.
  122. * @return mixed
  123. */
  124. public function skipIf($condition, $message = false) {
  125. if ($condition) {
  126. throw new Exception(is_string($message) ? $message : null);
  127. }
  128. }
  129. /**
  130. * Returns the class name that is the subject under test for this test case.
  131. *
  132. * @return string
  133. */
  134. public function subject() {
  135. return preg_replace('/Test$/', '', str_replace('tests\\cases\\', '', get_class($this)));
  136. }
  137. /**
  138. * Return test methods to run.
  139. *
  140. * @return array
  141. */
  142. public function methods() {
  143. static $methods;
  144. return $methods ?: $methods = array_values(preg_grep('/^test/', get_class_methods($this)));
  145. }
  146. /**
  147. * Returns the current results.
  148. *
  149. * @return array The Results... currently.
  150. */
  151. public function results() {
  152. return $this->_results;
  153. }
  154. /**
  155. * Runs the test methods in this test case, with the given options.
  156. *
  157. * Installs a temporary error handler that will convert regular errors to
  158. * exceptions in order to make both errors and exceptions be handled
  159. * in a unified way. ErrorExceptions created like this, will get the
  160. * error's code as their severity. As this comes closest to their meaning.
  161. *
  162. * The error handler honors the PHP `error_level` and will not convert errors
  163. * to exceptions if they are masked by the `error_level`. This allows test
  164. * methods to run assertions against i.e. deprecated functions. Usually
  165. * the error_level is set by the test runner so that all errors are converted.
  166. *
  167. * @link http://php.net/manual/function.error-reporting.php
  168. * @param array $options The options to use when running the test. Available options are:
  169. * - `'methods'`: An arbitrary array of method names to execute. If
  170. * unspecified, all methods starting with 'test' are run.
  171. * - `'reporter'`: A closure which gets called after each test result,
  172. * which may modify the results presented.
  173. * - `'handler'`: A closure which gets registered as the temporary error handler.
  174. * @return array
  175. */
  176. public function run(array $options = []) {
  177. $defaults = [
  178. 'methods' => $this->methods(),
  179. 'reporter' => $this->_reporter,
  180. 'handler' => function($code, $message, $file = null, $line = null) {
  181. if (error_reporting() & $code) {
  182. throw new ErrorException($message, 0, $code, $file, $line);
  183. }
  184. }
  185. ];
  186. $options += $defaults;
  187. $this->_results = [];
  188. $this->_reporter = $options['reporter'];
  189. try {
  190. $this->skip();
  191. } catch (Exception $e) {
  192. $this->_handleException($e);
  193. return $this->_results;
  194. }
  195. set_error_handler($options['handler']);
  196. foreach ($options['methods'] as $method) {
  197. if ($this->_runTestMethod($method, $options) === false) {
  198. break;
  199. }
  200. }
  201. restore_error_handler();
  202. return $this->_results;
  203. }
  204. /**
  205. * General assert method used by others for common output.
  206. *
  207. * @param boolean $expression
  208. * @param string|boolean $message The message to output. If the message is not a string,
  209. * then it will be converted to '{:message}'. Use '{:message}' in the string and it
  210. * will use the `$data` to format the message with `Text::insert()`.
  211. * @param array $data
  212. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  213. */
  214. public function assert($expression, $message = false, $data = []) {
  215. if (!is_string($message)) {
  216. $message = '{:message}';
  217. }
  218. if (strpos($message, "{:message}") !== false) {
  219. $params = $data;
  220. $params['message'] = $this->_message($params);
  221. $message = Text::insert($message, $params);
  222. }
  223. $trace = Debugger::trace([
  224. 'start' => 1, 'depth' => 4, 'format' => 'array', 'closures' => !$expression
  225. ]);
  226. $methods = $this->methods();
  227. $i = 1;
  228. while ($i < count($trace)) {
  229. if (in_array($trace[$i]['function'], $methods) && $trace[$i - 1]['object'] == $this) {
  230. break;
  231. }
  232. $i++;
  233. }
  234. $class = isset($trace[$i - 1]['object']) ? get_class($trace[$i - 1]['object']) : null;
  235. $method = isset($trace[$i]) ? $trace[$i]['function'] : $trace[$i - 1]['function'];
  236. $result = compact('class', 'method', 'message', 'data') + [
  237. 'file' => $trace[$i - 1]['file'],
  238. 'line' => $trace[$i - 1]['line'],
  239. 'assertion' => $trace[$i - 1]['function']
  240. ];
  241. $this->_result($expression ? 'pass' : 'fail', $result);
  242. return $expression;
  243. }
  244. /**
  245. * Generates a failed test with the given message.
  246. *
  247. * @param string $message
  248. */
  249. public function fail($message = false) {
  250. $this->assert(false, $message);
  251. }
  252. /**
  253. * Assert that the actual result is equal, but not neccessarily identical, to the expected
  254. * result.
  255. *
  256. * @see lithium\test\Unit::assert()
  257. * @param mixed $expected
  258. * @param mixed $result
  259. * @param string|boolean $message
  260. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  261. */
  262. public function assertEqual($expected, $result, $message = '{:message}') {
  263. list($expected, $result) = $this->_normalizeLineEndings($expected, $result);
  264. $data = ($expected != $result) ? $this->_compare('equal', $expected, $result) : null;
  265. return $this->assert($expected == $result, $message, $data);
  266. }
  267. /**
  268. * Assert that the actual result and the expected result are *not* equal to each other.
  269. *
  270. * @see lithium\test\Unit::assert()
  271. * @param mixed $expected
  272. * @param mixed $result
  273. * @param string|boolean $message
  274. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  275. */
  276. public function assertNotEqual($expected, $result, $message = '{:message}') {
  277. list($expected, $result) = $this->_normalizeLineEndings($expected, $result);
  278. return $this->assert($result != $expected, $message, compact('expected', 'result'));
  279. }
  280. /**
  281. * Assert that the actual result and the expected result are identical using a strict
  282. * comparison.
  283. *
  284. * @see lithium\test\Unit::assert()
  285. * @param mixed $expected
  286. * @param mixed $result
  287. * @param string|boolean $message
  288. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  289. */
  290. public function assertIdentical($expected, $result, $message = '{:message}') {
  291. $data = ($expected !== $result) ? $this->_compare('identical', $expected, $result) : null;
  292. return $this->assert($expected === $result, $message, $data);
  293. }
  294. /**
  295. * Assert that the actual result and the expected result are *not* identical using a strict
  296. * comparison.
  297. *
  298. * @see lithium\test\Unit::assert()
  299. * @param mixed $expected
  300. * @param mixed $result
  301. * @param string|boolean $message
  302. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  303. */
  304. public function assertNotIdentical($expected, $result, $message = '{:message}') {
  305. return $this->assert($expected !== $result, $message, compact('expected', 'result'));
  306. }
  307. /**
  308. * Assert that the result is strictly `true`.
  309. *
  310. * ```
  311. * $this->assertTrue(true, 'Boolean true'); // succeeds
  312. * $this->assertTrue('false', 'String has content'); // fails
  313. * $this->assertTrue(10, 'Non-Zero value'); // fails
  314. * ```
  315. *
  316. * @see lithium\test\Unit::assert()
  317. * @param mixed $result
  318. * @param string $message
  319. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  320. */
  321. public function assertTrue($result, $message = '{:message}') {
  322. $expected = true;
  323. return $this->assert($result === $expected, $message, compact('expected', 'result'));
  324. }
  325. /**
  326. * Assert that the result strictly is `false`.
  327. *
  328. * ```
  329. * $this->assertFalse(false, 'Boolean false'); // succeeds
  330. * $this->assertFalse('', 'String is empty'); // fails
  331. * $this->assertFalse(0, 'Zero value'); // fails
  332. * ```
  333. *
  334. * @see lithium\test\Unit::assert()
  335. * @param mixed $result
  336. * @param string $message
  337. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  338. */
  339. public function assertFalse($result, $message = '{:message}') {
  340. $expected = false;
  341. return $this->assert($result === $expected, $message, compact('expected', 'result'));
  342. }
  343. /**
  344. * Assert that the result is strictly `null`.
  345. *
  346. * @see lithium\test\Unit::assert()
  347. * @param mixed $result
  348. * @param string $message
  349. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  350. */
  351. public function assertNull($result, $message = '{:message}') {
  352. $expected = null;
  353. return $this->assert($result === null, $message, compact('expected', 'result'));
  354. }
  355. /**
  356. * Assert that the result is *not* strictly `null`.
  357. *
  358. * ```
  359. * $this->assertNotNull(1); // succeeds
  360. * $this->assertNotNull(null); // fails
  361. * ```
  362. *
  363. * @see lithium\test\Unit::assert()
  364. * @param mixed $result
  365. * @param string $message
  366. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  367. */
  368. public function assertNotNull($actual, $message = '{:message}') {
  369. return $this->assert($actual !== null, $message, [
  370. 'expected' => null,
  371. 'actual' => gettype($actual)
  372. ]);
  373. }
  374. /**
  375. * Assert that given result is empty.
  376. *
  377. * ```
  378. * $this->assertEmpty(''); // succeeds
  379. * $this->assertEmpty(0); // succeeds
  380. * $this->assertEmpty(0.0); // succeeds
  381. * $this->assertEmpty('0'); // succeeds
  382. * $this->assertEmpty(null); // succeeds
  383. * $this->assertEmpty(false); // succeeds
  384. * $this->assertEmpty([]); // succeeds
  385. * $this->assertEmpty(1); // fails
  386. * ```
  387. *
  388. * @link http://php.net/empty
  389. * @see lithium\test\Unit::assert()
  390. * @param string $actual
  391. * @param string|boolean $message
  392. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  393. */
  394. public function assertEmpty($actual, $message = '{:message}') {
  395. return $this->assert(empty($actual), $message, [
  396. 'expected' => $actual,
  397. 'result' => empty($actual)
  398. ]);
  399. }
  400. /**
  401. * Assert that given result is *not* empty.
  402. *
  403. * ```
  404. * $this->assertNotEmpty(1); // succeeds
  405. * $this->assertNotEmpty([]); // fails
  406. * ```
  407. *
  408. * @link http://php.net/empty
  409. * @see lithium\test\Unit::assert()
  410. * @param string $actual
  411. * @param string|boolean $message
  412. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  413. */
  414. public function assertNotEmpty($actual, $message = '{:message}') {
  415. return $this->assert(!empty($actual), $message, [
  416. 'expected' => $actual,
  417. 'result' => !empty($actual)
  418. ]);
  419. }
  420. /**
  421. * Assert that the code passed in a closure throws an exception or raises a PHP error. The
  422. * first argument to this method specifies which class name or message the exception must
  423. * have in order to make the assertion successful.
  424. *
  425. * @see lithium\test\Unit::assert()
  426. * @param mixed $expected A string indicating what the error text is expected to be. This can
  427. * be an exact string, a /-delimited regular expression, or true, indicating that
  428. * any error text is acceptable.
  429. * @param \Closure $closure A closure containing the code that should throw the exception.
  430. * @param string $message
  431. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  432. */
  433. public function assertException($expected, $closure, $message = '{:message}') {
  434. $result = null;
  435. try {
  436. $closure();
  437. $message = sprintf('An exception "%s" was expected but not thrown.', $expected);
  438. return $this->assert(false, $message, compact('expected', 'result'));
  439. } catch (Exception $e) {
  440. // fallthrough
  441. } catch (Error $e) {
  442. // fallthrough
  443. }
  444. $class = get_class($e);
  445. $eMessage = $e->getMessage();
  446. if (get_class($e) === $expected) {
  447. $result = $class;
  448. return $this->assert(true, $message, compact('expected', 'result'));
  449. }
  450. if ($eMessage === $expected) {
  451. $result = $eMessage;
  452. return $this->assert(true, $message, compact('expected', 'result'));
  453. }
  454. if (Validator::isRegex($expected) && preg_match($expected, $eMessage)) {
  455. $result = $eMessage;
  456. return $this->assert(true, $message, compact('expected', 'result'));
  457. }
  458. $message = sprintf(
  459. 'Exception "%s" was expected. Exception "%s" with message "%s" was thrown instead.',
  460. $expected, get_class($e), $eMessage
  461. );
  462. return $this->assert(false, $message);
  463. }
  464. /**
  465. * Assert that the code passed in a closure does not throw an exception matching the passed
  466. * expected exception.
  467. *
  468. * The value passed to `exepected` is either an exception class name or the expected message.
  469. *
  470. * @see lithium\test\Unit::assert()
  471. * @param mixed $expected A string indicating what the error text is not expected to be. This
  472. * can be an exact string, a /-delimited regular expression, or true, indicating
  473. * that any error text is acceptable.
  474. * @param \Closure $closure A closure containing the code that should throw the exception.
  475. * @param string $message
  476. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  477. */
  478. public function assertNotException($expected, $closure, $message = '{:message}') {
  479. $result = null;
  480. try {
  481. $closure();
  482. } catch (Exception $e) {
  483. $class = get_class($e);
  484. $eMessage = $e->getMessage();
  485. if (is_a($e, $expected)) {
  486. $result = $class;
  487. return $this->assert(false, $message, compact('expected', 'result'));
  488. }
  489. if ($eMessage === $expected) {
  490. $result = $eMessage;
  491. return $this->assert(false, $message, compact('expected', 'result'));
  492. }
  493. if (Validator::isRegex($expected) && preg_match($expected, $eMessage)) {
  494. $result = $eMessage;
  495. return $this->assert(false, $message, compact('expected', 'result'));
  496. }
  497. }
  498. $message = sprintf('Exception "%s" was not expected.', $expected);
  499. return $this->assert(true, $message, compact('expected', 'result'));
  500. }
  501. /**
  502. * Assert that the regular expression `$expected` is matched in the result.
  503. *
  504. * @see lithium\test\Unit::assert()
  505. * @param mixed $expected
  506. * @param mixed $result
  507. * @param string $message
  508. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  509. */
  510. public function assertPattern($expected, $result, $message = '{:message}') {
  511. list($expected, $result) = $this->_normalizeLineEndings($expected, $result);
  512. $params = compact('expected', 'result');
  513. return $this->assert(!!preg_match($expected, $result), $message, $params);
  514. }
  515. /**
  516. * Assert that the regular expression `$expected` is *not* matched in the result.
  517. *
  518. * @see lithium\test\Unit::assert()
  519. * @param mixed $expected
  520. * @param mixed $result
  521. * @param string $message
  522. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  523. */
  524. public function assertNotPattern($expected, $result, $message = '{:message}') {
  525. list($expected, $result) = $this->_normalizeLineEndings($expected, $result);
  526. $params = compact('expected', 'result');
  527. return $this->assert(!preg_match($expected, $result), $message, $params);
  528. }
  529. /**
  530. * Assert that given value matches the `sprintf` format.
  531. *
  532. * ```
  533. * $this->assertStringMatchesFormat('%d', '10'); // succeeds
  534. * $this->assertStringMatchesFormat('%d', '10.555'); // fails
  535. * ```
  536. *
  537. * @link http://php.net/sprintf
  538. * @link http://php.net/sscanf
  539. * @see lithium\test\Unit::assert()
  540. * @param string $expected Expected format using sscanf's format.
  541. * @param string $actual
  542. * @param string|boolean $message
  543. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  544. */
  545. public function assertStringMatchesFormat($expected, $actual, $message = '{:message}') {
  546. $result = sscanf($actual, $expected);
  547. return $this->assert($result[0] == $actual, $message, compact('expected', 'result'));
  548. }
  549. /**
  550. * Assert that given value does *not* matche the `sprintf` format.
  551. *
  552. * ```
  553. * $this->assertStringNotMatchesFormat('%d', '10.555'); // succeeds
  554. * $this->assertStringNotMatchesFormat('%d', '10'); // fails
  555. * ```
  556. *
  557. * @link http://php.net/sprintf
  558. * @link http://php.net/sscanf
  559. * @see lithium\test\Unit::assert()
  560. * @param string $expected Expected format using sscanf's format.
  561. * @param string $actual
  562. * @param string|boolean $message
  563. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  564. */
  565. public function assertStringNotMatchesFormat($expected, $actual, $message = '{:message}') {
  566. $result = sscanf($actual, $expected);
  567. return $this->assert($result[0] != $actual, $message, compact('expected', 'result'));
  568. }
  569. /**
  570. * Assert given result string has given suffix.
  571. *
  572. * ```
  573. * $this->assertStringEndsWith('bar', 'foobar'); // succeeds
  574. * $this->assertStringEndsWith('foo', 'foobar'); // fails
  575. * ```
  576. *
  577. * @param string $expected The suffix to check for.
  578. * @param string $actual
  579. * @param string|boolean $message
  580. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  581. */
  582. public function assertStringEndsWith($expected, $actual, $message = '{:message}') {
  583. return $this->assert(preg_match("/$expected$/", $actual, $matches) === 1, $message, [
  584. 'expected' => $expected,
  585. 'result' => $actual
  586. ]);
  587. }
  588. /**
  589. * Assert given result string has given prefix.
  590. *
  591. * ```
  592. * $this->assertStringStartsWith('foo', 'foobar'); // succeeds
  593. * $this->assertStringStartsWith('bar', 'foobar'); // fails
  594. * ```
  595. *
  596. * @param string $expected The prefix to check for.
  597. * @param string $actual
  598. * @param string|boolean $message
  599. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  600. */
  601. public function assertStringStartsWith($expected, $actual, $message = '{:message}') {
  602. return $this->assert(preg_match("/^$expected/", $actual, $matches) === 1, $message, [
  603. 'expected' => $expected,
  604. 'result' => $actual
  605. ]);
  606. }
  607. /**
  608. * Takes an array $expected and generates a regex from it to match the provided $string.
  609. * Samples for $expected:
  610. *
  611. * Checks for an input tag with a name attribute (contains any non-empty value) and an id
  612. * attribute that contains 'my-input':
  613. * ```
  614. * ['input' => ['name', 'id' => 'my-input']]
  615. * ```
  616. *
  617. * Checks for two p elements with some text in them:
  618. * ```
  619. * [
  620. * ['p' => true],
  621. * 'textA',
  622. * '/p',
  623. * ['p' => true],
  624. * 'textB',
  625. * '/p'
  626. * ]
  627. * ```
  628. *
  629. * You can also specify a pattern expression as part of the attribute values, or the tag
  630. * being defined, if you prepend the value with preg: and enclose it with slashes, like so:
  631. * ```
  632. * [
  633. * ['input' => ['name', 'id' => 'preg:/FieldName\d+/']],
  634. * 'preg:/My\s+field/'
  635. * ]
  636. * ```
  637. *
  638. * Important: This function is very forgiving about whitespace and also accepts any
  639. * permutation of attribute order. It will also allow whitespaces between specified tags.
  640. *
  641. * @see lithium\test\Unit::assert()
  642. * @param string $string An HTML/XHTML/XML string
  643. * @param array $expected An array, see above
  644. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  645. */
  646. public function assertTags($string, $expected) {
  647. $regex = [];
  648. $normalized = [];
  649. foreach ((array) $expected as $key => $val) {
  650. if (!is_numeric($key)) {
  651. $normalized[] = [$key => $val];
  652. } else {
  653. $normalized[] = $val;
  654. }
  655. }
  656. $i = 0;
  657. foreach ($normalized as $tags) {
  658. $i++;
  659. if (is_string($tags) && $tags[0] === '<') {
  660. $tags = [substr($tags, 1) => []];
  661. } elseif (is_string($tags)) {
  662. $tagsTrimmed = preg_replace('/\s+/m', '', $tags);
  663. if (preg_match('/^\*?\//', $tags, $match) && $tagsTrimmed !== '//') {
  664. $prefix = [null, null];
  665. if ($match[0] === '*/') {
  666. $prefix = ['Anything, ', '.*?'];
  667. }
  668. $regex[] = [
  669. sprintf('%sClose %s tag', $prefix[0], substr($tags, strlen($match[0]))),
  670. sprintf('%s<[\s]*\/[\s]*%s[\s]*>[\n\r]*', $prefix[1], substr(
  671. $tags, strlen($match[0])
  672. )),
  673. $i
  674. ];
  675. continue;
  676. }
  677. if (!empty($tags) && preg_match('/^regex\:\/(.+)\/$/i', $tags, $matches)) {
  678. $tags = $matches[1];
  679. $type = 'Regex matches';
  680. } else {
  681. $tags = preg_quote($tags, '/');
  682. $type = 'Text equals';
  683. }
  684. $regex[] = [sprintf('%s "%s"', $type, $tags), $tags, $i];
  685. continue;
  686. }
  687. foreach ($tags as $tag => $attributes) {
  688. $regex[] = [
  689. sprintf('Open %s tag', $tag),
  690. sprintf('[\s]*<%s', preg_quote($tag, '/')),
  691. $i
  692. ];
  693. if ($attributes === true) {
  694. $attributes = [];
  695. }
  696. $attrs = [];
  697. $explanations = [];
  698. foreach ($attributes as $attr => $val) {
  699. if (is_numeric($attr) && preg_match('/^regex\:\/(.+)\/$/i', $val, $matches)) {
  700. $attrs[] = $matches[1];
  701. $explanations[] = sprintf('Regex "%s" matches', $matches[1]);
  702. continue;
  703. } else {
  704. $quotes = '"';
  705. if (is_numeric($attr)) {
  706. $attr = $val;
  707. $val = '.+?';
  708. $explanations[] = sprintf('Attribute "%s" present', $attr);
  709. } elseif (
  710. !empty($val) && preg_match('/^regex\:\/(.+)\/$/i', $val, $matches)
  711. ) {
  712. $quotes = '"?';
  713. $val = $matches[1];
  714. $explanations[] = sprintf('Attribute "%s" matches "%s"', $attr, $val);
  715. } else {
  716. $explanations[] = sprintf('Attribute "%s" == "%s"', $attr, $val);
  717. $val = preg_quote($val, '/');
  718. }
  719. $attrs[] = '[\s]+' . preg_quote($attr, '/') . "={$quotes}{$val}{$quotes}";
  720. }
  721. }
  722. if ($attrs) {
  723. $permutations = $this->_arrayPermute($attrs);
  724. $permutationTokens = [];
  725. foreach ($permutations as $permutation) {
  726. $permutationTokens[] = join('', $permutation);
  727. }
  728. $regex[] = [
  729. sprintf('%s', join(', ', $explanations)),
  730. $permutationTokens,
  731. $i
  732. ];
  733. }
  734. $regex[] = [sprintf('End %s tag', $tag), '[\s]*\/?[\s]*>[\n\r]*', $i];
  735. }
  736. }
  737. foreach ($regex as $i => $assertation) {
  738. list($description, $expressions, $itemNum) = $assertation;
  739. $matches = false;
  740. foreach ((array) $expressions as $expression) {
  741. if (preg_match(sprintf('/^%s/s', $expression), $string, $match)) {
  742. $matches = true;
  743. $string = substr($string, strlen($match[0]));
  744. break;
  745. }
  746. }
  747. if (!$matches) {
  748. $this->assert(false, sprintf(
  749. '- Item #%d / regex #%d failed: %s', $itemNum, $i, $description
  750. ));
  751. return false;
  752. }
  753. }
  754. return $this->assert(true);
  755. }
  756. /**
  757. * Assert Cookie data is properly set in headers.
  758. *
  759. * The value passed to `exepected` is an array of the cookie data, with at least the key and
  760. * value expected, but can support any of the following keys:
  761. * - `key`: the expected key
  762. * - `value`: the expected value
  763. * - `path`: optionally specifiy a path
  764. * - `name`: optionally specify the cookie name
  765. * - `expires`: optionally assert a specific expire time
  766. *
  767. * @see lithium\test\Unit::assert()
  768. * @param array $expected
  769. * @param array $headers When empty, value of `headers_list()` is used.
  770. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  771. */
  772. public function assertCookie($expected, $headers = null) {
  773. $result = null;
  774. $matched = $this->_cookieMatch($expected, $headers);
  775. if (!$matched['match']) {
  776. $message = sprintf('%s - Cookie not found in headers.', $matched['pattern']);
  777. return $this->assert(false, $message, compact('expected', 'result'));
  778. }
  779. return $this->assert(true, '%s');
  780. }
  781. /**
  782. * Assert Cookie data is *not* set in headers.
  783. *
  784. * The value passed to `expected` is an array of the cookie data, with at least the key and
  785. * value expected, but can support any of the following keys:
  786. * - `key`: the expected key
  787. * - `value`: the expected value
  788. * - `path`: optionally specify a path
  789. * - `name`: optionally specify the cookie name
  790. * - `expires`: optionally assert a specific expire time
  791. *
  792. * @see lithium\test\Unit::assert()
  793. * @param array $expected
  794. * @param array $headers When empty, value of `headers_list()` is used.
  795. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  796. */
  797. public function assertNoCookie($expected, $headers = null) {
  798. $matched = $this->_cookieMatch($expected, $headers);
  799. if ($matched['match']) {
  800. $message = sprintf('%s - Cookie found in headers.', $matched['pattern']);
  801. return $this->assert(false, $message, compact('expected', 'result'));
  802. }
  803. return $this->assert(true, '%s');
  804. }
  805. /**
  806. * Match an `$expected` cookie with the given headers. If no headers are provided, then
  807. * the value of `headers_list()` will be used.
  808. *
  809. * @param array $expected
  810. * @param array $headers When empty, value of `headers_list()` will be used.
  811. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  812. */
  813. protected function _cookieMatch($expected, $headers) {
  814. $defaults = ['path' => '/', 'name' => '[\w.-]+'];
  815. $expected += $defaults;
  816. $headers = ($headers) ?: headers_list();
  817. $value = preg_quote(urlencode($expected['value']), '/');
  818. $key = explode('.', $expected['key']);
  819. $key = (count($key) === 1) ? '[' . current($key) . ']' : ('[' . join('][', $key) . ']');
  820. $key = preg_quote($key, '/');
  821. if (isset($expected['expires'])) {
  822. $expectedExpires = strtotime($expected['expires']);
  823. $expires = gmdate('D, d-M-Y H:i:s \G\M\T', $expectedExpires);
  824. $expires = preg_quote($expires, '/');
  825. $maxAge = $expectedExpires - time();
  826. } else {
  827. $expires = '(?:.+?)';
  828. $maxAge = '([0-9]+)';
  829. }
  830. $path = preg_quote($expected['path'], '/');
  831. $pattern = "/^Set\-Cookie:\s{$expected['name']}$key=$value;";
  832. $pattern .= "\sexpires=$expires;";
  833. $pattern .= "\sMax-Age=$maxAge;";
  834. $pattern .= "\spath=$path/";
  835. $match = false;
  836. foreach ($headers as $header) {
  837. if (preg_match($pattern, $header)) {
  838. $match = true;
  839. continue;
  840. }
  841. }
  842. return compact('match', 'pattern');
  843. }
  844. /**
  845. * Assert that the passed result array has expected number of elements.
  846. *
  847. * ```
  848. * $this->assertCount(1, ['foo']); // succeeds
  849. * $this->assertCount(2, ['foo', 'bar', 'bar']); // fails
  850. * ```
  851. *
  852. * @see lithium\test\Unit::assert()
  853. * @param integer $expected
  854. * @param array $array
  855. * @param string|boolean $message
  856. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  857. */
  858. public function assertCount($expected, $array, $message = '{:message}') {
  859. return $this->assert($expected === ($result = count($array)), $message, [
  860. 'expected' => $expected,
  861. 'result' => $result
  862. ]);
  863. }
  864. /**
  865. * Assert that the passed result array has *not* the expected number of elements.
  866. *
  867. * ```
  868. * $this->assertNotCount(2, ['foo', 'bar', 'bar']); // succeeds
  869. * $this->assertNotCount(1, ['foo']); // fails
  870. * ```
  871. *
  872. * @see lithium\test\Unit::assert()
  873. * @param integer $expected
  874. * @param array $array
  875. * @param string|boolean $message
  876. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  877. */
  878. public function assertNotCount($expected, $array, $message = '{:message}') {
  879. return $this->assert($expected !== ($result = count($array)), $message, [
  880. 'expected' => $expected,
  881. 'result' => $result
  882. ]);
  883. }
  884. /**
  885. * Assert that the result array has given key.
  886. *
  887. * ```
  888. * $this->assertArrayHasKey('bar', ['bar' => 'baz']); // succeeds
  889. * $this->assertArrayHasKey('foo', ['bar' => 'baz']); // fails
  890. * ```
  891. *
  892. * @see lithium\test\Unit::assert()
  893. * @param mixed $expected
  894. * @param array $array
  895. * @param string|boolean $message
  896. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  897. */
  898. public function assertArrayHasKey($key, $array, $message = '{:message}') {
  899. if (is_object($array) && $array instanceof \ArrayAccess) {
  900. $result = isset($array[$key]);
  901. } else {
  902. $result = array_key_exists($key, $array);
  903. }
  904. return $this->assert($result, $message, [
  905. 'expected' => $key,
  906. 'result' => $array
  907. ]);
  908. }
  909. /**
  910. * Assert that the result array does *not* have given key.
  911. *
  912. * ```
  913. * $this->assertArrayNotHasKey('foo', ['bar' => 'baz']); // succeeds
  914. * $this->assertArrayNotHasKey('bar', ['bar' => 'baz']); // fails
  915. * ```
  916. *
  917. * @see lithium\test\Unit::assert()
  918. * @param mixed $expected
  919. * @param array $array
  920. * @param string|boolean $message
  921. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  922. */
  923. public function assertArrayNotHasKey($key, $array, $message = '{:message}') {
  924. if (is_object($array) && $array instanceof \ArrayAccess) {
  925. $result = isset($array[$key]);
  926. } else {
  927. $result = array_key_exists($key, $array);
  928. }
  929. return $this->assert(!$result, $message, [
  930. 'expected' => $key,
  931. 'result' => $array
  932. ]);
  933. }
  934. /**
  935. * Assert that `$haystack` contains `$needle` as a value.
  936. *
  937. * ```
  938. * $this->assertContains('foo', ['foo', 'bar', 'baz']); // succeeds
  939. * $this->assertContains(4, [1,2,3]); // fails
  940. * ```
  941. *
  942. * @see lithium\test\Unit::assert()
  943. * @param string $needle The needle you are looking for.
  944. * @param mixed $haystack An array, iterable object, or string.
  945. * @param string|boolean $message
  946. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  947. */
  948. public function assertContains($needle, $haystack, $message = '{:message}') {
  949. if (is_string($haystack)) {
  950. return $this->assert(strpos($haystack, $needle) !== false, $message, [
  951. 'expected' => $needle,
  952. 'result' => $haystack
  953. ]);
  954. }
  955. foreach ($haystack as $key => $value) {
  956. if ($value === $needle) {
  957. return $this->assert(true, $message, [
  958. 'expected' => $needle,
  959. 'result' => $haystack
  960. ]);
  961. }
  962. }
  963. return $this->assert(false, $message, [
  964. 'expected' => $needle,
  965. 'result' => $haystack
  966. ]);
  967. }
  968. /**
  969. * Assert that `$haystack` does *not* contain `$needle` as a value.
  970. *
  971. * ```
  972. * $this->assertNotContains(4, [1,2,3]); // succeeds
  973. * $this->assertNotContains('foo', ['foo', 'bar', 'baz']); // fails
  974. * ```
  975. *
  976. * @see lithium\test\Unit::assert()
  977. * @param string $needle The needle you are looking for.
  978. * @param miexed $haystack Array or iterable object or a string.
  979. * @param string|boolean $message
  980. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  981. */
  982. public function assertNotContains($needle, $haystack, $message = '{:message}') {
  983. if (is_string($haystack)) {
  984. return $this->assert(strpos($haystack, $needle) === false, $message, [
  985. 'expected' => $needle,
  986. 'result' => $haystack
  987. ]);
  988. }
  989. foreach ($haystack as $key => $value) {
  990. if ($value === $needle) {
  991. return $this->assert(false, $message, [
  992. 'expected' => $needle,
  993. 'result' => $haystack
  994. ]);
  995. }
  996. }
  997. return $this->assert(true, $message, [
  998. 'expected' => $needle,
  999. 'result' => $haystack
  1000. ]);
  1001. }
  1002. /**
  1003. * Assert that `$haystack` does only contain item of given type.
  1004. *
  1005. * ```
  1006. * $this->assertContainsOnly('integer', [1,2,3]); // succeeds
  1007. * $this->assertContainsOnly('integer', ['foo', 'bar', 'baz']); // fails
  1008. * ```
  1009. *
  1010. * @see lithium\test\Unit::$_internalTypes
  1011. * @see lithium\test\Unit::assert()
  1012. * @param string $type
  1013. * @param array|object $haystack Array or iterable object.
  1014. * @param string|boolean $message
  1015. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1016. */
  1017. public function assertContainsOnly($type, $haystack, $message = '{:message}') {
  1018. $method = static::$_internalTypes[$type];
  1019. foreach ($haystack as $key => $value) {
  1020. if (!$method($value)) {
  1021. return $this->assert(false, $message, [
  1022. 'expected' => $type,
  1023. 'result' => $haystack
  1024. ]);
  1025. }
  1026. }
  1027. return $this->assert(true, $message, [
  1028. 'expected' => $type,
  1029. 'result' => $haystack
  1030. ]);
  1031. }
  1032. /**
  1033. * Assert that `$haystack` hasn't any items of given type.
  1034. *
  1035. * ```
  1036. * $this->assertNotContainsOnly('integer', ['foo', 'bar', 'baz']); // succeeds
  1037. * $this->assertNotContainsOnly('integer', [1,2,3]); // fails
  1038. * ```
  1039. *
  1040. * @see lithium\test\Unit::$_internalTypes
  1041. * @see lithium\test\Unit::assert()
  1042. * @param string $type
  1043. * @param array|object $haystack Array or iterable object.
  1044. * @param string|boolean $message
  1045. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1046. */
  1047. public function assertNotContainsOnly($type, $haystack, $message = '{:message}') {
  1048. $method = static::$_internalTypes[$type];
  1049. foreach ($haystack as $key => $value) {
  1050. if (!$method($value)) {
  1051. return $this->assert(true, $message, [
  1052. 'expected' => $type,
  1053. 'result' => $haystack
  1054. ]);
  1055. }
  1056. }
  1057. return $this->assert(false, $message, [
  1058. 'expected' => $type,
  1059. 'result' => $haystack
  1060. ]);
  1061. }
  1062. /**
  1063. * Assert that `$haystack` contains only instances of given class.
  1064. *
  1065. * ```
  1066. * $this->assertContainsOnlyInstancesOf('stdClass', [new \stdClass]); // succeeds
  1067. * $this->assertContainsOnlyInstancesOf('stdClass', [new \lithium\test\Unit]); // fails
  1068. * ```
  1069. *
  1070. * @see lithium\test\Unit::assert()
  1071. * @param string $class
  1072. * @param array|object $haystack Array or iterable object.
  1073. * @param string|boolean $message
  1074. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1075. */
  1076. public function assertContainsOnlyInstancesOf($class, $haystack, $message = '{:message}') {
  1077. $result = [];
  1078. foreach ($haystack as $key => &$value) {
  1079. if (!is_a($value, $class)) {
  1080. $result[$key] =& $value;
  1081. break;
  1082. }
  1083. }
  1084. return $this->assert(empty($result), $message, [
  1085. 'expected' => $class,
  1086. 'result' => $result
  1087. ]);
  1088. }
  1089. /**
  1090. * Assert that `$expected` is greater than `$actual`.
  1091. *
  1092. * ```
  1093. * $this->assertGreaterThan(5, 3); // succeeds
  1094. * $this->assertGreaterThan(3, 5); // fails
  1095. * ```
  1096. *
  1097. * @see lithium\test\Unit::assert()
  1098. * @param float|integer $expected
  1099. * @param float|integer $actual
  1100. * @param string|boolean $message
  1101. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1102. */
  1103. public function assertGreaterThan($expected, $actual, $message = '{:message}') {
  1104. return $this->assert($expected > $actual, $message, [
  1105. 'expected' => $expected,
  1106. 'result' => $actual
  1107. ]);
  1108. }
  1109. /**
  1110. * Assert that `$expected` is greater than or equal to `$actual`.
  1111. *
  1112. * ```
  1113. * $this->assertGreaterThanOrEqual(5, 5); // succeeds
  1114. * $this->assertGreaterThanOrEqual(3, 5); // fails
  1115. * ```
  1116. *
  1117. * @see lithium\test\Unit::assert()
  1118. * @param float|integer $expected
  1119. * @param float|integer $actual
  1120. * @param string|boolean $message
  1121. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1122. */
  1123. public function assertGreaterThanOrEqual($expected, $actual, $message = '{:message}') {
  1124. return $this->assert($expected >= $actual, $message, [
  1125. 'expected' => $expected,
  1126. 'result' => $actual
  1127. ]);
  1128. }
  1129. /**
  1130. * Assert that `$expected` is less than `$actual`.
  1131. *
  1132. * ```
  1133. * $this->assertLessThan(3, 5); // succeeds
  1134. * $this->assertLessThan(5, 3); // fails
  1135. * ```
  1136. *
  1137. * @see lithium\test\Unit::assert()
  1138. * @param float|integer $expected
  1139. * @param float|integer $actual
  1140. * @param string|boolean $message
  1141. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1142. */
  1143. public function assertLessThan($expected, $actual, $message = '{:message}') {
  1144. return $this->assert($expected < $actual, $message, [
  1145. 'expected' => $expected,
  1146. 'result' => $actual
  1147. ]);
  1148. }
  1149. /**
  1150. * Assert that `$expected` is less than or equal to `$actual`.
  1151. *
  1152. * ```
  1153. * $this->assertLessThanOrEqual(5, 5); // succeeds
  1154. * $this->assertLessThanOrEqual(5, 3); // fails
  1155. * ```
  1156. *
  1157. * @see lithium\test\Unit::assert()
  1158. * @param float|integer $expected
  1159. * @param float|integer $actual
  1160. * @param string|boolean $message
  1161. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1162. */
  1163. public function assertLessThanOrEqual($expected, $actual, $message = '{:message}') {
  1164. return $this->assert($expected <= $actual, $message, [
  1165. 'expected' => $expected,
  1166. 'result' => $actual
  1167. ]);
  1168. }
  1169. /**
  1170. * Assert that `$actual` is an instance of `$expected`.
  1171. *
  1172. * ```
  1173. * $this->assertInstanceOf('stdClass', new stdClass); // succeeds
  1174. * $this->assertInstanceOf('ReflectionClass', new stdClass); // fails
  1175. * ```
  1176. *
  1177. * @see lithium\test\Unit::assert()
  1178. * @param string $expected Fully namespaced expected class.
  1179. * @param object $actual Object you are testing.
  1180. * @param string|boolean $message
  1181. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1182. */
  1183. public function assertInstanceOf($expected, $actual, $message = '{:message}') {
  1184. return $this->assert(is_a($actual, $expected), $message, [
  1185. 'expected' => $expected,
  1186. 'result' => get_class($actual)
  1187. ]);
  1188. }
  1189. /**
  1190. * Assert that `$actual` is *not* an instance of `$expected`.
  1191. *
  1192. * ```
  1193. * $this->assertNotInstanceOf('ReflectionClass', new stdClass); // succeeds
  1194. * $this->assertNotInstanceOf('stdClass', new stdClass); // fails
  1195. * ```
  1196. *
  1197. * @see lithium\test\Unit::assert()
  1198. * @param string $expected Fully namespaced expected class.
  1199. * @param object $actual Object you are testing.
  1200. * @param string|boolean $message
  1201. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1202. */
  1203. public function assertNotInstanceOf($expected, $actual, $message = '{:message}') {
  1204. return $this->assert(!is_a($actual, $expected), $message, [
  1205. 'expected' => $expected,
  1206. 'result' => is_object($actual) ? get_class($actual) : gettype($actual),
  1207. ]);
  1208. }
  1209. /**
  1210. * Assert that `$actual` is of given type.
  1211. *
  1212. * ```
  1213. * $this->assertInternalType('string', 'foobar'); // succeeds
  1214. * $this->assertInternalType('integer', 'foobar'); // fails
  1215. * ```
  1216. *
  1217. * @see lithium\test\Unit::$_internalTypes
  1218. * @see lithium\test\Unit::assert()
  1219. * @param string $expected Internal type.
  1220. * @param object $actual Object you are testing.
  1221. * @param string|boolean $message
  1222. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1223. */
  1224. public function assertInternalType($expected, $actual, $message = '{:message}') {
  1225. $method = static::$_internalTypes[$expected];
  1226. return $this->assert($method($actual), $message, [
  1227. 'expected' => $expected,
  1228. 'result' => gettype($actual)
  1229. ]);
  1230. }
  1231. /**
  1232. * Assert that `$actual` is *not* of given type.
  1233. *
  1234. * ```
  1235. * $this->assertNotInternalType('integer', 'foobar'); // succeeds
  1236. * $this->assertNotInternalType('string', 'foobar'); // fails
  1237. * ```
  1238. *
  1239. * @see lithium\test\Unit::$_internalTypes
  1240. * @see lithium\test\Unit::assert()
  1241. * @param string $expected Internal type.
  1242. * @param object $actual Object you are testing.
  1243. * @param string|boolean $message
  1244. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1245. */
  1246. public function assertNotInternalType($expected, $actual, $message = '{:message}') {
  1247. $method = static::$_internalTypes[$expected];
  1248. return $this->assert(!$method($actual), $message, [
  1249. 'expected' => $expected,
  1250. 'result' => gettype($actual)
  1251. ]);
  1252. }
  1253. /**
  1254. * Assert that the file contents of `$expected` are equal to the contents of `$actual`.
  1255. *
  1256. * ```
  1257. * $this->assertFileEquals('/tmp/foo.txt', '/tmp/foo.txt'); // succeeds
  1258. * $this->assertFileEquals('/tmp/foo.txt', '/tmp/bar.txt'); // fails
  1259. * ```
  1260. *
  1261. * @see lithium\test\Unit::assert()
  1262. * @param string $expected Absolute path to the expected file.
  1263. * @param string $actual Absolute path to the actual file.
  1264. * @param string|boolean $message
  1265. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1266. */
  1267. public function assertFileEquals($expected, $actual, $message = '{:message}') {
  1268. $expected = md5_file($expected);
  1269. $result = md5_file($actual);
  1270. return $this->assert($expected === $result, $message, compact('expected', 'result'));
  1271. }
  1272. /**
  1273. * Assert that the file contents of `$expected` are *not* equal to the contents of `$actual`.
  1274. *
  1275. * ```
  1276. * $this->assertFileNotEquals('/tmp/foo.txt', '/tmp/bar.txt'); // succeeds
  1277. * $this->assertFileNotEquals('/tmp/foo.txt', '/tmp/foo.txt'); // fails
  1278. * ```
  1279. *
  1280. * @see lithium\test\Unit::assert()
  1281. * @param string $expected Absolute path to the expected file.
  1282. * @param string $actual Absolute path to the actual file.
  1283. * @param string|boolean $message
  1284. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1285. */
  1286. public function assertFileNotEquals($expected, $actual, $message = '{:message}') {
  1287. $expected = md5_file($expected);
  1288. $result = md5_file($actual);
  1289. return $this->assert($expected !== $result, $message, compact('expected', 'result'));
  1290. }
  1291. /**
  1292. * Assert that a file exists.
  1293. *
  1294. * ```
  1295. * $this->assertFileExists(__FILE__); // succeeds
  1296. * $this->assertFileExists('/tmp/bar.txt'); // fails
  1297. * ```
  1298. *
  1299. * @see lithium\test\Unit::assert()
  1300. * @param string $actual Absolute path to the actual file.
  1301. * @param string|boolean $message
  1302. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1303. */
  1304. public function assertFileExists($actual, $message = '{:message}') {
  1305. return $this->assert(file_exists($actual), $message, [
  1306. 'expected' => $actual,
  1307. 'result' => file_exists($actual)
  1308. ]);
  1309. }
  1310. /**
  1311. * Assert that a file does *not* exist.
  1312. *
  1313. * ```
  1314. * $this->assertFileNotExists('/tmp/bar.txt'); // succeeds
  1315. * $this->assertFileNotExists(__FILE__); // fails
  1316. * ```
  1317. *
  1318. * @see lithium\test\Unit::assert()
  1319. * @param string $actual Absolute path to the actual file.
  1320. * @param string|boolean $message
  1321. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1322. */
  1323. public function assertFileNotExists($actual, $message = '{:message}') {
  1324. return $this->assert(!file_exists($actual), $message, [
  1325. 'expected' => $actual,
  1326. 'result' => !file_exists($actual)
  1327. ]);
  1328. }
  1329. /**
  1330. * Assert that a class has a given attribute.
  1331. *
  1332. * ```
  1333. * $this->assertClassHasAttribute('__construct', 'ReflectionClass'); // succeeds
  1334. * $this->assertClassHasAttribute('name', 'ReflectionClass'); // fails
  1335. * ```
  1336. *
  1337. * @see lithium\test\Unit::assert()
  1338. * @see lithium\test\Unit::assertObjectHasAttribute()
  1339. * @throws InvalidArgumentException When $class does not exist.
  1340. * @param mixed $attributeName
  1341. * @param string $class
  1342. * @param string|boolean $message
  1343. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1344. */
  1345. public function assertClassHasAttribute($attributeName, $class, $message = '{:message}') {
  1346. if (!is_string($class)) {
  1347. throw new InvalidArgumentException('Argument $class must be a string');
  1348. }
  1349. $object = new ReflectionClass($class);
  1350. return $this->assert($object->hasProperty($attributeName), $message, [
  1351. 'expected' => $attributeName,
  1352. 'result' => $object->getProperties()
  1353. ]);
  1354. }
  1355. /**
  1356. * Assert that a class does *not* have a given attribute.
  1357. *
  1358. * ```
  1359. * $this->assertClassNotHasAttribute('name', 'ReflectionClass'); // succeeds
  1360. * $this->assertClassNotHasAttribute('__construct', 'ReflectionClass'); // fails
  1361. * ```
  1362. *
  1363. * @see lithium\test\Unit::assert()
  1364. * @see lithium\test\Unit::assertObjectHasAttribute()
  1365. * @throws InvalidArgumentException When $class does not exist.
  1366. * @param mixed $attributeName
  1367. * @param string $class
  1368. * @param string|boolean $message
  1369. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1370. */
  1371. public function assertClassNotHasAttribute($attributeName, $class, $message = '{:message}') {
  1372. if (!is_string($class)) {
  1373. throw new InvalidArgumentException('Argument $class must be a string.');
  1374. }
  1375. $object = new ReflectionClass($class);
  1376. return $this->assert(!$object->hasProperty($attributeName), $message, [
  1377. 'expected' => $attributeName,
  1378. 'result' => $object->getProperties()
  1379. ]);
  1380. }
  1381. /**
  1382. * Assert that a class does have a given _static_ attribute.
  1383. *
  1384. * ```
  1385. * $this->assertClassHasStaticAttribute('_methodFilters', '\lithium\core\StaticObjectDeprecated'); // succeeds
  1386. * $this->assertClassHasStaticAttribute('foobar', '\lithium\core\StaticObjectDeprecated'); // fails
  1387. * ```
  1388. *
  1389. * @see lithium\test\Unit::assert()
  1390. * @param mixed $attributeName
  1391. * @param string $class
  1392. * @param string|boolean $message
  1393. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1394. */
  1395. public function assertClassHasStaticAttribute($attributeName, $class, $message = '{:message}') {
  1396. $object = new ReflectionClass($class);
  1397. if ($object->hasProperty($attributeName)) {
  1398. $attribute = $object->getProperty($attributeName);
  1399. return $this->assert($attribute->isStatic(), $message, [
  1400. 'expected' => $attributeName,
  1401. 'result' => $object->getProperties()
  1402. ]);
  1403. }
  1404. return $this->assert(false, $message, [
  1405. 'expected' => $attributeName,
  1406. 'result' => $object->getProperties()
  1407. ]);
  1408. }
  1409. /**
  1410. * Assert that a class does *not* have a given _static_ attribute.
  1411. *
  1412. * ```
  1413. * $this->assertClassNotHasStaticAttribute('foobar', '\lithium\core\StaticObjectDeprecated'); // succeeds
  1414. * $this->assertClassNotHasStaticAttribute('_methodFilters', '\lithium\core\StaticObjectDeprecated'); // fails
  1415. * ```
  1416. *
  1417. * @see lithium\test\Unit::assert()
  1418. * @param mixed $attributeName
  1419. * @param string $class
  1420. * @param string|boolean $message
  1421. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1422. */
  1423. public function assertClassNotHasStaticAttribute($attrName, $class, $message = '{:message}') {
  1424. $object = new ReflectionClass($class);
  1425. if ($object->hasProperty($attrName)) {
  1426. $attribute = $object->getProperty($attrName);
  1427. return $this->assert(!$attribute->isStatic(), $message, [
  1428. 'expected' => $attrName,
  1429. 'result' => $object->getProperties()
  1430. ]);
  1431. }
  1432. return $this->assert(true, $message, [
  1433. 'expected' => $attrName,
  1434. 'result' => $object->getProperties()
  1435. ]);
  1436. }
  1437. /**
  1438. * Assert that `$object` has given attribute.
  1439. *
  1440. * ```
  1441. * $this->assertObjectHasAttribute('__construct', 'ReflectionClass'); // succeeds
  1442. * $this->assertObjectHasAttribute('name', 'ReflectionClass'); // fails
  1443. * ```
  1444. *
  1445. * @see lithium\test\Unit::assert()
  1446. * @throws InvalidArgumentException When $object is not an object.
  1447. * @param string $attributeName
  1448. * @param string $object
  1449. * @param string|boolean $message
  1450. * @return boolean `true` if the assertion succeeded, `false` otherwise.
  1451. */
  1452. public function assertObjectHasAttribute($attributeName, $object, $message = '{:message}') {
  1453. if (!is_object($object)) {
  1454. throw new InvalidArgumentException('Second argument $object must be an object.');
  1455. }
  1456. $object = new ReflectionClass($object);
  1457. return $this->assert($object->hasProperty($attributeName), $message, [
  1458. 'expected' => $attributeName,
  1459. 'result' => $object->getProperties()
  1460. ]);
  1461. }
  1462. /**
  1463. * Assert that `$object` does *not* have given attribute.
  1464. *
  1465. * ```
  1466. * $this->assertObjectNotHasAttribute('name', 'ReflectionClass'); // succeeds
  1467. * $this->assertObjectNotHasAttribute('__construct', 'ReflectionClass'); // fails
  1468. * ```
  1469. *
  1470. * @see lithium\test\Unit::assert()
  1471. * @throws InvalidArgumentException When $object is not an object.
  1472. * @param string $attributeName
  1473. * @param string $object
  1474. * @param string|boolean $message
  1475. * @return boolean `true` if the assertion succee…

Large files files are truncated, but you can click here to view the full file