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