Merge in Phergie changes

This commit is contained in:
Luke Fitzgerald 2010-08-12 11:58:53 -07:00
parent d2c72d8ae1
commit a3fea6f673
16 changed files with 1513 additions and 590 deletions

View File

@ -141,9 +141,9 @@ class Phergie_Connection
{ {
if (empty($this->hostmask)) { if (empty($this->hostmask)) {
$this->hostmask = new Phergie_Hostmask( $this->hostmask = new Phergie_Hostmask(
$this->nick, $this->getNick(),
$this->username, $this->getUsername(),
$this->host $this->getHost()
); );
} }
@ -223,7 +223,7 @@ class Phergie_Connection
if (!in_array($this->transport, stream_get_transports())) { if (!in_array($this->transport, stream_get_transports())) {
throw new Phergie_Connection_Exception( throw new Phergie_Connection_Exception(
'Transport ' . $this->transport . ' is not supported', 'Transport ' . $this->transport . ' is not supported',
Phergie_Connection_Exception::TRANSPORT_NOT_SUPPORTED Phergie_Connection_Exception::ERR_TRANSPORT_NOT_SUPPORTED
); );
} }

View File

@ -110,7 +110,7 @@ class Phergie_Plugin_Cron extends Phergie_Plugin_Abstract
*/ */
public function onTick() public function onTick()
{ {
$now = time(); $time = time();
foreach ($this->callbacks as $key => &$callback) { foreach ($this->callbacks as $key => &$callback) {
$callbackString = $this->getCallbackString($callback); $callbackString = $this->getCallbackString($callback);

View File

@ -98,6 +98,12 @@ class Phergie_Plugin_Handler implements IteratorAggregate, Countable
$this->paths = array(); $this->paths = array();
$this->autoload = false; $this->autoload = false;
if (!empty($config['plugins.paths'])) {
foreach ($config['plugins.paths'] as $dir => $prefix) {
$this->addPath($dir, $prefix);
}
}
$this->addPath(dirname(__FILE__), 'Phergie_Plugin_'); $this->addPath(dirname(__FILE__), 'Phergie_Plugin_');
} }
@ -134,6 +140,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate, Countable
* Returns metadata corresponding to a specified plugin. * Returns metadata corresponding to a specified plugin.
* *
* @param string $plugin Short name of the plugin class * @param string $plugin Short name of the plugin class
*
* @throws Phergie_Plugin_Exception Class file can't be found * @throws Phergie_Plugin_Exception Class file can't be found
* *
* @return array|boolean Associative array containing the path to the * @return array|boolean Associative array containing the path to the
@ -444,15 +451,21 @@ class Phergie_Plugin_Handler implements IteratorAggregate, Countable
$valid = true; $valid = true;
try { try {
$error_reporting = error_reporting(0); // ignore autoloader errors
$r = new ReflectionClass($class); $r = new ReflectionClass($class);
$valid = $r->isSubclassOf('FilterIterator'); error_reporting($error_reporting);
if (!$r->isSubclassOf('FilterIterator')) {
$message = 'Class ' . $class . ' is not a subclass of FilterIterator';
$valid = false;
}
} catch (ReflectionException $e) { } catch (ReflectionException $e) {
$message = $e->getMessage();
$valid = false; $valid = false;
} }
if (!$valid) { if (!$valid) {
throw new Phergie_Plugin_Exception( throw new Phergie_Plugin_Exception(
$e->getMessage(), $message,
Phergie_Plugin_Exception::ERR_INVALID_ITERATOR_CLASS Phergie_Plugin_Exception::ERR_INVALID_ITERATOR_CLASS
); );
} }

View File

@ -31,7 +31,6 @@
* @uses extension PDO * @uses extension PDO
* @uses extension pdo_sqlite * @uses extension pdo_sqlite
* @uses Phergie_Plugin_Command pear.phergie.org * @uses Phergie_Plugin_Command pear.phergie.org
* @uses Phergie_Plugin_Message pear.phergie.org
*/ */
class Phergie_Plugin_Karma extends Phergie_Plugin_Abstract class Phergie_Plugin_Karma extends Phergie_Plugin_Abstract
{ {
@ -94,11 +93,16 @@ class Phergie_Plugin_Karma extends Phergie_Plugin_Abstract
{ {
$plugins = $this->getPluginHandler(); $plugins = $this->getPluginHandler();
$plugins->getPlugin('Command'); $plugins->getPlugin('Command');
$plugins->getPlugin('Message'); $this->getDb();
}
$file = dirname(__FILE__) . '/Karma/karma.db';
$this->db = new PDO('sqlite:' . $file);
/**
* Initializes prepared statements used by the plugin.
*
* @return void
*/
protected function initializePreparedStatements()
{
$this->fetchKarma = $this->db->prepare(' $this->fetchKarma = $this->db->prepare('
SELECT karma SELECT karma
FROM karmas FROM karmas
@ -139,6 +143,36 @@ class Phergie_Plugin_Karma extends Phergie_Plugin_Abstract
'); ');
} }
/**
* Returns a connection to the plugin database, initializing one if none
* is explicitly set.
*
* @return PDO Database connection
*/
public function getDb()
{
if (empty($this->db)) {
$this->db = new PDO('sqlite:' . dirname(__FILE__) . '/Karma/karma.db');
$this->initializePreparedStatements();
}
return $this->db;
}
/**
* Sets the connection to the plugin database, mainly intended for unit
* testing.
*
* @param PDO $db Database connection
*
* @return Phergie_Plugin_Karma Provides a fluent interface
*/
public function setDb(PDO $db)
{
$this->db = $db;
$this->initializePreparedStatements();
return $this;
}
/** /**
* Get the canonical form of a given term. * Get the canonical form of a given term.
* *
@ -228,15 +262,11 @@ REGEX;
$source = $this->getEvent()->getSource(); $source = $this->getEvent()->getSource();
$nick = $this->getEvent()->getNick(); $nick = $this->getEvent()->getNick();
if (empty($term)) {
return;
}
$canonicalTerm = $this->getCanonicalTerm($term); $canonicalTerm = $this->getCanonicalTerm($term);
$fixedKarma = $this->fetchFixedKarma($canonicalTerm); $fixedKarma = $this->fetchFixedKarma($canonicalTerm);
if ($fixedKarma) { if ($fixedKarma) {
$message = $nick . ': ' . $term . ' ' . $fixedKarma . '.'; $message = $nick . ': ' . $term . ' ' . $fixedKarma;
$this->doPrivmsg($source, $message); $this->doPrivmsg($source, $message);
return; return;
} }
@ -302,33 +332,29 @@ REGEX;
$fixedKarma0 = $this->fetchFixedKarma($canonicalTerm0); $fixedKarma0 = $this->fetchFixedKarma($canonicalTerm0);
$fixedKarma1 = $this->fetchFixedKarma($canonicalTerm1); $fixedKarma1 = $this->fetchFixedKarma($canonicalTerm1);
if ($fixedKarma0 if ($fixedKarma0 || $fixedKarma1) {
|| $fixedKarma1
|| empty($canonicalTerm0)
|| empty($canonicalTerm1)
) {
return; return;
} }
if ($canonicalTerm0 == 'everything') { if ($canonicalTerm0 == 'everything') {
$change = $method == '<' ? '++' : '--'; $change = $method == '<' ? '++' : '--';
$this->modifyKarma($canonicalTerm1, $change);
$karma0 = 0; $karma0 = 0;
$karma1 = $this->fetchKarma($canonicalTerm1); $karma1 = $this->modifyKarma($canonicalTerm1, $change);
} elseif ($canonicalTerm1 == 'everything') { } elseif ($canonicalTerm1 == 'everything') {
$change = $method == '<' ? '--' : '++'; $change = $method == '<' ? '--' : '++';
$this->modifyKarma($canonicalTerm0, $change); $karma0 = $this->modifyKarma($canonicalTerm0, $change);
$karma0 = $this->fetchKarma($canonicalTerm1);
$karma1 = 0; $karma1 = 0;
} else { } else {
$karma0 = $this->fetchKarma($canonicalTerm0); $karma0 = $this->fetchKarma($canonicalTerm0);
$karma1 = $this->fetchKarma($canonicalTerm1); $karma1 = $this->fetchKarma($canonicalTerm1);
} }
if (($method == '<' // Combining the first and second branches here causes an odd
&& $karma0 < $karma1) // single-line lapse in code coverage, but the lapse disappears if
|| ($method == '>' // they're separated
&& $karma0 > $karma1)) { if ($method == '<' && $karma0 < $karma1) {
$replies = $this->fetchPositiveAnswer;
} elseif ($method == '>' && $karma0 > $karma1) {
$replies = $this->fetchPositiveAnswer; $replies = $this->fetchPositiveAnswer;
} else { } else {
$replies = $this->fetchNegativeAnswer; $replies = $this->fetchNegativeAnswer;
@ -356,14 +382,10 @@ REGEX;
* @param string $term Term to modify * @param string $term Term to modify
* @param string $action Karma action (either ++ or --) * @param string $action Karma action (either ++ or --)
* *
* @return void * @return int Modified karma rating
*/ */
protected function modifyKarma($term, $action) protected function modifyKarma($term, $action)
{ {
if (empty($term)) {
return;
}
$karma = $this->fetchKarma($term); $karma = $this->fetchKarma($term);
if ($karma !== false) { if ($karma !== false) {
$statement = $this->updateKarma; $statement = $this->updateKarma;
@ -378,6 +400,8 @@ REGEX;
':karma' => $karma ':karma' => $karma
); );
$statement->execute($args); $statement->execute($args);
return $karma;
} }
/** /**

View File

@ -54,10 +54,27 @@ class Phergie_Plugin_Reload extends Phergie_Plugin_Abstract
{ {
$plugin = ucfirst($plugin); $plugin = ucfirst($plugin);
$evalClass = true;
if (strpos($plugin, ' ') !== false) {
$args = explode(' ', $plugin);
$plugin = $args[0];
if (strtolower($args[1]) == 'force') {
$evalClass = false;
}
}
if (!$this->plugins->hasPlugin($plugin)) { if (!$this->plugins->hasPlugin($plugin)) {
echo 'DEBUG(Reload): ' . ucfirst($plugin) . ' is not loaded yet, loading', PHP_EOL; echo 'DEBUG(Reload): ' . ucfirst($plugin) . ' is not loaded yet, loading', PHP_EOL;
try {
$this->plugins->getPlugin($plugin); $this->plugins->getPlugin($plugin);
$this->plugins->command->populateMethodCache(); $this->plugins->command->populateMethodCache();
} catch (Phergie_Plugin_Exception $e) {
if ($e->getCode() == Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND) {
echo 'DEBUG(Reload): ', $e->getMessage(), PHP_EOL;
} else {
throw $e;
}
}
return; return;
} }
@ -75,16 +92,18 @@ class Phergie_Plugin_Reload extends Phergie_Plugin_Abstract
$newClass = $class . '_' . sha1($contents); $newClass = $class . '_' . sha1($contents);
if (class_exists($newClass, false)) { if (class_exists($newClass, false)) {
if ($evalClass == true) {
echo 'DEBUG(Reload): Class ', $class, ' has not changed since last reload', PHP_EOL; echo 'DEBUG(Reload): Class ', $class, ' has not changed since last reload', PHP_EOL;
return; return;
} }
} else {
$contents = preg_replace( $contents = preg_replace(
array('/^<\?(?:php)?/', '/class\s+' . $class . '/i'), array('/^<\?(?:php)?/', '/class\s+' . $class . '/i'),
array('', 'class ' . $newClass), array('', 'class ' . $newClass),
$contents $contents
); );
eval($contents); eval($contents);
}
$instance = new $newClass; $instance = new $newClass;
$instance->setName($plugin); $instance->setName($plugin);

View File

@ -34,7 +34,6 @@
*/ */
class Phergie_Plugin_SpellCheck extends Phergie_Plugin_Abstract class Phergie_Plugin_SpellCheck extends Phergie_Plugin_Abstract
{ {
/** /**
* Spell check dictionary handler * Spell check dictionary handler
* *
@ -86,7 +85,7 @@ class Phergie_Plugin_SpellCheck extends Phergie_Plugin_Abstract
$target = $this->event->getNick(); $target = $this->event->getNick();
$message = $target . ': The word "' . $word; $message = $target . ': The word "' . $word;
$message .= '" seems to be spelt correctly.'; $message .= '" seems to be spelled correctly.';
if (!pspell_check($this->pspell, $word)) { if (!pspell_check($this->pspell, $word)) {
$suggestions = pspell_suggest($this->pspell, $word); $suggestions = pspell_suggest($this->pspell, $word);
@ -116,5 +115,4 @@ class Phergie_Plugin_SpellCheck extends Phergie_Plugin_Abstract
{ {
$this->fail($errstr); $this->fail($errstr);
} }
} }

View File

@ -53,7 +53,7 @@ class Phergie_Plugin_TerryChay extends Phergie_Plugin_Abstract
*/ */
public function onLoad() public function onLoad()
{ {
$this->http = $this->getPluginHandler()->getPlugin('Http'); $this->getPluginHandler()->getPlugin('Http');
} }
/** /**
@ -63,7 +63,11 @@ class Phergie_Plugin_TerryChay extends Phergie_Plugin_Abstract
*/ */
public function getChayism() public function getChayism()
{ {
return $this->http->get(self::URL)->getContent(); return $this
->getPluginHandler()
->getPlugin('Http')
->get(self::URL)
->getContent();
} }
/** /**
@ -81,29 +85,10 @@ class Phergie_Plugin_TerryChay extends Phergie_Plugin_Abstract
= '{^(' . preg_quote($this->getConfig('command.prefix')) . = '{^(' . preg_quote($this->getConfig('command.prefix')) .
'\s*)?.*(terry\s+chay|tychay)}ix'; '\s*)?.*(terry\s+chay|tychay)}ix';
if (preg_match($pattern, $message) if (preg_match($pattern, $message)) {
&& $fact = $this->getChayism() if($fact = $this->getChayism()) {
) {
$this->doPrivmsg($source, 'Fact: ' . $fact); $this->doPrivmsg($source, 'Fact: ' . $fact);
} }
} }
/**
* Parses incoming CTCP request for "Terry Chay" and related variations
* and responds with a chayism.
*
* @return void
*/
public function onCtcp()
{
$event = $this->getEvent();
$source = $event->getSource();
$ctcp = $event->getArgument(1);
if (preg_match('({terry[\s_+-]*chay}|tychay)ix', $ctcp)
&& $fact = $this->getChayism()
) {
$this->doCtcpReply($source, 'TERRYCHAY', $fact);
}
} }
} }

View File

@ -0,0 +1,262 @@
<?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)}());
}
}
}

View File

@ -108,6 +108,77 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
); );
} }
/**
* 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. * Tests countability of the plugin handler.
* *
@ -714,23 +785,53 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
} }
/** /**
* Tests the plugin receiving and using a predefined iterator instance. * Tests that multiple plugin iterators can be used concurrently.
* *
* @depends testGetPlugins
* @return void * @return void
*/ */
public function testSetIterator() public function testUseMultiplePluginIteratorsConcurrently()
{ {
$plugin = $this->getMockPlugin('TestPlugin'); $plugin1 = $this->getMockPlugin('TestPlugin1');
$this->handler->addPlugin($plugin); $this->handler->addPlugin($plugin1);
$plugins = $this->handler->getPlugins();
$iterator = new ArrayIterator($plugins); $plugin2 = $this->getMockPlugin('TestPlugin2');
$this->handler->setIterator($iterator); $this->handler->addPlugin($plugin2);
$this->assertSame($this->handler->getIterator(), $iterator);
$iterated = array(); $iterator1 = $this->handler->getIterator();
foreach ($this->handler as $plugin) { $iterator1->next();
$iterated[strtolower($plugin->getName())] = $plugin; $this->assertSame($plugin2, $iterator1->current());
$iterator2 = $this->handler->getIterator();
$this->assertSame($plugin1, $iterator2->current());
} }
$this->assertEquals($iterated, $plugins);
/**
* 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');
} }
} }

View File

@ -0,0 +1,335 @@
<?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 . '.');
}
}
}

View File

@ -12,15 +12,13 @@
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie_Tests
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie * @link http://pear.phergie.org/package/Phergie_Tests
*/ */
require_once(dirname(__FILE__) . '/TestCase.php');
/** /**
* Unit test suite for Pherge_Plugin_Ping. * Unit test suite for Pherge_Plugin_Ping.
* *
@ -28,148 +26,139 @@ require_once(dirname(__FILE__) . '/TestCase.php');
* @package Phergie_Tests * @package Phergie_Tests
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie * @link http://pear.phergie.org/package/Phergie_Tests
*/ */
class Phergie_Plugin_PingTest extends Phergie_Plugin_TestCase class Phergie_Plugin_PingTest extends Phergie_Plugin_TestCase
{ {
protected $config = array('ping.ping' => 10,
'ping.event' => 300);
/** /**
* Sets up the fixture, for example, opens a network connection. * Tests that the last ping and event are initialized on connection to
* This method is called before a test is executed. * the server.
*/ *
protected function setUp() * @return void
{
$this->setPlugin(new Phergie_Plugin_Ping);
}
/**
* Test the lastEvent setter and getter
*/
public function testSetGetLastEvent()
{
$expected = rand(100000,200000);
$this->plugin->setLastEvent($expected);
$this->assertEquals($expected,
$this->plugin->getLastEvent(),
'Assert that the last event was set and gotten ' .
'correctly');
}
/**
* Test the lastPing setter and getter
*/
public function testSetGetLastPing()
{
$expected = rand(100000,200000);
$this->plugin->setLastPing($expected);
$this->assertEquals($expected,
$this->plugin->getLastPing(),
'Assert that the last ping was set and gotten ' .
'correctly');
}
/**
* Tests the onConnect hook
*/ */
public function testOnConnect() public function testOnConnect()
{ {
$time = time() - 1;
// We need to make sure time() is going to be creater next time it is called
$this->plugin->onConnect(); $this->plugin->onConnect();
$this->assertNull($this->plugin->getLastPing(),
'onConnect should set last ping to null'); $expected = time();
$this->assertGreaterThan($time, $actual = $this->plugin->getLastEvent();
$this->plugin->getLastEvent(), $this->assertEquals($expected, $actual);
'onConnect should update lastEvent with the ' .
'current timestamp'); $expected = null;
$this->assertLessThan($time + 2, $actual = $this->plugin->getLastPing();
$this->plugin->getLastEvent(), $this->assertEquals($expected, $actual);
'onConnect should update lastEvent with the ' .
'current timestamp');
} }
/** /**
* Test that the preEvent method updates the lastEvent with the current time * Tests that the last event is reset when an event occurs.
*
* @return void
*/ */
public function testPreEvent() public function testPreEvent()
{ {
$time = time() -1;
$this->plugin->preEvent(); $this->plugin->preEvent();
$this->assertGreaterThan($time,
$this->plugin->getLastEvent(), $expected = time();
'Last event time was set properly on preEvent'); $actual = $this->plugin->getLastEvent();
$this->assertLessThan($time +2, $this->assertEquals($expected, $actual);
$this->plugin->getLastEvent(),
'Last Event time was set properly on preEvent');
} }
/** /**
* @todo Implement testOnPingResponse(). * Tests that the last ping is reset when a ping is received.
*
* @return void
*/ */
public function testOnPingResponse() public function testOnPingResponse()
{ {
$this->plugin->setLastPing(time());
$this->plugin->onPingResponse(); $this->plugin->onPingResponse();
$this->assertNull($this->plugin->getLastPing(),
'Last ping time should be null after onPingResponse');
$expected = null;
$actual = $this->plugin->getLastPing();
$this->assertEquals($expected, $actual);
} }
/** /**
* Test that the plugin issues a quit when the ping threashold * Tests that the test suite is able to manipulate the value of the last
* has been exceeded * event.
*
* @return void
*/ */
public function testOnTickExceededPingThresholdQuits() public function testSetLastEvent()
{ {
$this->plugin->setLastPing(1); $expected = time() + 1;
$this->plugin->onTick(); $this->plugin->setLastEvent($expected);
$this->assertHasEvent(Phergie_Event_Command::TYPE_QUIT); $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) { }
} }
/** /**
* Test that the plugin issues a quit when the ping threashold * Tests that the test suite is able to manipulate the value of the last
* has been exceeded * ping.
*
* @return void
*/ */
public function testOnTickPingWithinThresholdDoesNotQuits() public function testSetLastPing()
{ {
$this->plugin->setLastPing(time()); $expected = time() + 1;
$this->plugin->onTick(); $this->plugin->setLastPing($expected);
$this->assertDoesNotHaveEvent(Phergie_Event_Command::TYPE_QUIT); $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) { }
} }
/** /**
* Test that a ping is emitted when the event threashold is exceeded * Tests that a ping event is sent after the appropriate time period has
* lapsed since receiving an event.
*
* @depends testSetLastEvent
* @return void
*/ */
public function testPingEmittedAfterThresholdExceeded() public function testPing()
{ {
$this->plugin->setLastEvent(time() - $this->config['ping.event'] - 1); $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(); $this->plugin->onTick();
$this->assertHasEvent(Phergie_Event_Command::TYPE_PING); $actual = $this->plugin->getLastPing();
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PING); $this->assertEquals($expected, $actual);
foreach ($events as $event) {
$this->assertEventEmitter($event,
$this->plugin,
'Assert that the event was emitted by the tested plugin');
}
} }
/** /**
* Test that no ping is emitted when the event thresthold is not exceeded * 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 testNoPingEmittedWhenThresholdNotExceeded() public function testQuit()
{ {
$this->plugin->setLastEvent(time() - $this->config['ping.event'] +1); $pingPing = 10;
$this->setConfig('ping.ping', $pingPing);
$lastPing = time() - ($pingPing + 1);
$this->plugin->setLastPing($lastPing);
$this->assertEmitsEvent('quit');
$this->plugin->onTick(); $this->plugin->onTick();
$this->assertDoesNotHaveEvent(Phergie_Event_Command::TYPE_PING);
} }
public function tearDown()
{
$this->handler->clearEvents();
}
} }

View File

@ -12,15 +12,13 @@
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie_Tests
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie * @link http://pear.phergie.org/package/Phergie_Tests
*/ */
require_once(dirname(__FILE__) . '/TestCase.php');
/** /**
* Unit test suite for Pherge_Plugin_Pong. * Unit test suite for Pherge_Plugin_Pong.
* *
@ -28,47 +26,21 @@ require_once(dirname(__FILE__) . '/TestCase.php');
* @package Phergie_Tests * @package Phergie_Tests
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie * @link http://pear.phergie.org/package/Phergie_Tests
*/ */
class Phergie_Plugin_PongTest extends Phergie_Plugin_TestCase class Phergie_Plugin_PongTest extends Phergie_Plugin_TestCase
{ {
/** /**
* Sets up the fixture, for example, opens a network connection. * Test that a pong event is sent when a ping event is received.
* This method is called before a test is executed.
*/
protected function setUp()
{
$this->setPlugin(new Phergie_Plugin_Pong);
}
/**
* Test that when a ping is received, a Phergie_Event_Command::TYPE_PONG
* is set to the handler
* *
* @event Phergie_Event_Command::TYPE_PING * @return void
*/ */
public function testOnPing() 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(); $this->plugin->onPing();
$this->assertHasEvent(Phergie_Event_Command::TYPE_PONG);
} }
/**
* Test that when a ping is received, a Phergie_Event_Command::TYPE_PONG
* is set to the handler
*
* @event Phergie_Event_Command::TYPE_PING
*/
public function testOnPingResponseArguement()
{
$this->plugin->onPing();
$this->assertHasEvent(Phergie_Event_Command::TYPE_PONG);
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PONG);
$this->assertTrue(count($events) === 1, 'Assert that only one pong is emitted');
$this->assertEventEmitter(current($events),
$this->plugin,
'Assert that the tested plugin emitted the event');
}
} }

View File

@ -12,15 +12,13 @@
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie_Tests
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie * @link http://pear.phergie.org/package/Phergie_Tests
*/ */
require_once dirname(__FILE__) . '/TestCase.php';
/** /**
* Unit test suite for Pherge_Plugin_SpellCheck. * Unit test suite for Pherge_Plugin_SpellCheck.
* *
@ -28,178 +26,141 @@ require_once dirname(__FILE__) . '/TestCase.php';
* @package Phergie_Tests * @package Phergie_Tests
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie * @link http://pear.phergie.org/package/Phergie_Tests
*/ */
class Phergie_Plugin_SpellCheckTest extends Phergie_Plugin_TestCase class Phergie_Plugin_SpellCheckTest extends Phergie_Plugin_TestCase
{ {
/** /**
* Current SpellCheck plugin instance * Checks for the pspell extension.
*
* @var Phergie_Plugin_SpellCheck
*/
protected $spell;
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
* *
* @return void * @return void
*/ */
protected function setUp() public function setUp()
{ {
$this->config = array('spellcheck.lang' => 'en'); parent::setUp();
$this->spell = new Phergie_Plugin_SpellCheck(); if (!extension_loaded('pspell')) {
$this->setPlugin(new Phergie_Plugin_Command()); $this->markTestSkipped('pspell extension not available');
$config = $this->plugin->getConfig();
$handler = new Phergie_Plugin_Handler($config, $this->handler);
$this->plugin->setPluginHandler($handler);
$handler->addPlugin($this->plugin);
$handler->addPlugin($this->spell);
$this->spell->setEventHandler($this->handler);
$this->spell->setConnection($this->connection);
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #zftalk
* @eventArg spell
*/
public function testSpell()
{
$this->spell->onLoad();
$this->copyEvent();
$this->plugin->onPrivMsg();
$this->assertDoesNotHaveEvent(Phergie_Event_Command::TYPE_PRIVMSG);
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #phergie
* @eventArg spell test
*/
public function testSpellTest()
{
$this->spell->onLoad();
$this->copyEvent();
$this->plugin->onPrivMsg();
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
$this->assertEquals(1, count($events));
foreach ($events as $event) {
$args = $event->getArguments();
$this->assertEquals('#phergie', $args[0]);
$this->assertContains('CheckSpellUser:', $args[1]);
$this->assertContains('test', $args[1]);
$this->assertContains('correct', $args[1]);
} }
} }
/** /**
* @event Phergie_Event_Request::privmsg * Tests for the plugin failing to load when the language setting is not
* @eventArg #phergie * specified.
* @eventArg spell testz
*/
public function testSpellTestz()
{
$this->spell->onLoad();
$this->copyEvent();
$this->plugin->onPrivMsg();
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
$this->assertEquals(1, count($events));
foreach ($events as $event) {
$args = $event->getArguments();
$this->assertEquals('#phergie', $args[0]);
$this->assertContains('CheckSpellUser:', $args[1]);
$this->assertRegExp('/([a-z]+, ){4}/', $args[1]);
$this->assertContains('testz', $args[1]);
$this->assertContains('test,', $args[1]);
}
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #phergie
* @eventArg spell testz
*/
public function testSpellMoreSuggestions()
{
$config = $this->spell->getConfig();
$this->copyEvent();
$config['spellcheck.limit'] = 6;
$this->spell->onLoad();
$this->plugin->onPrivMsg();
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
$this->assertEquals(1, count($events));
foreach ($events as $event) {
$args = $event->getArguments();
$this->assertEquals('#phergie', $args[0]);
$this->assertContains('CheckSpellUser:', $args[1]);
$this->assertRegExp('/([a-z]+, ){5}/', $args[1]);
$this->assertContains('testz', $args[1]);
$this->assertContains('test,', $args[1]);
}
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #phergie
* @eventArg spell qwertyuiopasdfghjklzxcvbnm
*/
public function testSpellNoSuggestions()
{
$this->spell->onLoad();
$this->copyEvent();
$this->plugin->onPrivMsg();
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
$this->assertEquals(1, count($events));
foreach ($events as $event) {
$args = $event->getArguments();
$this->assertEquals('#phergie', $args[0]);
$this->assertContains('CheckSpellUser:', $args[1]);
$this->assertContains('find any suggestions', $args[1]);
}
}
/**
* Copy event from command to spell plugin
* *
* @return void * @return void
*/ */
protected function copyEvent() public function testLanguageSettingNotSet()
{ {
$hostmask = Phergie_Hostmask::fromString('CheckSpellUser!test@testing.org'); try {
$this->plugin->onLoad();
$event = $this->plugin->getEvent(); $this->fail('Expected exception was not thrown');
$event->setHostmask($hostmask); } catch (Phergie_Plugin_Exception $e) {
return;
$this->spell->setEvent($event); }
$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);
}
} }

View File

@ -12,15 +12,13 @@
* http://phergie.org/license * http://phergie.org/license
* *
* @category Phergie * @category Phergie
* @package Phergie * @package Phergie_Tests
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @copyright 2008-2010 Phergie Development Team (http://phergie.org) * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie * @link http://pear.phergie.org/package/Phergie_Tests
*/ */
require_once(dirname(__FILE__) . '/TestCase.php');
/** /**
* Unit test suite for Pherge_Plugin_TerryChay. * Unit test suite for Pherge_Plugin_TerryChay.
* *
@ -28,72 +26,110 @@ require_once(dirname(__FILE__) . '/TestCase.php');
* @package Phergie_Tests * @package Phergie_Tests
* @author Phergie Development Team <team@phergie.org> * @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License * @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie * @link http://pear.phergie.org/package/Phergie_Tests
*/ */
class Phergie_Plugin_TerryChayTest extends Phergie_Plugin_TestCase class Phergie_Plugin_TerryChayTest extends Phergie_Plugin_TestCase
{ {
/** /**
* Sets up the fixture, for example, opens a network connection. * Chayism used as a consistent response when related events are
* This method is called before a test is executed. * triggered
*
* @var string
*/ */
protected function setUp() 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()
{ {
$this->setPlugin(new Phergie_Plugin_TerryChay()); $response = $this->getMock('Phergie_Plugin_Http_Response');
$config = new Phergie_Config(); $response
$handler = new Phergie_Plugin_Handler($config, $this->handler); ->expects($this->any())
$this->plugin->setPluginHandler($handler); ->method('getContent')
$handler->addPlugin($this->plugin); ->will($this->returnValue($this->chayism));
$handler->addPlugin(new Phergie_Plugin_Http($config));
$this->plugin->setConfig($config); $plugin = $this->getMock('Phergie_Plugin_Http');
$this->connection->setNick('phergie'); $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(); $this->plugin->onLoad();
} }
/** /**
* @event Phergie_Event_Request::privmsg * Data provider for testPrivmsgTriggerReturnsChayism().
* @eventArg #zftalk *
* @eventArg tychay * @return array Enumerated array of enumerated arrays each containing
* a set of parameters for a single call to
* testPrivmsgTriggerReturnsChayism()
*/ */
public function testWithTyChay() public function dataProviderTestPrivmsgTriggerReturnsChayism()
{ {
$this->plugin->onPrivMsg(); return array(
$this->assertHasEvent(Phergie_Event_Command::TYPE_PRIVMSG); array('terry chay'),
array('terry chay'),
array('tychay'),
array('!tychay'),
array('! tychay'),
array('foo tychay bar'),
);
} }
/** /**
* @event Phergie_Event_Request::privmsg * Tests that appropriate triggers result in a response with a Chayism.
* @eventArg #zftalk *
* @eventArg terrychay * @return void
* @dataProvider dataProviderTestPrivmsgTriggerReturnsChayism
*/ */
public function testWithTerryChay() public function testPrivmsgTriggerReturnsChayism($trigger)
{ {
$this->plugin->onPrivMsg(); $this->setConfig('command.prefix', '!');
$this->assertDoesNotHaveEvent(Phergie_Event_Command::TYPE_PRIVMSG, $this->setUpHttpClient();
'string "terrychay" should not invoke a response'); $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();
} }
/** /**
* @event Phergie_Event_Request::privmsg * Tests that lack of an appropriate trigger results in no response with
* @eventArg #zftalk * a Chayism.
* @eventArg terry chay *
* @return void
*/ */
public function testWithTerry_Chay() public function testNoPrivmsgTriggerDoesNotReturnChayism()
{ {
$this->plugin->onPrivMsg(); $args = array(
$this->assertHasEvent(Phergie_Event_Command::TYPE_PRIVMSG, 'receiver' => $this->source,
'string "terry chay" should invoke a response'); 'text' => 'foo bar baz'
} );
$event = $this->getMockEvent('privmsg', $args);
/** $this->plugin->setEvent($event);
* @event Phergie_Event_Request::privmsg $this->assertDoesNotEmitEvent('privmsg', array($this->source, 'Fact: ' . $this->chayism));
* @eventArg #zftalk $this->plugin->onPrivmsg();
* @eventArg Elazar is not Mr. Chay
*/
public function testWithNoTyChay()
{
$this->plugin->onPrivMsg();
$this->assertDoesNotHaveEvent(Phergie_Event_Command::TYPE_PRIVMSG,
'Failed asserting that elazar is not ' .
'tychay');
} }
} }

View File

@ -20,7 +20,7 @@
*/ */
/** /**
* Unit test suite for Pherge_Plugin classes * Unit test suite for plugin classes.
* *
* @category Phergie * @category Phergie
* @package Phergie_Tests * @package Phergie_Tests
@ -31,177 +31,405 @@
abstract class Phergie_Plugin_TestCase extends PHPUnit_Framework_TestCase abstract class Phergie_Plugin_TestCase extends PHPUnit_Framework_TestCase
{ {
/** /**
* @var Phergie_Event_Handler * Mock configuration
*
* @var Phergie_Config
*/ */
protected $handler; 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 * @var Phergie_Connection
*/ */
protected $connection; protected $connection;
/** /**
* @var array * Mock event handler
*
* @var Phergie_Event_Handler
*/ */
protected $eventArgs; protected $events;
/** /**
* Mock plugin handler
*
* @var Phergie_Plugin_Handler
*/
protected $plugins;
/**
* Plugin instance being tested
*
* @var Phergie_Plugin_Abstract * @var Phergie_Plugin_Abstract
*/ */
protected $plugin; protected $plugin;
/** /**
* @var array * Full name of the plugin class being tested, may be explicitly
*/ * specified in subclasses but is otherwise automatically derived from
protected $config = array(); * the test case class name
/**
* Constructs a test case with the given name.
* *
* @param string $name * @var string
* @param array $data
* @param string $dataName
*/ */
public function __construct($name = NULL, array $data = array(), $dataName = '') protected $pluginClass;
{
parent::__construct($name, $data, $dataName);
$this->connection = new Phergie_Connection();
$this->handler = new Phergie_Event_Handler();
}
/** /**
* Assert that a given event type exists in the event handler * User nick used in any events requiring one
* @param string $event
* @param string $message
*/
public function assertHasEvent($event, $message = null)
{
self::assertTrue($this->handler->hasEventOfType($event), $message);
}
/**
* Assert that a given event type DOES NOT exist in the event handler
* @param string $event
* @param string $message
*/
public function assertDoesNotHaveEvent($event, $message = null)
{
self::assertFalse($this->handler->hasEventOfType($event), $message);
}
/**
* Assert that the emitter of the given command event was the given
* plugin
* *
* @param Phergie_Event_Command $event * @var string
* @param Phergie_Plugin_Abstract $plugin
* @param string $message
*/ */
public function assertEventEmitter(Phergie_Event_Command $event, protected $nick = 'nick';
Phergie_Plugin_Abstract $plugin,
$message = null) /**
* Event source used in any events requiring one
*
* @var string
*/
protected $source = '#channel';
/**
* Initializes instance properties.
*
* @return void
*/
public function setUp()
{ {
$this->assertSame($plugin, $event->getPlugin(), $message); 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());
} }
/** /**
* Gets the events added to the handler by the plugin * Destroys all initialized instance properties.
* @param string $type *
* @return array | null * @return void
*/ */
public function getResponseEvents($type = null) public function tearDown()
{ {
if (is_string($type) && strlen($type) > 0) { unset(
return $this->handler->getEventsOfType($type); $this->plugins,
} $this->events,
return $this->handler->getEvents(); $this->connection,
$this->config,
$this->plugin
);
} }
/** /**
* Sets the event for the test * Returns a mock configuration object.
* @param array $event *
* @param array $eventArgs * @return Phergie_Config
*/ */
public function setEvent(array $event, array $eventArgs = null) protected function getMockConfig()
{ {
$eventClass = 'Phergie_Event_Request'; if (empty($this->config)) {
if (is_array($event)) { $this->config = $this->getMock('Phergie_Config', array('offsetExists', 'offsetGet'));
$eventClass = $event[0]; $this->config
$eventType = $event[1]; ->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 { } else {
throw new InvalidArgumentException("Invalid value for \$event"); $methods[] = 'get' . ucfirst($arg);
} }
$event = new $eventClass(); }
$event->setType($eventType);
$event->setArguments($eventArgs); $event = $this->getMock(
$this->plugin->setEvent($event); 'Phergie_Event_Request',
$this->eventArgs = $eventArgs; $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 plugin to be tested * Sets the value of a configuration setting.
* If a plugin requries config for testing, an array placed in *
* $this->config will be parsed into a Phergie_Config object and * @param string $setting Name of the setting
* attached to the plugin * @param mixed $value Value for the setting
*
* @return void
*/ */
protected function setPlugin(Phergie_Plugin_Abstract $plugin) protected function setConfig($setting, $value)
{ {
$this->plugin = $plugin; $this->settings[$setting] = $value;
$this->plugin->setEventHandler($this->handler);
$this->plugin->setConnection($this->connection);
$this->connection->setNick('test');
if (!empty($this->config)) {
$config = new Phergie_Config();
foreach ($this->config as $configKey => $configValue) {
$config[$configKey] = $configValue;
}
$plugin->setConfig($config);
}
} }
/** /**
* Overrides the runTest method to add additional annotations * Returns the absolute path to the Phergie/Plugin directory. Useful in
* @return PHPUnit_Framework_TestResult * conjunction with getMockDatabase().
*
* @param string $subpath Optional path to append to the directory path
*
* @return string Directory path
*/ */
protected function runTest() protected function getPluginsPath($subpath = null)
{ {
if (null === $this->plugin) { $path = realpath(dirname(__FILE__) . '/../../../Phergie/Plugin');
throw new RuntimeException( if (!empty($subpath)) {
'Tests cannot be run before plugin is set' $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);
// Clean the event handler... important!
$this->handler->clearEvents();
$info = $this->getAnnotations();
$event = null;
$eventArgs = array();
if (isset($info['method']['event']) && isset($info['method']['event'][0])) {
if (!is_string($info['method']['event'][0])) {
throw new InvalidArgumentException(
'Only one event may be specified'
);
} }
$event = $info['method']['event'][0]; $copy->commit();
unset($insert);
if (stristr($event, '::')) {
$event = explode('::', $event);
}
}
if (isset($info['method']['eventArg'])) {
$eventArgs = $info['method']['eventArg'];
}
if (null !== $event) {
$this->setEvent($event, $eventArgs);
} }
$testResult = parent::runTest(); return $copy;
// Clean the event handler again... just incase this time.
$this->handler->clearEvents();
return $testResult;
} }
} }