[TASK] Removes extra empty lines
[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\Tests\Unit\SignalSlot\Fixtures\OnlyClassNameSpecifiedFixture;
18 use TYPO3\CMS\Extbase\Tests\Unit\SignalSlot\Fixtures\SlotMethodDoesNotExistFixture;
19
20 /**
21 * Test case
22 */
23 class DispatcherTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
24 {
25 /**
26 * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher|\PHPUnit_Framework_MockObject_MockObject|\Tx_Phpunit_Interface_AccessibleObject
27 */
28 protected $signalSlotDispatcher;
29
30 protected function setUp()
31 {
32 $accessibleClassName = $this->getAccessibleMock(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class, array('dummy'));
33 $this->signalSlotDispatcher = new $accessibleClassName();
34 }
35
36 /**
37 * @test
38 */
39 public function connectAllowsForConnectingASlotWithASignal()
40 {
41 $mockSignal = $this->getMock('ClassA', array('emitSomeSignal'));
42 $mockSlot = $this->getMock('ClassB', array('someSlotMethod'));
43 $this->signalSlotDispatcher->connect(get_class($mockSignal), 'emitSomeSignal', get_class($mockSlot), 'someSlotMethod', true);
44 $expectedSlots = array(
45 array('class' => get_class($mockSlot), 'method' => 'someSlotMethod', 'object' => null, 'passSignalInformation' => true)
46 );
47 $this->assertSame($expectedSlots, $this->signalSlotDispatcher->getSlots(get_class($mockSignal), 'emitSomeSignal'));
48 }
49
50 /**
51 * @test
52 */
53 public function connectAlsoAcceptsObjectsInPlaceOfTheClassName()
54 {
55 $mockSignal = $this->getMock('ClassA', array('emitSomeSignal'));
56 $mockSlot = $this->getMock('ClassB', array('someSlotMethod'));
57 $this->signalSlotDispatcher->connect(get_class($mockSignal), 'emitSomeSignal', $mockSlot, 'someSlotMethod', true);
58 $expectedSlots = array(
59 array('class' => null, 'method' => 'someSlotMethod', 'object' => $mockSlot, 'passSignalInformation' => true)
60 );
61 $this->assertSame($expectedSlots, $this->signalSlotDispatcher->getSlots(get_class($mockSignal), 'emitSomeSignal'));
62 }
63
64 /**
65 * @test
66 */
67 public function connectAlsoAcceptsClosuresActingAsASlot()
68 {
69 $mockSignal = $this->getMock('ClassA', array('emitSomeSignal'));
70 $mockSlot = function () {
71 };
72 $this->signalSlotDispatcher->connect(get_class($mockSignal), 'emitSomeSignal', $mockSlot, 'foo', true);
73 $expectedSlots = array(
74 array('class' => null, 'method' => '__invoke', 'object' => $mockSlot, 'passSignalInformation' => true)
75 );
76 $this->assertSame($expectedSlots, $this->signalSlotDispatcher->getSlots(get_class($mockSignal), 'emitSomeSignal'));
77 }
78
79 /**
80 * @test
81 */
82 public function dispatchPassesTheSignalArgumentsToTheSlotMethod()
83 {
84 $arguments = array();
85 $mockSlot = function () use (&$arguments) {
86 ($arguments = func_get_args());
87 };
88 $this->signalSlotDispatcher->connect('Foo', 'bar', $mockSlot, null, false);
89 $this->signalSlotDispatcher->dispatch('Foo', 'bar', array('bar', 'quux'));
90 $this->assertSame(array('bar', 'quux'), $arguments);
91 }
92
93 /**
94 * @test
95 */
96 public function dispatchRetrievesSlotInstanceFromTheObjectManagerIfOnlyAClassNameWasSpecified()
97 {
98 $slotClassName = OnlyClassNameSpecifiedFixture::class;
99 $mockSlot = new OnlyClassNameSpecifiedFixture();
100 $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
101 $mockObjectManager->expects($this->once())->method('isRegistered')->with($slotClassName)->will($this->returnValue(true));
102 $mockObjectManager->expects($this->once())->method('get')->with($slotClassName)->will($this->returnValue($mockSlot));
103 $this->signalSlotDispatcher->_set('objectManager', $mockObjectManager);
104 $this->signalSlotDispatcher->_set('isInitialized', true);
105 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $slotClassName, 'slot', false);
106 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', array('bar', 'quux'));
107 $this->assertSame($mockSlot->arguments, array('bar', 'quux'));
108 }
109
110 /**
111 * @test
112 */
113 public function dispatchHandsOverArgumentsReturnedByAFormerSlot()
114 {
115 $this->signalSlotDispatcher->_set('isInitialized', true);
116
117 $firstMockSlot = $this->getMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
118 $firstMockSlot->expects($this->once())
119 ->method('slot')
120 ->will($this->returnCallback(
121 function ($foo, $baz) {
122 return array('modified_' . $foo, 'modified_' . $baz);}
123 ));
124
125 $secondMockSlot = $this->getMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
126 $secondMockSlot->expects($this->once())
127 ->method('slot')
128 ->with('modified_bar', 'modified_quux');
129
130 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $firstMockSlot, 'slot', false);
131 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $secondMockSlot, 'slot', false);
132
133 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', array('bar', 'quux'));
134 }
135
136 /**
137 * @test
138 */
139 public function dispatchHandsOverArgumentsReturnedByAFormerSlotWithoutInterferingWithSignalSlotInformation()
140 {
141 $this->signalSlotDispatcher->_set('isInitialized', true);
142
143 $firstMockSlot = $this->getMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
144 $firstMockSlot->expects($this->once())
145 ->method('slot')
146 ->will($this->returnCallback(
147 function ($foo, $baz) {
148 return array('modified_' . $foo, 'modified_' . $baz);}
149 ));
150
151 $secondMockSlot = $this->getMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
152 $secondMockSlot->expects($this->once())
153 ->method('slot')
154 ->with('modified_bar', 'modified_quux');
155
156 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $firstMockSlot, 'slot');
157 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $secondMockSlot, 'slot');
158
159 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', array('bar', 'quux'));
160 }
161
162 /**
163 * @test
164 */
165 public function dispatchHandsOverFormerArgumentsIfPreviousSlotDoesNotReturnAnything()
166 {
167 $this->signalSlotDispatcher->_set('isInitialized', true);
168
169 $firstMockSlot = $this->getMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
170 $firstMockSlot->expects($this->once())
171 ->method('slot')
172 ->will($this->returnCallback(
173 function ($foo, $baz) {
174 return array('modified_' . $foo, 'modified_' . $baz);}
175 ));
176
177 $secondMockSlot = $this->getMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
178 $secondMockSlot->expects($this->once())
179 ->method('slot');
180
181 $thirdMockSlot = $this->getMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
182 $thirdMockSlot->expects($this->once())
183 ->method('slot')
184 ->with('modified_bar', 'modified_quux');
185
186 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $firstMockSlot, 'slot');
187 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $secondMockSlot, 'slot');
188 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $thirdMockSlot, 'slot');
189
190 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', array('bar', 'quux'));
191 }
192
193 /**
194 * @test
195 * @expectedException \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
196 */
197 public function dispatchThrowsAnExceptionIfTheSlotReturnsNonArray()
198 {
199 $this->signalSlotDispatcher->_set('isInitialized', true);
200
201 $mockSlot = $this->getMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
202 $mockSlot->expects($this->once())
203 ->method('slot')
204 ->will($this->returnCallback(
205 function () {
206 return 'string';}
207 ));
208
209 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $mockSlot, 'slot', false);
210 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', array('bar', 'quux'));
211 }
212
213 /**
214 * @test
215 * @expectedException \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
216 */
217 public function dispatchThrowsAnExceptionIfTheSlotReturnsDifferentNumberOfItems()
218 {
219 $this->signalSlotDispatcher->_set('isInitialized', true);
220
221 $mockSlot = $this->getMock(\TYPO3\CMS\Extbase\Tests\Fixture\SlotFixture::class);
222 $mockSlot->expects($this->once())
223 ->method('slot')
224 ->will($this->returnCallback(
225 function () {
226 return array(1, 2, 3);}
227 ));
228
229 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $mockSlot, 'slot', false);
230 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', array('bar', 'quux'));
231 }
232
233 /**
234 * @test
235 * @expectedException \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
236 */
237 public function dispatchThrowsAnExceptionIfTheSpecifiedClassOfASlotIsUnknown()
238 {
239 $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
240 $mockObjectManager->expects($this->once())->method('isRegistered')->with('NonExistingClassName')->will($this->returnValue(false));
241 $this->signalSlotDispatcher->_set('objectManager', $mockObjectManager);
242 $this->signalSlotDispatcher->_set('isInitialized', true);
243 $this->signalSlotDispatcher->connect('Foo', 'emitBar', 'NonExistingClassName', 'slot', true);
244 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', array());
245 }
246
247 /**
248 * @test
249 * @expectedException \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
250 */
251 public function dispatchThrowsAnExceptionIfTheSpecifiedSlotMethodDoesNotExist()
252 {
253 $slotClassName = SlotMethodDoesNotExistFixture::class;
254 $mockSlot = new SlotMethodDoesNotExistFixture();
255 $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
256 $mockObjectManager->expects($this->once())->method('isRegistered')->with($slotClassName)->will($this->returnValue(true));
257 $mockObjectManager->expects($this->once())->method('get')->with($slotClassName)->will($this->returnValue($mockSlot));
258 $this->signalSlotDispatcher->_set('objectManager', $mockObjectManager);
259 $this->signalSlotDispatcher->_set('isInitialized', true);
260 $this->signalSlotDispatcher->connect('Foo', 'emitBar', $slotClassName, 'unknownMethodName', true);
261 $this->signalSlotDispatcher->dispatch('Foo', 'emitBar', array('bar', 'quux'));
262 $this->assertSame($mockSlot->arguments, array('bar', 'quux'));
263 }
264
265 /**
266 * @test
267 */
268 public function dispatchPassesFirstArgumentContainingSlotInformationIfTheConnectionStatesSo()
269 {
270 $arguments = array();
271 $mockSlot = function () use (&$arguments) {
272 ($arguments = func_get_args());
273 };
274 $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
275 $this->signalSlotDispatcher->connect('SignalClassName', 'methodName', $mockSlot, null, true);
276 $this->signalSlotDispatcher->_set('objectManager', $mockObjectManager);
277 $this->signalSlotDispatcher->_set('isInitialized', true);
278 $this->signalSlotDispatcher->dispatch('SignalClassName', 'methodName', array('bar', 'quux'));
279 $this->assertSame(array('bar', 'quux', 'SignalClassName::methodName'), $arguments);
280 }
281
282 /**
283 * @test
284 * @expectedException \InvalidArgumentException
285 */
286 public function connectThrowsInvalidArgumentExceptionIfSlotMethodNameIsEmptyAndSlotClassNameIsNoClosure()
287 {
288 $this->signalSlotDispatcher->connect('ClassA', 'emitSomeSignal', 'ClassB', '');
289 }
290
291 /**
292 * @test
293 */
294 public function dispatchReturnsEmptyArrayIfSignalNameAndOrSignalClassNameIsNotRegistered()
295 {
296 $this->assertSame(array(), $this->signalSlotDispatcher->dispatch('ClassA', 'someNotRegisteredSignalName'));
297 }
298
299 /**
300 * @test
301 */
302 public function dispatchReturnsEmptyArrayIfSignalDoesNotProvideAnyArguments()
303 {
304 $this->assertSame(array(), $this->signalSlotDispatcher->dispatch('ClassA', 'emitSomeSignal'));
305 }
306
307 /**
308 * @test
309 */
310 public function dispatchReturnsArgumentsArrayAsIsIfSignalIsNotRegistered()
311 {
312 $arguments = array(
313 42,
314 'a string',
315 new \stdClass()
316 );
317 $this->assertSame($arguments, $this->signalSlotDispatcher->dispatch('ClassA', 'emitSomeSignal', $arguments));
318 }
319
320 /**
321 * @test
322 * @expectedException \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
323 */
324 public function dispatchThrowsInvalidSlotExceptionIfObjectManagerOfSignalSlotDispatcherIsNotSet()
325 {
326 $this->signalSlotDispatcher->_set('isInitialized', true);
327 $this->signalSlotDispatcher->_set('objectManager', null);
328 $this->signalSlotDispatcher->_set('slots', array('ClassA' => array('emitSomeSignal' => array(array()))));
329
330 $this->assertSame(null, $this->signalSlotDispatcher->dispatch('ClassA', 'emitSomeSignal'));
331 }
332 }