Completed
Push — master ( a71bd7...d6582d )
by Alex
15s queued 13s
created

ListenerProviderTest   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 213
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 10
eloc 74
c 0
b 0
f 0
dl 0
loc 213
rs 10
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
final class ListenerProviderTest extends TestCase
19
{
20
    private EventNameResolverInterface&MockObject $eventNameResolver;
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected '&', expecting T_VARIABLE on line 20 at column 38
Loading history...
21
22
    public function setUp(): void
23
    {
24
        $this->eventNameResolver = $this->getMockForAbstractClass(EventNameResolverInterface::class);
25
    }
26
27
    public function testImplementsListenerProviderInterface(): void
28
    {
29
        $provider = new ListenerProvider();
30
31
        $this->assertInstanceOf(ListenerProviderInterface::class, $provider);
32
    }
33
34
    public function testImplementsAddListenerAwareInterface(): void
35
    {
36
        $provider = new ListenerProvider();
37
38
        $this->assertInstanceOf(AddListenerAwareInterface::class, $provider);
39
    }
40
41
42
    /**
43
     * @param iterable|callable[] $listeners The collection of event listeners to test.
44
     *
45
     * @dataProvider getAddListenersForEventAndGetListenerForEventData
46
     */
47
    public function testAddListenersForEventAndGetListenerForEvent(iterable $listeners): void
48
    {
49
        $provider = new ListenerProvider($this->eventNameResolver);
50
51
        // We resolve the event name twice, once for 'adding' and once for 'getting'
52
        $this->eventNameResolver
53
            ->expects($this->exactly(2))
54
            ->method('resolveEventName')
55
            ->willReturn(\stdClass::class);
56
57
        $event = new \stdClass();
58
59
        $provider->addListenersForEvent($event, $listeners);
60
61
        $collection = $provider->getListenersForEvent($event);
62
63
        $this->assertInstanceOf(ListenerCollectionInterface::class, $collection);
64
65
        $expected = [];
66
        foreach ($listeners as $listener) {
67
            $expected[] = $listener($event);
68
        }
69
70
        $actual = [];
71
        foreach ($collection as $listener) {
72
            $actual[] = $listener($event);
73
        }
74
75
        $this->assertSame($expected, $actual);
76
    }
77
78
    /**
79
     * @return array<mixed>
80
     */
81
    public function getAddListenersForEventAndGetListenerForEventData(): array
82
    {
83
        return [
84
85
            // Empty listener collection test...
86
            [
87
                [],
88
            ],
89
90
            // One Listener (with type hint)
91
            [
92
                [
93
                    static function () {
94
                        return 1;
95
                    },
96
                ],
97
            ],
98
99
            // Three Listeners
100
            [
101
                [
102
                    static function () {
103
                        return 0;
104
                    },
105
                    static function () {
106
                        return 1;
107
                    },
108
                    static function () {
109
                        return 2;
110
                    },
111
                ],
112
            ],
113
114
            // Traversable test
115
            [
116
                new ListenerCollection([
117
                    static function () {
118
                        return 0;
119
                    },
120
                    static function () {
121
                        return 1;
122
                    },
123
                    static function () {
124
                        return 2;
125
                    },
126
                ]),
127
            ],
128
        ];
129
    }
130
131
    public function testGetListenersForEventWillThrowEventListenerExceptionIfTheEventNameCannotBeResolved(): void
132
    {
133
        $provider = new ListenerProvider($this->eventNameResolver);
134
135
        $event = new \stdClass();
136
137
        $exceptionMessage = 'Test exception message';
138
        $exception = new EventNameResolverException($exceptionMessage);
139
140
        $this->eventNameResolver->expects($this->once())
141
            ->method('resolveEventName')
142
            ->with($event)
143
            ->willThrowException($exception);
144
145
        $this->expectException(EventListenerException::class);
146
        $this->expectExceptionMessage(sprintf('Failed to resolve the event name : %s', $exceptionMessage));
147
148
        $provider->getListenersForEvent($event);
149
    }
150
151
    /**
152
     * @dataProvider getAddListenerForEventData
153
     */
154
    public function testAddListenerForEvent(callable $listener, int $priority = 1): void
155
    {
156
        /** @var ListenerProvider&MockObject $provider */
157
        $provider = $this->getMockBuilder(ListenerProvider::class)
158
            ->setConstructorArgs([$this->eventNameResolver])
159
            ->onlyMethods(['createListenerCollection'])
160
            ->getMock();
161
162
        $event = new \stdClass();
163
        $eventName = \stdClass::class;
164
165
        $this->eventNameResolver->expects($this->once())
166
            ->method('resolveEventName')
167
            ->with($event)
168
            ->willReturn($eventName);
169
170
        /** @var ListenerCollectionInterface<mixed>&MockObject $collection */
171
        $collection = $this->getMockForAbstractClass(ListenerCollectionInterface::class);
172
173
        $provider->expects($this->once())
174
            ->method('createListenerCollection')
175
            ->willReturn($collection);
176
177
        $collection->expects($this->once())
178
            ->method('addListener')
179
            ->with($listener, $priority);
180
181
        $provider->addListenerForEvent($event, $listener, $priority);
182
    }
183
184
    /**
185
     * @return array<mixed>
186
     */
187
    public function getAddListenerForEventData(): array
188
    {
189
        return [
190
            [
191
                static function () {
192
                },
193
            ],
194
            [
195
                static function () {
196
                },
197
                100,
198
            ],
199
            [
200
                static function () {
201
                },
202
                -100,
203
            ],
204
        ];
205
    }
206
}
207