Skip to content

Commit

Permalink
Merge pull request #8985 from jeremyharris/feature-assert-events
Browse files Browse the repository at this point in the history
[RFC] Add assertEventFired and assertEventFiredWith
  • Loading branch information
lorenzo committed Jun 19, 2016
2 parents c62f39e + 92d871e commit 5add51d
Show file tree
Hide file tree
Showing 6 changed files with 384 additions and 0 deletions.
55 changes: 55 additions & 0 deletions src/TestSuite/Constraint/EventFired.php
@@ -0,0 +1,55 @@
<?php
namespace Cake\TestSuite\Constraint;

use Cake\Event\EventManager;
use PHPUnit_Framework_AssertionFailedError;
use PHPUnit_Framework_Constraint;

/**
* EventFired constraint
*/
class EventFired extends PHPUnit_Framework_Constraint
{
/**
* Array of fired events
*
* @var EventManager
*/
protected $_eventManager;

/**
* Constructor
*
* @param EventManager $eventManager Event manager to check
*/
public function __construct($eventManager)
{
parent::__construct();
$this->_eventManager = $eventManager;

if ($this->_eventManager->getEventList() === null) {
throw new PHPUnit_Framework_AssertionFailedError('The event manager you are asserting against is not configured to track events.');
}
}

/**
* Checks if event is in fired array
*
* @param mixed $other Constraint check
* @return bool
*/
public function matches($other)
{
return $this->_eventManager->getEventList()->hasEvent($other);
}

/**
* Assertion message string
*
* @return string
*/
public function toString()
{
return 'was fired';
}
}
105 changes: 105 additions & 0 deletions src/TestSuite/Constraint/EventFiredWith.php
@@ -0,0 +1,105 @@
<?php
namespace Cake\TestSuite\Constraint;

use Cake\Event\Event;
use Cake\Event\EventManager;
use PHPUnit_Framework_AssertionFailedError;
use PHPUnit_Framework_Constraint;

/**
* EventFiredWith constraint
*
* Another glorified in_array check
*/
class EventFiredWith extends PHPUnit_Framework_Constraint
{
/**
* Array of fired events
*
* @var EventManager
*/
protected $_eventManager;

/**
* Event data key
*
* @var string
*/
protected $_dataKey;

/**
* Event data value
*
* @var string
*/
protected $_dataValue;

/**
* Constructor
*
* @param EventManager $eventManager Event manager to check
* @param string $dataKey Data key
* @param string $dataValue Data value
*/
public function __construct($eventManager, $dataKey, $dataValue)
{
parent::__construct();
$this->_eventManager = $eventManager;
$this->_dataKey = $dataKey;
$this->_dataValue = $dataValue;

if ($this->_eventManager->getEventList() === null) {
throw new PHPUnit_Framework_AssertionFailedError('The event manager you are asserting against is not configured to track events.');
}
}

/**
* Checks if event is in fired array
*
* @param mixed $other Constraint check
* @return bool
*/
public function matches($other)
{
$firedEvents = [];
$list = $this->_eventManager->getEventList();
$totalEvents = count($list);
for ($e = 0; $e < $totalEvents; $e++) {
$firedEvents[] = $list[$e];
}

$eventGroup = collection($firedEvents)
->groupBy(function (Event $event) {
return $event->name();
})
->toArray();

if (!array_key_exists($other, $eventGroup)) {
return false;
}

$events = $eventGroup[$other];

if (count($events) > 1) {
throw new PHPUnit_Framework_AssertionFailedError(sprintf('Event "%s" was fired %d times, cannot make data assertion', $other, count($events)));
}

$event = $events[0];

if (array_key_exists($this->_dataKey, $event->data) === false) {
return false;
}

return $event->data[$this->_dataKey] === $this->_dataValue;
}

/**
* Assertion message string
*
* @return string
*/
public function toString()
{
return 'was fired with ' . $this->_dataKey . ' matching ' . (string)$this->_dataValue;
}
}
36 changes: 36 additions & 0 deletions src/TestSuite/TestCase.php
Expand Up @@ -140,6 +140,42 @@ public function loadFixtures()
}
}

/**
* Asserts that a global event was fired. You must track events in your event manager for this assertion to work
*
* @param string $name Event name
* @param EventManager $eventManager Event manager to check, defaults to global event manager
* @param string $message Assertion failure message
* @return void
*/
public function assertEventFired($name, $eventManager = null, $message = '')
{
if (!$eventManager) {
$eventManager = EventManager::instance();
}
$this->assertThat($name, new Constraint\EventFired($eventManager), $message);
}

/**
* Asserts an event was fired with data
*
* If a third argument is passed, that value is used to compare with the value in $dataKey
*
* @param string $name Event name
* @param string $dataKey Data key
* @param string $dataValue Data value
* @param EventManager $eventManager Event manager to check, defaults to global event manager
* @param string $message Assertion failure message
* @return void
*/
public function assertEventFiredWith($name, $dataKey, $dataValue, $eventManager = null, $message = '')
{
if (!$eventManager) {
$eventManager = EventManager::instance();
}
$this->assertThat($name, new Constraint\EventFiredWith($eventManager, $dataKey, $dataValue), $message);
}

/**
* Assert text equality, ignoring differences in newlines.
* Helpful for doing cross platform tests of blocks of text.
Expand Down
39 changes: 39 additions & 0 deletions tests/TestCase/TestSuite/Constraint/EventFiredTest.php
@@ -0,0 +1,39 @@
<?php
namespace Cake\Test\TestCase\TestSuite\Constraint;

use Cake\Event\Event;
use Cake\Event\EventList;
use Cake\Event\EventManager;
use Cake\TestSuite\Constraint\EventFired;
use Cake\TestSuite\TestCase;

/**
* EventFired Test
*/
class EventFiredTest extends TestCase
{

/**
* tests EventFired constraint
*
* @return void
*/
public function testMatches()
{
$manager = EventManager::instance();
$manager->setEventList(new EventList());
$manager->trackEvents(true);

$myEvent = new Event('my.event', $this, []);
$myOtherEvent = new Event('my.other.event', $this, []);

$manager->getEventList()->add($myEvent);
$manager->getEventList()->add($myOtherEvent);

$constraint = new EventFired($manager);

$this->assertTrue($constraint->matches('my.event'));
$this->assertTrue($constraint->matches('my.other.event'));
$this->assertFalse($constraint->matches('event.not.fired'));
}
}
72 changes: 72 additions & 0 deletions tests/TestCase/TestSuite/Constraint/EventFiredWithTest.php
@@ -0,0 +1,72 @@
<?php
namespace Cake\Test\TestCase\TestSuite\Constraint;

use Cake\Event\Event;
use Cake\Event\EventList;
use Cake\Event\EventManager;
use Cake\TestSuite\Constraint\EventFiredWith;
use Cake\TestSuite\TestCase;

/**
* EventFiredWith Test
*/
class EventFiredWithTest extends TestCase
{

/**
* tests EventFiredWith constraint
*
* @return void
*/
public function testMatches()
{
$manager = EventManager::instance();
$manager->setEventList(new EventList());
$manager->trackEvents(true);

$myEvent = new Event('my.event', $this, [
'key' => 'value'
]);
$myOtherEvent = new Event('my.other.event', $this, [
'key' => null
]);

$manager->getEventList()->add($myEvent);
$manager->getEventList()->add($myOtherEvent);

$constraint = new EventFiredWith($manager, 'key', 'value');

$this->assertTrue($constraint->matches('my.event'));
$this->assertFalse($constraint->matches('my.other.event'));
$this->assertFalse($constraint->matches('event.not.fired'));

$constraint = new EventFiredWith($manager, 'key', null);

$this->assertTrue($constraint->matches('my.other.event'));
$this->assertFalse($constraint->matches('my.event'));
}

/**
* tests trying to assert data key=>value when an event is fired multiple times
*
* @return void
* @expectedException \PHPUnit_Framework_AssertionFailedError
*/
public function testMatchesInvalid()
{
$manager = EventManager::instance();
$manager->setEventList(new EventList());
$manager->trackEvents(true);

$myEvent = new Event('my.event', $this, [
'key' => 'value'
]);

$manager->getEventList()->add($myEvent);
$manager->getEventList()->add($myEvent);

$constraint = new EventFiredWith($manager, 'key', 'value');

$constraint->matches('my.event');
}
}

0 comments on commit 5add51d

Please sign in to comment.