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