0337d704 |
1 | <?php |
2 | /** |
3 | * base include file for SimpleTest |
4 | * @package SimpleTest |
5 | * @subpackage UnitTester |
6 | * @version $Id: dumper.php,v 1.20 2004/08/15 02:24:38 lastcraft Exp $ |
7 | */ |
8 | /** |
9 | * does type matter |
10 | */ |
11 | define('TYPE_MATTERS', true); |
12 | |
13 | /** |
14 | * Displays variables as text and does diffs. |
15 | * @package SimpleTest |
16 | * @subpackage UnitTester |
17 | */ |
18 | class SimpleDumper { |
19 | |
20 | /** |
21 | * Do nothing constructor. |
22 | */ |
23 | function SimpleDumper() { |
24 | } |
25 | |
26 | /** |
27 | * Renders a variable in a shorter form than print_r(). |
28 | * @param mixed $value Variable to render as a string. |
29 | * @return string Human readable string form. |
30 | * @access public |
31 | */ |
32 | function describeValue($value) { |
33 | $type = $this->getType($value); |
34 | switch($type) { |
35 | case "Null": |
36 | return "NULL"; |
37 | case "Boolean": |
38 | return "Boolean: " . ($value ? "true" : "false"); |
39 | case "Array": |
40 | return "Array: " . count($value) . " items"; |
41 | case "Object": |
42 | return "Object: of " . get_class($value); |
43 | case "String": |
44 | return "String: " . $this->clipString($value, 100); |
45 | default: |
46 | return "$type: $value"; |
47 | } |
48 | return "Unknown"; |
49 | } |
50 | |
51 | /** |
52 | * Gets the string representation of a type. |
53 | * @param mixed $value Variable to check against. |
54 | * @return string Type. |
55 | * @access public |
56 | */ |
57 | function getType($value) { |
58 | if (! isset($value)) { |
59 | return "Null"; |
60 | } elseif (is_bool($value)) { |
61 | return "Boolean"; |
62 | } elseif (is_string($value)) { |
63 | return "String"; |
64 | } elseif (is_integer($value)) { |
65 | return "Integer"; |
66 | } elseif (is_float($value)) { |
67 | return "Float"; |
68 | } elseif (is_array($value)) { |
69 | return "Array"; |
70 | } elseif (is_resource($value)) { |
71 | return "Resource"; |
72 | } elseif (is_object($value)) { |
73 | return "Object"; |
74 | } |
75 | return "Unknown"; |
76 | } |
77 | |
78 | /** |
79 | * Creates a human readable description of the |
80 | * difference between two variables. Uses a |
81 | * dynamic call. |
82 | * @param mixed $first First variable. |
83 | * @param mixed $second Value to compare with. |
84 | * @param boolean $identical If true then type anomolies count. |
85 | * @return string Description of difference. |
86 | * @access public |
87 | */ |
88 | function describeDifference($first, $second, $identical = false) { |
89 | if ($identical) { |
90 | if (! $this->_isTypeMatch($first, $second)) { |
91 | return "with type mismatch as [" . $this->describeValue($first) . |
92 | "] does not match [" . $this->describeValue($second) . "]"; |
93 | } |
94 | } |
95 | $type = $this->getType($first); |
96 | if ($type == "Unknown") { |
97 | return "with unknown type"; |
98 | } |
99 | $method = '_describe' . $type . 'Difference'; |
100 | return $this->$method($first, $second, $identical); |
101 | } |
102 | |
103 | /** |
104 | * Tests to see if types match. |
105 | * @param mixed $first First variable. |
106 | * @param mixed $second Value to compare with. |
107 | * @return boolean True if matches. |
108 | * @access private |
109 | */ |
110 | function _isTypeMatch($first, $second) { |
111 | return ($this->getType($first) == $this->getType($second)); |
112 | } |
113 | |
114 | /** |
115 | * Clips a string to a maximum length. |
116 | * @param string $value String to truncate. |
117 | * @param integer $size Minimum string size to show. |
118 | * @param integer $position Centre of string section. |
119 | * @return string Shortened version. |
120 | * @access public |
121 | */ |
122 | function clipString($value, $size, $position = 0) { |
123 | $length = strlen($value); |
124 | if ($length <= $size) { |
125 | return $value; |
126 | } |
127 | $position = min($position, $length); |
128 | $start = ($size/2 > $position ? 0 : $position - $size/2); |
129 | if ($start + $size > $length) { |
130 | $start = $length - $size; |
131 | } |
132 | $value = substr($value, $start, $size); |
133 | return ($start > 0 ? "..." : "") . $value . ($start + $size < $length ? "..." : ""); |
134 | } |
135 | |
136 | /** |
137 | * Creates a human readable description of the |
138 | * difference between two variables. The minimal |
139 | * version. |
140 | * @param null $first First value. |
141 | * @param mixed $second Value to compare with. |
142 | * @return string Human readable description. |
143 | * @access private |
144 | */ |
145 | function _describeGenericDifference($first, $second) { |
146 | return "as [" . $this->describeValue($first) . |
147 | "] does not match [" . |
148 | $this->describeValue($second) . "]"; |
149 | } |
150 | |
151 | /** |
152 | * Creates a human readable description of the |
153 | * difference between a null and another variable. |
154 | * @param null $first First null. |
155 | * @param mixed $second Null to compare with. |
156 | * @param boolean $identical If true then type anomolies count. |
157 | * @return string Human readable description. |
158 | * @access private |
159 | */ |
160 | function _describeNullDifference($first, $second, $identical) { |
161 | return $this->_describeGenericDifference($first, $second); |
162 | } |
163 | |
164 | /** |
165 | * Creates a human readable description of the |
166 | * difference between a boolean and another variable. |
167 | * @param boolean $first First boolean. |
168 | * @param mixed $second Boolean to compare with. |
169 | * @param boolean $identical If true then type anomolies count. |
170 | * @return string Human readable description. |
171 | * @access private |
172 | */ |
173 | function _describeBooleanDifference($first, $second, $identical) { |
174 | return $this->_describeGenericDifference($first, $second); |
175 | } |
176 | |
177 | /** |
178 | * Creates a human readable description of the |
179 | * difference between a string and another variable. |
180 | * @param string $first First string. |
181 | * @param mixed $second String to compare with. |
182 | * @param boolean $identical If true then type anomolies count. |
183 | * @return string Human readable description. |
184 | * @access private |
185 | */ |
186 | function _describeStringDifference($first, $second, $identical) { |
187 | if (is_object($second) || is_array($second)) { |
188 | return $this->_describeGenericDifference($first, $second); |
189 | } |
190 | $position = $this->_stringDiffersAt($first, $second); |
191 | $message = "at character $position"; |
192 | $message .= " with [" . |
193 | $this->clipString($first, 100, $position) . "] and [" . |
194 | $this->clipString($second, 100, $position) . "]"; |
195 | return $message; |
196 | } |
197 | |
198 | /** |
199 | * Creates a human readable description of the |
200 | * difference between an integer and another variable. |
201 | * @param integer $first First number. |
202 | * @param mixed $second Number to compare with. |
203 | * @param boolean $identical If true then type anomolies count. |
204 | * @return string Human readable description. |
205 | * @access private |
206 | */ |
207 | function _describeIntegerDifference($first, $second, $identical) { |
208 | if (is_object($second) || is_array($second)) { |
209 | return $this->_describeGenericDifference($first, $second); |
210 | } |
211 | return "because [" . $this->describeValue($first) . |
212 | "] differs from [" . |
213 | $this->describeValue($second) . "] by " . |
214 | abs($first - $second); |
215 | } |
216 | |
217 | /** |
218 | * Creates a human readable description of the |
219 | * difference between two floating point numbers. |
220 | * @param float $first First float. |
221 | * @param mixed $second Float to compare with. |
222 | * @param boolean $identical If true then type anomolies count. |
223 | * @return string Human readable description. |
224 | * @access private |
225 | */ |
226 | function _describeFloatDifference($first, $second, $identical) { |
227 | if (is_object($second) || is_array($second)) { |
228 | return $this->_describeGenericDifference($first, $second); |
229 | } |
230 | return "because " . $this->describeValue($first) . |
231 | "] differs from [" . |
232 | $this->describeValue($second) . "]"; |
233 | } |
234 | |
235 | /** |
236 | * Creates a human readable description of the |
237 | * difference between two arrays. |
238 | * @param array $first First array. |
239 | * @param mixed $second Array to compare with. |
240 | * @param boolean $identical If true then type anomolies count. |
241 | * @return string Human readable description. |
242 | * @access private |
243 | */ |
244 | function _describeArrayDifference($first, $second, $identical) { |
245 | if (! is_array($second)) { |
246 | return $this->_describeGenericDifference($first, $second); |
247 | } |
248 | if (array_keys($first) !== array_keys($second)) { |
249 | return "as key list [" . |
250 | implode(", ", array_keys($first)) . "] does not match key list [" . |
251 | implode(", ", array_keys($second)) . "]"; |
252 | } |
253 | foreach (array_keys($first) as $key) { |
254 | if ($identical && ($first[$key] === $second[$key])) { |
255 | continue; |
256 | } |
257 | if (! $identical && ($first[$key] == $second[$key])) { |
258 | continue; |
259 | } |
260 | return "with member [$key] " . $this->describeDifference( |
261 | $first[$key], |
262 | $second[$key], |
263 | $identical); |
264 | } |
265 | return ""; |
266 | } |
267 | |
268 | /** |
269 | * Creates a human readable description of the |
270 | * difference between a resource and another variable. |
271 | * @param resource $first First resource. |
272 | * @param mixed $second Resource to compare with. |
273 | * @param boolean $identical If true then type anomolies count. |
274 | * @return string Human readable description. |
275 | * @access private |
276 | */ |
277 | function _describeResourceDifference($first, $second, $identical) { |
278 | return $this->_describeGenericDifference($first, $second); |
279 | } |
280 | |
281 | /** |
282 | * Creates a human readable description of the |
283 | * difference between two objects. |
284 | * @param object $first First object. |
285 | * @param mixed $second Object to compare with. |
286 | * @param boolean $identical If true then type anomolies count. |
287 | * @return string Human readable description. |
288 | * @access private |
289 | */ |
290 | function _describeObjectDifference($first, $second, $identical) { |
291 | if (! is_object($second)) { |
292 | return $this->_describeGenericDifference($first, $second); |
293 | } |
294 | return $this->_describeArrayDifference( |
295 | get_object_vars($first), |
296 | get_object_vars($second), |
297 | $identical); |
298 | } |
299 | |
300 | /** |
301 | * Find the first character position that differs |
302 | * in two strings by binary chop. |
303 | * @param string $first First string. |
304 | * @param string $second String to compare with. |
305 | * @return integer Position of first differing |
306 | * character. |
307 | * @access private |
308 | */ |
309 | function _stringDiffersAt($first, $second) { |
310 | if (! $first || ! $second) { |
311 | return 0; |
312 | } |
313 | if (strlen($first) < strlen($second)) { |
314 | list($first, $second) = array($second, $first); |
315 | } |
316 | $position = 0; |
317 | $step = strlen($first); |
318 | while ($step > 1) { |
319 | $step = (integer)(($step + 1)/2); |
320 | if (strncmp($first, $second, $position + $step) == 0) { |
321 | $position += $step; |
322 | } |
323 | } |
324 | return $position; |
325 | } |
326 | |
327 | /** |
328 | * Sends a formatted dump of a variable to a string. |
329 | * @param mixed $variable Variable to display. |
330 | * @return string Output from print_r(). |
331 | * @access public |
332 | * @static |
333 | */ |
334 | function dump($variable) { |
335 | ob_start(); |
336 | print_r($variable); |
337 | $formatted = ob_get_contents(); |
338 | ob_end_clean(); |
339 | return $formatted; |
340 | } |
341 | |
342 | /** |
343 | * Extracts the last assertion that was not within |
344 | * Simpletest itself. The name must start with "assert". |
345 | * @param array $stack List of stack frames. |
346 | * @param string $format String formatting. |
347 | * @param string $prefix Prefix of method to search for. |
348 | * @access public |
349 | * @static |
350 | */ |
351 | function getFormattedAssertionLine($stack, $format = '%d', $prefix = 'assert') { |
352 | foreach ($stack as $frame) { |
353 | if (substr(@dirname($frame['file']), -10) == 'simpletest') { |
354 | continue; |
355 | } |
356 | if (strncmp($frame['function'], $prefix, strlen($prefix)) == 0) { |
357 | return sprintf($format, $frame['line']); |
358 | } |
359 | } |
360 | return ''; |
361 | } |
362 | } |
363 | ?> |