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 countability of the plugin handler.
116 public function testImplementsCountable()
118 $reflection = new ReflectionObject($this->handler);
121 $reflection->implementsInterface('Countable'),
122 'Handler does not implement Countable'
127 count($this->handler),
128 'count() must return an integer'
133 * Tests the plugin handler exposing added plugins as instance
134 * properties of the handler via isset().
138 public function testImplementsIsset()
140 $pluginName = 'TestPlugin';
141 $this->assertFalse(isset($this->handler->{$pluginName}));
142 $plugin = $this->getMockPlugin($pluginName);
143 $this->handler->addPlugin($plugin);
144 $this->assertTrue(isset($this->handler->{$pluginName}));
148 * Tests the plugin handler exposing added plugins as instance
149 * properties of the handler.
151 * @depends testImplementsIsset
154 public function testImplementsGet()
156 $plugin = $this->getMockPlugin();
157 $this->handler->addPlugin($plugin);
158 $name = $plugin->getName();
159 $getPlugin = $this->handler->getPlugin($name);
160 $this->assertTrue(isset($this->handler->$name));
161 $get = $this->handler->$name;
162 $this->assertSame($getPlugin, $get);
166 * Tests the plugin handler allowing for plugin removal via unset().
168 * @depends testImplementsGet
171 public function testImplementsUnset()
173 $plugin = $this->getMockPlugin();
174 $this->handler->addPlugin($plugin);
175 unset($this->handler->{$plugin->getName()});
176 $this->assertFalse($this->handler->hasPlugin($plugin->getName()));
180 * Tests the plugin handler executing a callback on all contained
181 * plugins where one plugin short-circuits the process.
185 public function testImplementsCallWithShortCircuit()
187 $plugin1 = $this->getMockPlugin('TestPlugin1', array('callback'));
189 ->expects($this->once())
191 ->will($this->returnValue(false));
192 $this->handler->addPlugin($plugin1);
194 $plugin2 = $this->getMockPlugin('TestPlugin2', array('callback'));
196 ->expects($this->exactly(0))
197 ->method('callback');
198 $this->handler->addPlugin($plugin2);
200 $this->assertFalse($this->handler->callback());
204 * Tests the plugin handler executing a callback on all contained
205 * plugins where no plugins short-circuit the process.
209 public function testImplementsCallWithoutShortCircuit()
211 foreach (range(1, 2) as $index) {
212 $plugin = $this->getMockPlugin('TestPlugin' . $index, array('callback'));
214 ->expects($this->once())
215 ->method('callback');
216 $this->handler->addPlugin($plugin);
219 $this->assertTrue($this->handler->callback());
223 * Tests a newly instantiated handler not having plugins associated with
226 * @depends testImplementsCountable
229 public function testEmptyHandlerHasNoPlugins()
231 $this->assertEquals(0, count($this->handler));
235 * Tests a newly instantiated handler not having autoloading enabled by
240 public function testGetAutoloadDefaultsToNotAutoload()
242 $this->assertFalse($this->handler->getAutoload());
246 * Tests setAutoload().
248 * @depends testGetAutoloadDefaultsToNotAutoload
251 public function testSetAutoload()
254 $this->handler->setAutoload(true),
256 'setAutoload() does not provide a fluent interface'
260 $this->handler->getAutoload(),
261 'setAutoload() had no effect on getAutoload()'
266 * Tests addPath() providing a fluent interface.
270 public function testAddPathProvidesFluentInterface()
272 $handler = $this->handler->addPath(dirname(__FILE__));
273 $this->assertSame($this->handler, $handler);
277 * Tests addPath() throwing an exception when it cannot read the
282 public function testAddPathThrowsExceptionOnUnreadableDirectory()
285 $this->handler->addPath('/an/unreadable/directory/path');
286 } catch(Phergie_Plugin_Exception $e) {
288 Phergie_Plugin_Exception::ERR_DIRECTORY_NOT_READABLE,
294 $this->fail('An expected exception has not been raised');
298 * Tests adding a path to the plugin handler.
302 public function testAddPath()
304 $pluginName = 'Mock';
307 $this->handler->addPlugin($pluginName);
308 } catch(Phergie_Plugin_Exception $e) {
310 Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
316 $this->fail('Plugin loaded, path was already present');
319 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
322 $this->handler->addPlugin($pluginName);
323 } catch(Phergie_Plugin_Exception $e) {
324 $this->fail('Added path, plugin still not found');
329 * Tests addPlugin() returning an added plugin instance.
333 public function testAddPluginByInstanceReturnsPluginInstance()
335 $plugin = $this->getMockPlugin();
336 $returnedPlugin = $this->handler->addPlugin($plugin);
340 'addPlugin() does not return the instance passed to it'
345 * Tests adding a plugin to the handler using the plugin's short name.
349 public function testAddPluginByShortName()
351 $pluginName = 'Mock';
352 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
354 $returnedPlugin = $this->handler->addPlugin($pluginName);
355 $this->assertTrue($this->handler->hasPlugin($pluginName));
358 'Phergie_Plugin_Mock',
359 $this->handler->getPlugin($pluginName)
363 $this->handler->getPlugin($pluginName),
365 'Handler does not contain added plugin'
371 * Tests adding a plugin instance to the handler.
375 public function testAddPluginByInstance()
377 $plugin = $this->getMockPlugin();
378 $returnedPlugin = $this->handler->addPlugin($plugin);
379 $this->assertTrue($this->handler->hasPlugin('TestPlugin'));
384 'addPlugin() does not return added plugin instance'
389 $this->handler->getPlugin('TestPlugin'),
390 'getPlugin() does not return added plugin instance'
395 * Tests addPlugin() throwing an exception when the plugin class file
400 public function testAddPluginThrowsExceptionWhenPluginFileNotFound()
403 $this->handler->addPlugin('TestPlugin');
404 } catch(Phergie_Plugin_Exception $e) {
406 Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
412 $this->fail('An expected exception has not been raised');
416 * Recursively removes all files and subdirectories in a directory.
418 * @param string $path Directory path
421 private function removeDirectory($path)
423 if (file_exists($path)) {
424 $it = new RecursiveIteratorIterator(
425 new RecursiveDirectoryIterator($path),
426 RecursiveIteratorIterator::CHILD_FIRST
428 foreach ($it as $entry) {
432 if ($entry->isDir()) {
433 rmdir($entry->getPathname());
435 unlink($entry->getPathname());
442 * Tests addPlugin() throwing an exception when the plugin class file is
443 * found, but does not contain the plugin class as expected.
447 public function testAddPluginThrowsExceptionWhenPluginClassNotFound()
449 $path = sys_get_temp_dir() . '/Phergie/Plugin';
450 $this->removeDirectory(dirname($path));
451 mkdir($path, 0777, true);
452 touch($path . '/TestPlugin.php');
453 $this->handler->addPath($path, 'Phergie_Plugin_');
456 $this->handler->addPlugin('TestPlugin');
457 } catch(Phergie_Plugin_Exception $e) { }
461 Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
465 $this->fail('An expected exception has not been raised');
468 $this->removeDirectory(dirname($path));
472 * Tests addPlugin() throwing an exception when trying to instantiate a
473 * class that doesn't extend Phergie_Plugin_Abstract.
477 public function testAddPluginThrowsExceptionIfRequestingNonPlugin()
480 $this->handler->addPlugin('Handler');
481 } catch(Phergie_Plugin_Exception $e) {
483 Phergie_Plugin_Exception::ERR_INCORRECT_BASE_CLASS,
489 $this->fail('An expected exception has not been raised');
493 * Tests addPlugin() throwing an exception when trying to instantiate a
494 * class that can't be instantiated.
498 public function testAddPluginThrowsExceptionIfPluginNotInstantiable()
500 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
502 $this->handler->addPlugin('TestNonInstantiablePluginFromFile');
503 } catch(Phergie_Plugin_Exception $e) {
505 Phergie_Plugin_Exception::ERR_CLASS_NOT_INSTANTIABLE,
511 $this->fail('An expected exception has not been raised');
515 * Tests adding a plugin by its short name with arguments passed to the
516 * plugin constructor.
520 public function testAddPluginShortNamePassesArgsToConstructor()
522 $pluginName = 'Mock';
523 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
525 $arguments = array('a', 'b', 'c');
526 $plugin = $this->handler->addPlugin($pluginName, $arguments);
528 $this->assertAttributeSame(
532 'Arguments do not match'
537 * Tests addPlugin() passing Phergie_Config to an instantiated plugin.
541 public function testAddPluginPassesConstructorArguments()
543 $pluginName = 'Mock';
544 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
545 $plugin = $this->handler->addPlugin($pluginName);
549 $plugin->getConfig(),
550 'Phergie_Config instances do not match'
555 $plugin->getEventHandler(),
556 'Phergie_Event_Handler instances do not match'
561 * Tests addPlugin() calling onLoad() on an instantiated plugin.
565 public function testAddPluginCallsOnLoadOnInstantiatedPlugin()
567 $plugin = $this->getMockPlugin(null, array('onLoad'));
569 ->expects($this->once())
571 $this->handler->addPlugin($plugin);
575 * Tests addPlugin() returning the same plugin when called twice.
579 public function testAddPluginReturnsSamePluginWhenAskedTwice()
581 $pluginName = 'Mock';
582 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
583 $plugin1 = $this->handler->addPlugin($pluginName);
584 $plugin2 = $this->handler->addPlugin($pluginName);
585 $this->assertSame($plugin1, $plugin2);
589 * Tests getPlugin() throwing an exception when trying to get an
590 * unloaded plugin with autoload disabled.
592 * @depends testGetAutoloadDefaultsToNotAutoload
595 public function testExceptionThrownWhenLoadingPluginWithoutAutoload()
597 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
600 $this->handler->getPlugin('Mock');
601 } catch (Phergie_Plugin_Exception $expected) {
603 Phergie_Plugin_Exception::ERR_PLUGIN_NOT_LOADED,
609 $this->fail('An expected exception has not been raised');
613 * Tests addPlugins() with a plugin short name and no plugin constructor
616 * @depends testAddPluginByShortName
617 * @depends testAddPluginByInstance
620 public function testAddPluginsWithoutArguments()
622 $prefix = 'Phergie_Plugin_';
623 $this->handler->addPath(dirname(__FILE__), $prefix);
626 $this->handler->addPlugins(array($plugin));
627 $returnedPlugin = $this->handler->getPlugin($plugin);
628 $this->assertContains(
629 get_class($returnedPlugin),
631 'Short name plugin not of expected class'
636 * Tests addPlugins() with a plugin short name and plugin constructor
639 * @depends testAddPluginByShortName
640 * @depends testAddPluginByInstance
643 public function testAddPluginsWithArguments()
645 $prefix = 'Phergie_Plugin_';
646 $this->handler->addPath(dirname(__FILE__), $prefix);
648 $arguments = array(1, 2, 3);
649 $plugin = array('Mock', $arguments);
650 $this->handler->addPlugins(array($plugin));
651 $returnedPlugin = $this->handler->getPlugin('Mock');
654 $returnedPlugin->getArguments(),
655 'Constructor arguments for instance plugin do not match'
660 * Tests removePlugin() with a plugin instance.
662 * @depends testAddPluginByInstance
665 public function testRemovePluginByInstance()
667 $plugin = $this->getMockPlugin();
668 $this->handler->addPlugin($plugin);
669 $this->handler->removePlugin($plugin);
671 $this->handler->hasPlugin($plugin->getName()),
672 'Plugin was not removed'
677 * Tests removePlugin() with a plugin short name.
679 * @depends testAddPluginByShortName
682 public function testRemovePluginByShortName()
685 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
687 $this->handler->addPlugin($plugin);
688 $this->handler->removePlugin($plugin);
690 $this->handler->hasPlugin($plugin),
691 'Plugin was not removed'
696 * Tests getPlugin() when the plugin is not already loaded and
697 * autoloading is disabled.
699 * @depends testSetAutoload
702 public function testGetPluginWithAutoloadEnabled()
704 $this->handler->setAutoload(true);
705 $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
706 $plugin = $this->handler->getPlugin('Mock');
708 'Phergie_Plugin_Mock',
710 'Retrieved plugin not of expected class'
715 * Tests getPlugins().
717 * @depends testGetPluginWithAutoloadEnabled
720 public function testGetPlugins()
722 $plugin1 = $this->getMockPlugin('TestPlugin1');
723 $this->handler->addPlugin($plugin1);
725 $plugin2 = $this->getMockPlugin('TestPlugin2');
726 $this->handler->addPlugin($plugin2);
729 'testplugin1' => $plugin1,
730 'testplugin2' => $plugin2,
733 $actual = $this->handler->getPlugins();
734 $this->assertEquals($expected, $actual);
736 $actual = $this->handler->getPlugins(array('testplugin1', 'testplugin2'));
737 $this->assertEquals($expected, $actual);