統計
| ブランチ: | リビジョン:

pictcode / lib / Cake / Test / Case / Event / CakeEventManagerTest.php @ 0b1b8047

履歴 | 表示 | アノテート | ダウンロード (16.634 KB)

1 635eef61 spyder1211
<?php
2
/**
3
 * CakePHP : Rapid Development Framework (http://cakephp.org)
4
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
5
 *
6
 * Licensed under The MIT License
7
 * For full copyright and license information, please see the LICENSE.txt
8
 * Redistributions of files must retain the above copyright notice.
9
 *
10
 * @copyright          Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
11
 * @link                  http://cakephp.org CakePHP Project
12
 * @package                  Cake.Test.Case.Event
13
 * @since                  CakePHP v 2.1
14
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
15
 */
16
17
App::uses('CakeEvent', 'Event');
18
App::uses('CakeEventManager', 'Event');
19
App::uses('CakeEventListener', 'Event');
20
21
/**
22
 * Mock class used to test event dispatching
23
 *
24
 * @package Cake.Test.Case.Event
25
 */
26
class CakeEventTestListener {
27
28
        public $callStack = array();
29
30
/**
31
 * Test function to be used in event dispatching
32
 *
33
 * @return void
34
 */
35
        public function listenerFunction() {
36
                $this->callStack[] = __FUNCTION__;
37
        }
38
39
/**
40
 * Test function to be used in event dispatching
41
 *
42
 * @return void
43
 */
44
        public function secondListenerFunction() {
45
                $this->callStack[] = __FUNCTION__;
46
        }
47
48
/**
49
 * Auxiliary function to help in stopPropagation testing
50
 *
51
 * @param CakeEvent $event
52
 * @return void
53
 */
54
        public function stopListener($event) {
55
                $event->stopPropagation();
56
        }
57
58
}
59
60
/**
61
 * Mock used for testing the subscriber objects
62
 *
63
 * @package Cake.Test.Case.Event
64
 */
65
class CustomTestEventListener extends CakeEventTestListener implements CakeEventListener {
66
67
        public function implementedEvents() {
68
                return array(
69
                        'fake.event' => 'listenerFunction',
70
                        'another.event' => array('callable' => 'secondListenerFunction', 'passParams' => true),
71
                        'multiple.handlers' => array(
72
                                array('callable' => 'listenerFunction'),
73
                                array('callable' => 'thirdListenerFunction')
74
                        )
75
                );
76
        }
77
78
/**
79
 * Test function to be used in event dispatching
80
 *
81
 * @return void
82
 */
83
        public function thirdListenerFunction() {
84
                $this->callStack[] = __FUNCTION__;
85
        }
86
87
}
88
89
/**
90
 * Tests the CakeEventManager class functionality
91
 */
92
class CakeEventManagerTest extends CakeTestCase {
93
94
/**
95
 * Tests the attach() method for a single event key in multiple queues
96
 *
97
 * @return void
98
 */
99
        public function testAttachListeners() {
100
                $manager = new CakeEventManager();
101
                $manager->attach('fakeFunction', 'fake.event');
102
                $expected = array(
103
                        array('callable' => 'fakeFunction', 'passParams' => false)
104
                );
105
                $this->assertEquals($expected, $manager->listeners('fake.event'));
106
107
                $manager->attach('fakeFunction2', 'fake.event');
108
                $expected[] = array('callable' => 'fakeFunction2', 'passParams' => false);
109
                $this->assertEquals($expected, $manager->listeners('fake.event'));
110
111
                $manager->attach('inQ5', 'fake.event', array('priority' => 5));
112
                $manager->attach('inQ1', 'fake.event', array('priority' => 1));
113
                $manager->attach('otherInQ5', 'fake.event', array('priority' => 5));
114
115
                $expected = array_merge(
116
                        array(
117
                                array('callable' => 'inQ1', 'passParams' => false),
118
                                array('callable' => 'inQ5', 'passParams' => false),
119
                                array('callable' => 'otherInQ5', 'passParams' => false)
120
                        ),
121
                        $expected
122
                );
123
                $this->assertEquals($expected, $manager->listeners('fake.event'));
124
        }
125
126
/**
127
 * Tests the attach() method for multiple event key in multiple queues
128
 *
129
 * @return void
130
 */
131
        public function testAttachMultipleEventKeys() {
132
                $manager = new CakeEventManager();
133
                $manager->attach('fakeFunction', 'fake.event');
134
                $manager->attach('fakeFunction2', 'another.event');
135
                $manager->attach('fakeFunction3', 'another.event', array('priority' => 1, 'passParams' => true));
136
                $expected = array(
137
                        array('callable' => 'fakeFunction', 'passParams' => false)
138
                );
139
                $this->assertEquals($expected, $manager->listeners('fake.event'));
140
141
                $expected = array(
142
                        array('callable' => 'fakeFunction3', 'passParams' => true),
143
                        array('callable' => 'fakeFunction2', 'passParams' => false)
144
                );
145
                $this->assertEquals($expected, $manager->listeners('another.event'));
146
        }
147
148
/**
149
 * Tests detaching an event from a event key queue
150
 *
151
 * @return void
152
 */
153
        public function testDetach() {
154
                $manager = new CakeEventManager();
155
                $manager->attach(array('AClass', 'aMethod'), 'fake.event');
156
                $manager->attach(array('AClass', 'anotherMethod'), 'another.event');
157
                $manager->attach('fakeFunction', 'another.event', array('priority' => 1));
158
159
                $manager->detach(array('AClass', 'aMethod'), 'fake.event');
160
                $this->assertEquals(array(), $manager->listeners('fake.event'));
161
162
                $manager->detach(array('AClass', 'anotherMethod'), 'another.event');
163
                $expected = array(
164
                        array('callable' => 'fakeFunction', 'passParams' => false)
165
                );
166
                $this->assertEquals($expected, $manager->listeners('another.event'));
167
168
                $manager->detach('fakeFunction', 'another.event');
169
                $this->assertEquals(array(), $manager->listeners('another.event'));
170
        }
171
172
/**
173
 * Tests detaching an event from all event queues
174
 *
175
 * @return void
176
 */
177
        public function testDetachFromAll() {
178
                $manager = new CakeEventManager();
179
                $manager->attach(array('AClass', 'aMethod'), 'fake.event');
180
                $manager->attach(array('AClass', 'aMethod'), 'another.event');
181
                $manager->attach('fakeFunction', 'another.event', array('priority' => 1));
182
183
                $manager->detach(array('AClass', 'aMethod'));
184
                $expected = array(
185
                        array('callable' => 'fakeFunction', 'passParams' => false)
186
                );
187
                $this->assertEquals($expected, $manager->listeners('another.event'));
188
                $this->assertEquals(array(), $manager->listeners('fake.event'));
189
        }
190
191
/**
192
 * Tests event dispatching
193
 *
194
 * @return void
195
 * @triggers fake.event
196
 */
197
        public function testDispatch() {
198
                $manager = new CakeEventManager();
199
                $listener = $this->getMock('CakeEventTestListener');
200
                $anotherListener = $this->getMock('CakeEventTestListener');
201
                $manager->attach(array($listener, 'listenerFunction'), 'fake.event');
202
                $manager->attach(array($anotherListener, 'listenerFunction'), 'fake.event');
203
                $event = new CakeEvent('fake.event');
204
205
                $listener->expects($this->once())->method('listenerFunction')->with($event);
206
                $anotherListener->expects($this->once())->method('listenerFunction')->with($event);
207
                $manager->dispatch($event);
208
        }
209
210
/**
211
 * Tests event dispatching using event key name
212
 *
213
 * @return void
214
 */
215
        public function testDispatchWithKeyName() {
216
                $manager = new CakeEventManager();
217
                $listener = new CakeEventTestListener();
218
                $manager->attach(array($listener, 'listenerFunction'), 'fake.event');
219
                $event = 'fake.event';
220
                $manager->dispatch($event);
221
222
                $expected = array('listenerFunction');
223
                $this->assertEquals($expected, $listener->callStack);
224
        }
225
226
/**
227
 * Tests event dispatching with a return value
228
 *
229
 * @return void
230
 * @triggers fake.event
231
 */
232
        public function testDispatchReturnValue() {
233
                $this->skipIf(
234
                        version_compare(PHPUnit_Runner_Version::id(), '3.7', '<'),
235
                        'These tests fail in PHPUnit 3.6'
236
                );
237
                $manager = new CakeEventManager();
238
                $listener = $this->getMock('CakeEventTestListener');
239
                $anotherListener = $this->getMock('CakeEventTestListener');
240
                $manager->attach(array($listener, 'listenerFunction'), 'fake.event');
241
                $manager->attach(array($anotherListener, 'listenerFunction'), 'fake.event');
242
                $event = new CakeEvent('fake.event');
243
244
                $listener->expects($this->at(0))->method('listenerFunction')
245
                        ->with($event)
246
                        ->will($this->returnValue('something special'));
247
                $anotherListener->expects($this->at(0))
248
                        ->method('listenerFunction')
249
                        ->with($event);
250
                $manager->dispatch($event);
251
                $this->assertEquals('something special', $event->result);
252
        }
253
254
/**
255
 * Tests that returning false in a callback stops the event
256
 *
257
 * @return void
258
 * @triggers fake.event
259
 */
260
        public function testDispatchFalseStopsEvent() {
261
                $this->skipIf(
262
                        version_compare(PHPUnit_Runner_Version::id(), '3.7', '<'),
263
                        'These tests fail in PHPUnit 3.6'
264
                );
265
266
                $manager = new CakeEventManager();
267
                $listener = $this->getMock('CakeEventTestListener');
268
                $anotherListener = $this->getMock('CakeEventTestListener');
269
                $manager->attach(array($listener, 'listenerFunction'), 'fake.event');
270
                $manager->attach(array($anotherListener, 'listenerFunction'), 'fake.event');
271
                $event = new CakeEvent('fake.event');
272
273
                $listener->expects($this->at(0))->method('listenerFunction')
274
                        ->with($event)
275
                        ->will($this->returnValue(false));
276
                $anotherListener->expects($this->never())
277
                        ->method('listenerFunction');
278
                $manager->dispatch($event);
279
                $this->assertTrue($event->isStopped());
280
        }
281
282
/**
283
 * Tests event dispatching using priorities
284
 *
285
 * @return void
286
 * @triggers fake.event
287
 */
288
        public function testDispatchPrioritized() {
289
                $manager = new CakeEventManager();
290
                $listener = new CakeEventTestListener();
291
                $manager->attach(array($listener, 'listenerFunction'), 'fake.event');
292
                $manager->attach(array($listener, 'secondListenerFunction'), 'fake.event', array('priority' => 5));
293
                $event = new CakeEvent('fake.event');
294
                $manager->dispatch($event);
295
296
                $expected = array('secondListenerFunction', 'listenerFunction');
297
                $this->assertEquals($expected, $listener->callStack);
298
        }
299
300
/**
301
 * Tests event dispatching with passed params
302
 *
303
 * @return void
304
 * @triggers fake.event $this, array('some' => 'data')
305
 */
306
        public function testDispatchPassingParams() {
307
                $manager = new CakeEventManager();
308
                $listener = $this->getMock('CakeEventTestListener');
309
                $anotherListener = $this->getMock('CakeEventTestListener');
310
                $manager->attach(array($listener, 'listenerFunction'), 'fake.event');
311
                $manager->attach(array($anotherListener, 'secondListenerFunction'), 'fake.event', array('passParams' => true));
312
                $event = new CakeEvent('fake.event', $this, array('some' => 'data'));
313
314
                $listener->expects($this->once())->method('listenerFunction')->with($event);
315
                $anotherListener->expects($this->once())->method('secondListenerFunction')->with('data');
316
                $manager->dispatch($event);
317
        }
318
319
/**
320
 * Tests subscribing a listener object and firing the events it subscribed to
321
 *
322
 * @return void
323
 * @triggers fake.event
324
 * @triggers another.event $this, array('some' => 'data')
325
 * @triggers multiple.handlers
326
 */
327
        public function testAttachSubscriber() {
328
                $manager = new CakeEventManager();
329
                $listener = $this->getMock('CustomTestEventListener', array('secondListenerFunction'));
330
                $manager->attach($listener);
331
                $event = new CakeEvent('fake.event');
332
333
                $manager->dispatch($event);
334
335
                $expected = array('listenerFunction');
336
                $this->assertEquals($expected, $listener->callStack);
337
338
                $listener->expects($this->at(0))->method('secondListenerFunction')->with('data');
339
                $event = new CakeEvent('another.event', $this, array('some' => 'data'));
340
                $manager->dispatch($event);
341
342
                $manager = new CakeEventManager();
343
                $listener = $this->getMock('CustomTestEventListener', array('listenerFunction', 'thirdListenerFunction'));
344
                $manager->attach($listener);
345
                $event = new CakeEvent('multiple.handlers');
346
                $listener->expects($this->once())->method('listenerFunction')->with($event);
347
                $listener->expects($this->once())->method('thirdListenerFunction')->with($event);
348
                $manager->dispatch($event);
349
        }
350
351
/**
352
 * Tests subscribing a listener object and firing the events it subscribed to
353
 *
354
 * @return void
355
 */
356
        public function testDetachSubscriber() {
357
                $manager = new CakeEventManager();
358
                $listener = $this->getMock('CustomTestEventListener', array('secondListenerFunction'));
359
                $manager->attach($listener);
360
                $expected = array(
361
                        array('callable' => array($listener, 'secondListenerFunction'), 'passParams' => true)
362
                );
363
                $this->assertEquals($expected, $manager->listeners('another.event'));
364
                $expected = array(
365
                        array('callable' => array($listener, 'listenerFunction'), 'passParams' => false)
366
                );
367
                $this->assertEquals($expected, $manager->listeners('fake.event'));
368
                $manager->detach($listener);
369
                $this->assertEquals(array(), $manager->listeners('fake.event'));
370
                $this->assertEquals(array(), $manager->listeners('another.event'));
371
        }
372
373
/**
374
 * Tests that it is possible to get/set the manager singleton
375
 *
376
 * @return void
377
 */
378
        public function testGlobalDispatcherGetter() {
379
                $this->assertInstanceOf('CakeEventManager', CakeEventManager::instance());
380
                $manager = new CakeEventManager();
381
382
                CakeEventManager::instance($manager);
383
                $this->assertSame($manager, CakeEventManager::instance());
384
        }
385
386
/**
387
 * Tests that the global event manager gets the event too from any other manager
388
 *
389
 * @return void
390
 * @triggers fake.event
391
 */
392
        public function testDispatchWithGlobal() {
393
                $generalManager = $this->getMock('CakeEventManager', array('prioritisedListeners'));
394
                $manager = new CakeEventManager();
395
                $event = new CakeEvent('fake.event');
396
                CakeEventManager::instance($generalManager);
397
398
                $generalManager->expects($this->once())->method('prioritisedListeners')->with('fake.event');
399
                $manager->dispatch($event);
400
                CakeEventManager::instance(new CakeEventManager());
401
        }
402
403
/**
404
 * Tests that stopping an event will not notify the rest of the listeners
405
 *
406
 * @return void
407
 * @triggers fake.event
408
 */
409
        public function testStopPropagation() {
410
                $generalManager = $this->getMock('CakeEventManager');
411
                $manager = new CakeEventManager();
412
                $listener = new CakeEventTestListener();
413
414
                CakeEventManager::instance($generalManager);
415
                $generalManager->expects($this->any())
416
                                ->method('prioritisedListeners')
417
                                ->with('fake.event')
418
                                ->will($this->returnValue(array()));
419
420
                $manager->attach(array($listener, 'listenerFunction'), 'fake.event');
421
                $manager->attach(array($listener, 'stopListener'), 'fake.event', array('priority' => 8));
422
                $manager->attach(array($listener, 'secondListenerFunction'), 'fake.event', array('priority' => 5));
423
                $event = new CakeEvent('fake.event');
424
                $manager->dispatch($event);
425
426
                $expected = array('secondListenerFunction');
427
                $this->assertEquals($expected, $listener->callStack);
428
                CakeEventManager::instance(new CakeEventManager());
429
        }
430
431
/**
432
 * Tests event dispatching using priorities
433
 *
434
 * @return void
435
 * @triggers fake.event
436
 */
437
        public function testDispatchPrioritizedWithGlobal() {
438
                $generalManager = $this->getMock('CakeEventManager');
439
                $manager = new CakeEventManager();
440
                $listener = new CustomTestEventListener();
441
                $event = new CakeEvent('fake.event');
442
443
                CakeEventManager::instance($generalManager);
444
                $generalManager->expects($this->any())
445
                                ->method('prioritisedListeners')
446
                                ->with('fake.event')
447
                                ->will($this->returnValue(
448
                                        array(11 => array(
449
                                                array('callable' => array($listener, 'secondListenerFunction'), 'passParams' => false)
450
                                        ))
451
                                ));
452
453
                $manager->attach(array($listener, 'listenerFunction'), 'fake.event');
454
                $manager->attach(array($listener, 'thirdListenerFunction'), 'fake.event', array('priority' => 15));
455
456
                $manager->dispatch($event);
457
458
                $expected = array('listenerFunction', 'secondListenerFunction', 'thirdListenerFunction');
459
                $this->assertEquals($expected, $listener->callStack);
460
                CakeEventManager::instance(new CakeEventManager());
461
        }
462
463
/**
464
 * Tests event dispatching using priorities
465
 *
466
 * @return void
467
 * @triggers fake.event
468
 */
469
        public function testDispatchGlobalBeforeLocal() {
470
                $generalManager = $this->getMock('CakeEventManager');
471
                $manager = new CakeEventManager();
472
                $listener = new CustomTestEventListener();
473
                $event = new CakeEvent('fake.event');
474
475
                CakeEventManager::instance($generalManager);
476
                $generalManager->expects($this->any())
477
                                ->method('prioritisedListeners')
478
                                ->with('fake.event')
479
                                ->will($this->returnValue(
480
                                        array(10 => array(
481
                                                array('callable' => array($listener, 'listenerFunction'), 'passParams' => false)
482
                                        ))
483
                                ));
484
485
                $manager->attach(array($listener, 'secondListenerFunction'), 'fake.event');
486
487
                $manager->dispatch($event);
488
489
                $expected = array('listenerFunction', 'secondListenerFunction');
490
                $this->assertEquals($expected, $listener->callStack);
491
                CakeEventManager::instance(new CakeEventManager());
492
        }
493
494
/**
495
 * test callback
496
 */
497
        public function onMyEvent($event) {
498
                $event->data['callback'] = 'ok';
499
        }
500
501
/**
502
 * Tests events dispatched by a local manager can be handled by
503
 * handler registered in the global event manager
504
 * @triggers my_event $manager
505
 */
506
        public function testDispatchLocalHandledByGlobal() {
507
                $callback = array($this, 'onMyEvent');
508
                CakeEventManager::instance()->attach($callback, 'my_event');
509
                $manager = new CakeEventManager();
510
                $event = new CakeEvent('my_event', $manager);
511
                $manager->dispatch($event);
512
                $this->assertEquals('ok', $event->data['callback']);
513
        }
514
515
/**
516
 * Test that events are dispatched properly when there are global and local
517
 * listeners at the same priority.
518
 *
519
 * @return void
520
 * @triggers fake.event $this
521
 */
522
        public function testDispatchWithGlobalAndLocalEvents() {
523
                $listener = new CustomTestEventListener();
524
                CakeEventManager::instance()->attach($listener);
525
                $listener2 = new CakeEventTestListener();
526
                $manager = new CakeEventManager();
527
                $manager->attach(array($listener2, 'listenerFunction'), 'fake.event');
528
529
                $manager->dispatch(new CakeEvent('fake.event', $this));
530
                $this->assertEquals(array('listenerFunction'), $listener->callStack);
531
                $this->assertEquals(array('listenerFunction'), $listener2->callStack);
532
        }
533
534
}