code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie_Tests
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie_Tests
 */

/**
 * Unit test suite for Pherge_Connection.
 *
 * @category Phergie
 * @package  Phergie_Tests
 * @author   Phergie Development Team <team@phergie.org>
 * @license  http://phergie.org/license New BSD License
 * @link     http://pear.phergie.org/package/Phergie_Tests
 */
class Phergie_ConnectionTest extends PHPUnit_Framework_TestCase
{
    /**
     * Associative array containing an option-to-value mapping
     *
     * @var array
     */
    private $options = array(
        'host' => 'example.com',
        'port' => 4080,
        'transport' => 'udp',
        'encoding' => 'ASCII',
        'nick' => 'MyNick',
        'username' => 'MyUsername',
        'realname' => 'MyRealName',
        'password' => 'MyPassword',
    );

    /**
     * Data provider for testGetOptionReturnsDefault().
     *
     * @return array Enumerated array of enumerated arrays each containing a
     *               set of parameters for a single call to
     *               testGetOptionReturnsDefault()
     */
    public function dataProviderTestGetOptionReturnsDefault()
    {
        return array(
            array('transport', 'tcp'),
            array('encoding', 'ISO-8859-1'),
            array('port', 6667),
            array('password', null),
        );
    }

    /**
     * Tests that a default values are used for some options.
     *
     * @param string $option Name of the option with a default value
     * @param mixed  $value  Default value of the option
     *
     * @return void
     * @dataProvider dataProviderTestGetOptionReturnsDefault
     */
    public function testGetOptionReturnsDefault($option, $value)
    {
        $connection = new Phergie_Connection;
        $this->assertEquals($value, $connection->{'get' . ucfirst($option)}());
    }

    /**
     * Tests that a default encoding is used if one isn't specified.
     *
     * @return void
     */
    public function testGetEncodingReturnsDefault()
    {
        $connection = new Phergie_Connection;
        $this->assertEquals('ISO-8859-1', $connection->getEncoding());
    }

    /**
     * Tests that options can be set via the constructor.
     *
     * @return void
     */
    public function testSetOptionsViaConstructor()
    {
        $connection = new Phergie_Connection($this->options);
        foreach ($this->options as $key => $value) {
            $this->assertEquals($value, $connection->{'get' . ucfirst($key)}());
        }
    }

    /**
     * Data provider for testGetHostmaskMissingDataGeneratesException().
     *
     * @return array Enumerated array of enumerated arrays each containing a
     *               set of parameters for a single call to
     *               testGetHostmaskMissingDataGeneratesException()
     */
    public function dataProviderTestGetHostmaskMissingDataGeneratesException()
    {
        return array(
            array(null, $this->options['username'], $this->options['host']),
            array($this->options['nick'], null, $this->options['host']),
            array($this->options['nick'], $this->options['username'], null),
        );
    }

    /**
     * Tests that attempting to retrieve a hostmask without option values
     * for all of its constituents generates an exception.
     *
     * @param string $nick     Bot nick
     * @param string $username Bot username
     * @param string $host     Server hostname
     *
     * @return void
     * @dataProvider dataProviderTestGetHostmaskMissingDataGeneratesException
     */
    public function testGetHostmaskMissingDataGeneratesException($nick, $username, $host)
    {
        $options = array(
            'nick' => $nick,
            'username' => $username,
            'host' => $host,
        );

        $connection = new Phergie_Connection($options);

        try {
            $hostmask = $connection->getHostmask();
            $this->fail('Expected exception was not thrown');
        } catch (Phergie_Connection_Exception $e) {
            return;
        } catch (Exception $e) {
            $this->fail('Unexpected exception was thrown');
        }
    }

    /**
     * Tests that attempting to retrieve a hostmask with all required
     * options is successful.
     *
     * @return void
     */
    public function testGetHostmaskWithValidData()
    {
        $options = array(
            'nick' => 'MyNick',
            'username' => 'MyUsername',
            'host' => 'example.com'
        );

        $connection = new Phergie_Connection($options);
        $hostmask = $connection->getHostmask();
        $this->assertType('Phergie_Hostmask', $hostmask);
    }

    /**
     * Data provider for testGetRequiredOptionsWithoutValuesSet().
     *
     * @return array Enumerated array of enumerated arrays each containing a
     *               set of parameters for a single call to
     *               testGetRequiredOptionsWithoutValuesSet()
     */
    public function dataProviderTestGetRequiredOptionsWithoutValuesSet()
    {
        return array(
            array('host'),
            array('nick'),
            array('username'),
            array('realname'),
        );
    }

    /**
     * Tests that attempting to retrieve values of required options when no
     * values are set results in an exception.
     *
     * @param string $option Option name
     *
     * @return void
     * @dataProvider dataProviderTestGetRequiredOptionsWithoutValuesSet
     */
    public function testGetRequiredOptionsWithoutValuesSet($option)
    {
        try {
            $connection = new Phergie_Connection;
            $value = $connection->{'get' . ucfirst($option)}();
            $this->fail('Expected exception was not thrown');
        } catch (Phergie_Connection_Exception $e) {
            return;
        } catch (Exception $e) {
            $this->fail('Unexpected exception was thrown');
        }
    }

    /**
     * Tests that attempting to set an invalid value for the transport
     * results in an exception.
     *
     * @return void
     */
    public function testSetTransportWithInvalidValue()
    {
        $connection = new Phergie_Connection;
        try {
            $connection->setTransport('blah');
            $this->fail('Expected exception was not thrown');
        } catch (Phergie_Connection_Exception $e) {
            return;
        } catch (Exception $e) {
            $this->fail('Unexpected exception was thrown');
        }
    }

    /**
     * Tests that attempting to set an invalid value for the encoding
     * results in an exception.
     *
     * @return void
     */
    public function testSetEncodingWithInvalidValue()
    {
        $connection = new Phergie_Connection;
        try {
            $connection->setEncoding('blah');
            $this->fail('Expected exception was not thrown');
        } catch (Phergie_Connection_Exception $e) {
            return;
        } catch (Exception $e) {
            $this->fail('Unexpected exception was thrown');
        }
    }

    /**
     * Tests that options can be set collectively after the connection is
     * instantiated.
     *
     * @return void
     */
    public function testSetOptions()
    {
        $connection = new Phergie_Connection;
        $connection->setOptions($this->options);
        foreach ($this->options as $key => $value) {
            $this->assertEquals($value, $connection->{'get' . ucfirst($key)}());
        }
    }
}


code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie_Tests
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie_Tests
 */

/**
 * Unit test suite for Pherge_Plugin_Handler.
 *
 * @category Phergie
 * @package  Phergie_Tests
 * @author   Phergie Development Team <team@phergie.org>
 * @license  http://phergie.org/license New BSD License
 * @link     http://pear.phergie.org/package/Phergie_Tests
 */
class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
{
    /**
     * Plugin handler instance being tested
     *
     * @var Phergie_Plugin_Handler
     */
    protected $handler;

    /**
     * Mock Phergie_Config instance passed to the plugin handler constructor
     *
     * @var Phergie_Config
     */
    protected $config;

    /**
     * Mock Phergie_Event_Handler instance passed to the plugin handler
     * constructor
     *
     * @var Phergie_Event_Handler
     */
    protected $events;

    /**
     * Returns a mock plugin instance.
     *
     * @param string $name    Optional short name for the mock plugin, defaults
     *        to 'TestPlugin'
     * @param array  $methods Optional list of methods to override
     *
     * @return Phergie_Plugin_Abstract
     */
    protected function getMockPlugin($name = 'TestPlugin', array $methods = array())
    {
        $methods[] = 'getName';
        $plugin = $this->getMock('Phergie_Plugin_Abstract', $methods);
        $plugin
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue($name));
        return $plugin;
    }

    /**
     * Sets up a new handler instance before each test.
     *
     * @return void
     */
    public function setUp()
    {
        $this->config = $this->getMock('Phergie_Config');
        $this->events = $this->getMock('Phergie_Event_Handler');
        $this->handler = new Phergie_Plugin_Handler(
            $this->config,
            $this->events
        );
    }

    /**
     * Tests iterability of the plugin handler.
     *
     * @return void
     */
    public function testImplementsIteratorAggregate()
    {
        $reflection = new ReflectionObject($this->handler);

        $this->assertTrue(
            $reflection->implementsInterface('IteratorAggregate'),
            'Handler does not implement IteratorAggregate'
        );

        $this->assertType(
            'Iterator',
            $this->handler->getIterator(),
            'getIterator() must return an iterator'
        );
    }

    /**
     * Tests that a default iterator is returned if none is explicitly set.
     *
     * @return void
     */
    public function testGetIteratorReturnsDefault()
    {
        $this->assertType(
            'Phergie_Plugin_Iterator',
            $this->handler->getIterator()
        );
    }

    /**
     * Tests the ability to change the handler's iterator class when a valid
     * class is specified.
     *
     * @return void
     */
    public function testSetIteratorClassWithValidClass()
    {
        eval('
            class DummyIterator extends FilterIterator {
                public function accept() {
                    return true;
                }
            }
        ');

        $this->handler->setIteratorClass('DummyIterator');

        $this->assertType(
            'DummyIterator',
            $this->handler->getIterator()
        );
    }

    /**
     * Tests that a failure occurs when a nonexistent iterator class is
     * specified.
     *
     * @return void
     */
    public function testSetIteratorClassWithNonexistentClass()
    {
        try {
            $this->handler->setIteratorClass('FooIterator');
            $this->fail('Expected exception was not thrown');
        } catch (Phergie_Plugin_Exception $e) {
            return;
        }
        $this->fail('Unexpected exception was thrown');
    }

    /**
     * Tests that a failure occurs when a class that is not a subclass of
     * FilterIterator is specified.
     *
     * @return void
     */
    public function testSetIteratorClassWithNonFilterIteratorClass()
    {
        try {
            $this->handler->setIteratorClass('ArrayIterator');
            $this->fail('Expected exception was not thrown');
        } catch (Phergie_Plugin_Exception $e) {
            return;
        }
        $this->fail('Unexpected exception was thrown');
    }

    /**
     * Tests countability of the plugin handler.
     *
     * @return void
     */
    public function testImplementsCountable()
    {
        $reflection = new ReflectionObject($this->handler);

        $this->assertTrue(
            $reflection->implementsInterface('Countable'),
            'Handler does not implement Countable'
        );

        $this->assertType(
            'int',
            count($this->handler),
            'count() must return an integer'
        );
    }

    /**
     * Tests the plugin handler exposing added plugins as instance
     * properties of the handler via isset().
     *
     * @return void
     */
    public function testImplementsIsset()
    {
        $pluginName = 'TestPlugin';
        $this->assertFalse(isset($this->handler->{$pluginName}));
        $plugin = $this->getMockPlugin($pluginName);
        $this->handler->addPlugin($plugin);
        $this->assertTrue(isset($this->handler->{$pluginName}));
    }

    /**
     * Tests the plugin handler exposing added plugins as instance
     * properties of the handler.
     *
     * @depends testImplementsIsset
     * @return void
     */
    public function testImplementsGet()
    {
        $plugin = $this->getMockPlugin();
        $this->handler->addPlugin($plugin);
        $name = $plugin->getName();
        $getPlugin = $this->handler->getPlugin($name);
        $this->assertTrue(isset($this->handler->$name));
        $get = $this->handler->$name;
        $this->assertSame($getPlugin, $get);
    }

    /**
     * Tests the plugin handler allowing for plugin removal via unset().
     *
     * @depends testImplementsGet
     * @return void
     */
    public function testImplementsUnset()
    {
        $plugin = $this->getMockPlugin();
        $this->handler->addPlugin($plugin);
        unset($this->handler->{$plugin->getName()});
        $this->assertFalse($this->handler->hasPlugin($plugin->getName()));
    }

    /**
     * Tests the plugin handler executing a callback on all contained
     * plugins.
     *
     * @return void
     */
    public function testImplementsCall()
    {
        foreach (range(1, 2) as $index) {
            $plugin = $this->getMockPlugin('TestPlugin' . $index, array('callback'));
            $plugin
                ->expects($this->once())
                ->method('callback');
            $this->handler->addPlugin($plugin);
        }

        $this->assertTrue($this->handler->callback());
    }

    /**
     * Tests a newly instantiated handler not having plugins associated with
     * it.
     *
     * @depends testImplementsCountable
     * @return void
     */
    public function testEmptyHandlerHasNoPlugins()
    {
        $this->assertEquals(0, count($this->handler));
    }

    /**
     * Tests a newly instantiated handler not having autoloading enabled by
     * default.
     *
     * @return void
     */
    public function testGetAutoloadDefaultsToNotAutoload()
    {
        $this->assertFalse($this->handler->getAutoload());
    }

    /**
     * Tests setAutoload().
     *
     * @depends testGetAutoloadDefaultsToNotAutoload
     * @return void
     */
    public function testSetAutoload()
    {
        $this->assertSame(
            $this->handler->setAutoload(true),
            $this->handler,
            'setAutoload() does not provide a fluent interface'
        );

        $this->assertTrue(
            $this->handler->getAutoload(),
            'setAutoload() had no effect on getAutoload()'
        );
    }

    /**
     * Tests addPath() providing a fluent interface.
     *
     * @return void
     */
    public function testAddPathProvidesFluentInterface()
    {
        $handler = $this->handler->addPath(dirname(__FILE__));
        $this->assertSame($this->handler, $handler);
    }

    /**
     * Tests addPath() throwing an exception when it cannot read the
     * directory.
     *
     * @return void
     */
    public function testAddPathThrowsExceptionOnUnreadableDirectory()
    {
        try {
            $this->handler->addPath('/an/unreadable/directory/path');
        } catch(Phergie_Plugin_Exception $e) {
            $this->assertEquals(
                Phergie_Plugin_Exception::ERR_DIRECTORY_NOT_READABLE,
                $e->getCode()
            );
            return;
        }

        $this->fail('An expected exception has not been raised');
    }

    /**
     * Tests adding a path to the plugin handler.
     *
     * @return void
     */
    public function testAddPath()
    {
        $pluginName = 'Mock';

        try {
            $this->handler->addPlugin($pluginName);
        } catch(Phergie_Plugin_Exception $e) {
            $this->assertEquals(
                Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
                $e->getCode()
            );
        }

        if (!isset($e)) {
            $this->fail('Plugin loaded, path was already present');
        }

        $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');

        try {
            $this->handler->addPlugin($pluginName);
        } catch(Phergie_Plugin_Exception $e) {
            $this->fail('Added path, plugin still not found');
        }
    }

    /**
     * Tests addPlugin() returning an added plugin instance.
     *
     * @return void
     */
    public function testAddPluginByInstanceReturnsPluginInstance()
    {
        $plugin = $this->getMockPlugin();
        $returnedPlugin = $this->handler->addPlugin($plugin);
        $this->assertSame(
            $returnedPlugin,
            $plugin,
            'addPlugin() does not return the instance passed to it'
        );
    }

    /**
     * Tests adding a plugin to the handler using the plugin's short name.
     *
     * @return void
     */
    public function testAddPluginByShortName()
    {
        $pluginName = 'Mock';
        $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');

        $returnedPlugin = $this->handler->addPlugin($pluginName);
        $this->assertTrue($this->handler->hasPlugin($pluginName));

        $this->assertType(
            'Phergie_Plugin_Mock',
            $this->handler->getPlugin($pluginName)
        );

        $this->assertSame(
            $this->handler->getPlugin($pluginName),
            $returnedPlugin,
            'Handler does not contain added plugin'
        );
    }

    /**
     * Tests adding a plugin instance to the handler.
     *
     * @return void
     */
    public function testAddPluginByInstance()
    {
        $plugin = $this->getMockPlugin();
        $returnedPlugin = $this->handler->addPlugin($plugin);
        $this->assertTrue($this->handler->hasPlugin('TestPlugin'));

        $this->assertSame(
            $plugin,
            $returnedPlugin,
            'addPlugin() does not return added plugin instance'
        );

        $this->assertSame(
            $plugin,
            $this->handler->getPlugin('TestPlugin'),
            'getPlugin() does not return added plugin instance'
        );
    }

    /**
     * Tests addPlugin() throwing an exception when the plugin class file
     * can't be found.
     *
     * @return void
     */
    public function testAddPluginThrowsExceptionWhenPluginFileNotFound()
    {
        try {
            $this->handler->addPlugin('TestPlugin');
        } catch(Phergie_Plugin_Exception $e) {
            $this->assertEquals(
                Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
                $e->getCode()
            );
            return;
        }

        $this->fail('An expected exception has not been raised');
    }

    /**
     * Recursively removes all files and subdirectories in a directory.
     *
     * @param string $path Directory path
     * @return void
     */
    private function removeDirectory($path)
    {
        if (file_exists($path)) {
            $it = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($path),
                RecursiveIteratorIterator::CHILD_FIRST
            );
            foreach ($it as $entry) {
                if ($it->isDot()) {
                    continue;
                }
                if ($entry->isDir()) {
                    rmdir($entry->getPathname());
                } else {
                    unlink($entry->getPathname());
                }
            }
        }
    }

    /**
     * Tests addPlugin() throwing an exception when the plugin class file is
     * found, but does not contain the plugin class as expected.
     *
     * @return void
     */
    public function testAddPluginThrowsExceptionWhenPluginClassNotFound()
    {
        $path = sys_get_temp_dir() . '/Phergie/Plugin';
        $this->removeDirectory(dirname($path));
        mkdir($path, 0777, true);
        touch($path . '/TestPlugin.php');
        $this->handler->addPath($path, 'Phergie_Plugin_');

        try {
            $this->handler->addPlugin('TestPlugin');
        } catch(Phergie_Plugin_Exception $e) { }

        if (isset($e)) {
            $this->assertEquals(
                Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
                $e->getCode()
            );
        } else {
            $this->fail('An expected exception has not been raised');
        }

        $this->removeDirectory(dirname($path));
    }

    /**
     * Tests addPlugin() throwing an exception when trying to instantiate a
     * class that doesn't extend Phergie_Plugin_Abstract.
     *
     * @return void
     */
    public function testAddPluginThrowsExceptionIfRequestingNonPlugin()
    {
        try {
            $this->handler->addPlugin('Handler');
        } catch(Phergie_Plugin_Exception $e) {
            $this->assertEquals(
                Phergie_Plugin_Exception::ERR_INCORRECT_BASE_CLASS,
                $e->getCode()
            );
            return;
        }

        $this->fail('An expected exception has not been raised');
    }

    /**
     * Tests addPlugin() throwing an exception when trying to instantiate a
     * class that can't be instantiated.
     *
     * @return void
     */
    public function testAddPluginThrowsExceptionIfPluginNotInstantiable()
    {
        $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
        try {
            $this->handler->addPlugin('TestNonInstantiablePluginFromFile');
        } catch(Phergie_Plugin_Exception $e) {
            $this->assertEquals(
                Phergie_Plugin_Exception::ERR_CLASS_NOT_INSTANTIABLE,
                $e->getCode()
            );
            return;
        }

        $this->fail('An expected exception has not been raised');
    }

    /**
     * Tests adding a plugin by its short name with arguments passed to the
     * plugin constructor.
     *
     * @return void
     */
    public function testAddPluginShortNamePassesArgsToConstructor()
    {
        $pluginName = 'Mock';
        $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');

        $arguments = array('a', 'b', 'c');
        $plugin = $this->handler->addPlugin($pluginName, $arguments);

        $this->assertAttributeSame(
            $arguments,
            'arguments',
            $plugin,
            'Arguments do not match'
        );
    }

    /**
     * Tests addPlugin() passing Phergie_Config to an instantiated plugin.
     *
     * @return void
     */
    public function testAddPluginPassesConstructorArguments()
    {
        $pluginName = 'Mock';
        $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
        $plugin = $this->handler->addPlugin($pluginName);

        $this->assertSame(
            $this->config,
            $plugin->getConfig(),
            'Phergie_Config instances do not match'
        );

        $this->assertSame(
            $this->events,
            $plugin->getEventHandler(),
            'Phergie_Event_Handler instances do not match'
        );
    }

    /**
     * Tests addPlugin() calling onLoad() on an instantiated plugin.
     *
     * @return void
     */
    public function testAddPluginCallsOnLoadOnInstantiatedPlugin()
    {
        $plugin = $this->getMockPlugin(null, array('onLoad'));
        $plugin
            ->expects($this->once())
            ->method('onLoad');
        $this->handler->addPlugin($plugin);
    }

    /**
     * Tests addPlugin() returning the same plugin when called twice.
     *
     * @return void
     */
    public function testAddPluginReturnsSamePluginWhenAskedTwice()
    {
        $pluginName = 'Mock';
        $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
        $plugin1 = $this->handler->addPlugin($pluginName);
        $plugin2 = $this->handler->addPlugin($pluginName);
        $this->assertSame($plugin1, $plugin2);
    }

    /**
     * Tests getPlugin() throwing an exception when trying to get an
     * unloaded plugin with autoload disabled.
     *
     * @depends testGetAutoloadDefaultsToNotAutoload
     * @return void
     */
    public function testExceptionThrownWhenLoadingPluginWithoutAutoload()
    {
        $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');

        try {
            $this->handler->getPlugin('Mock');
        } catch (Phergie_Plugin_Exception $expected) {
            $this->assertEquals(
                Phergie_Plugin_Exception::ERR_PLUGIN_NOT_LOADED,
                $expected->getCode()
            );
            return;
        }

        $this->fail('An expected exception has not been raised');
    }

    /**
     * Tests addPlugins() with a plugin short name and no plugin constructor
     * arguments.
     *
     * @depends testAddPluginByShortName
     * @depends testAddPluginByInstance
     * @return void
     */
    public function testAddPluginsWithoutArguments()
    {
        $prefix = 'Phergie_Plugin_';
        $this->handler->addPath(dirname(__FILE__), $prefix);

        $plugin = 'Mock';
        $this->handler->addPlugins(array($plugin));
        $returnedPlugin = $this->handler->getPlugin($plugin);
        $this->assertContains(
            get_class($returnedPlugin),
            $prefix . $plugin,
            'Short name plugin not of expected class'
        );
    }

    /**
     * Tests addPlugins() with a plugin short name and plugin constructor
     * arguments.
     *
     * @depends testAddPluginByShortName
     * @depends testAddPluginByInstance
     * @return void
     */
    public function testAddPluginsWithArguments()
    {
        $prefix = 'Phergie_Plugin_';
        $this->handler->addPath(dirname(__FILE__), $prefix);

        $arguments = array(1, 2, 3);
        $plugin = array('Mock', $arguments);
        $this->handler->addPlugins(array($plugin));
        $returnedPlugin = $this->handler->getPlugin('Mock');
        $this->assertEquals(
            $arguments,
            $returnedPlugin->getArguments(),
            'Constructor arguments for instance plugin do not match'
        );
    }

    /**
     * Tests removePlugin() with a plugin instance.
     *
     * @depends testAddPluginByInstance
     * @return void
     */
    public function testRemovePluginByInstance()
    {
        $plugin = $this->getMockPlugin();
        $this->handler->addPlugin($plugin);
        $this->handler->removePlugin($plugin);
        $this->assertFalse(
            $this->handler->hasPlugin($plugin->getName()),
            'Plugin was not removed'
        );
    }

    /**
     * Tests removePlugin() with a plugin short name.
     *
     * @depends testAddPluginByShortName
     * @return void
     */
    public function testRemovePluginByShortName()
    {
        $plugin = 'Mock';
        $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');

        $this->handler->addPlugin($plugin);
        $this->handler->removePlugin($plugin);
        $this->assertFalse(
            $this->handler->hasPlugin($plugin),
            'Plugin was not removed'
        );
    }

    /**
     * Tests getPlugin() when the plugin is not already loaded and
     * autoloading is disabled.
     *
     * @depends testSetAutoload
     * @return void
     */
    public function testGetPluginWithAutoloadEnabled()
    {
        $this->handler->setAutoload(true);
        $this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
        $plugin = $this->handler->getPlugin('Mock');
        $this->assertType(
            'Phergie_Plugin_Mock',
            $plugin,
            'Retrieved plugin not of expected class'
        );
    }

    /**
     * Tests getPlugins().
     *
     * @depends testGetPluginWithAutoloadEnabled
     * @return void
     */
    public function testGetPlugins()
    {
        $plugin1 = $this->getMockPlugin('TestPlugin1');
        $this->handler->addPlugin($plugin1);

        $plugin2 = $this->getMockPlugin('TestPlugin2');
        $this->handler->addPlugin($plugin2);

        $expected = array(
            'testplugin1' => $plugin1,
            'testplugin2' => $plugin2,
        );

        $actual = $this->handler->getPlugins();
        $this->assertEquals($expected, $actual);

        $actual = $this->handler->getPlugins(array('testplugin1', 'testplugin2'));
        $this->assertEquals($expected, $actual);
    }

    /**
     * Tests that multiple plugin iterators can be used concurrently.
     *
     * @return void
     */
    public function testUseMultiplePluginIteratorsConcurrently()
    {
        $plugin1 = $this->getMockPlugin('TestPlugin1');
        $this->handler->addPlugin($plugin1);

        $plugin2 = $this->getMockPlugin('TestPlugin2');
        $this->handler->addPlugin($plugin2);

        $iterator1 = $this->handler->getIterator();
        $iterator1->next();
        $this->assertSame($plugin2, $iterator1->current());

        $iterator2 = $this->handler->getIterator();
        $this->assertSame($plugin1, $iterator2->current());
    }

    /**
     * Tests adding plugin paths via configuration.
     *
     * @return void
     */
    public function testAddPluginPathsViaConfiguration()
    {
        $dir = dirname(__FILE__);
        $prefix = 'Phergie_Plugin_';
        $paths = array($dir => $prefix);
        $this->config
            ->expects($this->any())
            ->method('offsetExists')
            ->will($this->returnValue(true));
        $this->config
            ->expects($this->any())
            ->method('offsetGet')
            ->will($this->returnValue($paths));

        // Reinitialize the handler so the configuration change takes effect
        // within the constructor
        $this->handler = new Phergie_Plugin_Handler(
            $this->config,
            $this->events
        );

        $this->handler->setAutoload(true);
        $this->handler->getPlugin('Mock');
    }
}

license: mit


code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie_Tests
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie_Tests
 */

/**
 * Unit test suite for Pherge_Plugin_Iterator.
 *
 * @category Phergie
 * @package  Phergie_Tests
 * @author   Phergie Development Team <team@phergie.org>
 * @license  http://phergie.org/license New BSD License
 * @link     http://pear.phergie.org/package/Phergie_Tests
 */
class Phergie_Plugin_IteratorTest extends PHPUnit_Framework_TestCase
{
    /**
     * Iterator instance being tested
     *
     * @var Phergie_Plugin_Iterator
     */
    protected $iterator;

    /**
     * List of mock plugin instances to be iterated
     *
     * @var array
     */
    protected $plugins;

    /**
     * Initializes the iterator instance being tested.
     *
     * @return void
     */
    public function setUp()
    {
        $this->plugins = array();
        foreach (range(0, 4) as $index) {
            $plugin = $this->getMock('Phergie_Plugin_Abstract');
            $plugin
                ->expects($this->any())
                ->method('getName')
                ->will($this->returnValue($index));
            $this->plugins[] = $plugin;
        }

        $this->iterator = new Phergie_Plugin_Iterator(
            new ArrayIterator($this->plugins)
        );
    }

    /**
     * Tests that all plugins are iterated when no filters are applied.
     */
    public function testIteratesAllPluginsWithNoFilters()
    {
        $expected = range(0, 4);
        $actual = array();
        foreach ($this->iterator as $plugin) {
            $actual[] = $plugin->getName();
        }
        $this->assertEquals($expected, $actual);
    }

    /**
     * Tests that appropriate plugins are iterated when plugin name filters
     * are applied.
     */
    public function testIteratesPluginsWithNameFilters()
    {
        // Test acceptance of strings and fluent interface implementation
        $returned = $this->iterator->addPluginFilter('0');
        $this->assertSame($this->iterator, $returned);

        // Test acceptance of arrays
        $this->iterator->addPluginFilter(array('1', '3'));

        // Test application of filters to iteration
        $expected = array('2', '4');
        $actual = array();
        foreach ($this->iterator as $plugin) {
            $actual[] = $plugin->getName();
        }
        $this->assertEquals($expected, $actual);
    }

    /**
     * Tests that appropriate plugins are iterated when method name filters
     * are applied.
     *
     * The same method name is used in all cases here because mocked methods
     * of mock objects do not appear to be detected by method_exists() or
     * ReflectionClass, so filtering by a method defined in the base plugin
     * class seems the easiest way to test that method filtering really
     * works.
     */
    public function testIteratesPluginsWithMethodFilters()
    {
        // Tests acceptance of strings and fluent interface implementation
        $returned = $this->iterator->addMethodFilter('getName');
        $this->assertSame($this->iterator, $returned);

        // Test acceptance of arrays
        $this->iterator->addMethodFilter(array('getName', 'getName'));

        // Test application of filters to iteration
        $expected = array();
        $actual = array();
        foreach ($this->iterator as $plugin) {
            $actual[] = $plugin->getName();
        }
        $this->assertEquals($expected, $actual);
    }

    /**
     * Tests that all plugins are iterated after filters are cleared.
     *
     * @depends testIteratesPluginsWithNameFilters
     * @depends testIteratesPluginsWithMethodFilters
     */
    public function testIteratesPluginsAfterClearingFilters()
    {
        $this->iterator->addPluginFilter('0');
        $this->iterator->addMethodFilter('method1');
        $this->iterator->clearFilters();

        $expected = range(0, 4);
        $actual = array();
        foreach ($this->iterator as $plugin) {
            $actual[] = $plugin->getName();
        }
        $this->assertEquals($expected, $actual);
    }
}


code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie_Tests
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie_Tests
 */

/**
 * Unit test suite for Pherge_Plugin_Karma.
 *
 * @category Phergie
 * @package  Phergie_Tests
 * @author   Phergie Development Team <team@phergie.org>
 * @license  http://phergie.org/license New BSD License
 * @link     http://pear.phergie.org/package/Phergie_Tests
 */
class Phergie_Plugin_KarmaTest extends Phergie_Plugin_TestCase
{
    /**
     * Skips tests if the SQLite PDO driver is not available.
     *
     * @return void
     */
    public function setUp()
    {
        if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) {
            $this->markTestSkipped('PDO or pdo_sqlite extension is required');
        }

        parent::setUp();
    }

    /**
     * Configures the plugin to use a temporary copy of the database.
     *
     * @return PDO Connection to the temporary database
     */
    private function createMockDatabase()
    {
        $dbPath = $this->getPluginsPath('Karma/karma.db');
        $db = $this->getMockDatabase($dbPath);
        $this->plugin->setDb($db);
        return $db;
    }

    /**
     * Tests the requirement of the Command plugin.
     *
     * @return void
     */
    public function testRequiresCommandPlugin()
    {
        $this->assertRequiresPlugin('Command');
        $this->plugin->onLoad();
    }

    /**
     * Initiates a karma event with a specified term.
     *
     * @param string $term Karma term
     *
     * @return Phergie_Event_Request Initiated mock event
     */
    private function initiateKarmaEvent($term)
    {
        $args = array(
            'receiver' => $this->source,
            'text' => 'karma ' . $term
        );
        $event = $this->getMockEvent('privmsg', $args);
        $this->plugin->setEvent($event);
        return $event;
    }

    /**
     * Checks for an expected karma response.
     *
     * @param Phergie_Event_Request $event    Event containing the karma
     *                                        request
     * @param string                $term     Karma term
     * @param string                $response Portion of the response
     *                                        message following the term
     *                                        from the original event
     *
     * @return void
     */
    private function checkForKarmaResponse($event, $term, $response)
    {
        $text = $event->getNick() . ': ' . $response;
        $this->assertEmitsEvent('privmsg', array($event->getSource(), $text));
        $this->plugin->onCommandKarma($term);
    }

    /**
     * Tests that a default database is used when none is specified.
     *
     * @return void
     */
    public function testGetDb()
    {
        $db = $this->plugin->getDb();
        $this->assertType('PDO', $db);
    }

    /**
     * Tests specifying a custom database for the plugin to use.
     *
     * @return void
     */
    public function testSetDb()
    {
        $db = $this->createMockDatabase();
        $this->assertSame($db, $this->plugin->getDb());
    }

    /**
     * Tests that issuing the karma command with an unknown term returns a
     * neutral rating.
     *
     * @return void
     */
    public function testKarmaCommandOnUnknownTerm()
    {
        $term = 'foo';
        $this->createMockDatabase();
        $event = $this->initiateKarmaEvent($term);
        $this->checkForKarmaResponse($event, $term, $term . ' has neutral karma.');
    }

    /**
     * Tests that issuing the karma command with the term "me" returns the
     * the karma rating for the initiating user.
     *
     * @return void
     */
    public function testKarmaCommandOnUser()
    {
        $term = 'me';
        $this->createMockDatabase();
        $event = $this->initiateKarmaEvent($term);
        $this->checkForKarmaResponse($event, $term, 'You have neutral karma.');
    }

    /**
     * Tests that issuing the karma command with a term that has a fixed
     * karma rating results in that rating being returned.
     *
     * @return void
     */
    public function testKarmaCommandWithFixedKarmaTerm()
    {
        $term = 'phergie';
        $this->createMockDatabase();
        $event = $this->initiateKarmaEvent($term);
        $this->checkForKarmaResponse($event, $term, 'phergie has karma of awesome.');
    }

    /**
     * Supporting method that tests the result of a karma term rating change.
     *
     * @param string $term      Karma term for which the rating is being
     *                          changed
     * @param string $operation ++ or --
     * @param int    $karma     Expected karma rating after the change is
     *                          applied
     */
    private function checkForKarmaRatingChange($term, $operation, $karma)
    {
        $args = array(
            'receiver' => $this->source,
            'text' => $term . $operation
        );
        $event = $this->getMockEvent('privmsg', $args);
        $this->plugin->setEvent($event);
        $this->plugin->onPrivmsg();
        $event = $this->initiateKarmaEvent($term);
        $this->checkForKarmaResponse($event, $term, $term . ' has karma of ' . $karma . '.');
    }

    /**
     * Tests incrementing the karma rating of a new term.
     *
     * @return void
     */
    public function testIncrementingKarmaRating()
    {
        $this->createMockDatabase();
        $this->checkForKarmaRatingChange('foo', '++', 1);
    }

    /**
     * Tests decrementing the karma rating of a new term.
     *
     * @return void
     */
    public function testDecrementingKarmaRating()
    {
        $this->createMockDatabase();
        $this->checkForKarmaRatingChange('foo', '--', -1);
    }

    /**
     * Tests modifying the karma rating of an existing term.
     *
     * @return void
     */
    public function testChangingExistingKarmaRating()
    {
        $term = 'foo';
        $this->createMockDatabase();
        $this->checkForKarmaRatingChange($term, '++', 1);
        $this->checkForKarmaRatingChange($term, '++', 2);
    }

    /**
     * Tests resetting the karma rating of an existing term to 0.
     *
     * @return void
     */
    public function testResettingExistingKarmaRating()
    {
        $term = 'foo';
        $this->createMockDatabase();
        $this->checkForKarmaRatingChange($term, '++', 1);
        $this->plugin->onCommandReincarnate($term);
        $event = $this->initiateKarmaEvent($term);
        $this->checkForKarmaResponse($event, $term, $term . ' has neutral karma.');
    }

    /**
     * Data provider for testKarmaComparisons().
     *
     * @return array Enumerated array of enumerated arrays each containing a
     *               set of parameter values for a single call to
     *               testKarmaComparisons()
     */
    public function dataProviderTestKarmaComparisons()
    {
        $term1 = 'foo';
        $term2 = 'bar';

        $positive = 'True that.';
        $negative = 'No sir, not at all.';

        return array(
            array($term1, $term2, 1, 0, '>', $positive),
            array($term1, $term2, 0, 1, '>', $negative),
            array($term1, $term2, 1, 1, '>', $negative),
            array($term1, $term2, 1, 0, '<', $negative),
            array($term1, $term2, 0, 1, '<', $positive),
            array($term1, $term2, 1, 1, '<', $negative),
            array($term1, 'phergie', 1, 0, '>', $positive),
            array('phergie', $term2, 0, 1, '<', $positive),
            array($term1, 'everything', 0, 0, '>', $positive),
            array('everything', $term2, 0, 0, '>', $positive),
        );
    }

    /**
     * Tests comparing the karma ratings of two terms.
     *
     * @param string $term1    First term
     * @param string $term2    Second term
     * @param int    $karma1   Karma rating of the first time, 0 or 1
     * @param int    $karma2   Karma rating of the second term, 0 or 1
     * @param string $operator Comparison operator, > or <
     * @param string $response Response to check for
     *
     * @return void
     * @dataProvider dataProviderTestKarmaComparisons
     */
    public function testKarmaComparisons($term1, $term2, $karma1, $karma2,
        $operator, $response
    ) {
        $db = $this->createMockDatabase();

        // Reduce answer tables to expected response
        $stmt = $db->prepare('DELETE FROM positive_answers WHERE answer != ?');
        $stmt->execute(array($response));
        $stmt = $db->prepare('DELETE FROM negative_answers WHERE answer != ?');
        $stmt->execute(array($response));

        if ($karma1) {
            $this->checkForKarmaRatingChange($term1, '++', 1);
        }

        if ($karma2) {
            $this->checkForKarmaRatingChange($term2, '++', 1);
        }

        $args = array(
            'receiver' => $this->source,
            'text' => $term1 . ' ' . $operator . ' ' . $term2
        );
        $event = $this->getMockEvent('privmsg', $args);
        $this->plugin->setEvent($event);

        // Test lack of a response for terms with fixed karma ratings
        if ($term1 == 'phergie' || $term2 == 'phergie') {
            $callback = 'assertDoesNotEmitEvent';
        } else {
            $callback = 'assertEmitsEvent';
        }

        $this->$callback('privmsg', array($event->getSource(), $response));
        $this->plugin->onPrivmsg();

        // Test for karma changes when one term is "everything"
        if ($term1 == 'everything' || $term2 == 'everything') {
            if ($term1 == 'everything') {
                $term = $term2;
                $karma = ($operator == '>') ? -1 : 1;
            } else {
                $term = $term1;
                $karma = ($operator == '>') ? 1 : -1;
            }
            $event = $this->initiateKarmaEvent($term);
            $this->checkForKarmaResponse($event, $term, $term . ' has karma of ' . $karma . '.');
        }
    }
}


code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie_Tests
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie_Tests
 */

/**
 * Creates a plugin on the filesystem that can be used by
 * Phergie_Plugin_Handler::addPath() to be located and loaded.
 *
 * @category Phergie
 * @package  Phergie_Tests
 * @author   Phergie Development Team <team@phergie.org>
 * @license  http://phergie.org/license New BSD License
 * @link     http://pear.phergie.org/package/Phergie_Tests
 */
class Phergie_Plugin_Mock extends Phergie_Plugin_Abstract
{
    /**
     * Arguments passed to the constructor
     *
     * @var array
     */
    protected $arguments;

    /**
     * Stores all arguments for later use.
     *
     * @return void
     */
    public function __construct()
    {
        $this->arguments = func_get_args();
    }

    /**
     * Returns all constructor arguments.
     *
     * @return array Enumerated array containing the arguments passed to the
     *         constructor in order
     */
    public function getArguments()
    {
        return $this->arguments;
    }
}


code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie_Tests
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie_Tests
 */

/**
 * Unit test suite for Pherge_Plugin_Ping.
 *
 * @category Phergie
 * @package  Phergie_Tests
 * @author   Phergie Development Team <team@phergie.org>
 * @license  http://phergie.org/license New BSD License
 * @link     http://pear.phergie.org/package/Phergie_Tests
 */
class Phergie_Plugin_PingTest extends Phergie_Plugin_TestCase
{
    /**
     * Tests that the last ping and event are initialized on connection to
     * the server.
     *
     * @return void
     */
    public function testOnConnect()
    {
        $this->plugin->onConnect();

        $expected = time();
        $actual = $this->plugin->getLastEvent();
        $this->assertEquals($expected, $actual);

        $expected = null;
        $actual = $this->plugin->getLastPing();
        $this->assertEquals($expected, $actual);
    }

    /**
     * Tests that the last event is reset when an event occurs.
     *
     * @return void
     */
    public function testPreEvent()
    {
        $this->plugin->preEvent();

        $expected = time();
        $actual = $this->plugin->getLastEvent();
        $this->assertEquals($expected, $actual);
    }

    /**
     * Tests that the last ping is reset when a ping is received.
     *
     * @return void
     */
    public function testOnPingResponse()
    {
        $this->plugin->onPingResponse();

        $expected = null;
        $actual = $this->plugin->getLastPing();
        $this->assertEquals($expected, $actual);
    }

    /**
     * Tests that the test suite is able to manipulate the value of the last
     * event.
     *
     * @return void
     */
    public function testSetLastEvent()
    {
        $expected = time() + 1;
        $this->plugin->setLastEvent($expected);
        $actual = $this->plugin->getLastEvent();
        $this->assertEquals($expected, $actual);

        $this->plugin->setLastEvent();
        $expected = time();
        $actual = $this->plugin->getLastEvent();
        $this->assertEquals($expected, $actual);

        try {
            $this->plugin->setLastEvent('foo');
            $this->fail('Expected exception was not thrown');
        } catch (Exception $e) { }
    }

    /**
     * Tests that the test suite is able to manipulate the value of the last
     * ping.
     *
     * @return void
     */
    public function testSetLastPing()
    {
        $expected = time() + 1;
        $this->plugin->setLastPing($expected);
        $actual = $this->plugin->getLastPing();
        $this->assertEquals($expected, $actual);

        $this->plugin->setLastPing();
        $expected = time();
        $actual = $this->plugin->getLastPing();
        $this->assertEquals($expected, $actual);

        try {
            $this->plugin->setLastPing('foo');
            $this->fail('Expected exception was not thrown');
        } catch (Exception $e) { }
    }

    /**
     * Tests that a ping event is sent after the appropriate time period has
     * lapsed since receiving an event.
     *
     * @depends testSetLastEvent
     * @return void
     */
    public function testPing()
    {
        $pingEvent = 10;
        $this->setConfig('ping.event', $pingEvent);
        $lastEvent = time() - ($pingEvent + 1);
        $this->plugin->setLastEvent($lastEvent);
        $expected = time();
        $this->assertEmitsEvent('ping', array($this->nick, $expected));
        $this->plugin->onTick();
        $actual = $this->plugin->getLastPing();
        $this->assertEquals($expected, $actual);
    }

    /**
     * Tests that a quit event is sent after the appropriate time period has
     * lapsed since sending a ping event.
     *
     * @depends testPing
     * @return void
     */
    public function testQuit()
    {
        $pingPing = 10;
        $this->setConfig('ping.ping', $pingPing);
        $lastPing = time() - ($pingPing + 1);
        $this->plugin->setLastPing($lastPing);
        $this->assertEmitsEvent('quit');
        $this->plugin->onTick();
    }
}


code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie_Tests
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie_Tests
 */

/**
 * Unit test suite for Pherge_Plugin_Pong.
 *
 * @category Phergie
 * @package  Phergie_Tests
 * @author   Phergie Development Team <team@phergie.org>
 * @license  http://phergie.org/license New BSD License
 * @link     http://pear.phergie.org/package/Phergie_Tests
 */
class Phergie_Plugin_PongTest extends Phergie_Plugin_TestCase
{
    /**
     * Test that a pong event is sent when a ping event is received.
     *
     * @return void
     */
    public function testPong()
    {
        $expected = 'irc.freenode.net';
        $event = $this->getMockEvent('ping', array($expected));
        $this->plugin->setEvent($event);
        $this->assertEmitsEvent('pong', array($expected));
        $this->plugin->onPing();
    }
}


code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie_Tests
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie_Tests
 */

/**
 * Unit test suite for Pherge_Plugin_SpellCheck.
 *
 * @category Phergie
 * @package  Phergie_Tests
 * @author   Phergie Development Team <team@phergie.org>
 * @license  http://phergie.org/license New BSD License
 * @link     http://pear.phergie.org/package/Phergie_Tests
 */
class Phergie_Plugin_SpellCheckTest extends Phergie_Plugin_TestCase
{
    /**
     * Checks for the pspell extension.
     *
     * @return void
     */
    public function setUp()
    {
        parent::setUp();

        if (!extension_loaded('pspell')) {
            $this->markTestSkipped('pspell extension not available');
        }
    }

    /**
     * Tests for the plugin failing to load when the language setting is not
     * specified.
     *
     * @return void
     */
    public function testLanguageSettingNotSet()
    {
        try {
            $this->plugin->onLoad();
            $this->fail('Expected exception was not thrown');
        } catch (Phergie_Plugin_Exception $e) {
            return;
        }
        $this->fail('Unexpected exception was thrown');
    }

    /**
     * Tests for the plugin requiring the Command plugin as a dependency.
     *
     * @return void
     */
    public function testRequiresCommandPlugin()
    {
        $this->setConfig('spellcheck.lang', 'en');
        $this->assertRequiresPlugin('Command');
        $this->plugin->onLoad();
    }

    /**
     * Tests for the plugin failing to load because of a dictionary error.
     *
     * @return void
     */
    public function testLoadDictionaryError()
    {
        $this->setConfig('spellcheck.lang', 'foo');
        try {
            $this->plugin->onLoad();
            $this->fail('Expected exception not thrown');
        } catch (Phergie_Plugin_Exception $e) {
            return;
        }
        $this->fail('Unexpected exception was thrown');
    }

    /**
     * Initializes a spell check event.
     *
     * @param string $word Word to be checked
     *
     * @return void
     */
    private function initializeSpellCheckEvent($word)
    {
        $this->setConfig('spellcheck.lang', 'en');
        $this->plugin->onLoad();
        $args = array(
            'receiver' => $this->source,
            'text' => 'spell ' . $word
        );
        $event = $this->getMockEvent('privmsg', $args);
        $this->plugin->setEvent($event);
    }

    /**
     * Checks for a specified response to a spell check event.
     *
     * @param string $word     Work being checked
     * @param string $response Expected response
     *
     * @return void
     */
    private function checkForSpellCheckResponse($word, $response)
    {
        $this->assertEmitsEvent('privmsg', array($this->source, $response));
        $this->plugin->onCommandSpell($word);
    }

    /**
     * Tests for the plugin returning a response for a correctly spelled word.
     *
     * @return void
     */
    public function testRespondsForCorrectlySpelledWord()
    {
        $word = 'test';
        $this->initializeSpellCheckEvent($word);
        $response = $this->nick . ': The word "' . $word . '" seems to be spelled correctly.';
        $this->checkForSpellCheckResponse($word, $response);
    }

    /**
     * Tests for the plugin returning a response when it can't find any
     * suggestions for a word.
     *
     * @return void
     */
    public function testRespondsWithoutSuggestions()
    {
        $word = 'kjlfljlkjljkljlj';
        $this->initializeSpellCheckEvent($word);
        $response = $this->nick . ': I could not find any suggestions for "' . $word . '".';
        $this->checkForSpellCheckResponse($word, $response);
    }

    /**
     * Tests for the plugin returning a response when it is able to find
     * suggestions for a word.
     *
     * @return void
     */
    public function testRespondsWithSuggestions()
    {
        $word = 'teh';
        $this->initializeSpellCheckEvent($word);
        $response = $this->nick . ': Suggestions for "' . $word . '": the, Te, tech, Th, eh.';
        $this->checkForSpellCheckResponse($word, $response);
    }
}


code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie_Tests
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie_Tests
 */

/**
 * Unit test suite for Pherge_Plugin_TerryChay.
 *
 * @category Phergie
 * @package  Phergie_Tests
 * @author   Phergie Development Team <team@phergie.org>
 * @license  http://phergie.org/license New BSD License
 * @link     http://pear.phergie.org/package/Phergie_Tests
 */
class Phergie_Plugin_TerryChayTest extends Phergie_Plugin_TestCase
{
    /**
     * Chayism used as a consistent response when related events are
     * triggered
     *
     * @var string
     */
    private $chayism = 'Terry Chay doesn\'t need a framework; he already knows everyone\'s code';

    /**
     * Configures the mock plugin handler to return a mock Http plugin with
     * a mock response object populated with predetermined content.
     *
     * @return void
     */
    public function setUpHttpClient()
    {
        $response = $this->getMock('Phergie_Plugin_Http_Response');
        $response
            ->expects($this->any())
            ->method('getContent')
            ->will($this->returnValue($this->chayism));

        $plugin = $this->getMock('Phergie_Plugin_Http');
        $plugin
            ->expects($this->any())
            ->method('get')
            ->will($this->returnValue($response));

        $this->getMockPluginHandler()
            ->expects($this->any())
            ->method('getPlugin')
            ->with('Http')
            ->will($this->returnValue($plugin));
    }

    /**
     * Tests that the plugin requires the Http plugin as a dependency.
     *
     * @return void
     */
    public function testRequiresHttpPlugin()
    {
        $this->assertRequiresPlugin('Http');
        $this->plugin->onLoad();
    }

    /**
     * Data provider for testPrivmsgTriggerReturnsChayism().
     *
     * @return array Enumerated array of enumerated arrays each containing
     *               a set of parameters for a single call to
     *               testPrivmsgTriggerReturnsChayism()
     */
    public function dataProviderTestPrivmsgTriggerReturnsChayism()
    {
        return array(
            array('terry chay'),
            array('terry  chay'),
            array('tychay'),
            array('!tychay'),
            array('! tychay'),
            array('foo tychay bar'),
        );
    }

    /**
     * Tests that appropriate triggers result in a response with a Chayism.
     *
     * @return void
     * @dataProvider dataProviderTestPrivmsgTriggerReturnsChayism
     */
    public function testPrivmsgTriggerReturnsChayism($trigger)
    {
        $this->setConfig('command.prefix', '!');
        $this->setUpHttpClient();
        $args = array(
            'receiver' => $this->source,
            'text' => $trigger
        );
        $event = $this->getMockEvent('privmsg', $args);
        $this->plugin->setEvent($event);
        $this->assertEmitsEvent('privmsg', array($this->source, 'Fact: ' . $this->chayism));
        $this->plugin->onPrivmsg();
    }

    /**
     * Tests that lack of an appropriate trigger results in no response with
     * a Chayism.
     *
     * @return void
     */
    public function testNoPrivmsgTriggerDoesNotReturnChayism()
    {
        $args = array(
            'receiver' => $this->source,
            'text' => 'foo bar baz'
        );
        $event = $this->getMockEvent('privmsg', $args);
        $this->plugin->setEvent($event);
        $this->assertDoesNotEmitEvent('privmsg', array($this->source, 'Fact: ' . $this->chayism));
        $this->plugin->onPrivmsg();
    }
}


code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie_Tests
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie_Tests
 */

/**
 * Unit test suite for plugin classes.
 *
 * @category Phergie
 * @package  Phergie_Tests
 * @author   Phergie Development Team <team@phergie.org>
 * @license  http://phergie.org/license New BSD License
 * @link     http://pear.phergie.org/package/Phergie_Tests
 */
abstract class Phergie_Plugin_TestCase extends PHPUnit_Framework_TestCase
{
    /**
     * 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 $settings = array();

    /**
     * Mock connection
     *
     * @var Phergie_Connection
     */
    protected $connection;

    /**
     * Mock event handler
     *
     * @var Phergie_Event_Handler
     */
    protected $events;

    /**
     * Mock plugin handler
     *
     * @var Phergie_Plugin_Handler
     */
    protected $plugins;

    /**
     * Plugin instance being tested
     *
     * @var Phergie_Plugin_Abstract
     */
    protected $plugin;

    /**
     * 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 $source = '#channel';

    /**
     * Initializes instance properties.
     *
     * @return void
     */
    public function setUp()
    {
        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());
    }

    /**
     * Destroys all initialized instance properties.
     *
     * @return void
     */
    public function tearDown()
    {
        unset(
            $this->plugins,
            $this->events,
            $this->connection,
            $this->config,
            $this->plugin
        );
    }

    /**
     * Returns a mock configuration object.
     *
     * @return Phergie_Config
     */
    protected function getMockConfig()
    {
        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;
    }

    /**
     * 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
     *
     * @return boolean TRUE if the setting has a value, FALSE otherwise
     */
    public function configOffsetExists($name)
    {
        return isset($this->settings[$name]);
    }

    /**
     * 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 configOffsetGet($name)
    {
        return $this->settings[$name];
    }

    /**
     * Returns a mock connection object.
     *
     * @return Phergie_Connection
     */
    protected function getMockConnection()
    {
        if (empty($this->connection)) {
            $this->connection = $this->getMock('Phergie_Connection');
            $this->connection
                ->expects($this->any())
                ->method('getNick')
                ->will($this->returnValue($this->nick));
        }
        return $this->connection;
    }

    /**
     * Returns a mock event handler object.
     *
     * @return Phergie_Event_Handler
     */
    protected function getMockEventHandler()
    {
        if (empty($this->events)) {
            $this->events = $this->getMock('Phergie_Event_Handler', array('addEvent'));
        }
        return $this->events;
    }

    /**
     * Returns a mock plugin handler object.
     *
     * @return Phergie_Plugin_Handler
     */
    protected function getMockPluginHandler()
    {
        if (empty($this->plugins)) {
            $config = $this->getMockConfig();
            $events = $this->getMockEventHandler();
            $this->plugins = $this->getMock(
                'Phergie_Plugin_Handler',
                array(), // mock everything
                array($config, $events)
            );
        }
        return $this->plugins;
    }

    /**
     * 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);
            }
        }

        $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));
            }
        }

        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);
    }

    /**
     * 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);
            }'
        );

        $this->events
            ->expects($this->any())
            ->method('addEvent')
            ->will($this->returnCallback($callback));
    }

    /**
     * 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;
    }
}


code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie_Tests
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie_Tests
 */

/**
 * Creates a plugin on the filesystem that can be used by
 * Phergie_Plugin_Handler's addPath utility to be located and loaded.
 *
 * @category Phergie
 * @package  Phergie_Tests
 * @author   Phergie Development Team <team@phergie.org>
 * @license  http://phergie.org/license New BSD License
 * @link     http://pear.phergie.org/package/Phergie_Tests
 */
class Phergie_Plugin_TestNonInstantiablePluginFromFile
extends Phergie_Plugin_Abstract
{
    /**
     * Private constructor to ensure that this class is not instantiable.
     *
     * @return void
     */
    private function __construct()
    {
    }
}


code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie_Tests
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie_Tests
 */

error_reporting(E_ALL | E_STRICT);

// Phergie components require Phergie_Autoload to function correctly.
require_once dirname(__FILE__) . '/../Phergie/Autoload.php';
Phergie_Autoload::registerAutoloader();


code:
<!--
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie_Tests
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie_Tests
 */
-->
<phpunit colors="true" bootstrap="./TestHelper.php">
    <testsuite name="Phergie Test Suite">
        <directory>./</directory>
    </testsuite>
</phpunit>


code:
<?xml version="1.0" encoding="UTF-8"?>

<project name="Phergie" default="core">

    <tstamp>
        <format property="DSTAMP" pattern="%Y-%m-%d" />
    </tstamp>

    <taskdef name="phergiepkg" classname="PhergiePackageTask" />
    <taskdef name="phpdocumentor" classname="phing.tasks.ext.phpdoc.PhpDocumentorTask" />

    <available file="./build.properties" property="have_properties_file" />

    <property name="clean" value="true" />

    <target name="input">

        <if>
            <equals arg1="${have_properties_file}" arg2="true" />
            <then>
                <property file="./build.properties" />
            </then>
            <else>
                <input propertyname="build.srcdir" defaultvalue="./" message="Source directory" />
                <input propertyname="build.dstdir" defaultvalue="./" message="Destination directory" />
                <input propertyname="build.version.release" message="Release version" />
                <input propertyname="build.version.api" message="API version" />
                <input propertyname="build.stability.release" defaultvalue="stable" message="Release stability" validArgs="snapshot,devel,alpha,beta,stable" />
                <input propertyname="build.stability.api" defaultvalue="stable"  message="API stability" validArgs="snapshot,devel,alpha,beta,stable" />
                <input propertyname="build.notes" message="Release notes" />
                <input propertyname="build.phpdep" defaultvalue="5.2.0" message="PHP version required" />
                <input propertyname="build.pearinstallerdep" defaultvalue="1.9.0" message="PEAR installer version required" />
            </else>
        </if>

        <fileset dir="${build.srcdir}" id="core">
            <include name="phergie.php" />
            <include name="phergie.bat" />
            <include name="LICENSE" />
            <include name="Settings.php.dist" />
            <include name="Phergie/Autoload.php" />
            <include name="Phergie/Bot.php" />
            <include name="Phergie/Config/Exception.php" />
            <include name="Phergie/Config.php" />
            <include name="Phergie/Connection/Exception.php" />
            <include name="Phergie/Connection/Handler.php" />
            <include name="Phergie/Connection.php" />
            <include name="Phergie/Db/Exception.php" />
            <include name="Phergie/Db/Manager.php" />
            <include name="Phergie/Db/Sqlite.php" />
            <include name="Phergie/Driver/Abstract.php" />
            <include name="Phergie/Driver/Exception.php" />
            <include name="Phergie/Driver/Streams.php" />
            <include name="Phergie/Event/Abstract.php" />
            <include name="Phergie/Event/Command.php" />
            <include name="Phergie/Event/Exception.php" />
            <include name="Phergie/Event/Handler.php" />
            <include name="Phergie/Event/Request.php" />
            <include name="Phergie/Event/Response.php" />
            <include name="Phergie/Exception.php" />
            <include name="Phergie/Hostmask/Exception.php" />
            <include name="Phergie/Hostmask.php" />
            <include name="Phergie/Plugin/Abstract.php" />
            <include name="Phergie/Plugin/Exception.php" />
            <include name="Phergie/Plugin/Handler.php" />
            <include name="Phergie/Ui/Abstract.php" />
            <include name="Phergie/Ui/Console.php" />
        </fileset>

    </target>

    <target name="core" depends="input">

        <property name="build.tmpdir" value="Phergie-${build.version.release}" />
        <property name="build.tarball" value="${build.dstdir}${build.tmpdir}.tgz" />

        <delete file="${build.tarball}" quiet="true" />

        <mkdir dir="${build.tmpdir}" />

        <copy todir="${build.tmpdir}">
            <fileset refid="core" />
        </copy>

        <reflexive file="${build.tmpdir}/Phergie/Bot.php">
            <filterchain>
                <replaceregexp>
                    <regexp
                        pattern="const VERSION = '[^']+';"
                        replace="const VERSION = '${build.version.release}';"
                    />
                </replaceregexp>
            </filterchain>
        </reflexive>

        <phergiepkg name="Phergie" dir="${build.tmpdir}">
            <fileset refid="core" />
            <option name="baseinstalldir" value="/" />
            <option name="outputdirectory" value="${build.dstdir}" />
            <option name="channel" value="pear.phergie.org" />
            <option name="summary" value="Phergie core library" />
            <option name="description" value="The Phergie package provides all files necessary to run a basic IRC bot." />
            <option name="apiversion" value="${build.version.api}" />
            <option name="apistability" value="${build.stability.api}" />
            <option name="releaseversion" value="${build.version.release}" />
            <option name="releasestability" value="${build.stability.release}" />
            <option name="phpdep" value="${build.phpdep}" />
            <option name="pearinstallerdep" value="${build.pearinstallerdep}" />
            <option name="license" value="http://phergie.org/license New BSD License" />
            <option name="packagetype" value="php" />
            <option name="notes" value="${build.notes}" />
            <mapping name="replacements">
                <element>
                    <element key="path" value="phergie.php" />
                    <element key="type" value="pear-config" />
                    <element key="from" value="/usr/bin/env php" />
                    <element key="to" value="php_bin" />
                </element>
                <element>
                    <element key="path" value="phergie.bat" />
                    <element key="type" value="pear-config" />
                    <element key="from" value="@php_bin@" />
                    <element key="to" value="php_bin" />
                </element>
                <element>
                    <element key="path" value="phergie.bat" />
                    <element key="type" value="pear-config" />
                    <element key="from" value="@bin_dir@" />
                    <element key="to" value="bin_dir" />
                </element>
            </mapping>
            <mapping name="exceptions">
                <element key="phergie.php" value="script" />
                <element key="phergie.bat" value="script" />
            </mapping>
            <mapping name="releases">
                <element>
                    <element key="installconditions">
                        <element key="os" value="windows" />
                    </element>
                    <element key="filelist">
                        <element key="install">
                            <element key="phergie.php" value="phergie" />
                        </element>
                    </element>
                </element>
                <element>
                    <element key="filelist">
                        <element key="install">
                            <element key="phergie.php" value="phergie" />
                        </element>
                        <element key="ignore">
                            <element value="phergie.bat" />
                        </element>
                    </element>
                </element>
            </mapping>
            <mapping name="deps">
                <element>
                    <element key="type" value="ext" />
                    <element key="name" value="pcre" />
                </element>
                <element>
                    <element key="type" value="ext" />
                    <element key="name" value="reflection" />
                </element>
            </mapping>
        </phergiepkg>

        <phingcall target="build" />

        <phingcall target="clean" />

    </target>

    <target name="plugin" depends="input">

        <if>
            <equals arg1="${have_properties_file}" arg2="true" />
            <then>
                <property file="./build.properties" />
            </then>
            <else>
                <input propertyname="build.plugin" message="Short plugin name" />
                <input propertyname="build.summary" message="Plugin summary" />
                <input propertyname="build.description" message="Plugin description" />
            </else>
        </if>

        <property name="build.class" value="Phergie_Plugin_${build.plugin}" />
        <property name="build.tmpdir" value="${build.class}-${build.version.release}" />
        <property name="build.tarball" value="${build.dstdir}${build.tmpdir}.tgz" />

        <fileset dir="${build.srcdir}" id="plugin">
            <include name="Phergie/Plugin/${build.plugin}.php" />
            <include name="Phergie/Plugin/${build.plugin}/**" />
        </fileset>

        <delete file="${build.tarball}" quiet="true" />

        <mkdir dir="${build.tmpdir}" />

        <copy todir="${build.tmpdir}">
            <fileset refid="plugin" />
        </copy>

        <phergiepkg name="${build.class}" dir="${build.tmpdir}">
            <fileset refid="plugin" />
            <option name="baseinstalldir" value="/" />
            <option name="outputdirectory" value="${build.dstdir}" />
            <option name="channel" value="pear.phergie.org"/>
            <option name="summary" value="${build.summary}"/>
            <option name="description" value="${build.description}"/>
            <option name="apiversion" value="${build.version.api}"/>
            <option name="apistability" value="${build.stability.api}"/>
            <option name="releaseversion" value="${build.version.release}"/>
            <option name="releasestability" value="${build.stability.release}"/>
            <option name="phpdep" value="${build.phpdep}" />
            <option name="pearinstallerdep" value="${build.pearinstallerdep}" />
            <option name="license" value="http://phergie.org/license New BSD License"/>
            <option name="packagetype" value="php"/>
            <option name="notes" value="${build.notes}"/>
        </phergiepkg>

        <phingcall target="build" />

        <phingcall target="clean" />

    </target>

    <target name="docs" depends="input">

        <property name="build.tmpdir" value="Phergie_Docs-${build.version.release}" />
        <property name="build.tarball" value="${build.dstdir}${build.tmpdir}.tgz" />

        <delete file="${build.tarball}" quiet="true" />

        <mkdir dir="${build.tmpdir}" />

        <phpdocumentor title="API Documentation"
            destdir="${build.tmpdir}/api"
            output="HTML:Smarty:PHP">
            <fileset refid="core" />
            <projdocfileset dir=".">
                <include name="LICENSE" />
            </projdocfileset>
        </phpdocumentor>

        <phergiepkg name="Phergie_Docs" dir="${build.tmpdir}">
            <fileset dir="${build.tmpdir}">
                <include name="api**" />
            </fileset>
            <option name="baseinstalldir" value="/" />
            <option name="outputdirectory" value="${build.dstdir}" />
            <option name="channel" value="pear.phergie.org" />
            <option name="summary" value="Phergie core library documentation" />
            <option name="description" value="The Phergie_Docs package provides documentation for the Phergie core libraries." />
            <option name="apiversion" value="${build.version.api}" />
            <option name="apistability" value="${build.stability.api}" />
            <option name="releaseversion" value="${build.version.release}" />
            <option name="releasestability" value="${build.stability.release}" />
            <option name="phpdep" value="${build.phpdep}" />
            <option name="pearinstallerdep" value="${build.pearinstallerdep}" />
            <option name="license" value="http://phergie.org/license New BSD License" />
            <option name="packagetype" value="php" />
            <option name="notes" value="${build.notes}" />
            <mapping name="exceptions">
                <element key="api" value="doc" />
            </mapping>
        </phergiepkg>

        <phingcall target="build" />

        <phingcall target="clean" />

    </target>

    <target name="build">

        <tar destfile="${build.tarball}" compression="gzip">
            <fileset dir="${build.dstdir}">
                <include name="${build.tmpdir}**" />
                <include name="package.xml" />
            </fileset>
        </tar>

    </target>

    <target name="clean">

        <if>
            <istrue value="${clean}" />
            <then>
                <delete dir="${build.tmpdir}" />
                <delete file="${build.dstdir}package.xml" />
            </then>
        </if>

    </target>

</project>


code:
@echo off
REM  Phergie
REM
REM  PHP version 5
REM
REM  LICENSE
REM
REM  This source file is subject to the new BSD license that is bundled
REM  with this package in the file LICENSE.
REM  It is also available through the world-wide-web at this URL:
REM  http://phergie.org/license

set PHPBIN="@php_bin@"
%PHPBIN% "@bin_dir@\phergie" %*


code:
#!/usr/bin/env php
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie
 */

/**
 * @see Phergie_Autoload
 */
require 'Phergie/Autoload.php';
Phergie_Autoload::registerAutoloader();

$bot = new Phergie_Bot;

if (!isset($argc)) {
    echo
        'The PHP setting register_argc_argv must be enabled for Phergie ',
        'configuration files to be specified using command line arguments; ',
        'defaulting to Settings.php in the current working directory',
        PHP_EOL;
} else if ($argc > 0) {
    // Skip the current file for manual installations
    // ex: php phergie.php Settings.php
    if (realpath($argv[0]) == __FILE__) {
        array_shift($argv);
    }

    // If configuration files were specified, override default behavior
    if (count($argv) > 0) {
        $config = new Phergie_Config;
        foreach ($argv as $file) {
            $config->read($file);
        }
        $bot->setConfig($config);
    }
}

$bot->run();


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Extend the IMChannel class to allow commands to send messages
 * to a channel instead of PMing a user
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Network
 * @package   StatusNet
 * @author    Luke Fitzgerald <lw.fitzgerald@googlemail.com>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

class ChannelResponseChannel extends IMChannel {
    protected $ircChannel;

    /**
    * Construct a ChannelResponseChannel
    *
    * @param IMplugin $imPlugin IMPlugin
    * @param string $ircChannel IRC Channel to reply to
    * @return ChannelResponseChannel
    */
    public function __construct($imPlugin, $ircChannel) {
        $this->ircChannel = $ircChannel;
        parent::__construct($imPlugin);
    }

    /**
    * Send a message using the plugin
    *
    * @param User $user User
    * @param string $text Message text
    * @return void
    */
    public function output($user, $text) {
        $text = $user->nickname.': ['.common_config('site', 'name') . '] ' . $text;
        $this->imPlugin->sendMessage($this->ircChannel, $text);
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Instead of sending IRC messages, retrieve the raw data that would be sent
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Network
 * @package   StatusNet
 * @author    Luke Fitzgerald <lw.fitzgerald@googlemail.com>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

class FakeIrc extends Phergie_Driver_Streams {
    public $would_be_sent = null;

    /**
    * Store the components for sending a command
    *
    * @param string $command Command
    * @param array $args Arguments
    * @return void
    */
    protected function send($command, $args = '') {
        $this->would_be_sent = array('command' => $command, 'args' => $args);
    }
}