PromiseInterfaceTestCase::pendingThenTest()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 14
nc 1
nop 1
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\Promise;
12
13
use Cubiche\Core\Async\Promise\PromiseInterface;
14
use Cubiche\Core\Async\Promise\State;
15
use Cubiche\Core\Async\Tests\Units\TestCase;
16
use Cubiche\Core\Async\Promise\Deferred;
17
use Cubiche\Core\Async\Promise\RejectedPromise;
18
19
/**
20
 * Promise Interface Test Case Class.
21
 *
22
 * @author Ivannis Suárez Jerez <[email protected]>
23
 * @author Karel Osorio Ramírez <[email protected]>
24
 */
25
abstract class PromiseInterfaceTestCase extends TestCase
26
{
27
    protected $defaultRejectReason;
28
29
    /**
30
     * @return mixed
31
     */
32
    protected function defaultResolveValue()
33
    {
34
        return 'foo';
35
    }
36
37
    /**
38
     * @return mixed
39
     */
40
    protected function defaultRejectReason()
41
    {
42
        if ($this->defaultRejectReason === null) {
43
            $this->defaultRejectReason = new \Exception();
44
        }
45
46
        return $this->defaultRejectReason;
47
    }
48
49
    /**
50
     * Test class.
51
     */
52
    public function testClass()
53
    {
54
        $this
55
            ->testedClass
56
                ->implements(PromiseInterface::class)
57
        ;
58
    }
59
60
    /**
61
     * Test then.
62
     *
63
     * @param PromiseInterface $promise
64
     *
65
     * @dataProvider promiseDataProvider
66
     */
67
    public function testThen(PromiseInterface $promise)
68
    {
69
        $this
70
            ->given($promise)
71
            ->when($then = $promise->then())
72
            ->then()
73
                ->object($then)
74
                    ->isInstanceOf(PromiseInterface::class)
75
                ->boolean($promise->state()->equals($then->state()))
76
                    ->isTrue();
77
78
        if ($promise->state()->equals(State::FULFILLED())) {
79
            $this->fulfilledThenTest($promise);
80
        }
81
82
        if ($promise->state()->equals(State::REJECTED())) {
83
            $this->rejectedThenTest($promise);
84
        }
85
86
        if ($promise->state()->equals(State::PENDING())) {
87
            $this->pendingThenTest($promise);
88
        }
89
    }
90
91
    /**
92
     * @param PromiseInterface $promise
93
     */
94
    protected function fulfilledThenTest(PromiseInterface $promise)
95
    {
96
        $this
97
            ->given(
98
                $onFulfilled = $this->delegateMock(),
99
                $onRejected = $this->delegateMock(),
100
                $onNotify = $this->delegateMock(),
101
                $value = $this->defaultResolveValue()
102
            )
103
            ->when($promise->then($onFulfilled, $onRejected, $onNotify))
104
            ->then()
105
                ->delegateCall($onFulfilled)
106
                    ->withArguments($value)
107
                    ->once()
108
                ->delegateCall($onRejected)
109
                    ->never()
110
                ->delegateCall($onNotify)
111
                    ->never();
112
113
        $this
114
            ->given(
115
                $onFulfilled = $this->delegateMockWithReturn('bar'),
116
                $onFulfilledThen = $this->delegateMock()
117
            )
118
            ->when($promise->then($onFulfilled)->then($onFulfilledThen))
119
            ->then()
120
                ->delegateCall($onFulfilled)
121
                    ->withArguments($value)
122
                    ->once()
123
                ->delegateCall($onFulfilledThen)
124
                    ->withArguments('bar')
125
                    ->once();
126
127
        $this
128
            ->given(
129
                $e = new \Exception(),
130
                $onFulfilled = $this->delegateMockWithException($e),
131
                $onRejectedThen = $this->delegateMock(),
132
                $onFulfilledThen = $this->delegateMock()
133
            )
134
            ->when($promise->then($onFulfilled)->then($onFulfilledThen, $onRejectedThen))
135
            ->then()
136
                ->delegateCall($onFulfilled)
137
                    ->withArguments($value)
138
                    ->once()
139
                ->delegateCall($onFulfilledThen)
140
                    ->never()
141
                ->delegateCall($onRejectedThen)
142
                    ->withArguments($e)
143
                    ->once()
144
        ;
145
146
        $this->chainingTest($promise);
147
    }
148
149
    /**
150
     * @param PromiseInterface $promise
151
     */
152
    protected function chainingTest(PromiseInterface $promise)
153
    {
154
        $this
155
            ->given(
156
                $deferred = new Deferred(),
157
                $onFulfilled = $this->delegateMockWithReturn($deferred->promise())
158
            )
159
            ->when($thenPromise = $promise->then($onFulfilled))
160
            ->then()
161
                ->boolean($thenPromise->state()->equals(State::PENDING()))
162
                    ->isTrue()
163
        ;
164
165
        $this
166
            ->given(
167
                $onFulfilledThen = $this->delegateMock(),
168
                $onNotify = $this->delegateMock()
169
            )
170
            ->when(function () use ($deferred, $thenPromise, $onFulfilledThen, $onNotify) {
171
                $thenPromise->then($onFulfilledThen, null, $onNotify);
172
                $deferred->notify('state');
173
                $deferred->resolve('bar');
174
            })
175
            ->then()
176
                ->delegateCall($onNotify)
177
                    ->withArguments('state')
178
                    ->once()
179
                ->delegateCall($onFulfilledThen)
180
                    ->withArguments('bar')
181
                    ->once()
182
        ;
183
184
        $this
185
            ->given(
186
                $onFulfilled = $this->delegateMockWithReturn(new RejectedPromise($this->defaultRejectReason())),
187
                $onRejectedThen = $this->delegateMock()
188
            )
189
            ->when($promise->then($onFulfilled)->then(null, $onRejectedThen))
190
            ->then()
191
                ->delegateCall($onRejectedThen)
192
                    ->withArguments($this->defaultRejectReason())
193
                    ->once()
194
        ;
195
    }
196
197
    /**
198
     * @param PromiseInterface $promise
199
     */
200
    protected function rejectedThenTest(PromiseInterface $promise)
201
    {
202
        $this
203
            ->given(
204
                $onFulfilled = $this->delegateMock(),
205
                $onRejected = $this->delegateMock(),
206
                $onNotify = $this->delegateMock(),
207
                $reason = $this->defaultRejectReason()
208
            )
209
            ->when($promise->then($onFulfilled, $onRejected, $onNotify))
210
            ->then()
211
                ->delegateCall($onFulfilled)
212
                    ->never()
213
                ->delegateCall($onRejected)
214
                    ->withArguments($reason)
215
                    ->once()
216
                ->delegateCall($onNotify)
217
                    ->never()
218
        ;
219
220
        $this
221
            ->given(
222
                $e = new \Exception(),
223
                $onRejected = $this->delegateMockWithException($e),
224
                $onRejectedThen = $this->delegateMock(),
225
                $onFulfilledThen = $this->delegateMock()
226
            )
227
            ->when($promise->then(null, $onRejected)->then($onFulfilledThen, $onRejectedThen))
228
            ->then()
229
                ->delegateCall($onRejected)
230
                    ->withArguments($reason)
231
                    ->once()
232
                ->delegateCall($onFulfilledThen)
233
                    ->never()
234
                ->delegateCall($onRejectedThen)
235
                     ->withArguments($e)
236
                     ->once();
237
    }
238
239
    /**
240
     * @param PromiseInterface $promise
241
     */
242
    protected function pendingThenTest(PromiseInterface $promise)
243
    {
244
        $this
245
            ->given(
246
                $onFulfilled = $this->delegateMock(),
247
                $onRejected = $this->delegateMock(),
248
                $onNotify = $this->delegateMock()
249
            )
250
            ->when($promise->then($onFulfilled, $onRejected, $onNotify))
251
            ->then()
252
                ->delegateCall($onFulfilled)
253
                    ->never()
254
                ->delegateCall($onRejected)
255
                    ->never()
256
                ->delegateCall($onNotify)
257
                    ->never();
258
    }
259
260
    /**
261
     * Test done.
262
     *
263
     * @param PromiseInterface $promise
264
     *
265
     * @dataProvider promiseDataProvider
266
     */
267
    public function testDone(PromiseInterface $promise)
268
    {
269
        $this
270
            ->given($promise)
271
            ->when($null = $promise->done())
272
            ->then()
273
                ->variable($null)
274
                    ->isNull();
275
276 View Code Duplication
        if ($promise->state()->equals(State::FULFILLED())) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
277
            $this
278
                ->given(
279
                    $onFulfilled = $this->delegateMock(),
280
                    $onRejected = $this->delegateMock(),
281
                    $onNotify = $this->delegateMock(),
282
                    $value = $this->defaultResolveValue()
283
                )
284
                ->when($promise->done($onFulfilled, $onRejected, $onNotify))
285
                ->then()
286
                    ->delegateCall($onFulfilled)
287
                        ->withArguments($value)
288
                        ->once()
289
                    ->delegateCall($onRejected)
290
                        ->never()
291
                    ->delegateCall($onNotify)
292
                        ->never();
293
294
            $this
295
                    ->given(
296
                        $onFulfilled = $this->delegateMockWithException(new \Exception())
297
                    )
298
                    ->exception(function () use ($promise, $onFulfilled) {
299
                        $promise->done($onFulfilled);
300
                    })->isInstanceof(\Exception::class)
301
                ;
302
        }
303
304 View Code Duplication
        if ($promise->state()->equals(State::REJECTED())) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
305
            $this
306
                ->given(
307
                    $onFulfilled = $this->delegateMock(),
308
                    $onRejected = $this->delegateMock(),
309
                    $onNotify = $this->delegateMock(),
310
                    $reason = $this->defaultRejectReason()
311
                )
312
                ->when($promise->done($onFulfilled, $onRejected, $onNotify))
313
                ->then()
314
                    ->delegateCall($onFulfilled)
315
                        ->never()
316
                    ->delegateCall($onRejected)
317
                        ->withArguments($reason)
318
                        ->once()
319
                    ->delegateCall($onNotify)
320
                        ->never()
321
            ;
322
323
            $this
324
                ->given(
325
                    $onRejected = $this->delegateMockWithException(new \Exception())
326
                )
327
                ->exception(function () use ($promise, $onRejected) {
328
                    $promise->done(null, $onRejected);
329
                })->isInstanceof(\Exception::class)
330
            ;
331
        }
332
    }
333
334
    /**
335
     * Test otherwise.
336
     *
337
     * @param PromiseInterface $promise
338
     *
339
     * @dataProvider promiseDataProvider
340
     */
341
    public function testOtherwise(PromiseInterface $promise)
342
    {
343
        $this
344
            ->given(
345
                $promise,
346
                $onRejected = $this->delegateMock()
347
            )
348
            ->when($otherwise = $promise->otherwise($onRejected))
349
            ->then()
350
                ->object($otherwise)
351
                    ->isInstanceOf(PromiseInterface::class)
352
                ->boolean($promise->state()->equals($otherwise->state()))
353
                    ->isTrue();
354
355
        if ($promise->state()->equals(State::FULFILLED())) {
356
            $this
357
                ->then()
358
                    ->delegateCall($onRejected)
359
                        ->never()
360
            ;
361
        }
362
363 View Code Duplication
        if ($promise->state()->equals(State::REJECTED())) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
364
            $this
365
                ->given($reason = $this->defaultRejectReason())
366
                ->then()
367
                    ->delegateCall($onRejected)
368
                        ->withArguments($reason)
369
                        ->once()
370
            ;
371
        }
372
    }
373
374
    /**
375
     * Test always.
376
     *
377
     * @param PromiseInterface $promise
378
     *
379
     * @dataProvider promiseDataProvider
380
     */
381
    public function testAlways(PromiseInterface $promise)
382
    {
383
        $this
384
            ->given(
385
                $promise,
386
                $onFulfilledOrRejected = $this->delegateMock(),
387
                $onNotify = $this->delegateMock()
388
            )
389
            ->when($always = $promise->always($onFulfilledOrRejected, $onNotify))
390
            ->then()
391
                ->object($always)
392
                    ->isInstanceOf(PromiseInterface::class)
393
                ->boolean($promise->state()->equals($always->state()))
394
                    ->isTrue();
395
396
        if ($promise->state()->equals(State::FULFILLED())) {
397
            $this
398
                ->given($value = $this->defaultResolveValue())
399
                ->then()
400
                    ->delegateCall($onFulfilledOrRejected)
401
                        ->withArguments($value)
402
                        ->once()
403
            ;
404
        }
405
406 View Code Duplication
        if ($promise->state()->equals(State::REJECTED())) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
407
            $this
408
                ->given($reason = $this->defaultRejectReason())
409
                ->then()
410
                    ->delegateCall($onFulfilledOrRejected)
411
                        ->withArguments($reason)
412
                        ->once()
413
            ;
414
        }
415
    }
416
417
    /**
418
     * @return array
419
     */
420
    abstract protected function promiseDataProvider();
421
}
422