Passed
Pull Request — master (#29)
by Markus
04:26
created

AssertsPromises::assertPromiseFulfills()   A

Complexity

Conditions 5
Paths 12

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 5.0592

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 5
eloc 16
c 1
b 0
f 1
nc 12
nop 2
dl 0
loc 26
ccs 13
cts 15
cp 0.8667
crap 5.0592
rs 9.4222
1
<?php
2
3
namespace Butler\Graphql\Concerns;
4
5
use Closure;
6
use Exception;
7
use React\EventLoop\Factory as LoopFactory;
8
use React\EventLoop\LoopInterface;
9
use React\Promise\PromiseInterface;
10
11
use function React\Promise\all;
12
13
trait AssertsPromises
14
{
15
    private $loop;
16
17
    /**
18
     * @param  \React\Promise\PromiseInterface|array  $promise
19
     * @param  mixed|Closure  $expectedValue
20
     */
21 4
    public function assertPromiseFulfills($promise, $expectedValue = null): void
22
    {
23 4
        $this->addToAssertionCount(1);
0 ignored issues
show
Bug introduced by
It seems like addToAssertionCount() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

23
        $this->/** @scrutinizer ignore-call */ 
24
               addToAssertionCount(1);
Loading history...
24
25 4
        if (! $promise instanceof PromiseInterface) {
26 2
            $promise = all($promise);
27
        }
28
29
        try {
30 4
            $result = $this->waitForPromise($promise);
31
        } catch (Exception $_) {
32
            $this->fail('Failed asserting that promise fulfills. Promise was rejected.');
0 ignored issues
show
Bug introduced by
It seems like fail() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

32
            $this->/** @scrutinizer ignore-call */ 
33
                   fail('Failed asserting that promise fulfills. Promise was rejected.');
Loading history...
33
        }
34
35 4
        if ($expectedValue instanceof Closure) {
36 1
            $this->assertTrue($expectedValue($result));
0 ignored issues
show
Bug introduced by
It seems like assertTrue() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

36
            $this->/** @scrutinizer ignore-call */ 
37
                   assertTrue($expectedValue($result));
Loading history...
37 1
            return;
38
        }
39
40 3
        if (! is_null($expectedValue)) {
41 3
            $this->assertEquals(
0 ignored issues
show
Bug introduced by
It seems like assertEquals() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

41
            $this->/** @scrutinizer ignore-call */ 
42
                   assertEquals(
Loading history...
42 3
                $expectedValue,
43
                $result,
44 3
                'Failed asserting that promise fulfills with a specified value.'
45
            );
46 2
            return;
47
        }
48
    }
49
50 4
    protected function getLoop(): LoopInterface
51
    {
52 4
        if (! $this->loop) {
53 4
            $this->loop = LoopFactory::create();
54
        }
55
56 4
        return $this->loop;
57
    }
58
59 4
    private function waitForPromise(PromiseInterface $promise)
60
    {
61 4
        $wait = true;
62 4
        $resolved = null;
63 4
        $exception = null;
64 4
        $rejected = false;
65
66 4
        $promise->then(
67
            function ($c) use (&$resolved, &$wait) {
68 4
                $resolved = $c;
69 4
                $wait = false;
70 4
                $this->getLoop()->stop();
71 4
            },
72
            function ($error) use (&$exception, &$rejected, &$wait) {
73
                $exception = $error;
74
                $rejected = true;
75
                $wait = false;
76
                $this->getLoop()->stop();
77 4
            }
78
        );
79
80
        // Explicitly overwrite argument with null value. This ensure that this
81
        // argument does not show up in the stack trace in PHP 7+ only.
82 4
        $promise = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $promise is dead and can be removed.
Loading history...
83
84 4
        while ($wait) {
85 4
            $this->getLoop()->run();
86
        }
87
88 4
        if ($rejected) {
89
            if (! $exception instanceof Exception) {
90
                $type = is_object($exception) ? get_class($exception) : gettype($exception);
91
                $exception = new \UnexpectedValueException(
92
                    'Promise rejected with unexpected value of type ' . $type,
93
                    0,
94
                    $exception instanceof \Throwable ? $exception : null
95
                );
96
            }
97
98
            throw $exception;
99
        }
100
101 4
        return $resolved;
102
    }
103
}
104