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 plugin classes.
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 abstract class Phergie_Plugin_TestCase extends PHPUnit_Framework_TestCase
41 * Associative array for configuration setting values, accessed by the
42 * mock configuration object using a callback
46 protected $settings = array();
51 * @var Phergie_Connection
53 protected $connection;
58 * @var Phergie_Event_Handler
65 * @var Phergie_Plugin_Handler
70 * Plugin instance being tested
72 * @var Phergie_Plugin_Abstract
77 * Full name of the plugin class being tested, may be explicitly
78 * specified in subclasses but is otherwise automatically derived from
79 * the test case class name
83 protected $pluginClass;
86 * User nick used in any events requiring one
90 protected $nick = 'nick';
93 * Event source used in any events requiring one
97 protected $source = '#channel';
100 * Initializes instance properties.
104 public function setUp()
106 if (empty($this->pluginClass)) {
107 $this->pluginClass = preg_replace('/Test$/', '', get_class($this));
110 if (empty($this->plugin)) {
111 $this->plugin = new $this->pluginClass;
114 $this->plugin->setConfig($this->getMockConfig());
115 $this->plugin->setConnection($this->getMockConnection());
116 $this->plugin->setEventHandler($this->getMockEventHandler());
117 $this->plugin->setPluginHandler($this->getMockPluginHandler());
121 * Destroys all initialized instance properties.
125 public function tearDown()
137 * Returns a mock configuration object.
139 * @return Phergie_Config
141 protected function getMockConfig()
143 if (empty($this->config)) {
144 $this->config = $this->getMock('Phergie_Config', array('offsetExists', 'offsetGet'));
146 ->expects($this->any())
147 ->method('offsetExists')
148 ->will($this->returnCallback(array($this, 'configOffsetExists')));
150 ->expects($this->any())
151 ->method('offsetGet')
152 ->will($this->returnCallback(array($this, 'configOffsetGet')));
154 return $this->config;
158 * Returns whether a specific configuration setting has a value. Only
159 * intended for use by this class, but must be public for PHPUnit to
162 * @param string $name Name of the setting
164 * @return boolean TRUE if the setting has a value, FALSE otherwise
166 public function configOffsetExists($name)
168 return isset($this->settings[$name]);
172 * Returns the value of a specific configuration setting. Only intended
173 * for use by this class, but must be public for PHPUnit to call them.
175 * @param string $name Name of the setting
177 * @return mixed Value of the setting
179 public function configOffsetGet($name)
181 return $this->settings[$name];
185 * Returns a mock connection object.
187 * @return Phergie_Connection
189 protected function getMockConnection()
191 if (empty($this->connection)) {
192 $this->connection = $this->getMock('Phergie_Connection');
194 ->expects($this->any())
196 ->will($this->returnValue($this->nick));
198 return $this->connection;
202 * Returns a mock event handler object.
204 * @return Phergie_Event_Handler
206 protected function getMockEventHandler()
208 if (empty($this->events)) {
209 $this->events = $this->getMock('Phergie_Event_Handler', array('addEvent'));
211 return $this->events;
215 * Returns a mock plugin handler object.
217 * @return Phergie_Plugin_Handler
219 protected function getMockPluginHandler()
221 if (empty($this->plugins)) {
222 $config = $this->getMockConfig();
223 $events = $this->getMockEventHandler();
224 $this->plugins = $this->getMock(
225 'Phergie_Plugin_Handler',
226 array(), // mock everything
227 array($config, $events)
230 return $this->plugins;
234 * Returns a mock event object.
236 * @param string $type Event type
237 * @param array $args Optional associative array of event arguments
238 * @param string $nick Optional user nick to associate with the event
239 * @param string $source Optional user nick or channel name to associate
240 * with the event as its source
242 * @return Phergie_Event_Request
244 protected function getMockEvent($type, array $args = array(),
245 $nick = null, $source = null
247 $methods = array('getNick', 'getSource');
248 foreach (array_keys($args) as $arg) {
249 if (is_int($arg) || ctype_digit($arg)) {
250 $methods[] = 'getArgument';
252 $methods[] = 'get' . ucfirst($arg);
256 $event = $this->getMock(
257 'Phergie_Event_Request',
261 $nick = $nick ? $nick : $this->nick;
263 ->expects($this->any())
265 ->will($this->returnValue($nick));
267 $source = $source ? $source : $this->source;
269 ->expects($this->any())
270 ->method('getSource')
271 ->will($this->returnValue($source));
273 foreach ($args as $key => $value) {
274 if (is_int($key) || ctype_digit($key)) {
276 ->expects($this->any())
277 ->method('getArgument')
279 ->will($this->returnValue($value));
282 ->expects($this->any())
283 ->method('get' . ucfirst($key))
284 ->will($this->returnValue($value));
292 * Sets the value of a configuration setting.
294 * @param string $setting Name of the setting
295 * @param mixed $value Value for the setting
299 protected function setConfig($setting, $value)
301 $this->settings[$setting] = $value;
305 * Returns the absolute path to the Phergie/Plugin directory. Useful in
306 * conjunction with getMockDatabase().
308 * @param string $subpath Optional path to append to the directory path
310 * @return string Directory path
312 protected function getPluginsPath($subpath = null)
314 $path = realpath(dirname(__FILE__) . '/../../../Phergie/Plugin');
315 if (!empty($subpath)) {
316 $path .= '/' . ltrim($subpath, '/');
322 * Modifies the event handler to include an expectation of an event
323 * being added by the plugin being tested. Note that this must be called
324 * BEFORE executing the plugin code intended to initiate the event.
326 * @param string $type Event type
327 * @param array $args Optional enumerated array of event arguments
331 protected function assertEmitsEvent($type, array $args = array())
334 ->expects($this->at(0))
336 ->with($this->plugin, $type, $args);
340 * Modifies the event handler to include an expectation of an event NOT
341 * being added by the plugin being tested. Note that this must be called
342 * BEFORE executing plugin code that may initiate the event.
344 * @param string $type Event type
345 * @param array $args Optional enumerated array of event arguments
349 protected function assertDoesNotEmitEvent($type, array $args = array())
351 // Ugly hack to get around an issue in PHPUnit
352 // @link http://github.com/sebastianbergmann/phpunit-mock-objects/issues/issue/5#issue/5/comment/343524
353 $callback = create_function(
354 '$plugin, $type, $args',
355 'if (get_class($plugin) == "' . $this->pluginClass . '"
356 && $type == "' . $type . '"
357 && $args == "' . var_export($args, true) . '") {
358 trigger_error("Instance of ' . $this->pluginClass
359 . ' unexpectedly emitted event of type ' . $type
365 ->expects($this->any())
367 ->will($this->returnCallback($callback));
371 * Modifies the plugin handler to include an expectation of a plugin
372 * being retrieved, indicating a dependency. Note that this must be
373 * called BEFORE executing the plugin code that may load that plugin
374 * dependency, which is usually located in onLoad().
376 * @param string $name Short name of the plugin required as a dependency
380 public function assertRequiresPlugin($name)
383 ->expects($this->atLeastOnce())
384 ->method('getPlugin')
389 * Creates an in-memory copy of a specified SQLite database file and
390 * returns a connection to it.
392 * @param string $path Path to the SQLite file to copy
394 * @return PDO Connection to the database copy
396 public function getMockDatabase($path)
398 $original = new PDO('sqlite:' . $path);
399 $copy = new PDO('sqlite::memory:');
401 $result = $original->query('SELECT sql FROM sqlite_master');
402 while ($sql = $result->fetchColumn()) {
407 $result = $original->query('SELECT name FROM sqlite_master WHERE type = "table"');
408 while ($table = $result->fetchColumn()) {
412 foreach ($tables as $table) {
413 $result = $original->query('SELECT * FROM ' . $table);
415 $copy->beginTransaction();
416 while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
417 $columns = array_keys($row);
418 if (empty($insert)) {
419 $insert = $copy->prepare(
420 'INSERT INTO "' . $table . '" (' .
421 '"' . implode('", "', $columns) . '"' .
423 ':' . implode(', :', $columns) .
427 $insert->execute($row);