Passed
Push — master ( eb9f5d...c5bf56 )
by Markus
06:52
created

AssertsPromises::getLoop()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 3
c 1
b 0
f 1
nc 2
nop 0
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
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 6
    public function assertPromiseFulfills($promise, $expectedValue = null): void
22
    {
23 6
        $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 6
        if (! $promise instanceof PromiseInterface) {
26 2
            $promise = all($promise);
27
        }
28
29
        try {
30 6
            $result = $this->waitForPromise($promise);
31 2
        } catch (Exception $_) {
32 2
            $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
        }
47 2
    }
48
49 6
    protected function getLoop(): LoopInterface
50
    {
51 6
        if (! $this->loop) {
52 6
            $this->loop = LoopFactory::create();
53
        }
54
55 6
        return $this->loop;
56
    }
57
58 6
    private function waitForPromise(PromiseInterface $promise)
59
    {
60 6
        $wait = true;
61 6
        $resolved = null;
62 6
        $exception = null;
63 6
        $rejected = false;
64
65 6
        $promise->then(
66
            function ($c) use (&$resolved, &$wait) {
67 4
                $resolved = $c;
68 4
                $wait = false;
69 4
                $this->getLoop()->stop();
70 6
            },
71
            function ($error) use (&$exception, &$rejected, &$wait) {
72 1
                $exception = $error;
73 1
                $rejected = true;
74 1
                $wait = false;
75 1
                $this->getLoop()->stop();
76 6
            }
77
        );
78
79
        // Explicitly overwrite argument with null value. This ensure that this
80
        // argument does not show up in the stack trace in PHP 7+ only.
81 6
        $promise = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $promise is dead and can be removed.
Loading history...
82
83 6
        while ($wait) {
84 6
            $this->getLoop()->run();
85
        }
86
87 5
        if ($rejected) {
88 1
            if (! $exception instanceof Exception) {
89 1
                $type = is_object($exception) ? get_class($exception) : gettype($exception);
90 1
                $exception = new \UnexpectedValueException(
91 1
                    'Promise rejected with unexpected value of type ' . $type,
92 1
                    0,
93 1
                    $exception instanceof \Throwable ? $exception : null
94
                );
95
            }
96
97 1
            throw $exception;
98
        }
99
100 4
        return $resolved;
101
    }
102
}
103