Line # | Frequency | Source Line |
1 | | <?php |
2 | | /** |
3 | | * base include file for SimpleTest |
4 | | * @package SimpleTest |
5 | | * @subpackage UnitTester |
6 | | * @version $Id: errors.php 1672 2008-03-02 04:47:34Z edwardzyang $ |
7 | | */ |
8 | |
|
9 | | /** |
10 | | * @ignore - PHP5 compatibility fix. |
11 | | */ |
12 | | if (! defined('E_STRICT')) { |
13 | | define('E_STRICT', 2048); |
14 | | } |
15 | |
|
16 | | /**#@+ |
17 | | * Includes SimpleTest files. |
18 | | */ |
19 | | require_once dirname(__FILE__) . '/invoker.php'; |
20 | | require_once dirname(__FILE__) . '/test_case.php'; |
21 | | require_once dirname(__FILE__) . '/expectation.php'; |
22 | | /**#@-*/ |
23 | |
|
24 | | /** |
25 | | * Extension that traps errors into an error queue. |
26 | | * @package SimpleTest |
27 | | * @subpackage UnitTester |
28 | | */ |
29 | | class SimpleErrorTrappingInvoker extends SimpleInvokerDecorator { |
30 | |
|
31 | | /** |
32 | | * Stores the invoker to wrap. |
33 | | * @param SimpleInvoker $invoker Test method runner. |
34 | | */ |
35 | | function SimpleErrorTrappingInvoker(&$invoker) { |
36 | 1 | $this->SimpleInvokerDecorator($invoker); |
37 | | } |
38 | |
|
39 | | /** |
40 | | * Invokes a test method and dispatches any |
41 | | * untrapped errors. Called back from |
42 | | * the visiting runner. |
43 | | * @param string $method Test method to call. |
44 | | * @access public |
45 | | */ |
46 | | function invoke($method) { |
47 | 1 | $queue = &$this->_createErrorQueue(); |
48 | 1 | set_error_handler('SimpleTestErrorHandler'); |
49 | 1 | parent::invoke($method); |
50 | 1 | restore_error_handler(); |
51 | 1 | $queue->tally(); |
52 | | } |
53 | | |
54 | | /** |
55 | | * Wires up the error queue for a single test. |
56 | | * @return SimpleErrorQueue Queue connected to the test. |
57 | | * @access private |
58 | | */ |
59 | | function &_createErrorQueue() { |
60 | 1 | $context = &SimpleTest::getContext(); |
61 | 1 | $test = &$this->getTestCase(); |
62 | 1 | $queue = &$context->get('SimpleErrorQueue'); |
63 | 1 | $queue->setTestCase($test); |
64 | 1 | return $queue; |
65 | | } |
66 | | } |
67 | |
|
68 | | /** |
69 | | * Error queue used to record trapped |
70 | | * errors. |
71 | | * @package SimpleTest |
72 | | * @subpackage UnitTester |
73 | | */ |
74 | | class SimpleErrorQueue { |
75 | | var $_queue; |
76 | | var $_expectation_queue; |
77 | | var $_test; |
78 | | var $_using_expect_style = false; |
79 | |
|
80 | | /** |
81 | | * Starts with an empty queue. |
82 | | */ |
83 | | function SimpleErrorQueue() { |
84 | 1 | $this->clear(); |
85 | | } |
86 | |
|
87 | | /** |
88 | | * Discards the contents of the error queue. |
89 | | * @access public |
90 | | */ |
91 | | function clear() { |
92 | 1 | $this->_queue = array(); |
93 | 1 | $this->_expectation_queue = array(); |
94 | | } |
95 | |
|
96 | | /** |
97 | | * Sets the currently running test case. |
98 | | * @param SimpleTestCase $test Test case to send messages to. |
99 | | * @access public |
100 | | */ |
101 | | function setTestCase(&$test) { |
102 | 1 | $this->_test = &$test; |
103 | | } |
104 | |
|
105 | | /** |
106 | | * Sets up an expectation of an error. If this is |
107 | | * not fulfilled at the end of the test, a failure |
108 | | * will occour. If the error does happen, then this |
109 | | * will cancel it out and send a pass message. |
110 | | * @param SimpleExpectation $expected Expected error match. |
111 | | * @param string $message Message to display. |
112 | | * @access public |
113 | | */ |
114 | | function expectError($expected, $message) { |
115 | | $this->_using_expect_style = true; |
116 | | array_push($this->_expectation_queue, array($expected, $message)); |
117 | | } |
118 | |
|
119 | | /** |
120 | | * Adds an error to the front of the queue. |
121 | | * @param integer $severity PHP error code. |
122 | | * @param string $content Text of error. |
123 | | * @param string $filename File error occoured in. |
124 | | * @param integer $line Line number of error. |
125 | | * @access public |
126 | | */ |
127 | | function add($severity, $content, $filename, $line) { |
128 | | $content = str_replace('%', '%%', $content); |
129 | | if ($this->_using_expect_style) { |
130 | | $this->_testLatestError($severity, $content, $filename, $line); |
131 | | } else { |
132 | | array_push( |
133 | | $this->_queue, |
134 | | array($severity, $content, $filename, $line)); |
135 | | } |
136 | | } |
137 | | |
138 | | /** |
139 | | * Any errors still in the queue are sent to the test |
140 | | * case. Any unfulfilled expectations trigger failures. |
141 | | * @access public |
142 | | */ |
143 | | function tally() { |
144 | 1 | while (list($severity, $message, $file, $line) = $this->extract()) { |
145 | | $severity = $this->getSeverityAsString($severity); |
146 | | $this->_test->error($severity, $message, $file, $line); |
147 | | } |
148 | 1 | while (list($expected, $message) = $this->_extractExpectation()) { |
149 | | $this->_test->assert($expected, false, "%s -> Expected error not caught"); |
150 | | } |
151 | | } |
152 | |
|
153 | | /** |
154 | | * Tests the error against the most recent expected |
155 | | * error. |
156 | | * @param integer $severity PHP error code. |
157 | | * @param string $content Text of error. |
158 | | * @param string $filename File error occoured in. |
159 | | * @param integer $line Line number of error. |
160 | | * @access private |
161 | | */ |
162 | | function _testLatestError($severity, $content, $filename, $line) { |
163 | | if ($expectation = $this->_extractExpectation()) { |
164 | | list($expected, $message) = $expectation; |
165 | | $this->_test->assert($expected, $content, sprintf( |
166 | | $message, |
167 | | "%s -> PHP error [$content] severity [" . |
168 | | $this->getSeverityAsString($severity) . |
169 | | "] in [$filename] line [$line]")); |
170 | | } else { |
171 | | $this->_test->error($severity, $content, $filename, $line); |
172 | | } |
173 | | } |
174 | |
|
175 | | /** |
176 | | * Pulls the earliest error from the queue. |
177 | | * @return mixed False if none, or a list of error |
178 | | * information. Elements are: severity |
179 | | * as the PHP error code, the error message, |
180 | | * the file with the error, the line number |
181 | | * and a list of PHP super global arrays. |
182 | | * @access public |
183 | | */ |
184 | | function extract() { |
185 | 1 | if (count($this->_queue)) { |
186 | | return array_shift($this->_queue); |
187 | | } |
188 | 1 | return false; |
189 | | } |
190 | |
|
191 | | /** |
192 | | * Pulls the earliest expectation from the queue. |
193 | | * @return SimpleExpectation False if none. |
194 | | * @access private |
195 | | */ |
196 | | function _extractExpectation() { |
197 | 1 | if (count($this->_expectation_queue)) { |
198 | | return array_shift($this->_expectation_queue); |
199 | | } |
200 | 1 | return false; |
201 | | } |
202 | |
|
203 | | /** |
204 | | * @deprecated |
205 | | */ |
206 | | function assertNoErrors($message) { |
207 | | return $this->_test->assert( |
208 | | new TrueExpectation(), |
209 | | count($this->_queue) == 0, |
210 | | sprintf($message, 'Should be no errors')); |
211 | | } |
212 | |
|
213 | | /** |
214 | | * @deprecated |
215 | | */ |
216 | | function assertError($expected, $message) { |
217 | | if (count($this->_queue) == 0) { |
218 | | $this->_test->fail(sprintf($message, 'Expected error not found')); |
219 | | return false; |
220 | | } |
221 | | list($severity, $content, $file, $line) = $this->extract(); |
222 | | $severity = $this->getSeverityAsString($severity); |
223 | | return $this->_test->assert( |
224 | | $expected, |
225 | | $content, |
226 | | sprintf($message, "Expected PHP error [$content] severity [$severity] in [$file] line [$line]")); |
227 | | } |
228 | |
|
229 | | /** |
230 | | * Converts an error code into it's string |
231 | | * representation. |
232 | | * @param $severity PHP integer error code. |
233 | | * @return String version of error code. |
234 | | * @access public |
235 | | * @static |
236 | | */ |
237 | | function getSeverityAsString($severity) { |
238 | | static $map = array( |
239 | | E_STRICT => 'E_STRICT', |
240 | | E_ERROR => 'E_ERROR', |
241 | | E_WARNING => 'E_WARNING', |
242 | | E_PARSE => 'E_PARSE', |
243 | | E_NOTICE => 'E_NOTICE', |
244 | | E_CORE_ERROR => 'E_CORE_ERROR', |
245 | | E_CORE_WARNING => 'E_CORE_WARNING', |
246 | | E_COMPILE_ERROR => 'E_COMPILE_ERROR', |
247 | | E_COMPILE_WARNING => 'E_COMPILE_WARNING', |
248 | | E_USER_ERROR => 'E_USER_ERROR', |
249 | | E_USER_WARNING => 'E_USER_WARNING', |
250 | | E_USER_NOTICE => 'E_USER_NOTICE'); |
251 | | if (defined('E_RECOVERABLE_ERROR')) { |
252 | | $map[E_RECOVERABLE_ERROR] = 'E_RECOVERABLE_ERROR'; |
253 | | } |
254 | | if (defined('E_DEPRECATED')) { |
255 | | $map[E_DEPRECATED] = 'E_DEPRECATED'; |
256 | | } |
257 | | return $map[$severity]; |
258 | | } |
259 | | } |
260 | |
|
261 | | /** |
262 | | * Error handler that simply stashes any errors into the global |
263 | | * error queue. Simulates the existing behaviour with respect to |
264 | | * logging errors, but this feature may be removed in future. |
265 | | * @param $severity PHP error code. |
266 | | * @param $message Text of error. |
267 | | * @param $filename File error occoured in. |
268 | | * @param $line Line number of error. |
269 | | * @param $super_globals Hash of PHP super global arrays. |
270 | | * @static |
271 | | * @access public |
272 | | */ |
273 | | function SimpleTestErrorHandler($severity, $message, $filename = null, $line = null, $super_globals = null, $mask = null) { |
274 | 1 | $severity = $severity & error_reporting(); |
275 | 1 | if ($severity) { |
276 | | restore_error_handler(); |
277 | | if (ini_get('log_errors')) { |
278 | | $label = SimpleErrorQueue::getSeverityAsString($severity); |
279 | | error_log("$label: $message in $filename on line $line"); |
280 | | } |
281 | | $context = &SimpleTest::getContext(); |
282 | | $queue = &$context->get('SimpleErrorQueue'); |
283 | | $queue->add($severity, $message, $filename, $line); |
284 | | set_error_handler('SimpleTestErrorHandler'); |
285 | | } |
286 | 1 | return true; |
287 | | } |
288 | | ? |