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

AssertsPromises   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 88
Duplicated Lines 0 %

Test Coverage

Coverage 76.09%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 44
c 1
b 0
f 1
dl 0
loc 88
ccs 35
cts 46
cp 0.7609
rs 10
wmc 13

3 Methods

Rating   Name   Duplication   Size   Complexity  
B waitForPromise() 0 43 6
A getLoop() 0 7 2
A assertPromiseFulfills() 0 24 5
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 5
    public function assertPromiseFulfills($promise, $expectedValue = null): void
22
    {
23 5
        $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 5
        if (! $promise instanceof PromiseInterface) {
26 2
            $promise = all($promise);
27
        }
28
29
        try {
30 5
            $result = $this->waitForPromise($promise);
31 1
        } catch (Exception $_) {
32 1
            $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 5
    protected function getLoop(): LoopInterface
50
    {
51 5
        if (! $this->loop) {
52 5
            $this->loop = LoopFactory::create();
53
        }
54
55 5
        return $this->loop;
56
    }
57
58 5
    private function waitForPromise(PromiseInterface $promise)
59
    {
60 5
        $wait = true;
61 5
        $resolved = null;
62 5
        $exception = null;
63 5
        $rejected = false;
64
65 5
        $promise->then(
66
            function ($c) use (&$resolved, &$wait) {
67 4
                $resolved = $c;
68 4
                $wait = false;
69 4
                $this->getLoop()->stop();
70 5
            },
71
            function ($error) use (&$exception, &$rejected, &$wait) {
72
                $exception = $error;
73
                $rejected = true;
74
                $wait = false;
75
                $this->getLoop()->stop();
76 5
            }
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 5
        $promise = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $promise is dead and can be removed.
Loading history...
82
83 5
        while ($wait) {
84 5
            $this->getLoop()->run();
85
        }
86
87 4
        if ($rejected) {
88
            if (! $exception instanceof Exception) {
89
                $type = is_object($exception) ? get_class($exception) : gettype($exception);
90
                $exception = new \UnexpectedValueException(
91
                    'Promise rejected with unexpected value of type ' . $type,
92
                    0,
93
                    $exception instanceof \Throwable ? $exception : null
94
                );
95
            }
96
97
            throw $exception;
98
        }
99
100 4
        return $resolved;
101
    }
102
}
103