]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Irc/extlib/phergie/Tests/Phergie/Plugin/HandlerTest.php
Merge remote-tracking branch 'upstream/master' into social-master
[quix0rs-gnu-social.git] / plugins / Irc / extlib / phergie / Tests / Phergie / Plugin / HandlerTest.php
1 <?php
2 /**
3  * Phergie
4  *
5  * PHP version 5
6  *
7  * LICENSE
8  *
9  * This source file is subject to the new BSD license that is bundled
10  * with this package in the file LICENSE.
11  * It is also available through the world-wide-web at this URL:
12  * http://phergie.org/license
13  *
14  * @category  Phergie
15  * @package   Phergie_Tests
16  * @author    Phergie Development Team <team@phergie.org>
17  * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
18  * @license   http://phergie.org/license New BSD License
19  * @link      http://pear.phergie.org/package/Phergie_Tests
20  */
21
22 /**
23  * Unit test suite for Pherge_Plugin_Handler.
24  *
25  * @category Phergie
26  * @package  Phergie_Tests
27  * @author   Phergie Development Team <team@phergie.org>
28  * @license  http://phergie.org/license New BSD License
29  * @link     http://pear.phergie.org/package/Phergie_Tests
30  */
31 class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
32 {
33     /**
34      * Plugin handler instance being tested
35      *
36      * @var Phergie_Plugin_Handler
37      */
38     protected $handler;
39
40     /**
41      * Mock Phergie_Config instance passed to the plugin handler constructor
42      *
43      * @var Phergie_Config
44      */
45     protected $config;
46
47     /**
48      * Mock Phergie_Event_Handler instance passed to the plugin handler
49      * constructor
50      *
51      * @var Phergie_Event_Handler
52      */
53     protected $events;
54
55     /**
56      * Returns a mock plugin instance.
57      *
58      * @param string $name    Optional short name for the mock plugin, defaults
59      *        to 'TestPlugin'
60      * @param array  $methods Optional list of methods to override
61      *
62      * @return Phergie_Plugin_Abstract
63      */
64     protected function getMockPlugin($name = 'TestPlugin', array $methods = array())
65     {
66         $methods[] = 'getName';
67         $plugin = $this->getMock('Phergie_Plugin_Abstract', $methods);
68         $plugin
69             ->expects($this->any())
70             ->method('getName')
71             ->will($this->returnValue($name));
72         return $plugin;
73     }
74
75     /**
76      * Sets up a new handler instance before each test.
77      *
78      * @return void
79      */
80     public function setUp()
81     {
82         $this->config = $this->getMock('Phergie_Config');
83         $this->events = $this->getMock('Phergie_Event_Handler');
84         $this->handler = new Phergie_Plugin_Handler(
85             $this->config,
86             $this->events
87         );
88     }
89
90     /**
91      * Tests iterability of the plugin handler.
92      *
93      * @return void
94      */
95     public function testImplementsIteratorAggregate()
96     {
97         $reflection = new ReflectionObject($this->handler);
98
99         $this->assertTrue(
100             $reflection->implementsInterface('IteratorAggregate'),
101             'Handler does not implement IteratorAggregate'
102         );
103
104         $this->assertType(
105             'Iterator',
106             $this->handler->getIterator(),
107             'getIterator() must return an iterator'
108         );
109     }
110
111     /**
112      * Tests that a default iterator is returned if none is explicitly set.
113      *
114      * @return void
115      */
116     public function testGetIteratorReturnsDefault()
117     {
118         $this->assertType(
119             'Phergie_Plugin_Iterator',
120             $this->handler->getIterator()
121         );
122     }
123
124     /**
125      * Tests the ability to change the handler's iterator class when a valid
126      * class is specified.
127      *
128      * @return void
129      */
130     public function testSetIteratorClassWithValidClass()
131     {
132         eval('
133             class DummyIterator extends FilterIterator {
134                 public function accept() {
135                     return true;
136                 }
137             }
138         ');
139
140         $this->handler->setIteratorClass('DummyIterator');
141
142         $this->assertType(
143             'DummyIterator',
144             $this->handler->getIterator()
145         );
146     }
147
148     /**
149      * Tests that a failure occurs when a nonexistent iterator class is
150      * specified.
151      *
152      * @return void
153      */
154     public function testSetIteratorClassWithNonexistentClass()
155     {
156         try {
157             $this->handler->setIteratorClass('FooIterator');
158             $this->fail('Expected exception was not thrown');
159         } catch (Phergie_Plugin_Exception $e) {
160             return;
161         }
162         $this->fail('Unexpected exception was thrown');
163     }
164
165     /**
166      * Tests that a failure occurs when a class that is not a subclass of
167      * FilterIterator is specified.
168      *
169      * @return void
170      */
171     public function testSetIteratorClassWithNonFilterIteratorClass()
172     {
173         try {
174             $this->handler->setIteratorClass('ArrayIterator');
175             $this->fail('Expected exception was not thrown');
176         } catch (Phergie_Plugin_Exception $e) {
177             return;
178         }
179         $this->fail('Unexpected exception was thrown');
180     }
181
182     /**
183      * Tests countability of the plugin handler.
184      *
185      * @return void
186      */
187     public function testImplementsCountable()
188     {
189         $reflection = new ReflectionObject($this->handler);
190
191         $this->assertTrue(
192             $reflection->implementsInterface('Countable'),
193             'Handler does not implement Countable'
194         );
195
196         $this->assertType(
197             'int',
198             count($this->handler),
199             'count() must return an integer'
200         );
201     }
202
203     /**
204      * Tests the plugin handler exposing added plugins as instance
205      * properties of the handler via isset().
206      *
207      * @return void
208      */
209     public function testImplementsIsset()
210     {
211         $pluginName = 'TestPlugin';
212         $this->assertFalse(isset($this->handler->{$pluginName}));
213         $plugin = $this->getMockPlugin($pluginName);
214         $this->handler->addPlugin($plugin);
215         $this->assertTrue(isset($this->handler->{$pluginName}));
216     }
217
218     /**
219      * Tests the plugin handler exposing added plugins as instance
220      * properties of the handler.
221      *
222      * @depends testImplementsIsset
223      * @return void
224      */
225     public function testImplementsGet()
226     {
227         $plugin = $this->getMockPlugin();
228         $this->handler->addPlugin($plugin);
229         $name = $plugin->getName();
230         $getPlugin = $this->handler->getPlugin($name);
231         $this->assertTrue(isset($this->handler->$name));
232         $get = $this->handler->$name;
233         $this->assertSame($getPlugin, $get);
234     }
235
236     /**
237      * Tests the plugin handler allowing for plugin removal via unset().
238      *
239      * @depends testImplementsGet
240      * @return void
241      */
242     public function testImplementsUnset()
243     {
244         $plugin = $this->getMockPlugin();
245         $this->handler->addPlugin($plugin);
246         unset($this->handler->{$plugin->getName()});
247         $this->assertFalse($this->handler->hasPlugin($plugin->getName()));
248     }
249
250     /**
251      * Tests the plugin handler executing a callback on all contained
252      * plugins.
253      *
254      * @return void
255      */
256     public function testImplementsCall()
257     {
258         foreach (range(1, 2) as $index) {
259             $plugin = $this->getMockPlugin('TestPlugin' . $index, array('callback'));
260             $plugin
261                 ->expects($this->once())
262                 ->method('callback');
263             $this->handler->addPlugin($plugin);
264         }
265
266         $this->assertTrue($this->handler->callback());
267     }
268
269     /**
270      * Tests a newly instantiated handler not having plugins associated with
271      * it.
272      *
273      * @depends testImplementsCountable
274      * @return void
275      */
276     public function testEmptyHandlerHasNoPlugins()
277     {
278         $this->assertEquals(0, count($this->handler));
279     }
280
281     /**
282      * Tests a newly instantiated handler not having autoloading enabled by
283      * default.
284      *
285      * @return void
286      */
287     public function testGetAutoloadDefaultsToNotAutoload()
288     {
289         $this->assertFalse($this->handler->getAutoload());
290     }
291
292     /**
293      * Tests setAutoload().
294      *
295      * @depends testGetAutoloadDefaultsToNotAutoload
296      * @return void
297      */
298     public function testSetAutoload()
299     {
300         $this->assertSame(
301             $this->handler->setAutoload(true),
302             $this->handler,
303             'setAutoload() does not provide a fluent interface'
304         );
305
306         $this->assertTrue(
307             $this->handler->getAutoload(),
308             'setAutoload() had no effect on getAutoload()'
309         );
310     }
311
312     /**
313      * Tests addPath() providing a fluent interface.
314      *
315      * @return void
316      */
317     public function testAddPathProvidesFluentInterface()
318     {
319         $handler = $this->handler->addPath(dirname(__FILE__));
320         $this->assertSame($this->handler, $handler);
321     }
322
323     /**
324      * Tests addPath() throwing an exception when it cannot read the
325      * directory.
326      *
327      * @return void
328      */
329     public function testAddPathThrowsExceptionOnUnreadableDirectory()
330     {
331         try {
332             $this->handler->addPath('/an/unreadable/directory/path');
333         } catch(Phergie_Plugin_Exception $e) {
334             $this->assertEquals(
335                 Phergie_Plugin_Exception::ERR_DIRECTORY_NOT_READABLE,
336                 $e->getCode()
337             );
338             return;
339         }
340
341         $this->fail('An expected exception has not been raised');
342     }
343
344     /**
345      * Tests adding a path to the plugin handler.
346      *
347      * @return void
348      */
349     public function testAddPath()
350     {
351         $pluginName = 'Mock';
352
353         try {
354             $this->handler->addPlugin($pluginName);
355         } catch(Phergie_Plugin_Exception $e) {
356             $this->assertEquals(
357                 Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
358                 $e->getCode()
359             );
360         }
361
362         if (!isset($e)) {
363             $this->fail('Plugin loaded, path was already present');
364         }
365
366         $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
367
368         try {
369             $this->handler->addPlugin($pluginName);
370         } catch(Phergie_Plugin_Exception $e) {
371             $this->fail('Added path, plugin still not found');
372         }
373     }
374
375     /**
376      * Tests addPlugin() returning an added plugin instance.
377      *
378      * @return void
379      */
380     public function testAddPluginByInstanceReturnsPluginInstance()
381     {
382         $plugin = $this->getMockPlugin();
383         $returnedPlugin = $this->handler->addPlugin($plugin);
384         $this->assertSame(
385             $returnedPlugin,
386             $plugin,
387             'addPlugin() does not return the instance passed to it'
388         );
389     }
390
391     /**
392      * Tests adding a plugin to the handler using the plugin's short name.
393      *
394      * @return void
395      */
396     public function testAddPluginByShortName()
397     {
398         $pluginName = 'Mock';
399         $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
400
401         $returnedPlugin = $this->handler->addPlugin($pluginName);
402         $this->assertTrue($this->handler->hasPlugin($pluginName));
403
404         $this->assertType(
405             'Phergie_Plugin_Mock',
406             $this->handler->getPlugin($pluginName)
407         );
408
409         $this->assertSame(
410             $this->handler->getPlugin($pluginName),
411             $returnedPlugin,
412             'Handler does not contain added plugin'
413         );
414     }
415
416
417     /**
418      * Tests adding a plugin instance to the handler.
419      *
420      * @return void
421      */
422     public function testAddPluginByInstance()
423     {
424         $plugin = $this->getMockPlugin();
425         $returnedPlugin = $this->handler->addPlugin($plugin);
426         $this->assertTrue($this->handler->hasPlugin('TestPlugin'));
427
428         $this->assertSame(
429             $plugin,
430             $returnedPlugin,
431             'addPlugin() does not return added plugin instance'
432         );
433
434         $this->assertSame(
435             $plugin,
436             $this->handler->getPlugin('TestPlugin'),
437             'getPlugin() does not return added plugin instance'
438         );
439     }
440
441     /**
442      * Tests addPlugin() throwing an exception when the plugin class file
443      * can't be found.
444      *
445      * @return void
446      */
447     public function testAddPluginThrowsExceptionWhenPluginFileNotFound()
448     {
449         try {
450             $this->handler->addPlugin('TestPlugin');
451         } catch(Phergie_Plugin_Exception $e) {
452             $this->assertEquals(
453                 Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
454                 $e->getCode()
455             );
456             return;
457         }
458
459         $this->fail('An expected exception has not been raised');
460     }
461
462     /**
463      * Recursively removes all files and subdirectories in a directory.
464      *
465      * @param string $path Directory path
466      * @return void
467      */
468     private function removeDirectory($path)
469     {
470         if (file_exists($path)) {
471             $it = new RecursiveIteratorIterator(
472                 new RecursiveDirectoryIterator($path),
473                 RecursiveIteratorIterator::CHILD_FIRST
474             );
475             foreach ($it as $entry) {
476                 if ($it->isDot()) {
477                     continue;
478                 }
479                 if ($entry->isDir()) {
480                     rmdir($entry->getPathname());
481                 } else {
482                     unlink($entry->getPathname());
483                 }
484             }
485         }
486     }
487
488     /**
489      * Tests addPlugin() throwing an exception when the plugin class file is
490      * found, but does not contain the plugin class as expected.
491      *
492      * @return void
493      */
494     public function testAddPluginThrowsExceptionWhenPluginClassNotFound()
495     {
496         $path = common_get_temp_dir() . '/Phergie/Plugin';
497         $this->removeDirectory(dirname($path));
498         mkdir($path, 0777, true);
499         touch($path . '/TestPlugin.php');
500         $this->handler->addPath($path, 'Phergie_Plugin_');
501
502         try {
503             $this->handler->addPlugin('TestPlugin');
504         } catch(Phergie_Plugin_Exception $e) { }
505
506         if (isset($e)) {
507             $this->assertEquals(
508                 Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
509                 $e->getCode()
510             );
511         } else {
512             $this->fail('An expected exception has not been raised');
513         }
514
515         $this->removeDirectory(dirname($path));
516     }
517
518     /**
519      * Tests addPlugin() throwing an exception when trying to instantiate a
520      * class that doesn't extend Phergie_Plugin_Abstract.
521      *
522      * @return void
523      */
524     public function testAddPluginThrowsExceptionIfRequestingNonPlugin()
525     {
526         try {
527             $this->handler->addPlugin('Handler');
528         } catch(Phergie_Plugin_Exception $e) {
529             $this->assertEquals(
530                 Phergie_Plugin_Exception::ERR_INCORRECT_BASE_CLASS,
531                 $e->getCode()
532             );
533             return;
534         }
535
536         $this->fail('An expected exception has not been raised');
537     }
538
539     /**
540      * Tests addPlugin() throwing an exception when trying to instantiate a
541      * class that can't be instantiated.
542      *
543      * @return void
544      */
545     public function testAddPluginThrowsExceptionIfPluginNotInstantiable()
546     {
547         $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
548         try {
549             $this->handler->addPlugin('TestNonInstantiablePluginFromFile');
550         } catch(Phergie_Plugin_Exception $e) {
551             $this->assertEquals(
552                 Phergie_Plugin_Exception::ERR_CLASS_NOT_INSTANTIABLE,
553                 $e->getCode()
554             );
555             return;
556         }
557
558         $this->fail('An expected exception has not been raised');
559     }
560
561     /**
562      * Tests adding a plugin by its short name with arguments passed to the
563      * plugin constructor.
564      *
565      * @return void
566      */
567     public function testAddPluginShortNamePassesArgsToConstructor()
568     {
569         $pluginName = 'Mock';
570         $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
571
572         $arguments = array('a', 'b', 'c');
573         $plugin = $this->handler->addPlugin($pluginName, $arguments);
574
575         $this->assertAttributeSame(
576             $arguments,
577             'arguments',
578             $plugin,
579             'Arguments do not match'
580         );
581     }
582
583     /**
584      * Tests addPlugin() passing Phergie_Config to an instantiated plugin.
585      *
586      * @return void
587      */
588     public function testAddPluginPassesConstructorArguments()
589     {
590         $pluginName = 'Mock';
591         $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
592         $plugin = $this->handler->addPlugin($pluginName);
593
594         $this->assertSame(
595             $this->config,
596             $plugin->getConfig(),
597             'Phergie_Config instances do not match'
598         );
599
600         $this->assertSame(
601             $this->events,
602             $plugin->getEventHandler(),
603             'Phergie_Event_Handler instances do not match'
604         );
605     }
606
607     /**
608      * Tests addPlugin() calling onLoad() on an instantiated plugin.
609      *
610      * @return void
611      */
612     public function testAddPluginCallsOnLoadOnInstantiatedPlugin()
613     {
614         $plugin = $this->getMockPlugin(null, array('onLoad'));
615         $plugin
616             ->expects($this->once())
617             ->method('onLoad');
618         $this->handler->addPlugin($plugin);
619     }
620
621     /**
622      * Tests addPlugin() returning the same plugin when called twice.
623      *
624      * @return void
625      */
626     public function testAddPluginReturnsSamePluginWhenAskedTwice()
627     {
628         $pluginName = 'Mock';
629         $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
630         $plugin1 = $this->handler->addPlugin($pluginName);
631         $plugin2 = $this->handler->addPlugin($pluginName);
632         $this->assertSame($plugin1, $plugin2);
633     }
634
635     /**
636      * Tests getPlugin() throwing an exception when trying to get an
637      * unloaded plugin with autoload disabled.
638      *
639      * @depends testGetAutoloadDefaultsToNotAutoload
640      * @return void
641      */
642     public function testExceptionThrownWhenLoadingPluginWithoutAutoload()
643     {
644         $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
645
646         try {
647             $this->handler->getPlugin('Mock');
648         } catch (Phergie_Plugin_Exception $expected) {
649             $this->assertEquals(
650                 Phergie_Plugin_Exception::ERR_PLUGIN_NOT_LOADED,
651                 $expected->getCode()
652             );
653             return;
654         }
655
656         $this->fail('An expected exception has not been raised');
657     }
658
659     /**
660      * Tests addPlugins() with a plugin short name and no plugin constructor
661      * arguments.
662      *
663      * @depends testAddPluginByShortName
664      * @depends testAddPluginByInstance
665      * @return void
666      */
667     public function testAddPluginsWithoutArguments()
668     {
669         $prefix = 'Phergie_Plugin_';
670         $this->handler->addPath(dirname(__FILE__), $prefix);
671
672         $plugin = 'Mock';
673         $this->handler->addPlugins(array($plugin));
674         $returnedPlugin = $this->handler->getPlugin($plugin);
675         $this->assertContains(
676             get_class($returnedPlugin),
677             $prefix . $plugin,
678             'Short name plugin not of expected class'
679         );
680     }
681
682     /**
683      * Tests addPlugins() with a plugin short name and plugin constructor
684      * arguments.
685      *
686      * @depends testAddPluginByShortName
687      * @depends testAddPluginByInstance
688      * @return void
689      */
690     public function testAddPluginsWithArguments()
691     {
692         $prefix = 'Phergie_Plugin_';
693         $this->handler->addPath(dirname(__FILE__), $prefix);
694
695         $arguments = array(1, 2, 3);
696         $plugin = array('Mock', $arguments);
697         $this->handler->addPlugins(array($plugin));
698         $returnedPlugin = $this->handler->getPlugin('Mock');
699         $this->assertEquals(
700             $arguments,
701             $returnedPlugin->getArguments(),
702             'Constructor arguments for instance plugin do not match'
703         );
704     }
705
706     /**
707      * Tests removePlugin() with a plugin instance.
708      *
709      * @depends testAddPluginByInstance
710      * @return void
711      */
712     public function testRemovePluginByInstance()
713     {
714         $plugin = $this->getMockPlugin();
715         $this->handler->addPlugin($plugin);
716         $this->handler->removePlugin($plugin);
717         $this->assertFalse(
718             $this->handler->hasPlugin($plugin->getName()),
719             'Plugin was not removed'
720         );
721     }
722
723     /**
724      * Tests removePlugin() with a plugin short name.
725      *
726      * @depends testAddPluginByShortName
727      * @return void
728      */
729     public function testRemovePluginByShortName()
730     {
731         $plugin = 'Mock';
732         $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
733
734         $this->handler->addPlugin($plugin);
735         $this->handler->removePlugin($plugin);
736         $this->assertFalse(
737             $this->handler->hasPlugin($plugin),
738             'Plugin was not removed'
739         );
740     }
741
742     /**
743      * Tests getPlugin() when the plugin is not already loaded and
744      * autoloading is disabled.
745      *
746      * @depends testSetAutoload
747      * @return void
748      */
749     public function testGetPluginWithAutoloadEnabled()
750     {
751         $this->handler->setAutoload(true);
752         $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
753         $plugin = $this->handler->getPlugin('Mock');
754         $this->assertType(
755             'Phergie_Plugin_Mock',
756             $plugin,
757             'Retrieved plugin not of expected class'
758         );
759     }
760
761     /**
762      * Tests getPlugins().
763      *
764      * @depends testGetPluginWithAutoloadEnabled
765      * @return void
766      */
767     public function testGetPlugins()
768     {
769         $plugin1 = $this->getMockPlugin('TestPlugin1');
770         $this->handler->addPlugin($plugin1);
771
772         $plugin2 = $this->getMockPlugin('TestPlugin2');
773         $this->handler->addPlugin($plugin2);
774
775         $expected = array(
776             'testplugin1' => $plugin1,
777             'testplugin2' => $plugin2,
778         );
779
780         $actual = $this->handler->getPlugins();
781         $this->assertEquals($expected, $actual);
782
783         $actual = $this->handler->getPlugins(array('testplugin1', 'testplugin2'));
784         $this->assertEquals($expected, $actual);
785     }
786
787     /**
788      * Tests that multiple plugin iterators can be used concurrently.
789      *
790      * @return void
791      */
792     public function testUseMultiplePluginIteratorsConcurrently()
793     {
794         $plugin1 = $this->getMockPlugin('TestPlugin1');
795         $this->handler->addPlugin($plugin1);
796
797         $plugin2 = $this->getMockPlugin('TestPlugin2');
798         $this->handler->addPlugin($plugin2);
799
800         $iterator1 = $this->handler->getIterator();
801         $iterator1->next();
802         $this->assertSame($plugin2, $iterator1->current());
803
804         $iterator2 = $this->handler->getIterator();
805         $this->assertSame($plugin1, $iterator2->current());
806     }
807
808     /**
809      * Tests adding plugin paths via configuration.
810      *
811      * @return void
812      */
813     public function testAddPluginPathsViaConfiguration()
814     {
815         $dir = dirname(__FILE__);
816         $prefix = 'Phergie_Plugin_';
817         $paths = array($dir => $prefix);
818         $this->config
819             ->expects($this->any())
820             ->method('offsetExists')
821             ->will($this->returnValue(true));
822         $this->config
823             ->expects($this->any())
824             ->method('offsetGet')
825             ->will($this->returnValue($paths));
826
827         // Reinitialize the handler so the configuration change takes effect
828         // within the constructor
829         $this->handler = new Phergie_Plugin_Handler(
830             $this->config,
831             $this->events
832         );
833
834         $this->handler->setAutoload(true);
835         $this->handler->getPlugin('Mock');
836     }
837 }