exceptions.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. <?php
  2. /**
  3. * base include file for SimpleTest
  4. * @package SimpleTest
  5. * @subpackage UnitTester
  6. * @version $Id$
  7. */
  8. /**#@+
  9. * Include required SimpleTest files
  10. */
  11. require_once dirname(__FILE__) . '/invoker.php';
  12. require_once dirname(__FILE__) . '/expectation.php';
  13. /**#@-*/
  14. /**
  15. * Extension that traps exceptions and turns them into
  16. * an error message. PHP5 only.
  17. * @package SimpleTest
  18. * @subpackage UnitTester
  19. */
  20. class SimpleExceptionTrappingInvoker extends SimpleInvokerDecorator {
  21. /**
  22. * Stores the invoker to be wrapped.
  23. * @param SimpleInvoker $invoker Test method runner.
  24. */
  25. function __construct($invoker) {
  26. parent::__construct($invoker);
  27. }
  28. /**
  29. * Invokes a test method whilst trapping expected
  30. * exceptions. Any left over unthrown exceptions
  31. * are then reported as failures.
  32. * @param string $method Test method to call.
  33. */
  34. function invoke($method) {
  35. $trap = SimpleTest::getContext()->get('SimpleExceptionTrap');
  36. $trap->clear();
  37. try {
  38. $has_thrown = false;
  39. parent::invoke($method);
  40. } catch (Exception $exception) {
  41. $has_thrown = true;
  42. if (! $trap->isExpected($this->getTestCase(), $exception)) {
  43. $this->getTestCase()->exception($exception);
  44. }
  45. $trap->clear();
  46. }
  47. if ($message = $trap->getOutstanding()) {
  48. $this->getTestCase()->fail($message);
  49. }
  50. if ($has_thrown) {
  51. try {
  52. parent::getTestCase()->tearDown();
  53. } catch (Exception $e) { }
  54. }
  55. }
  56. }
  57. /**
  58. * Tests exceptions either by type or the exact
  59. * exception. This could be improved to accept
  60. * a pattern expectation to test the error
  61. * message, but that will have to come later.
  62. * @package SimpleTest
  63. * @subpackage UnitTester
  64. */
  65. class ExceptionExpectation extends SimpleExpectation {
  66. private $expected;
  67. /**
  68. * Sets up the conditions to test against.
  69. * If the expected value is a string, then
  70. * it will act as a test of the class name.
  71. * An exception as the comparison will
  72. * trigger an identical match. Writing this
  73. * down now makes it look doubly dumb. I hope
  74. * come up with a better scheme later.
  75. * @param mixed $expected A class name or an actual
  76. * exception to compare with.
  77. * @param string $message Message to display.
  78. */
  79. function __construct($expected, $message = '%s') {
  80. $this->expected = $expected;
  81. parent::__construct($message);
  82. }
  83. /**
  84. * Carry out the test.
  85. * @param Exception $compare Value to check.
  86. * @return boolean True if matched.
  87. */
  88. function test($compare) {
  89. if (is_string($this->expected)) {
  90. return ($compare instanceof $this->expected);
  91. }
  92. if (get_class($compare) != get_class($this->expected)) {
  93. return false;
  94. }
  95. return $compare->getMessage() == $this->expected->getMessage();
  96. }
  97. /**
  98. * Create the message to display describing the test.
  99. * @param Exception $compare Exception to match.
  100. * @return string Final message.
  101. */
  102. function testMessage($compare) {
  103. if (is_string($this->expected)) {
  104. return "Exception [" . $this->describeException($compare) .
  105. "] should be type [" . $this->expected . "]";
  106. }
  107. return "Exception [" . $this->describeException($compare) .
  108. "] should match [" .
  109. $this->describeException($this->expected) . "]";
  110. }
  111. /**
  112. * Summary of an Exception object.
  113. * @param Exception $compare Exception to describe.
  114. * @return string Text description.
  115. */
  116. protected function describeException($exception) {
  117. return get_class($exception) . ": " . $exception->getMessage();
  118. }
  119. }
  120. /**
  121. * Stores expected exceptions for when they
  122. * get thrown. Saves the irritating try...catch
  123. * block.
  124. * @package SimpleTest
  125. * @subpackage UnitTester
  126. */
  127. class SimpleExceptionTrap {
  128. private $expected;
  129. private $ignored;
  130. private $message;
  131. /**
  132. * Clears down the queue ready for action.
  133. */
  134. function __construct() {
  135. $this->clear();
  136. }
  137. /**
  138. * Sets up an expectation of an exception.
  139. * This has the effect of intercepting an
  140. * exception that matches.
  141. * @param SimpleExpectation $expected Expected exception to match.
  142. * @param string $message Message to display.
  143. * @access public
  144. */
  145. function expectException($expected = false, $message = '%s') {
  146. $this->expected = $this->coerceToExpectation($expected);
  147. $this->message = $message;
  148. }
  149. /**
  150. * Adds an exception to the ignore list. This is the list
  151. * of exceptions that when thrown do not affect the test.
  152. * @param SimpleExpectation $ignored Exception to skip.
  153. * @access public
  154. */
  155. function ignoreException($ignored) {
  156. $this->ignored[] = $this->coerceToExpectation($ignored);
  157. }
  158. /**
  159. * Compares the expected exception with any
  160. * in the queue. Issues a pass or fail and
  161. * returns the state of the test.
  162. * @param SimpleTestCase $test Test case to send messages to.
  163. * @param Exception $exception Exception to compare.
  164. * @return boolean False on no match.
  165. */
  166. function isExpected($test, $exception) {
  167. if ($this->expected) {
  168. return $test->assert($this->expected, $exception, $this->message);
  169. }
  170. foreach ($this->ignored as $ignored) {
  171. if ($ignored->test($exception)) {
  172. return true;
  173. }
  174. }
  175. return false;
  176. }
  177. /**
  178. * Turns an expected exception into a SimpleExpectation object.
  179. * @param mixed $exception Exception, expectation or
  180. * class name of exception.
  181. * @return SimpleExpectation Expectation that will match the
  182. * exception.
  183. */
  184. private function coerceToExpectation($exception) {
  185. if ($exception === false) {
  186. return new AnythingExpectation();
  187. }
  188. if (! SimpleExpectation::isExpectation($exception)) {
  189. return new ExceptionExpectation($exception);
  190. }
  191. return $exception;
  192. }
  193. /**
  194. * Tests for any left over exception.
  195. * @return string/false The failure message or false if none.
  196. */
  197. function getOutstanding() {
  198. return sprintf($this->message, 'Failed to trap exception');
  199. }
  200. /**
  201. * Discards the contents of the error queue.
  202. */
  203. function clear() {
  204. $this->expected = false;
  205. $this->message = false;
  206. $this->ignored = array();
  207. }
  208. }
  209. ?>