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 |
} |