]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - plugins/Irc/extlib/phergie/Tests/Phergie/Plugin/TestCase.php
Merge branch '0.9.x' into merge
[quix0rs-gnu-social.git] / plugins / Irc / extlib / phergie / Tests / Phergie / Plugin / TestCase.php
index 36b81d6fae307450491c4bb80a7954c7983bbfbc..941e7cb41078f83a7937279d2dbcf844df9e8584 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /**
- * Unit test suite for Pherge_Plugin classes
+ * Unit test suite for plugin classes.
  *
  * @category Phergie
  * @package  Phergie_Tests
 abstract class Phergie_Plugin_TestCase extends PHPUnit_Framework_TestCase
 {
     /**
-     * @var Phergie_Event_Handler
+     * Mock configuration
+     *
+     * @var Phergie_Config
+     */
+    protected $config;
+
+    /**
+     * Associative array for configuration setting values, accessed by the
+     * mock configuration object using a callback
+     *
+     * @var array
      */
-    protected $handler;
+    protected $settings = array();
 
     /**
+     * Mock connection
+     *
      * @var Phergie_Connection
      */
     protected $connection;
 
     /**
-     * @var array
+     * Mock event handler
+     *
+     * @var Phergie_Event_Handler
      */
-    protected $eventArgs;
+    protected $events;
 
     /**
+     * Mock plugin handler
+     *
+     * @var Phergie_Plugin_Handler
+     */
+    protected $plugins;
+
+    /**
+     * Plugin instance being tested
+     *
      * @var Phergie_Plugin_Abstract
      */
     protected $plugin;
 
     /**
-     * @var array
+     * Full name of the plugin class being tested, may be explicitly
+     * specified in subclasses but is otherwise automatically derived from
+     * the test case class name
+     *
+     * @var string
+     */
+    protected $pluginClass;
+
+    /**
+     * User nick used in any events requiring one
+     *
+     * @var string
+     */
+    protected $nick = 'nick';
+
+    /**
+     * Event source used in any events requiring one
+     *
+     * @var string
      */
-    protected $config = array();
+    protected $source = '#channel';
 
     /**
-     * Constructs a test case with the given name.
+     * Initializes instance properties.
      *
-     * @param  string $name
-     * @param  array  $data
-     * @param  string $dataName
+     * @return void
      */
-    public function __construct($name = NULL, array $data = array(), $dataName = '')
+    public function setUp()
     {
-        parent::__construct($name, $data, $dataName);
-        $this->connection = new Phergie_Connection();
-        $this->handler    = new Phergie_Event_Handler();
+        if (empty($this->pluginClass)) {
+            $this->pluginClass = preg_replace('/Test$/', '', get_class($this));
+        }
+
+        if (empty($this->plugin)) {
+            $this->plugin = new $this->pluginClass;
+        }
+
+        $this->plugin->setConfig($this->getMockConfig());
+        $this->plugin->setConnection($this->getMockConnection());
+        $this->plugin->setEventHandler($this->getMockEventHandler());
+        $this->plugin->setPluginHandler($this->getMockPluginHandler());
     }
 
     /**
-     * Assert that a given event type exists in the event handler
-     * @param string $event
-     * @param string $message
+     * Destroys all initialized instance properties.
+     *
+     * @return void
      */
-    public function assertHasEvent($event, $message = null)
+    public function tearDown()
     {
-        self::assertTrue($this->handler->hasEventOfType($event), $message);
+        unset(
+            $this->plugins,
+            $this->events,
+            $this->connection,
+            $this->config,
+            $this->plugin
+        );
     }
 
     /**
-     * Assert that a given event type DOES NOT exist in the event handler
-     * @param string $event
-     * @param string $message
+     * Returns a mock configuration object.
+     *
+     * @return Phergie_Config
      */
-    public function assertDoesNotHaveEvent($event, $message = null)
+    protected function getMockConfig()
     {
-        self::assertFalse($this->handler->hasEventOfType($event), $message);
+        if (empty($this->config)) {
+            $this->config = $this->getMock('Phergie_Config', array('offsetExists', 'offsetGet'));
+            $this->config
+                ->expects($this->any())
+                ->method('offsetExists')
+                ->will($this->returnCallback(array($this, 'configOffsetExists')));
+            $this->config
+                ->expects($this->any())
+                ->method('offsetGet')
+                ->will($this->returnCallback(array($this, 'configOffsetGet')));
+        }
+        return $this->config;
     }
 
     /**
-     * Assert that the emitter of the given command event was the given
-     * plugin
+     * Returns whether a specific configuration setting has a value. Only
+     * intended for use by this class, but must be public for PHPUnit to
+     * call them.
+     *
+     * @param string $name Name of the setting
      *
-     * @param Phergie_Event_Command   $event
-     * @param Phergie_Plugin_Abstract $plugin
-     * @param string                  $message
+     * @return boolean TRUE if the setting has a value, FALSE otherwise
      */
-    public function assertEventEmitter(Phergie_Event_Command $event,
-                                       Phergie_Plugin_Abstract $plugin,
-                                       $message = null)
+    public function configOffsetExists($name)
     {
-        $this->assertSame($plugin, $event->getPlugin(), $message);
+        return isset($this->settings[$name]);
     }
 
     /**
-     * Gets the events added to the handler by the plugin
-     * @param string $type
-     * @return array | null
+     * Returns the value of a specific configuration setting. Only intended
+     * for use by this class, but must be public for PHPUnit to call them.
+     *
+     * @param string $name Name of the setting
+     *
+     * @return mixed Value of the setting
      */
-    public function getResponseEvents($type = null)
+    public function configOffsetGet($name)
     {
-        if (is_string($type) && strlen($type) > 0) {
-            return $this->handler->getEventsOfType($type);
-        }
-        return $this->handler->getEvents();
+        return $this->settings[$name];
     }
 
     /**
-     * Sets the event for the test
-     * @param array $event
-     * @param array $eventArgs
+     * Returns a mock connection object.
+     *
+     * @return Phergie_Connection
      */
-    public function setEvent(array $event, array $eventArgs = null)
+    protected function getMockConnection()
     {
-        $eventClass = 'Phergie_Event_Request';
-        if (is_array($event)) {
-            $eventClass = $event[0];
-            $eventType  = $event[1];
-        } else {
-            throw new InvalidArgumentException("Invalid value for \$event");
+        if (empty($this->connection)) {
+            $this->connection = $this->getMock('Phergie_Connection');
+            $this->connection
+                ->expects($this->any())
+                ->method('getNick')
+                ->will($this->returnValue($this->nick));
         }
-        $event = new $eventClass();
-        $event->setType($eventType);
-        $event->setArguments($eventArgs);
-        $this->plugin->setEvent($event);
-        $this->eventArgs = $eventArgs;
+        return $this->connection;
     }
 
     /**
-     * Sets the plugin to be tested
-     * If a plugin requries config for testing, an array placed in
-     * $this->config will be parsed into a Phergie_Config object and
-     * attached to the plugin
+     * Returns a mock event handler object.
+     *
+     * @return Phergie_Event_Handler
      */
-    protected function setPlugin(Phergie_Plugin_Abstract $plugin)
+    protected function getMockEventHandler()
     {
-        $this->plugin = $plugin;
-        $this->plugin->setEventHandler($this->handler);
-        $this->plugin->setConnection($this->connection);
-        $this->connection->setNick('test');
-        if (!empty($this->config)) {
-            $config = new Phergie_Config();
-            foreach ($this->config as $configKey => $configValue) {
-                $config[$configKey] = $configValue;
-            }
-            $plugin->setConfig($config);
+        if (empty($this->events)) {
+            $this->events = $this->getMock('Phergie_Event_Handler', array('addEvent'));
         }
+        return $this->events;
     }
 
     /**
-     * Overrides the runTest method to add additional annotations
-     * @return PHPUnit_Framework_TestResult
+     * Returns a mock plugin handler object.
+     *
+     * @return Phergie_Plugin_Handler
      */
-    protected function runTest()
+    protected function getMockPluginHandler()
     {
-        if (null === $this->plugin) {
-            throw new RuntimeException(
-                    'Tests cannot be run before plugin is set'
+        if (empty($this->plugins)) {
+            $config = $this->getMockConfig();
+            $events = $this->getMockEventHandler();
+            $this->plugins = $this->getMock(
+                'Phergie_Plugin_Handler',
+                array(), // mock everything
+                array($config, $events)
             );
         }
-        
-        // Clean the event handler... important!
-        $this->handler->clearEvents();
-
-        $info      = $this->getAnnotations();
-        $event     = null;
-        $eventArgs = array();
-        if (isset($info['method']['event']) && isset($info['method']['event'][0])) {
-            if (!is_string($info['method']['event'][0])) {
-                throw new InvalidArgumentException(
-                        'Only one event may be specified'
-                );
-            }
-            $event = $info['method']['event'][0];
+        return $this->plugins;
+    }
 
-            if (stristr($event, '::')) {
-                $event = explode('::', $event);
+    /**
+     * Returns a mock event object.
+     *
+     * @param string $type   Event type
+     * @param array  $args   Optional associative array of event arguments
+     * @param string $nick   Optional user nick to associate with the event
+     * @param string $source Optional user nick or channel name to associate
+     *        with the event as its source
+     *
+     * @return Phergie_Event_Request
+     */
+    protected function getMockEvent($type, array $args = array(),
+        $nick = null, $source = null
+    ) {
+        $methods = array('getNick', 'getSource');
+        foreach (array_keys($args) as $arg) {
+            if (is_int($arg) || ctype_digit($arg)) {
+                $methods[] = 'getArgument';
+            } else {
+                $methods[] = 'get' . ucfirst($arg);
             }
         }
-        if (isset($info['method']['eventArg'])) {
-            $eventArgs = $info['method']['eventArg'];
+
+        $event = $this->getMock(
+            'Phergie_Event_Request',
+            $methods
+        );
+
+        $nick = $nick ? $nick : $this->nick;
+        $event
+            ->expects($this->any())
+            ->method('getNick')
+            ->will($this->returnValue($nick));
+
+        $source = $source ? $source : $this->source;
+        $event
+            ->expects($this->any())
+            ->method('getSource')
+            ->will($this->returnValue($source));
+
+        foreach ($args as $key => $value) {
+            if (is_int($key) || ctype_digit($key)) {
+                $event
+                    ->expects($this->any())
+                    ->method('getArgument')
+                    ->with($key)
+                    ->will($this->returnValue($value));
+            } else {
+                $event
+                    ->expects($this->any())
+                    ->method('get' . ucfirst($key))
+                    ->will($this->returnValue($value));
+            }
         }
-        if (null !== $event) {
-            $this->setEvent($event, $eventArgs);
+
+        return $event;
+    }
+
+    /**
+     * Sets the value of a configuration setting.
+     *
+     * @param string $setting Name of the setting
+     * @param mixed  $value   Value for the setting
+     *
+     * @return void
+     */
+    protected function setConfig($setting, $value)
+    {
+        $this->settings[$setting] = $value;
+    }
+
+    /**
+     * Returns the absolute path to the Phergie/Plugin directory. Useful in
+     * conjunction with getMockDatabase().
+     *
+     * @param string $subpath Optional path to append to the directory path
+     *
+     * @return string Directory path
+     */
+    protected function getPluginsPath($subpath = null)
+    {
+        $path = realpath(dirname(__FILE__) . '/../../../Phergie/Plugin');
+        if (!empty($subpath)) {
+            $path .= '/' . ltrim($subpath, '/');
         }
+        return $path;
+    }
+
+    /**
+     * Modifies the event handler to include an expectation of an event
+     * being added by the plugin being tested. Note that this must be called
+     * BEFORE executing the plugin code intended to initiate the event.
+     *
+     * @param string $type Event type
+     * @param array  $args Optional enumerated array of event arguments
+     *
+     * @return void
+     */
+    protected function assertEmitsEvent($type, array $args = array())
+    {
+        $this->events
+            ->expects($this->at(0))
+            ->method('addEvent')
+            ->with($this->plugin, $type, $args);
+    }
 
-        $testResult = parent::runTest();
+    /**
+     * Modifies the event handler to include an expectation of an event NOT
+     * being added by the plugin being tested. Note that this must be called
+     * BEFORE executing plugin code that may initiate the event.
+     *
+     * @param string $type Event type
+     * @param array  $args Optional enumerated array of event arguments
+     *
+     * @return void
+     */
+    protected function assertDoesNotEmitEvent($type, array $args = array())
+    {
+        // Ugly hack to get around an issue in PHPUnit
+        // @link http://github.com/sebastianbergmann/phpunit-mock-objects/issues/issue/5#issue/5/comment/343524
+        $callback = create_function(
+            '$plugin, $type, $args',
+            'if (get_class($plugin) == "' . $this->pluginClass . '"
+            && $type == "' . $type . '"
+            && $args == "' . var_export($args, true) . '") {
+                trigger_error("Instance of ' . $this->pluginClass
+                . ' unexpectedly emitted event of type ' . $type
+                . '", E_USER_ERROR);
+            }'
+        );
 
-        // Clean the event handler again... just incase this time.
-        $this->handler->clearEvents();
+        $this->events
+            ->expects($this->any())
+            ->method('addEvent')
+            ->will($this->returnCallback($callback));
+    }
 
-        return $testResult;
+    /**
+     * Modifies the plugin handler to include an expectation of a plugin
+     * being retrieved, indicating a dependency. Note that this must be
+     * called BEFORE executing the plugin code that may load that plugin
+     * dependency, which is usually located in onLoad().
+     *
+     * @param string $name Short name of the plugin required as a dependency
+     *
+     * @return void
+     */
+    public function assertRequiresPlugin($name)
+    {
+        $this->plugins
+            ->expects($this->atLeastOnce())
+            ->method('getPlugin')
+            ->with($name);
     }
 
+    /**
+     * Creates an in-memory copy of a specified SQLite database file and
+     * returns a connection to it.
+     *
+     * @param string $path Path to the SQLite file to copy
+     *
+     * @return PDO Connection to the database copy
+     */
+    public function getMockDatabase($path)
+    {
+        $original = new PDO('sqlite:' . $path);
+        $copy = new PDO('sqlite::memory:');
+
+        $result = $original->query('SELECT sql FROM sqlite_master');
+        while ($sql = $result->fetchColumn()) {
+            $copy->exec($sql);
+        }
+
+        $tables = array();
+        $result = $original->query('SELECT name FROM sqlite_master WHERE type = "table"');
+        while ($table = $result->fetchColumn()) {
+            $tables[] = $table;
+        }
+
+        foreach ($tables as $table) {
+            $result = $original->query('SELECT * FROM ' . $table);
+            $insert = null;
+            $copy->beginTransaction();
+            while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
+                $columns = array_keys($row);
+                if (empty($insert)) {
+                    $insert = $copy->prepare(
+                        'INSERT INTO "' . $table . '" (' .
+                        '"' . implode('", "', $columns) . '"' .
+                        ') VALUES (' .
+                        ':' . implode(', :', $columns) .
+                        ')'
+                    );
+                }
+                $insert->execute($row);
+            }
+            $copy->commit();
+            unset($insert);
+        }
+
+        return $copy;
+    }
 }