Passed
Push — master ( 43534e...6dc374 )
by Alex
01:15 queued 12s
created

ListenerProviderTest   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 215
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 10
eloc 73
c 2
b 0
f 0
dl 0
loc 215
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A testAddListenersForEventAndGetListenerForEvent() 0 27 3
A testGetListenersForEventWillThrowEventListenerExceptionIfTheEventNameCannotBeResolved() 0 18 1
A setUp() 0 3 1
A testImplementsListenerProviderInterface() 0 5 1
A testAddListenerForEvent() 0 28 1
A getAddListenerForEventData() 0 16 1
A getAddListenersForEventAndGetListenerForEventData() 0 44 1
A testImplementsAddListenerAwareInterface() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ArpTest\EventDispatcher\Listener;
6
7
use Arp\EventDispatcher\Listener\AddListenerAwareInterface;
8
use Arp\EventDispatcher\Listener\Exception\EventListenerException;
9
use Arp\EventDispatcher\Listener\ListenerCollection;
10
use Arp\EventDispatcher\Listener\ListenerCollectionInterface;
11
use Arp\EventDispatcher\Listener\ListenerProvider;
12
use Arp\EventDispatcher\Resolver\EventNameResolverInterface;
13
use Arp\EventDispatcher\Resolver\Exception\EventNameResolverException;
14
use PHPUnit\Framework\MockObject\MockObject;
15
use PHPUnit\Framework\TestCase;
16
use Psr\EventDispatcher\ListenerProviderInterface;
17
18
/**
19
 * @author  Alex Patterson <[email protected]>
20
 * @package ArpTest\EventDispatcher\Listener
21
 */
22
final class ListenerProviderTest extends TestCase
23
{
24
    /**
25
     * @var EventNameResolverInterface|MockObject
26
     */
27
    private $eventNameResolver;
28
29
    /**
30
     * Prepare the test case dependencies.
31
     *
32
     * @return void
33
     */
34
    public function setUp(): void
35
    {
36
        $this->eventNameResolver = $this->getMockForAbstractClass(EventNameResolverInterface::class);
37
    }
38
39
    /**
40
     * Assert that the listener provider implements ListenerProviderInterface.
41
     *
42
     * @covers \Arp\EventDispatcher\Listener\ListenerProvider
43
     */
44
    public function testImplementsListenerProviderInterface(): void
45
    {
46
        $provider = new ListenerProvider();
47
48
        $this->assertInstanceOf(ListenerProviderInterface::class, $provider);
49
    }
50
51
    /**
52
     * Assert that the listener collection implements AddListenerAwareInterface.
53
     *
54
     * @covers \Arp\EventDispatcher\Listener\ListenerProvider
55
     */
56
    public function testImplementsAddListenerAwareInterface(): void
57
    {
58
        $provider = new ListenerProvider();
59
60
        $this->assertInstanceOf(AddListenerAwareInterface::class, $provider);
61
    }
62
63
64
    /**
65
     * Assert that the listener provider will return a clone of the internal listener collection which contains
66
     * the required event listeners in the correct priority order.
67
     *
68
     * @param iterable|callable[] $listeners The collection of event listeners to test.
69
     *
70
     * @dataProvider getAddListenersForEventAndGetListenerForEventData
71
     */
72
    public function testAddListenersForEventAndGetListenerForEvent(iterable $listeners): void
73
    {
74
        $provider = new ListenerProvider($this->eventNameResolver);
75
76
        $this->eventNameResolver
77
            ->method('resolveEventName')
0 ignored issues
show
Bug introduced by
The method method() does not exist on Arp\EventDispatcher\Reso...ntNameResolverInterface. ( Ignorable by Annotation )

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

77
            ->/** @scrutinizer ignore-call */ 
78
              method('resolveEventName')

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
78
            ->willReturn(\stdClass::class);
79
80
        $event = new \stdClass();
81
82
        $provider->addListenersForEvent($event, $listeners);
83
84
        $collection = $provider->getListenersForEvent($event);
85
86
        $this->assertInstanceOf(ListenerCollectionInterface::class, $collection);
87
88
        $expected = [];
89
        foreach ($listeners as $listener) {
90
            $expected[] = $listener($event);
91
        }
92
93
        $actual = [];
94
        foreach ($collection as $listener) {
95
            $actual[] = $listener($event);
96
        }
97
98
        $this->assertSame($expected, $actual);
99
    }
100
101
    /**
102
     * @return array
103
     */
104
    public function getAddListenersForEventAndGetListenerForEventData(): array
105
    {
106
        return [
107
108
            // Empty listener collection test...
109
            [
110
                [],
111
            ],
112
113
            // One Listener (with type hint)
114
            [
115
                [
116
                    static function () {
117
                        return 1;
118
                    },
119
                ],
120
            ],
121
122
            // Three Listeners
123
            [
124
                [
125
                    static function () {
126
                        return 0;
127
                    },
128
                    static function () {
129
                        return 1;
130
                    },
131
                    static function () {
132
                        return 2;
133
                    },
134
                ],
135
            ],
136
137
            // Traversable test
138
            [
139
                new ListenerCollection([
140
                    static function () {
141
                        return 0;
142
                    },
143
                    static function () {
144
                        return 1;
145
                    },
146
                    static function () {
147
                        return 2;
148
                    },
149
                ]),
150
            ],
151
        ];
152
    }
153
154
    /**
155
     * Assert that a EventListenerException will be thrown if the provided event name cannot be resolved.
156
     *
157
     * @return void
158
     */
159
    public function testGetListenersForEventWillThrowEventListenerExceptionIfTheEventNameCannotBeResolved(): void
160
    {
161
        $provider = new ListenerProvider($this->eventNameResolver);
162
163
        $event = new \stdClass();
164
165
        $exceptionMessage = 'Test exception message';
166
        $exception = new EventNameResolverException($exceptionMessage);
167
168
        $this->eventNameResolver->expects($this->once())
169
            ->method('resolveEventName')
170
            ->with($event)
171
            ->willThrowException($exception);
172
173
        $this->expectException(EventListenerException::class);
174
        $this->expectExceptionMessage(sprintf('Failed to resolve the event name : %s', $exceptionMessage));
175
176
        $provider->getListenersForEvent($event);
177
    }
178
179
    /**
180
     * Assert calls to addListenerForEvent() will fetch a listener collection and add the provided listener.
181
     *
182
     * @param callable $listener
183
     * @param int      $priority
184
     *
185
     * @dataProvider getAddListenerForEventData
186
     * @return void
187
     */
188
    public function testAddListenerForEvent(callable $listener, int $priority = 1): void
189
    {
190
        /** @var ListenerProvider|MockObject $provider */
191
        $provider = $this->getMockBuilder(ListenerProvider::class)
192
            ->setConstructorArgs([$this->eventNameResolver])
193
            ->onlyMethods(['createListenerCollection'])
194
            ->getMock();
195
196
        $event = new \stdClass();
197
        $eventName = \stdClass::class;
198
199
        $this->eventNameResolver->expects($this->once())
200
            ->method('resolveEventName')
201
            ->with($event)
202
            ->willReturn($eventName);
203
204
        /** @var ListenerCollectionInterface|MockObject $collection */
205
        $collection = $this->getMockForAbstractClass(ListenerCollectionInterface::class);
206
207
        $provider->expects($this->once())
208
            ->method('createListenerCollection')
209
            ->willReturn($collection);
210
211
        $collection->expects($this->once())
212
            ->method('addListener')
213
            ->with($listener, $priority);
214
215
        $provider->addListenerForEvent($event, $listener, $priority);
216
    }
217
218
    /**
219
     * @return array
220
     */
221
    public function getAddListenerForEventData(): array
222
    {
223
        return [
224
            [
225
                static function () {
226
                },
227
            ],
228
            [
229
                static function () {
230
                },
231
                100,
232
            ],
233
            [
234
                static function () {
235
                },
236
                -100,
237
            ],
238
        ];
239
    }
240
}
241