Completed
Push — master ( b5ca72...63f4f3 )
by Ivannis Suárez
02:05
created

PromiseInterfaceTestCase::testResolvedPromise()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
3
/**
4
 * This file is part of the Cubiche package.
5
 *
6
 * Copyright (c) Cubiche
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
namespace Cubiche\Core\Async\Tests\Units;
12
13
use Cubiche\Core\Async\PromiseInterface;
14
use Cubiche\Tests\TestCase;
15
use mageekguy\atoum\adapter as Adapter;
16
use mageekguy\atoum\annotations\extractor as Extractor;
17
use mageekguy\atoum\asserter\generator as Generator;
18
use mageekguy\atoum\mock\aggregator as MockAggregator;
19
use mageekguy\atoum\test\assertion\manager as Manager;
20
use mageekguy\atoum\tools\variable\analyzer as Analyzer;
21
22
/**
23
 * Promise Interface Test Case Class.
24
 *
25
 * @author Ivannis Suárez Jerez <[email protected]>
26
 * @author Karel Osorio Ramírez <[email protected]>
27
 */
28
abstract class PromiseInterfaceTestCase extends TestCase
29
{
30
    /**
31
     * @param Adapter   $adapter
32
     * @param Extractor $annotationExtractor
33
     * @param Generator $asserterGenerator
34
     * @param Manager   $assertionManager
35
     * @param Closure   $reflectionClassFactory
36
     * @param Closure   $phpExtensionFactory
37
     * @param Analyzer  $analyzer
38
     */
39
    public function __construct(
40
        Adapter $adapter = null,
41
        Extractor $annotationExtractor = null,
42
        Generator $asserterGenerator = null,
43
        Manager $assertionManager = null,
44
        \Closure $reflectionClassFactory = null,
45
        \Closure $phpExtensionFactory = null,
46
        Analyzer $analyzer = null
47
    ) {
48
        parent::__construct(
49
            $adapter,
50
            $annotationExtractor,
51
            $asserterGenerator,
52
            $assertionManager,
53
            $reflectionClassFactory,
54
            $phpExtensionFactory,
55
            $analyzer
56
        );
57
58
        $this
59
            ->getAssertionManager()
60
                ->setHandler('delegateCall', function (MockAggregator $mock) {
61
                    return $this->delegateCall($mock);
62
                })
63
        ;
64
    }
65
66
    /**
67
     * @return PromiseInterface
68
     */
69
    abstract protected function promise();
70
71
    /**
72
     * @param mixed $value
73
     */
74
    abstract protected function resolve($value = null);
75
76
    /**
77
     * @param mixed $reason
78
     */
79
    abstract protected function reject($reason = null);
80
81
    /**
82
     * @param mixed $state
83
     */
84
    abstract protected function notify($state = null);
85
86
    /**
87
     * @return bool
88
     */
89
    abstract protected function cancel();
90
91
    /**
92
     * Test class.
93
     */
94
    public function testClass()
95
    {
96
        $this
97
            ->testedClass
98
                ->implements(PromiseInterface::class)
99
        ;
100
    }
101
102
    /*
103
     * Test then.
104
     */
105
    public function testThen()
106
    {
107
        $this
108
            ->given(
109
                $promise = $this->promise(),
110
                $succeed = $this->delegateMock(),
111
                $rejected = $this->delegateMock(),
112
                $notify = $this->delegateMock()
113
            )
114
            ->when(function () use ($promise, $succeed, $rejected, $notify) {
115
                $promise->then($succeed, $rejected, $notify);
116
                $this->resolve('foo');
117
            })
118
            ->then()
119
                ->delegateCall($succeed)
120
                    ->withArguments('foo')
121
                    ->once()
122
                ->delegateCall($rejected)
123
                    ->never()
124
                ->delegateCall($notify)
125
                    ->never()
126
        ;
127
128
        $this
129
            ->given(
130
                $promise = $this->promise(),
131
                $succeed = $this->delegateMock(),
132
                $rejected = $this->delegateMock(),
133
                $notify = $this->delegateMock(),
134
                $reason = new \Exception()
135
            )
136
            ->when(function () use ($promise, $succeed, $rejected, $notify, $reason) {
137
                $promise->then($succeed, $rejected, $notify);
138
                $this->reject($reason);
139
            })
140
            ->then()
141
                ->delegateCall($succeed)
142
                    ->never()
143
                ->delegateCall($rejected)
144
                    ->withArguments($reason)
145
                    ->once()
146
                ->delegateCall($notify)
147
                    ->never()
148
        ;
149
150
        $this
151
            ->given(
152
                $promise = $this->promise(),
153
                $succeed = $this->delegateMock(),
154
                $rejected = $this->delegateMock(),
155
                $notify = $this->delegateMock()
156
            )
157
            ->when(function () use ($promise, $succeed, $rejected, $notify) {
158
                $promise->then($succeed, $rejected, $notify);
159
                for ($i = 0; $i < 10; ++$i) {
160
                    $this->notify(($i + 1) * 10);
161
                }
162
            })
163
            ->then()
164
                ->delegateCall($succeed)
165
                    ->never()
166
                ->delegateCall($rejected)
167
                    ->never()
168
                ->delegateCall($notify)
169
                    ->exactly(10)
170
        ;
171
172
        $this
173
            ->given(
174
                $promise = $this->promise(),
175
                $succeed = $this->delegateMockWithReturn('bar'),
176
                $rejected = $this->delegateMock(),
177
                $notify = $this->delegateMock(),
178
                $succeedThen = $this->delegateMock()
179
            )
180
            ->let($promiseThen = $promise->then($succeed, $rejected, $notify))
181
            ->when(function () use ($promiseThen, $succeedThen) {
182
                $promiseThen->then($succeedThen);
183
                $this->resolve('foo');
184
            })
185
            ->then()
186
                ->object($promiseThen)
187
                    ->isInstanceOf(PromiseInterface::class)
188
                ->delegateCall($succeed)
189
                    ->withArguments('foo')
190
                    ->once()
191
                ->delegateCall($rejected)
192
                    ->never()
193
                ->delegateCall($notify)
194
                    ->never()
195
                ->delegateCall($succeedThen)
196
                    ->withArguments('bar')
197
                    ->once()
198
        ;
199
    }
200
201
    /**
202
     * Test otherwise.
203
     */
204
    public function testOtherwise()
205
    {
206
        $this
207
            ->given(
208
                $promise = $this->promise(),
209
                $otherwise = $this->delegateMock()
210
            )
211
            ->if($promiseOtherwise = $promise->otherwise($otherwise))
212
            ->when($this->reject($reason = new \Exception()))
213
            ->then()
214
                ->object($promiseOtherwise)
215
                    ->isInstanceOf(PromiseInterface::class)
216
                ->delegateCall($otherwise)
217
                    ->withArguments($reason)
218
                    ->once()
219
        ;
220
221
        $this
222
            ->given(
223
                $promise = $this->promise(),
224
                $succeed = $this->delegateMock(),
225
                $rejected = $this->delegateMock(),
226
                $notify = $this->delegateMock(),
227
                $otherwise = $this->delegateMock()
228
            )
229
            ->if(
230
                $promiseOtherwise = $promise
231
                    ->then($succeed, $rejected, $notify)
232
                    ->otherwise($otherwise)
233
            )
234
            ->when($this->reject($reason = new \Exception()))
235
            ->then()
236
                ->object($promiseOtherwise)
237
                    ->isInstanceOf(PromiseInterface::class)
238
                ->delegateCall($rejected)
239
                    ->withArguments($reason)
240
                    ->once()
241
                ->delegateCall($otherwise)
242
                    ->withArguments($reason)
243
                    ->once()
244
        ;
245
    }
246
247
    /**
248
     * Test always.
249
     */
250
    public function testAlways()
251
    {
252
        $this
253
            ->given(
254
                $promise = $this->promise(),
255
                $notify = $this->delegateMock(),
256
                $finally = $this->delegateMock()
257
            )
258
            ->if($promiseAlways = $promise->always($finally, $notify))
259
            ->when($this->resolve('foo'))
260
            ->then()
261
                ->object($promiseAlways)
262
                    ->isInstanceOf(PromiseInterface::class)
263
                ->delegateCall($finally)
264
                    ->withArguments('foo')
265
                    ->once()
266
                ->delegateCall($notify)
267
                    ->never()
268
        ;
269
270
        $this
271
            ->given(
272
                $promise = $this->promise(),
273
                $notify = $this->delegateMock(),
274
                $finally = $this->delegateMock()
275
            )
276
            ->if($promiseAlways = $promise->always($finally, $notify))
277
            ->when($this->reject($reason = new \Exception()))
278
            ->then()
279
                ->delegateCall($finally)
280
                    ->withArguments(null, $reason)
281
                    ->once()
282
                ->delegateCall($notify)
283
                    ->never()
284
        ;
285
    }
286
287
    /**
288
     * Test cancel.
289
     */
290
    public function testCancel()
291
    {
292
        $this
293
            ->given(
294
                $promise = $this->promise(),
295
                $otherwise = $this->delegateMock()
296
            )
297
            ->if($promise->otherwise($otherwise))
298
            ->when($this->cancel())
299
            ->then()
300
                ->delegateCall($otherwise)
301
                    ->with()
302
                    ->arguments(0, function ($argument) {
303
                        $this->object($argument)->isInstanceOf(\RuntimeException::class);
304
                    })
305
                    ->once()
306
        ;
307
308
        $this
309
            ->given(
310
                $promise = $this->promise(),
311
                $succeed = $this->delegateMock(),
312
                $rejected = $this->delegateMock(),
313
                $notify = $this->delegateMock()
314
            )
315
            ->if($promise->then($succeed, $rejected, $notify))
316
            ->when($this->resolve('foo'))
317
            ->and($this->cancel())
318
            ->then()
319
                ->delegateCall($succeed)
320
                    ->withArguments('foo')
321
                    ->once()
322
                ->delegateCall($rejected)
323
                    ->never()
324
                ->delegateCall($notify)
325
                    ->never()
326
        ;
327
    }
328
329
    /**
330
     * Test resolved promise.
331
     */
332
    public function testResolvedPromise()
333
    {
334
        $this->resolvedRejectedPromiseTest(function () {
335
            $this->resolve();
336
        });
337
    }
338
339
    /**
340
     * Test rejected promise.
341
     */
342
    public function testRejectedPromise()
343
    {
344
        $this->resolvedRejectedPromiseTest(function () {
345
            $this->reject(new \Exception());
346
        });
347
    }
348
349
    /**
350
     * @param callable $when
351
     */
352
    protected function resolvedRejectedPromiseTest(callable $when)
353
    {
354
        $this
355
        ->if($this->promise())
356
            ->when($when)
357
            ->then()
358
            ->exception(function () {
359
                $this->resolve();
360
            })->isInstanceOf(\LogicException::class)
361
            ->exception(function () {
362
                $this->reject();
363
            })->isInstanceOf(\LogicException::class)
364
            ->exception(function () {
365
                $this->notify();
366
            })->isInstanceOf(\LogicException::class)
367
            ;
368
    }
369
370
    /**
371
     * @return \Cubiche\Core\Delegate\Delegate
372
     */
373
    protected function delegateMock($return = null)
374
    {
375
        $mockName = '\mock\Cubiche\Core\Delegate\Delegate';
376
377
        return new $mockName(function ($value = null) use ($return) {
378
            return $return === null ? $value : $return;
379
        });
380
    }
381
382
    /**
383
     * @param mixed $return
384
     *
385
     * @return \Cubiche\Core\Delegate\Delegate
386
     */
387
    protected function delegateMockWithReturn($return)
388
    {
389
        return $this->delegateMock($return);
390
    }
391
392
    /**
393
     * @param MockAggregator $mock
394
     *
395
     * @return mixed
396
     */
397
    protected function delegateCall(MockAggregator $mock)
398
    {
399
        return $this->mock($mock)->call('__invoke');
400
    }
401
}
402