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
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
23 * Unit test suite for Pherge_Plugin_Handler.
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
31 class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
34 * Plugin handler instance being tested
36 * @var Phergie_Plugin_Handler
41 * Mock Phergie_Config instance passed to the plugin handler constructor
48 * Mock Phergie_Event_Handler instance passed to the plugin handler
51 * @var Phergie_Event_Handler
56 * Returns a mock plugin instance.
58 * @param string $name Optional short name for the mock plugin, defaults
60 * @param array $methods Optional list of methods to override
62 * @return Phergie_Plugin_Abstract
64 protected function getMockPlugin($name = 'TestPlugin', array $methods = array())
66 $methods[] = 'getName';
67 $plugin = $this->getMock('Phergie_Plugin_Abstract', $methods);
69 ->expects($this->any())
71 ->will($this->returnValue($name));
76 * Sets up a new handler instance before each test.
80 public function setUp()
82 $this->config = $this->getMock('Phergie_Config');
83 $this->events = $this->getMock('Phergie_Event_Handler');
84 $this->handler = new Phergie_Plugin_Handler(
91 * Tests iterability of the plugin handler.
95 public function testImplementsIteratorAggregate()
97 $reflection = new ReflectionObject($this->handler);
100 $reflection->implementsInterface('IteratorAggregate'),
101 'Handler does not implement IteratorAggregate'
106 $this->handler->getIterator(),
107 'getIterator() must return an iterator'
112 * Tests that a default iterator is returned if none is explicitly set.
116 public function testGetIteratorReturnsDefault()
119 'Phergie_Plugin_Iterator',
120 $this->handler->getIterator()
125 * Tests the ability to change the handler's iterator class when a valid
126 * class is specified.
130 public function testSetIteratorClassWithValidClass()
133 class DummyIterator extends FilterIterator {
134 public function accept() {
140 $this->handler->setIteratorClass('DummyIterator');
144 $this->handler->getIterator()
149 * Tests that a failure occurs when a nonexistent iterator class is
154 public function testSetIteratorClassWithNonexistentClass()
157 $this->handler->setIteratorClass('FooIterator');
158 $this->fail('Expected exception was not thrown');
159 } catch (Phergie_Plugin_Exception $e) {
162 $this->fail('Unexpected exception was thrown');
166 * Tests that a failure occurs when a class that is not a subclass of
167 * FilterIterator is specified.
171 public function testSetIteratorClassWithNonFilterIteratorClass()
174 $this->handler->setIteratorClass('ArrayIterator');
175 $this->fail('Expected exception was not thrown');
176 } catch (Phergie_Plugin_Exception $e) {
179 $this->fail('Unexpected exception was thrown');
183 * Tests countability of the plugin handler.
187 public function testImplementsCountable()
189 $reflection = new ReflectionObject($this->handler);
192 $reflection->implementsInterface('Countable'),
193 'Handler does not implement Countable'
198 count($this->handler),
199 'count() must return an integer'
204 * Tests the plugin handler exposing added plugins as instance
205 * properties of the handler via isset().
209 public function testImplementsIsset()
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}));
219 * Tests the plugin handler exposing added plugins as instance
220 * properties of the handler.
222 * @depends testImplementsIsset
225 public function testImplementsGet()
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);
237 * Tests the plugin handler allowing for plugin removal via unset().
239 * @depends testImplementsGet
242 public function testImplementsUnset()
244 $plugin = $this->getMockPlugin();
245 $this->handler->addPlugin($plugin);
246 unset($this->handler->{$plugin->getName()});
247 $this->assertFalse($this->handler->hasPlugin($plugin->getName()));
251 * Tests the plugin handler executing a callback on all contained
256 public function testImplementsCall()
258 foreach (range(1, 2) as $index) {
259 $plugin = $this->getMockPlugin('TestPlugin' . $index, array('callback'));
261 ->expects($this->once())
262 ->method('callback');
263 $this->handler->addPlugin($plugin);
266 $this->assertTrue($this->handler->callback());
270 * Tests a newly instantiated handler not having plugins associated with
273 * @depends testImplementsCountable
276 public function testEmptyHandlerHasNoPlugins()
278 $this->assertEquals(0, count($this->handler));
282 * Tests a newly instantiated handler not having autoloading enabled by
287 public function testGetAutoloadDefaultsToNotAutoload()
289 $this->assertFalse($this->handler->getAutoload());
293 * Tests setAutoload().
295 * @depends testGetAutoloadDefaultsToNotAutoload
298 public function testSetAutoload()
301 $this->handler->setAutoload(true),
303 'setAutoload() does not provide a fluent interface'
307 $this->handler->getAutoload(),
308 'setAutoload() had no effect on getAutoload()'
313 * Tests addPath() providing a fluent interface.
317 public function testAddPathProvidesFluentInterface()
319 $handler = $this->handler->addPath(dirname(__FILE__));
320 $this->assertSame($this->handler, $handler);
324 * Tests addPath() throwing an exception when it cannot read the
329 public function testAddPathThrowsExceptionOnUnreadableDirectory()
332 $this->handler->addPath('/an/unreadable/directory/path');
333 } catch(Phergie_Plugin_Exception $e) {
335 Phergie_Plugin_Exception::ERR_DIRECTORY_NOT_READABLE,
341 $this->fail('An expected exception has not been raised');
345 * Tests adding a path to the plugin handler.
349 public function testAddPath()
351 $pluginName = 'Mock';
354 $this->handler->addPlugin($pluginName);
355 } catch(Phergie_Plugin_Exception $e) {
357 Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
363 $this->fail('Plugin loaded, path was already present');
366 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
369 $this->handler->addPlugin($pluginName);
370 } catch(Phergie_Plugin_Exception $e) {
371 $this->fail('Added path, plugin still not found');
376 * Tests addPlugin() returning an added plugin instance.
380 public function testAddPluginByInstanceReturnsPluginInstance()
382 $plugin = $this->getMockPlugin();
383 $returnedPlugin = $this->handler->addPlugin($plugin);
387 'addPlugin() does not return the instance passed to it'
392 * Tests adding a plugin to the handler using the plugin's short name.
396 public function testAddPluginByShortName()
398 $pluginName = 'Mock';
399 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
401 $returnedPlugin = $this->handler->addPlugin($pluginName);
402 $this->assertTrue($this->handler->hasPlugin($pluginName));
405 'Phergie_Plugin_Mock',
406 $this->handler->getPlugin($pluginName)
410 $this->handler->getPlugin($pluginName),
412 'Handler does not contain added plugin'
418 * Tests adding a plugin instance to the handler.
422 public function testAddPluginByInstance()
424 $plugin = $this->getMockPlugin();
425 $returnedPlugin = $this->handler->addPlugin($plugin);
426 $this->assertTrue($this->handler->hasPlugin('TestPlugin'));
431 'addPlugin() does not return added plugin instance'
436 $this->handler->getPlugin('TestPlugin'),
437 'getPlugin() does not return added plugin instance'
442 * Tests addPlugin() throwing an exception when the plugin class file
447 public function testAddPluginThrowsExceptionWhenPluginFileNotFound()
450 $this->handler->addPlugin('TestPlugin');
451 } catch(Phergie_Plugin_Exception $e) {
453 Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
459 $this->fail('An expected exception has not been raised');
463 * Recursively removes all files and subdirectories in a directory.
465 * @param string $path Directory path
468 private function removeDirectory($path)
470 if (file_exists($path)) {
471 $it = new RecursiveIteratorIterator(
472 new RecursiveDirectoryIterator($path),
473 RecursiveIteratorIterator::CHILD_FIRST
475 foreach ($it as $entry) {
479 if ($entry->isDir()) {
480 rmdir($entry->getPathname());
482 unlink($entry->getPathname());
489 * Tests addPlugin() throwing an exception when the plugin class file is
490 * found, but does not contain the plugin class as expected.
494 public function testAddPluginThrowsExceptionWhenPluginClassNotFound()
496 $path = sys_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_');
503 $this->handler->addPlugin('TestPlugin');
504 } catch(Phergie_Plugin_Exception $e) { }
508 Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
512 $this->fail('An expected exception has not been raised');
515 $this->removeDirectory(dirname($path));
519 * Tests addPlugin() throwing an exception when trying to instantiate a
520 * class that doesn't extend Phergie_Plugin_Abstract.
524 public function testAddPluginThrowsExceptionIfRequestingNonPlugin()
527 $this->handler->addPlugin('Handler');
528 } catch(Phergie_Plugin_Exception $e) {
530 Phergie_Plugin_Exception::ERR_INCORRECT_BASE_CLASS,
536 $this->fail('An expected exception has not been raised');
540 * Tests addPlugin() throwing an exception when trying to instantiate a
541 * class that can't be instantiated.
545 public function testAddPluginThrowsExceptionIfPluginNotInstantiable()
547 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
549 $this->handler->addPlugin('TestNonInstantiablePluginFromFile');
550 } catch(Phergie_Plugin_Exception $e) {
552 Phergie_Plugin_Exception::ERR_CLASS_NOT_INSTANTIABLE,
558 $this->fail('An expected exception has not been raised');
562 * Tests adding a plugin by its short name with arguments passed to the
563 * plugin constructor.
567 public function testAddPluginShortNamePassesArgsToConstructor()
569 $pluginName = 'Mock';
570 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
572 $arguments = array('a', 'b', 'c');
573 $plugin = $this->handler->addPlugin($pluginName, $arguments);
575 $this->assertAttributeSame(
579 'Arguments do not match'
584 * Tests addPlugin() passing Phergie_Config to an instantiated plugin.
588 public function testAddPluginPassesConstructorArguments()
590 $pluginName = 'Mock';
591 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
592 $plugin = $this->handler->addPlugin($pluginName);
596 $plugin->getConfig(),
597 'Phergie_Config instances do not match'
602 $plugin->getEventHandler(),
603 'Phergie_Event_Handler instances do not match'
608 * Tests addPlugin() calling onLoad() on an instantiated plugin.
612 public function testAddPluginCallsOnLoadOnInstantiatedPlugin()
614 $plugin = $this->getMockPlugin(null, array('onLoad'));
616 ->expects($this->once())
618 $this->handler->addPlugin($plugin);
622 * Tests addPlugin() returning the same plugin when called twice.
626 public function testAddPluginReturnsSamePluginWhenAskedTwice()
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);
636 * Tests getPlugin() throwing an exception when trying to get an
637 * unloaded plugin with autoload disabled.
639 * @depends testGetAutoloadDefaultsToNotAutoload
642 public function testExceptionThrownWhenLoadingPluginWithoutAutoload()
644 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
647 $this->handler->getPlugin('Mock');
648 } catch (Phergie_Plugin_Exception $expected) {
650 Phergie_Plugin_Exception::ERR_PLUGIN_NOT_LOADED,
656 $this->fail('An expected exception has not been raised');
660 * Tests addPlugins() with a plugin short name and no plugin constructor
663 * @depends testAddPluginByShortName
664 * @depends testAddPluginByInstance
667 public function testAddPluginsWithoutArguments()
669 $prefix = 'Phergie_Plugin_';
670 $this->handler->addPath(dirname(__FILE__), $prefix);
673 $this->handler->addPlugins(array($plugin));
674 $returnedPlugin = $this->handler->getPlugin($plugin);
675 $this->assertContains(
676 get_class($returnedPlugin),
678 'Short name plugin not of expected class'
683 * Tests addPlugins() with a plugin short name and plugin constructor
686 * @depends testAddPluginByShortName
687 * @depends testAddPluginByInstance
690 public function testAddPluginsWithArguments()
692 $prefix = 'Phergie_Plugin_';
693 $this->handler->addPath(dirname(__FILE__), $prefix);
695 $arguments = array(1, 2, 3);
696 $plugin = array('Mock', $arguments);
697 $this->handler->addPlugins(array($plugin));
698 $returnedPlugin = $this->handler->getPlugin('Mock');
701 $returnedPlugin->getArguments(),
702 'Constructor arguments for instance plugin do not match'
707 * Tests removePlugin() with a plugin instance.
709 * @depends testAddPluginByInstance
712 public function testRemovePluginByInstance()
714 $plugin = $this->getMockPlugin();
715 $this->handler->addPlugin($plugin);
716 $this->handler->removePlugin($plugin);
718 $this->handler->hasPlugin($plugin->getName()),
719 'Plugin was not removed'
724 * Tests removePlugin() with a plugin short name.
726 * @depends testAddPluginByShortName
729 public function testRemovePluginByShortName()
732 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
734 $this->handler->addPlugin($plugin);
735 $this->handler->removePlugin($plugin);
737 $this->handler->hasPlugin($plugin),
738 'Plugin was not removed'
743 * Tests getPlugin() when the plugin is not already loaded and
744 * autoloading is disabled.
746 * @depends testSetAutoload
749 public function testGetPluginWithAutoloadEnabled()
751 $this->handler->setAutoload(true);
752 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
753 $plugin = $this->handler->getPlugin('Mock');
755 'Phergie_Plugin_Mock',
757 'Retrieved plugin not of expected class'
762 * Tests getPlugins().
764 * @depends testGetPluginWithAutoloadEnabled
767 public function testGetPlugins()
769 $plugin1 = $this->getMockPlugin('TestPlugin1');
770 $this->handler->addPlugin($plugin1);
772 $plugin2 = $this->getMockPlugin('TestPlugin2');
773 $this->handler->addPlugin($plugin2);
776 'testplugin1' => $plugin1,
777 'testplugin2' => $plugin2,
780 $actual = $this->handler->getPlugins();
781 $this->assertEquals($expected, $actual);
783 $actual = $this->handler->getPlugins(array('testplugin1', 'testplugin2'));
784 $this->assertEquals($expected, $actual);
788 * Tests that multiple plugin iterators can be used concurrently.
792 public function testUseMultiplePluginIteratorsConcurrently()
794 $plugin1 = $this->getMockPlugin('TestPlugin1');
795 $this->handler->addPlugin($plugin1);
797 $plugin2 = $this->getMockPlugin('TestPlugin2');
798 $this->handler->addPlugin($plugin2);
800 $iterator1 = $this->handler->getIterator();
802 $this->assertSame($plugin2, $iterator1->current());
804 $iterator2 = $this->handler->getIterator();
805 $this->assertSame($plugin1, $iterator2->current());
809 * Tests adding plugin paths via configuration.
813 public function testAddPluginPathsViaConfiguration()
815 $dir = dirname(__FILE__);
816 $prefix = 'Phergie_Plugin_';
817 $paths = array($dir => $prefix);
819 ->expects($this->any())
820 ->method('offsetExists')
821 ->will($this->returnValue(true));
823 ->expects($this->any())
824 ->method('offsetGet')
825 ->will($this->returnValue($paths));
827 // Reinitialize the handler so the configuration change takes effect
828 // within the constructor
829 $this->handler = new Phergie_Plugin_Handler(
834 $this->handler->setAutoload(true);
835 $this->handler->getPlugin('Mock');