87% of 1179OPs |
96% of 222Lines |
75% of 208Branches |
9% of 540Paths |
# | |
---|---|
1 |
<?php |
2 |
|
3 |
namespace mageekguy\atoum\asserters\adapter; |
4 |
|
5 |
use |
6 |
mageekguy\atoum, |
7 |
mageekguy\atoum\php, |
8 |
mageekguy\atoum\test, |
9 |
mageekguy\atoum\asserter, |
10 |
mageekguy\atoum\tools\variable, |
11 |
mageekguy\atoum\asserters\adapter\call\exceptions |
12 |
; |
13 |
|
14 |
abstract class call extends atoum\asserter |
15 |
{ |
16 |
protected $adapter = null; |
17 |
protected $call = null; |
18 |
protected $identicalCall = false; |
19 |
protected $beforeCalls = array(); |
20 |
protected $afterCalls = array(); |
21 |
protected $trace = array('file' => null, 'line' => null); |
22 |
protected $manager = null; |
23 |
|
24 |
public function __construct(asserter\generator $generator = null, variable\analyzer $analyzer = null, atoum\locale $locale = null)100% |
25 |
{ |
26 |
parent::__construct($generator, $analyzer, $locale); |
27 |
|
28 |
$this->setCall(); |
29 |
} |
30 |
|
31 |
public function __get($property)80% |
32 |
{ |
33 |
if (is_numeric($property) === true) |
34 |
{ |
35 |
return $this->exactly($property); |
36 |
} |
37 |
else switch (strtolower($property)) |
38 |
{ |
39 |
case 'once': |
40 |
case 'twice': |
41 |
case 'thrice': |
42 |
case 'never': |
43 |
case 'atleastonce': |
44 |
case 'wascalled': |
45 |
case 'wasnotcalled': |
46 |
return $this->{$property}(); |
47 |
|
48 |
default: |
49 |
return parent::__get($property); |
50 |
} |
51 |
} |
52 |
|
53 |
public function setManager(call\manager $manager)100% |
54 |
{ |
55 |
$this->manager = $manager; |
56 |
|
57 |
return $this; |
58 |
} |
59 |
|
60 |
public function setCall(test\adapter\call $call = null)100% |
61 |
{ |
62 |
if ($call === null) |
63 |
{ |
64 |
$call = new test\adapter\call(); |
65 |
} |
66 |
|
67 |
if ($this->call !== null) |
68 |
{ |
69 |
$call->copy($this->call); |
70 |
} |
71 | |
72 |
$this->call = $call; |
73 |
|
74 |
return $this; |
75 |
} |
76 |
|
77 |
public function getCall()100% |
78 |
{ |
79 |
return clone $this->call; |
80 |
} |
81 |
|
82 |
public function disableEvaluationChecking()100% |
83 |
{ |
84 |
return $this->removeFromManager(); |
85 |
} |
86 |
|
87 |
public function getLastAssertionFile()100% |
88 |
{ |
89 |
return $this->trace['file']; |
90 |
} |
91 |
|
92 |
public function getLastAssertionLine()100% |
93 |
{ |
94 |
return $this->trace['line']; |
95 |
} |
96 |
|
97 |
public function reset()100% |
98 |
{ |
99 |
if ($this->adapter !== null) |
100 |
{ |
101 |
$this->adapter->resetCalls(); |
102 |
} |
103 |
|
104 |
return $this; |
105 |
} |
106 |
|
107 |
public function setWithTest(test $test)100% |
108 |
{ |
109 |
$this->setManager($test->getAsserterCallManager()); |
110 |
|
111 |
return parent::setWithTest($test); |
112 |
} |
113 |
|
114 |
public function setWith($adapter)100% |
115 |
{ |
116 |
$this->adapter = $adapter; |
117 |
|
118 |
if ($this->adapter instanceof \mageekguy\atoum\test\adapter) |
119 |
{ |
120 |
$this->pass(); |
121 |
} |
122 |
else |
123 |
{ |
124 |
$this->fail($this->_('%s is not a test adapter', $this->getTypeOf($this->adapter))); |
125 |
} |
126 |
|
127 |
return $this; |
128 |
} |
129 |
|
130 |
public function getAdapter()100% |
131 |
{ |
132 |
return $this->adapter; |
133 |
} |
134 |
|
135 |
public function before(call $call)100% |
136 |
{ |
137 |
$this->setTrace(); |
138 |
|
139 |
foreach (func_get_args() as $call) |
140 |
{ |
141 |
$this->addBeforeCall($call); |
142 |
} |
143 |
|
144 |
return $this; |
145 |
} |
146 |
|
147 |
public function getBefore()100% |
148 |
{ |
149 |
return $this->beforeCalls; |
150 |
} |
151 |
|
152 |
public function after(call $call)100% |
153 |
{ |
154 |
$this->setTrace(); |
155 |
|
156 |
foreach (func_get_args() as $call) |
157 |
{ |
158 |
$this->addAfterCall($call); |
159 |
} |
160 |
|
161 |
return $this; |
162 |
} |
163 |
|
164 |
public function getAfter()100% |
165 |
{ |
166 |
return $this->afterCalls; |
167 |
} |
168 |
|
169 |
public function once($failMessage = null)100% |
170 |
{ |
171 |
return $this->exactly(1, $failMessage); |
172 |
} |
173 |
|
174 |
public function twice($failMessage = null)100% |
175 |
{ |
176 |
return $this->exactly(2, $failMessage); |
177 |
} |
178 |
|
179 |
public function thrice($failMessage = null)100% |
180 |
{ |
181 |
return $this->exactly(3, $failMessage); |
182 |
} |
183 |
|
184 |
public function atLeastOnce($failMessage = null)100% |
185 |
{ |
186 |
$this->removeFromManager(); |
187 |
|
188 |
if ($this->countBeforeAndAfterCalls() >= 1) |
189 |
{ |
190 |
$this->pass(); |
191 |
} |
192 |
else |
193 |
{ |
194 |
$this->fail($failMessage ?: $this->_('%s is called 0 time', $this->call) . $this->getCallsAsString()); |
195 |
} |
196 |
|
197 |
return $this; |
198 |
} |
199 |
|
200 |
public function exactly($number, $failMessage = null)100% |
201 |
{ |
202 |
$callsNumber = $this->removeFromManager()->countBeforeAndAfterCalls(); |
203 |
|
204 |
if ((int) $number != $number) |
205 |
{ |
206 |
throw new atoum\exceptions\logic\invalidArgument('Argument 1 of ' . __FUNCTION__ . ' must be an integer'); |
207 |
} |
208 |
|
209 |
if ($callsNumber == $number) |
210 |
{ |
211 |
$this->pass(); |
212 |
} |
213 |
else |
214 |
{ |
215 |
if ($failMessage === null) |
216 |
{ |
217 |
$failMessage = $this->__('%s is called %d time instead of %d', '%s is called %d times instead of %d', $callsNumber, $this->call, $callsNumber, $number); |
218 |
|
219 |
if (sizeof($this->beforeCalls) > 0) |
220 |
{ |
221 |
$beforeCalls = array(); |
222 |
|
223 |
foreach ($this->beforeCalls as $asserter) |
224 |
{ |
225 |
$beforeCalls[] = (string) $asserter->getCall(); |
226 |
} |
227 |
|
228 |
$failMessage = $this->_('%s before %s', $failMessage, join(', ', $beforeCalls)); |
229 |
} |
230 |
|
231 |
if (sizeof($this->afterCalls) > 0) |
232 |
{ |
233 |
$afterCalls = array(); |
234 |
|
235 |
foreach ($this->afterCalls as $asserter) |
236 |
{ |
237 |
$afterCalls[] = (string) $asserter->getCall(); |
238 |
} |
239 |
|
240 |
$failMessage = $this->_('%s after %s', $failMessage, join(', ', $afterCalls)); |
241 |
} |
242 |
|
243 |
$failMessage .= $this->getCallsAsString(); |
244 |
} |
245 |
|
246 |
$this->fail($failMessage); |
247 |
} |
248 |
|
249 |
return $this; |
250 |
} |
251 |
|
252 |
public function never($failMessage = null)100% |
253 |
{ |
254 |
return $this->exactly(0, $failMessage); |
255 |
} |
256 |
|
257 |
public function getFunction()100% |
258 |
{ |
259 |
return $this->call->getFunction(); |
260 |
} |
261 |
|
262 |
public function getArguments()100% |
263 |
{ |
264 |
return $this->adapterIsSet()->call->getArguments(); |
265 |
} |
266 |
|
267 |
protected function adapterIsSet()100% |
268 |
{ |
269 |
if ($this->adapter === null) |
270 |
{ |
271 |
throw new exceptions\logic('Adapter is undefined'); |
272 |
} |
273 |
|
274 |
return $this; |
275 |
} |
276 |
|
277 |
protected function callIsSet()100% |
278 |
{ |
279 |
if ($this->adapterIsSet()->call->getFunction() === null) |
280 |
{ |
281 |
throw new exceptions\logic('Call is undefined'); |
282 |
} |
283 |
|
284 |
return $this; |
285 |
} |
286 |
|
287 |
protected function countBeforeAndAfterCalls()95% |
288 |
{ |
289 |
$calls = $this->callIsSet()->adapter->getCalls($this->call, $this->identicalCall); |
290 |
|
291 |
if (sizeof($calls) > 0 && (sizeof($this->beforeCalls) > 0 || sizeof($this->afterCalls) > 0)) |
292 |
{ |
293 |
foreach ($this->beforeCalls as $asserter) |
294 |
{ |
295 |
$pass = false; |
296 |
|
297 |
foreach ($calls->getTimeline() as $position => $call) |
298 |
{ |
299 |
$hasAfterCalls = $asserter->hasAfterCalls($position); |
300 |
|
301 |
if ($hasAfterCalls === false) |
302 |
{ |
303 |
$calls->removeCall($call, $position); |
304 |
} |
305 |
else if ($pass === false) |
306 |
{ |
307 |
$pass = $hasAfterCalls; |
308 |
} |
309 |
} |
310 |
|
311 |
if ($pass === false) |
312 |
{ |
313 |
$this->fail($this->_('%s is not called before %s', $this->call, $asserter->getCall())); |
314 |
} |
315 |
} |
316 |
|
317 |
foreach ($this->afterCalls as $asserter) |
318 |
{ |
319 |
$pass = false; |
320 |
|
321 |
foreach ($calls->getTimeline() as $position => $call) |
322 |
{ |
323 |
$hasPreviousCalls = $asserter->hasPreviousCalls($position); |
324 |
|
325 |
if ($hasPreviousCalls === false) |
326 |
{ |
327 |
$calls->removeCall($call, $position); |
328 |
} |
329 |
else if ($pass === false) |
330 |
{ |
331 |
$pass = $hasPreviousCalls; |
332 |
} |
333 |
} |
334 |
|
335 |
if ($pass === false) |
336 |
{ |
337 |
$this->fail($this->_('%s is not called after %s', $this->call, $asserter->getCall())); |
338 |
} |
339 |
} |
340 |
} |
341 |
|
342 |
return sizeof($calls); |
343 |
} |
344 |
|
345 |
protected function setFunction($function)100% |
346 |
{ |
347 |
$this |
348 |
->adapterIsSet() |
349 |
->setTrace() |
350 |
->addToManager() |
351 |
->call |
352 |
->setFunction($function) |
353 |
->unsetArguments() |
354 |
; |
355 |
|
356 |
$this->beforeCalls = array(); |
357 |
$this->afterCalls = array(); |
358 |
|
359 |
return $this; |
360 |
} |
361 |
|
362 |
protected function setArguments(array $arguments)100% |
363 |
{ |
364 |
$this |
365 |
->adapterIsSet() |
366 |
->callIsSet() |
367 |
->setTrace() |
368 |
->call |
369 |
->setArguments($arguments) |
370 |
; |
371 |
|
372 |
$this->identicalCall = false; |
373 |
|
374 |
return $this; |
375 |
} |
376 |
|
377 |
protected function unsetArguments()100% |
378 |
{ |
379 |
$this |
380 |
->adapterIsSet() |
381 |
->callIsSet() |
382 |
->setTrace() |
383 |
->call |
384 |
->unsetArguments() |
385 |
; |
386 |
|
387 |
$this->identicalCall = false; |
388 |
|
389 |
return $this; |
390 |
} |
391 |
|
392 |
protected function setIdenticalArguments(array $arguments)100% |
393 |
{ |
394 |
$this->setArguments($arguments)->identicalCall = true; |
395 |
|
396 |
return $this; |
397 |
} |
398 |
|
399 |
protected function hasPreviousCalls($position)100% |
400 |
{ |
401 |
return $this->adapter->hasPreviousCalls($this->call, $position, $this->identicalCall); |
402 |
} |
403 |
|
404 |
protected function hasAfterCalls($position)100% |
405 |
{ |
406 |
return $this->adapter->hasAfterCalls($this->call, $position, $this->identicalCall); |
407 |
} |
408 |
|
409 |
protected function getCalls($call)0% |
410 |
{ |
411 |
return $this->adapter->getCalls($call); |
412 |
} |
413 |
|
414 |
protected function getCallsAsString()100% |
415 |
{ |
416 |
$string = ''; |
417 |
|
418 |
if (sizeof($this->beforeCalls) <= 0 && sizeof($this->afterCalls) <= 0) |
419 |
{ |
420 |
$calls = $this->adapter->getCallsEqualTo($this->call->unsetArguments()); |
421 |
|
422 |
$string = (sizeof($calls) <= 0 ? '' : PHP_EOL . rtrim($calls)); |
423 |
} |
424 |
|
425 |
return $string; |
426 |
} |
427 |
|
428 |
protected function setTrace()77% |
429 |
{ |
430 |
foreach (debug_backtrace() as $trace) |
431 |
{ |
432 |
if (isset($trace['function']) === true && isset($trace['file']) === true && isset($trace['line']) === true) |
433 |
{ |
434 |
if (isset($trace['object']) === false || $trace['object'] !== $this) |
435 |
{ |
436 |
return $this; |
437 |
} |
438 |
|
439 |
$this->trace['file'] = $trace['file']; |
440 |
$this->trace['line'] = $trace['line']; |
441 |
} |
442 |
} |
443 |
|
444 |
$this->trace['file'] = null; |
445 |
$this->trace['line'] = null; |
446 |
|
447 |
return $this; |
448 |
} |
449 |
|
450 |
private function addBeforeCall(call $call)100% |
451 |
{ |
452 |
$this->beforeCalls[] = $call->disableEvaluationChecking(); |
453 |
|
454 |
return $this; |
455 |
} |
456 |
|
457 |
private function addAfterCall(call $call)100% |
458 |
{ |
459 |
$this->afterCalls[] = $call->disableEvaluationChecking(); |
460 |
|
461 |
return $this; |
462 |
} |
463 |
|
464 |
private function addToManager()100% |
465 |
{ |
466 |
if ($this->manager !== null) |
467 |
{ |
468 |
$this->manager->add($this); |
469 |
} |
470 |
|
471 |
return $this; |
472 |
} |
473 |
|
474 |
private function removeFromManager()100% |
475 |
{ |
476 |
if ($this->manager !== null) |
477 |
{ |
478 |
$this->manager->remove($this); |
479 |
} |
480 |
|
481 |
return $this; |
482 |
} |
483 |
} |