[TASK] Add more fixers for php-cs-fixer
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / SignalSlot / DispatcherTest.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Tests\Unit\SignalSlot;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException;
18 use TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException;
19 use TYPO3\CMS\Extbase\Tests\Unit\SignalSlot\Fixtures\OnlyClassNameSpecifiedFixture;
20 use TYPO3\CMS\Extbase\Tests\Unit\SignalSlot\Fixtures\SlotMethodDoesNotExistFixture;
21
22 /**
23 * Test case
24 */
25 class DispatcherTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
26 {
27 /**
28 * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface
29 */
30 protected $signalSlotDispatcher;
31
32 protected function setUp()
33 {
34 $accessibleClassName = $this->getAccessibleMock(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class, ['dummy']);
35 $this->signalSlotDispatcher = new $accessibleClassName();
36 }
37
38 /**
39 * @test
40 */
41 public function connectAllowsForConnectingASlotWithASignal()
42 {
43 $mockSignal = $this->getMockBuilder('ClassA')
44 ->setMethods(['emitSomeSignal'])
45 ->getMock();
46 $mockSlot = $this->getMockBuilder('ClassB')
47 ->setMethods(['someSlotMethod'])
48 ->getMock();
49 $this->signalSlotDispatcher->connect(get_class($mockSignal), 'emitSomeSignal', get_class($mockSlot), 'someSlotMethod', true);
50 $expectedSlots = [
51 ['class' => get_class($mockSlot), 'method' => 'someSlotMethod', 'object' => null, 'passSignalInformation' => true]
52 ];
53 $this->assertSame($expectedSlots, $this->signalSlotDispatcher->getSlots(get_class($mockSignal), 'emitSomeSignal'));
54 }
55
56 /**
57 * @test
58 */
59 public function connectAlsoAcceptsObjectsInPlaceOfTheClassName()
60 {
61 $mockSignal = $this->getMockBuilder('ClassA')
62 ->setMethods(['emitSomeSignal'])
63 ->getMock();
64 $mockSlot = $this->getMockBuilder('ClassB')
65 ->setMethods(['someSlotMethod'])
66 ->getMock();
67 $this->signalSlotDispatcher->connect(get_class($mockSignal), 'emitSomeSignal', $mockSlot, 'someSlotMethod', true);
68 $expectedSlots = [
69 ['class' => null, 'method' => 'someSlotMethod', 'object' => $mockSlot, 'passSignalInformation' => true]
70 ];
71 $this->assertSame($expectedSlots, $this->signalSlotDispatcher->getSlots(get_class($mockSignal), 'emitSomeSignal'));
72 }
73
74 /**
75 * @test
76 */
77 public function connectAlsoAcceptsClosuresActingAsASlot()
78 {
79 $mockSignal = $this->getMockBuilder('ClassA')
80 ->setMethods(['emitSomeSignal'])
81 ->getMock();
82 $mockSlot = function () {
83 };
84 $this->signalSlotDispatcher->connect(get_class($mockSignal), 'emitSomeSignal', $mockSlot, 'foo', true);
85 $expectedSlots = [
86 ['class' => null, 'method' => '__invoke', 'object' => $mockSlot, 'passSignalInformation' => true]
87 ];
88 $this->assertSame($expectedSlots, $this->signalSlotDispatcher->getSlots(get_class($mockSignal), 'emitSomeSignal'));
89 }
90
91 /**
92 * @test
93 */
94 public function dispatchPassesTheSignalArgumentsToTheSlotMethod()
95 {
96 $arguments = [];
97 $mockSlot = function () use (&$arguments) {
98 ($arguments = func_get_args());
99 };
100 $this->signalSlotDispatcher->connect('Foo', 'bar', $mockSlot, null, false);
101 $this->signalSlotDispatcher->dispatch('Foo', 'bar', ['bar', 'quux']);
102 $this->assertSame(['bar', 'quux'], $arguments);
103 }
104
105 /**
106 * @test
107 */
108 public function dispatchRetrievesSlotInstanceFromTheObjectManagerIfOnlyAClassNameWasSpecified()
109 {
110 $slotClassName = OnlyClassNameSpecifiedFixture::class;
111 $mockSlot = new OnlyClassNameSpecifiedFixture();
112 $mockObjectManager = $this->createMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
113 $mockObjectManager->expects($this->once())->method('isRegistered')->with($slotClassName)->will($this->returnValue(true));
114 $mockObjectManager->expects($this->once())->method('get')->with($slotClassName)->will($this->returnValue($mockSlot));
115 $this->signalSlotDispatcher->_set('objectManager', $mockObjectManager);
116 $this->signalSlotDispatcher->_set('isInitialized', true);
117 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $slotClassName, 'slot', false);
118 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', ['bar', 'quux']);
119 $this->assertSame($mockSlot->arguments, ['bar', 'quux']);
120 }
121
122 /**
123 * @test
124 */
125 public function dispatchHandsOverArgumentsReturnedByAFormerSlot()
126 {
127 $this->signalSlotDispatcher->_set('isInitialized', true);
128
129 $firstMockSlot = $this->createMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
130 $firstMockSlot->expects($this->once())
131 ->method('slot')
132 ->will($this->returnCallback(
133 function ($foo, $baz) {
134 return ['modified_' . $foo, 'modified_' . $baz];
135 }
136 ));
137
138 $secondMockSlot = $this->createMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
139 $secondMockSlot->expects($this->once())
140 ->method('slot')
141 ->with('modified_bar', 'modified_quux');
142
143 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $firstMockSlot, 'slot', false);
144 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $secondMockSlot, 'slot', false);
145
146 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', ['bar', 'quux']);
147 }
148
149 /**
150 * @test
151 */
152 public function dispatchHandsOverArgumentsReturnedByAFormerSlotWithoutInterferingWithSignalSlotInformation()
153 {
154 $this->signalSlotDispatcher->_set('isInitialized', true);
155
156 $firstMockSlot = $this->createMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
157 $firstMockSlot->expects($this->once())
158 ->method('slot')
159 ->will($this->returnCallback(
160 function ($foo, $baz) {
161 return ['modified_' . $foo, 'modified_' . $baz];
162 }
163 ));
164
165 $secondMockSlot = $this->createMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
166 $secondMockSlot->expects($this->once())
167 ->method('slot')
168 ->with('modified_bar', 'modified_quux');
169
170 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $firstMockSlot, 'slot');
171 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $secondMockSlot, 'slot');
172
173 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', ['bar', 'quux']);
174 }
175
176 /**
177 * @test
178 */
179 public function dispatchHandsOverFormerArgumentsIfPreviousSlotDoesNotReturnAnything()
180 {
181 $this->signalSlotDispatcher->_set('isInitialized', true);
182
183 $firstMockSlot = $this->createMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
184 $firstMockSlot->expects($this->once())
185 ->method('slot')
186 ->will($this->returnCallback(
187 function ($foo, $baz) {
188 return ['modified_' . $foo, 'modified_' . $baz];
189 }
190 ));
191
192 $secondMockSlot = $this->createMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
193 $secondMockSlot->expects($this->once())
194 ->method('slot');
195
196 $thirdMockSlot = $this->createMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
197 $thirdMockSlot->expects($this->once())
198 ->method('slot')
199 ->with('modified_bar', 'modified_quux');
200
201 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $firstMockSlot, 'slot');
202 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $secondMockSlot, 'slot');
203 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $thirdMockSlot, 'slot');
204
205 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', ['bar', 'quux']);
206 }
207
208 /**
209 * @test
210 */
211 public function dispatchThrowsAnExceptionIfTheSlotReturnsNonArray()
212 {
213 $this->expectException(InvalidSlotReturnException::class);
214 $this->expectExceptionCode(1376683067);
215 $this->signalSlotDispatcher->_set('isInitialized', true);
216
217 $mockSlot = $this->createMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
218 $mockSlot->expects($this->once())
219 ->method('slot')
220 ->will($this->returnCallback(
221 function () {
222 return 'string';
223 }
224 ));
225
226 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $mockSlot, 'slot', false);
227 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', ['bar', 'quux']);
228 }
229
230 /**
231 * @test
232 */
233 public function dispatchThrowsAnExceptionIfTheSlotReturnsDifferentNumberOfItems()
234 {
235 $this->expectException(InvalidSlotReturnException::class);
236 $this->expectExceptionCode(1376683066);
237 $this->signalSlotDispatcher->_set('isInitialized', true);
238
239 $mockSlot = $this->createMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
240 $mockSlot->expects($this->once())
241 ->method('slot')
242 ->will($this->returnCallback(
243 function () {
244 return [1, 2, 3];
245 }
246 ));
247
248 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $mockSlot, 'slot', false);
249 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', ['bar', 'quux']);
250 }
251
252 /**
253 * @test
254 */
255 public function dispatchThrowsAnExceptionIfTheSpecifiedClassOfASlotIsUnknown()
256 {
257 $this->expectException(InvalidSlotException::class);
258 $this->expectExceptionCode(1245673367);
259 $mockObjectManager = $this->createMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
260 $mockObjectManager->expects($this->once())->method('isRegistered')->with('NonExistingClassName')->will($this->returnValue(false));
261 $this->signalSlotDispatcher->_set('objectManager', $mockObjectManager);
262 $this->signalSlotDispatcher->_set('isInitialized', true);
263 $this->signalSlotDispatcher->connect('Foo', 'emitBar', 'NonExistingClassName', 'slot', true);
264 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', []);
265 }
266
267 /**
268 * @test
269 */
270 public function dispatchThrowsAnExceptionIfTheSpecifiedSlotMethodDoesNotExist()
271 {
272 $this->expectException(InvalidSlotException::class);
273 $this->expectExceptionCode(1245673368);
274 $slotClassName = SlotMethodDoesNotExistFixture::class;
275 $mockSlot = new SlotMethodDoesNotExistFixture();
276 $mockObjectManager = $this->createMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
277 $mockObjectManager->expects($this->once())->method('isRegistered')->with($slotClassName)->will($this->returnValue(true));
278 $mockObjectManager->expects($this->once())->method('get')->with($slotClassName)->will($this->returnValue($mockSlot));
279 $this->signalSlotDispatcher->_set('objectManager', $mockObjectManager);
280 $this->signalSlotDispatcher->_set('isInitialized', true);
281 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $slotClassName, 'unknownMethodName', true);
282 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', ['bar', 'quux']);
283 $this->assertSame($mockSlot->arguments, ['bar', 'quux']);
284 }
285
286 /**
287 * @test
288 */
289 public function dispatchPassesFirstArgumentContainingSlotInformationIfTheConnectionStatesSo()
290 {
291 $arguments = [];
292 $mockSlot = function () use (&$arguments) {
293 ($arguments = func_get_args());
294 };
295 $mockObjectManager = $this->createMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
296 $this->signalSlotDispatcher->connect('SignalClassName', 'methodName', $mockSlot, null, true);
297 $this->signalSlotDispatcher->_set('objectManager', $mockObjectManager);
298 $this->signalSlotDispatcher->_set('isInitialized', true);
299 $this->signalSlotDispatcher->dispatch('SignalClassName', 'methodName', ['bar', 'quux']);
300 $this->assertSame(['bar', 'quux', 'SignalClassName::methodName'], $arguments);
301 }
302
303 /**
304 * @test
305 */
306 public function connectThrowsInvalidArgumentExceptionIfSlotMethodNameIsEmptyAndSlotClassNameIsNoClosure()
307 {
308 $this->expectException(\InvalidArgumentException::class);
309 $this->expectExceptionCode(1229531659);
310 $this->signalSlotDispatcher->connect('ClassA', 'emitSomeSignal', 'ClassB', '');
311 }
312
313 /**
314 * @test
315 */
316 public function dispatchReturnsEmptyArrayIfSignalNameAndOrSignalClassNameIsNotRegistered()
317 {
318 $this->assertSame([], $this->signalSlotDispatcher->dispatch('ClassA', 'someNotRegisteredSignalName'));
319 }
320
321 /**
322 * @test
323 */
324 public function dispatchReturnsEmptyArrayIfSignalDoesNotProvideAnyArguments()
325 {
326 $this->assertSame([], $this->signalSlotDispatcher->dispatch('ClassA', 'emitSomeSignal'));
327 }
328
329 /**
330 * @test
331 */
332 public function dispatchReturnsArgumentsArrayAsIsIfSignalIsNotRegistered()
333 {
334 $arguments = [
335 42,
336 'a string',
337 new \stdClass()
338 ];
339 $this->assertSame($arguments, $this->signalSlotDispatcher->dispatch('ClassA', 'emitSomeSignal', $arguments));
340 }
341
342 /**
343 * @test
344 */
345 public function dispatchThrowsInvalidSlotExceptionIfObjectManagerOfSignalSlotDispatcherIsNotSet()
346 {
347 $this->expectException(InvalidSlotException::class);
348 $this->expectExceptionCode(1298113624);
349 $this->signalSlotDispatcher->_set('isInitialized', true);
350 $this->signalSlotDispatcher->_set('objectManager', null);
351 $this->signalSlotDispatcher->_set('slots', ['ClassA' => ['emitSomeSignal' => [[]]]]);
352
353 $this->assertSame(null, $this->signalSlotDispatcher->dispatch('ClassA', 'emitSomeSignal'));
354 }
355 }