PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/inc/simpletest/test_case.php

https://github.com/chregu/fluxcms
PHP | 616 lines | 267 code | 45 blank | 304 comment | 31 complexity | 2ca478a6c578a16db92f3dec7c8187cb MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, Apache-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * Base include file for SimpleTest
  4. * @package SimpleTest
  5. * @subpackage UnitTester
  6. * @version $Id: test_case.php,v 1.5 2005/08/16 04:27:41 lastcraft Exp $
  7. */
  8. /**#@+
  9. * Includes SimpleTest files and defined the root constant
  10. * for dependent libraries.
  11. */
  12. require_once(dirname(__FILE__) . '/errors.php');
  13. require_once(dirname(__FILE__) . '/compatibility.php');
  14. require_once(dirname(__FILE__) . '/runner.php');
  15. require_once(dirname(__FILE__) . '/scorer.php');
  16. require_once(dirname(__FILE__) . '/expectation.php');
  17. require_once(dirname(__FILE__) . '/dumper.php');
  18. require_once(dirname(__FILE__) . '/simpletest.php');
  19. if (! defined('SIMPLE_TEST')) {
  20. /**
  21. * @ignore
  22. */
  23. define('SIMPLE_TEST', dirname(__FILE__) . '/');
  24. }
  25. /**#@-*/
  26. /**
  27. * Basic test case. This is the smallest unit of a test
  28. * suite. It searches for
  29. * all methods that start with the the string "test" and
  30. * runs them. Working test cases extend this class.
  31. * @package SimpleTest
  32. * @subpackage UnitTester
  33. */
  34. class SimpleTestCase {
  35. var $_label = false;
  36. var $_runner = false;
  37. var $_observers;
  38. /**
  39. * Sets up the test with no display.
  40. * @param string $label If no test name is given then
  41. * the class name is used.
  42. * @access public
  43. */
  44. function SimpleTestCase($label = false) {
  45. if ($label) {
  46. $this->_label = $label;
  47. }
  48. }
  49. /**
  50. * Accessor for the test name for subclasses.
  51. * @return string Name of the test.
  52. * @access public
  53. */
  54. function getLabel() {
  55. return $this->_label ? $this->_label : get_class($this);
  56. }
  57. /**
  58. * Used to invoke the single tests.
  59. * @return SimpleInvoker Individual test runner.
  60. * @access public
  61. */
  62. function &createInvoker() {
  63. $invoker = &new SimpleErrorTrappingInvoker(new SimpleInvoker($this));
  64. return $invoker;
  65. }
  66. /**
  67. * Can modify the incoming reporter so as to run
  68. * the tests differently. This version simply
  69. * passes it straight through.
  70. * @param SimpleReporter $reporter Incoming observer.
  71. * @return SimpleReporter
  72. * @access protected
  73. */
  74. function &_createRunner(&$reporter) {
  75. $runner = &new SimpleRunner($this, $reporter);
  76. return $runner;
  77. }
  78. /**
  79. * Uses reflection to run every method within itself
  80. * starting with the string "test" unless a method
  81. * is specified.
  82. * @param SimpleReporter $reporter Current test reporter.
  83. * @access public
  84. */
  85. function run(&$reporter) {
  86. SimpleTest::setCurrent($this);
  87. $reporter->paintCaseStart($this->getLabel());
  88. $this->_runner = &$this->_createRunner($reporter);
  89. $this->_runner->run();
  90. $this->_runner = false;
  91. $reporter->paintCaseEnd($this->getLabel());
  92. return $reporter->getStatus();
  93. }
  94. /**
  95. * Announces the start of the test.
  96. * @param string $method Test method just started.
  97. * @access public
  98. */
  99. function before($method) {
  100. $this->_runner->paintMethodStart($method);
  101. $this->_observers = array();
  102. }
  103. /**
  104. * Sets up unit test wide variables at the start
  105. * of each test method. To be overridden in
  106. * actual user test cases.
  107. * @access public
  108. */
  109. function setUp() {
  110. }
  111. /**
  112. * Clears the data set in the setUp() method call.
  113. * To be overridden by the user in actual user test cases.
  114. * @access public
  115. */
  116. function tearDown() {
  117. }
  118. /**
  119. * Announces the end of the test. Includes private clean up.
  120. * @param string $method Test method just finished.
  121. * @access public
  122. */
  123. function after($method) {
  124. for ($i = 0; $i < count($this->_observers); $i++) {
  125. $this->_observers[$i]->atTestEnd($method);
  126. }
  127. $this->_runner->paintMethodEnd($method);
  128. }
  129. /**
  130. * Sets up an observer for the test end.
  131. * @param object $observer Must have atTestEnd()
  132. * method.
  133. * @access public
  134. */
  135. function tell(&$observer) {
  136. $this->_observers[] = &$observer;
  137. }
  138. /**
  139. * Sends a pass event with a message.
  140. * @param string $message Message to send.
  141. * @access public
  142. */
  143. function pass($message = "Pass") {
  144. $this->_runner->paintPass($message . $this->getAssertionLine(' at line [%d]'));
  145. return true;
  146. }
  147. /**
  148. * Sends a fail event with a message.
  149. * @param string $message Message to send.
  150. * @access public
  151. */
  152. function fail($message = "Fail") {
  153. $this->_runner->paintFail($message . $this->getAssertionLine(' at line [%d]'));
  154. return false;
  155. }
  156. /**
  157. * Formats a PHP error and dispatches it to the
  158. * runner.
  159. * @param integer $severity PHP error code.
  160. * @param string $message Text of error.
  161. * @param string $file File error occoured in.
  162. * @param integer $line Line number of error.
  163. * @param hash $globals PHP super global arrays.
  164. * @access public
  165. */
  166. function error($severity, $message, $file, $line, $globals) {
  167. $severity = SimpleErrorQueue::getSeverityAsString($severity);
  168. $this->_runner->paintError(
  169. "Unexpected PHP error [$message] severity [$severity] in [$file] line [$line]");
  170. }
  171. /**
  172. * Sends a user defined event to the test runner.
  173. * This is for small scale extension where
  174. * both the test case and either the runner or
  175. * display are subclassed.
  176. * @param string $type Type of event.
  177. * @param mixed $payload Object or message to deliver.
  178. * @access public
  179. */
  180. function signal($type, &$payload) {
  181. $this->_runner->paintSignal($type, $payload);
  182. }
  183. /**
  184. * Cancels any outstanding errors.
  185. * @access public
  186. */
  187. function swallowErrors() {
  188. $queue = &SimpleErrorQueue::instance();
  189. $queue->clear();
  190. }
  191. /**
  192. * Runs an expectation directly, for extending the
  193. * tests with new expectation classes.
  194. * @param SimpleExpectation $expectation Expectation subclass.
  195. * @param mixed $compare Value to compare.
  196. * @param string $message Message to display.
  197. * @return boolean True on pass
  198. * @access public
  199. */
  200. function assert(&$expectation, $compare, $message = '%s') {
  201. return $this->assertTrue(
  202. $expectation->test($compare),
  203. sprintf($message, $expectation->overlayMessage($compare)));
  204. }
  205. /**
  206. * @deprecated
  207. */
  208. function assertExpectation(&$expectation, $compare, $message = '%s') {
  209. return $this->assert($expectation, $compare, $message);
  210. }
  211. /**
  212. * Called from within the test methods to register
  213. * passes and failures.
  214. * @param boolean $result Pass on true.
  215. * @param string $message Message to display describing
  216. * the test state.
  217. * @return boolean True on pass
  218. * @access public
  219. */
  220. function assertTrue($result, $message = false) {
  221. if (! $message) {
  222. $message = 'True assertion got ' . ($result ? 'True' : 'False');
  223. }
  224. if ($result) {
  225. return $this->pass($message);
  226. } else {
  227. return $this->fail($message);
  228. }
  229. }
  230. /**
  231. * Will be true on false and vice versa. False
  232. * is the PHP definition of false, so that null,
  233. * empty strings, zero and an empty array all count
  234. * as false.
  235. * @param boolean $result Pass on false.
  236. * @param string $message Message to display.
  237. * @return boolean True on pass
  238. * @access public
  239. */
  240. function assertFalse($result, $message = false) {
  241. if (! $message) {
  242. $message = 'False assertion got ' . ($result ? 'True' : 'False');
  243. }
  244. return $this->assertTrue(! $result, $message);
  245. }
  246. /**
  247. * Uses a stack trace to find the line of an assertion.
  248. * @param string $format String formatting.
  249. * @param array $stack Stack frames top most first. Only
  250. * needed if not using the PHP
  251. * backtrace function.
  252. * @return string Line number of first assert*
  253. * method embedded in format string.
  254. * @access public
  255. */
  256. function getAssertionLine($format = '%d', $stack = false) {
  257. if ($stack === false) {
  258. $stack = SimpleTestCompatibility::getStackTrace();
  259. }
  260. return SimpleDumper::getFormattedAssertionLine($stack, $format);
  261. }
  262. /**
  263. * Sends a formatted dump of a variable to the
  264. * test suite for those emergency debugging
  265. * situations.
  266. * @param mixed $variable Variable to display.
  267. * @param string $message Message to display.
  268. * @return mixed The original variable.
  269. * @access public
  270. */
  271. function dump($variable, $message = false) {
  272. $formatted = SimpleDumper::dump($variable);
  273. if ($message) {
  274. $formatted = $message . "\n" . $formatted;
  275. }
  276. $this->_runner->paintFormattedMessage($formatted);
  277. return $variable;
  278. }
  279. /**
  280. * Dispatches a text message straight to the
  281. * test suite. Useful for status bar displays.
  282. * @param string $message Message to show.
  283. * @access public
  284. */
  285. function sendMessage($message) {
  286. $this->_runner->PaintMessage($message);
  287. }
  288. /**
  289. * Accessor for the number of subtests.
  290. * @return integer Number of test cases.
  291. * @access public
  292. * @static
  293. */
  294. function getSize() {
  295. return 1;
  296. }
  297. }
  298. /**
  299. * This is a composite test class for combining
  300. * test cases and other RunnableTest classes into
  301. * a group test.
  302. * @package SimpleTest
  303. * @subpackage UnitTester
  304. */
  305. class GroupTest {
  306. var $_label;
  307. var $_test_cases;
  308. var $_old_track_errors;
  309. var $_xdebug_is_enabled;
  310. /**
  311. * Sets the name of the test suite.
  312. * @param string $label Name sent at the start and end
  313. * of the test.
  314. * @access public
  315. */
  316. function GroupTest($label = false) {
  317. $this->_label = $label ? $label : get_class($this);
  318. $this->_test_cases = array();
  319. $this->_old_track_errors = ini_get('track_errors');
  320. $this->_xdebug_is_enabled = function_exists('xdebug_is_enabled') ?
  321. xdebug_is_enabled() : false;
  322. }
  323. /**
  324. * Accessor for the test name for subclasses.
  325. * @return string Name of the test.
  326. * @access public
  327. */
  328. function getLabel() {
  329. return $this->_label;
  330. }
  331. /**
  332. * Adds a test into the suite. Can be either a group
  333. * test or some other unit test.
  334. * @param SimpleTestCase $test_case Suite or individual test
  335. * case implementing the
  336. * runnable test interface.
  337. * @access public
  338. */
  339. function addTestCase(&$test_case) {
  340. $this->_test_cases[] = &$test_case;
  341. }
  342. /**
  343. * Adds a test into the suite by class name. The class will
  344. * be instantiated as needed.
  345. * @param SimpleTestCase $test_case Suite or individual test
  346. * case implementing the
  347. * runnable test interface.
  348. * @access public
  349. */
  350. function addTestClass($class) {
  351. if ($this->_getBaseTestCase($class) == 'grouptest') {
  352. $this->_test_cases[] = &new $class();
  353. } else {
  354. $this->_test_cases[] = $class;
  355. }
  356. }
  357. /**
  358. * Builds a group test from a library of test cases.
  359. * The new group is composed into this one.
  360. * @param string $test_file File name of library with
  361. * test case classes.
  362. * @access public
  363. */
  364. function addTestFile($test_file) {
  365. $existing_classes = get_declared_classes();
  366. if ($error = $this->_requireWithError($test_file)) {
  367. $this->addTestCase(new BadGroupTest($test_file, $error));
  368. return;
  369. }
  370. $classes = $this->_selectRunnableTests($existing_classes, get_declared_classes());
  371. if (count($classes) == 0) {
  372. $this->addTestCase(new BadGroupTest($test_file, 'No new test cases'));
  373. return;
  374. }
  375. $this->addTestCase($this->_createGroupFromClasses($test_file, $classes));
  376. }
  377. /**
  378. * Requires a source file recording any syntax errors.
  379. * @param string $file File name to require in.
  380. * @return string/boolean An error message on failure or false
  381. * if no errors.
  382. * @access private
  383. */
  384. function _requireWithError($file) {
  385. $this->_enableErrorReporting();
  386. include($file);
  387. $error = isset($php_errormsg) ? $php_errormsg : false;
  388. $this->_disableErrorReporting();
  389. $self_inflicted_errors = array(
  390. 'Assigning the return value of new by reference is deprecated',
  391. 'var: Deprecated. Please use the public/private/protected modifiers');
  392. if (in_array($error, $self_inflicted_errors)) {
  393. return false;
  394. }
  395. return $error;
  396. }
  397. /**
  398. * Sets up detection of parse errors. Note that XDebug
  399. * interferes with this and has to be disabled. This is
  400. * to make sure the correct error code is returned
  401. * from unattended scripts.
  402. * @access private
  403. */
  404. function _enableErrorReporting() {
  405. if ($this->_xdebug_is_enabled) {
  406. xdebug_disable();
  407. }
  408. ini_set('track_errors', true);
  409. }
  410. /**
  411. * Resets detection of parse errors to their old values.
  412. * This is to make sure the correct error code is returned
  413. * from unattended scripts.
  414. * @access private
  415. */
  416. function _disableErrorReporting() {
  417. ini_set('track_errors', $this->_old_track_errors);
  418. if ($this->_xdebug_is_enabled) {
  419. xdebug_enable();
  420. }
  421. }
  422. /**
  423. * Calculates the incoming test cases from a before
  424. * and after list of loaded classes.
  425. * @param array $existing_classes Classes before require().
  426. * @param array $new_classes Classes after require().
  427. * @return array New classes which are test
  428. * cases that shouldn't be ignored.
  429. * @access private
  430. */
  431. function _selectRunnableTests($existing_classes, $new_classes) {
  432. $classes = array();
  433. foreach ($new_classes as $class) {
  434. if (in_array($class, $existing_classes)) {
  435. continue;
  436. }
  437. if ($this->_getBaseTestCase($class)) {
  438. $classes[] = $class;
  439. }
  440. }
  441. return $classes;
  442. }
  443. /**
  444. * Builds a group test from a class list.
  445. * @param string $title Title of new group.
  446. * @param array $classes Test classes.
  447. * @return GroupTest Group loaded with the new
  448. * test cases.
  449. * @access private
  450. */
  451. function _createGroupFromClasses($title, $classes) {
  452. $group = new GroupTest($title);
  453. foreach ($classes as $class) {
  454. if (SimpleTest::isIgnored($class)) {
  455. continue;
  456. }
  457. $group->addTestClass($class);
  458. }
  459. return $group;
  460. }
  461. /**
  462. * Test to see if a class is derived from the
  463. * SimpleTestCase class.
  464. * @param string $class Class name.
  465. * @access private
  466. */
  467. function _getBaseTestCase($class) {
  468. while ($class = get_parent_class($class)) {
  469. $class = strtolower($class);
  470. if ($class == "simpletestcase" || $class == "grouptest") {
  471. return $class;
  472. }
  473. }
  474. return false;
  475. }
  476. /**
  477. * Delegates to a visiting collector to add test
  478. * files.
  479. * @param string $path Path to scan from.
  480. * @param SimpleCollector $collector Directory scanner.
  481. * @access public
  482. */
  483. function collect($path, &$collector) {
  484. $collector->collect($this, $path);
  485. }
  486. /**
  487. * Invokes run() on all of the held test cases, instantiating
  488. * them if necessary.
  489. * @param SimpleReporter $reporter Current test reporter.
  490. * @access public
  491. */
  492. function run(&$reporter) {
  493. $reporter->paintGroupStart($this->getLabel(), $this->getSize());
  494. for ($i = 0, $count = count($this->_test_cases); $i < $count; $i++) {
  495. if (is_string($this->_test_cases[$i])) {
  496. $class = $this->_test_cases[$i];
  497. $test = &new $class();
  498. $test->run($reporter);
  499. } else {
  500. $this->_test_cases[$i]->run($reporter);
  501. }
  502. }
  503. $reporter->paintGroupEnd($this->getLabel());
  504. return $reporter->getStatus();
  505. }
  506. /**
  507. * Number of contained test cases.
  508. * @return integer Total count of cases in the group.
  509. * @access public
  510. */
  511. function getSize() {
  512. $count = 0;
  513. foreach ($this->_test_cases as $case) {
  514. if (is_string($case)) {
  515. $count++;
  516. } else {
  517. $count += $case->getSize();
  518. }
  519. }
  520. return $count;
  521. }
  522. }
  523. /**
  524. * This is a failing group test for when a test suite hasn't
  525. * loaded properly.
  526. * @package SimpleTest
  527. * @subpackage UnitTester
  528. */
  529. class BadGroupTest {
  530. var $_label;
  531. var $_error;
  532. /**
  533. * Sets the name of the test suite and error message.
  534. * @param string $label Name sent at the start and end
  535. * of the test.
  536. * @access public
  537. */
  538. function BadGroupTest($label, $error) {
  539. $this->_label = $label;
  540. $this->_error = $error;
  541. }
  542. /**
  543. * Accessor for the test name for subclasses.
  544. * @return string Name of the test.
  545. * @access public
  546. */
  547. function getLabel() {
  548. return $this->_label;
  549. }
  550. /**
  551. * Sends a single error to the reporter.
  552. * @param SimpleReporter $reporter Current test reporter.
  553. * @access public
  554. */
  555. function run(&$reporter) {
  556. $reporter->paintGroupStart($this->getLabel(), $this->getSize());
  557. $reporter->paintFail('Bad GroupTest [' . $this->getLabel() .
  558. '] with error [' . $this->_error . ']');
  559. $reporter->paintGroupEnd($this->getLabel());
  560. return $reporter->getStatus();
  561. }
  562. /**
  563. * Number of contained test cases. Always zero.
  564. * @return integer Total count of cases in the group.
  565. * @access public
  566. */
  567. function getSize() {
  568. return 0;
  569. }
  570. }
  571. ?>