diff --git a/.gitattributes b/.gitattributes index a504929..07eb776 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,5 @@ # Auto detect text files and perform LF normalization -* text=auto +text eol=lf tests/ export-ignore .travis.yml export-ignore diff --git a/.travis.yml b/.travis.yml index bef7082..6735e1a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,12 @@ php: - 5.5 - 5.6 - hhvm - + matrix: allow_failures: - php: hhvm before_script: - - composer self-update - composer install --no-progress --prefer-source script: diff --git a/src/Monkey/Functions.php b/src/Monkey/Functions.php index 4c9011a..a89c0a2 100644 --- a/src/Monkey/Functions.php +++ b/src/Monkey/Functions.php @@ -185,7 +185,10 @@ public function echoArg($n = 1) $value = func_num_args() > $n0 ? func_get_arg($n0) : ''; - if (! is_scalar($value) && ! (is_object($value) && method_exists($value, '__toString'))) { + if ( + ! is_scalar($value) + && ! (is_object($value) && method_exists($value, '__toString')) + ) { throw new RuntimeException( sprintf( "%s received as argument %d a %s, can't echo it.", @@ -211,7 +214,7 @@ public function alias(callable $callback) } /** - * @param int $n + * @param int $n * @return int */ private function ensureArg($n) diff --git a/src/Monkey/MockeryBridge.php b/src/Monkey/MockeryBridge.php index 2265d96..631c4a1 100644 --- a/src/Monkey/MockeryBridge.php +++ b/src/Monkey/MockeryBridge.php @@ -65,6 +65,7 @@ public function __construct(ExpectationInterface $expectation, $parent = null) $this->expectation = $expectation; $name = $this->expectation->__toString(); if (is_string($parent) && class_exists($parent)) { + $parent = trim($parent, '\\'); $reflection = new \ReflectionClass($parent); $this->isHook = $reflection->isSubclassOf('Brain\Monkey\WP\Hooks'); $this->isAction = diff --git a/src/Monkey/WP/Actions.php b/src/Monkey/WP/Actions.php index 135738d..60d28b1 100644 --- a/src/Monkey/WP/Actions.php +++ b/src/Monkey/WP/Actions.php @@ -10,7 +10,6 @@ namespace Brain\Monkey\WP; -use Brain\Monkey\MockeryBridge; use Mockery; use InvalidArgumentException; use LogicException; @@ -31,13 +30,7 @@ class Actions extends Hooks */ public static function expectFired($action) { - $type = self::ACTION; - $sanitized = self::sanitizeHookName($action); - $mock = Mockery::mock("do_{$sanitized}"); - $expectation = $mock->shouldReceive("do_{$type}_{$sanitized}"); - parent::instance($type)->mocks[$sanitized]['run'] = $mock; - - return new MockeryHookBridge(new MockeryBridge($expectation, __CLASS__)); + return self::createBridgeFor(self::ACTION, $action, 'run'); } /** @@ -48,13 +41,7 @@ public static function expectFired($action) */ public static function expectAdded($action) { - $type = self::ACTION; - $sanitized = self::sanitizeHookName($action); - $mock = Mockery::mock("add_{$sanitized}"); - $expectation = $mock->shouldReceive("add_{$type}_{$sanitized}"); - parent::instance($type)->mocks[$sanitized]['add'] = $mock; - - return new MockeryHookBridge(new MockeryBridge($expectation, __CLASS__)); + return self::createBridgeFor(self::ACTION, $action, 'add'); } /** diff --git a/src/Monkey/WP/Filters.php b/src/Monkey/WP/Filters.php index c3501eb..3d1e4a5 100644 --- a/src/Monkey/WP/Filters.php +++ b/src/Monkey/WP/Filters.php @@ -10,8 +10,6 @@ namespace Brain\Monkey\WP; -use Brain\Monkey\MockeryBridge; -use Mockery; use LogicException; use InvalidArgumentException; @@ -22,28 +20,27 @@ */ class Filters extends Hooks { + /** + * @param string $filter + * @return \Brain\Monkey\WP\MockeryHookBridge + */ public static function expectApplied($filter) { - $type = self::FILTER; - $sanitized = self::sanitizeHookName($filter); - $mock = Mockery::mock("apply_{$sanitized}"); - $expectation = $mock->shouldReceive("apply_{$type}_{$sanitized}"); - parent::instance($type)->mocks[$sanitized]['run'] = $mock; - - return new MockeryHookBridge(new MockeryBridge($expectation, __CLASS__)); + return self::createBridgeFor(self::FILTER, $filter, 'run'); } + /** + * @param string $filter + * @return \Brain\Monkey\WP\MockeryHookBridge + */ public static function expectAdded($filter) { - $type = self::FILTER; - $sanitized = self::sanitizeHookName($filter); - $mock = Mockery::mock("add_{$sanitized}"); - $expectation = $mock->shouldReceive("add_{$type}_{$sanitized}"); - parent::instance($type)->mocks[$sanitized]['add'] = $mock; - - return new MockeryHookBridge(new MockeryBridge($expectation, __CLASS__)); + return self::createBridgeFor(self::FILTER, $filter, 'add'); } + /** + * @inheritdoc + */ public function add() { $args = func_get_args(); @@ -52,6 +49,9 @@ public function add() return call_user_func_array([$this, 'addHook'], $args); } + /** + * @inheritdoc + */ public function remove() { $args = func_get_args(); @@ -60,6 +60,9 @@ public function remove() return call_user_func_array([$this, 'removeHook'], $args); } + /** + * @inheritdoc + */ public function run() { $args = func_get_args(); @@ -68,6 +71,9 @@ public function run() return call_user_func_array([$this, 'runHook'], $args); } + /** + * @inheritdoc + */ public function runRef() { if (func_num_args() < 2 || ! is_array(func_get_arg(1))) { @@ -79,6 +85,9 @@ public function runRef() return call_user_func_array([$this, 'run'], $args); } + /** + * @inheritdoc + */ public function has() { $args = func_get_args(); @@ -102,6 +111,9 @@ public function applied($filter) return in_array($filter, $this->done, true) ? array_count_values($this->done)[$filter] : 0; } + /** + * @inheritdoc + */ public function clean() { $this->cleanInstance($this); diff --git a/src/Monkey/WP/Hooks.php b/src/Monkey/WP/Hooks.php index b83a106..31ed48d 100644 --- a/src/Monkey/WP/Hooks.php +++ b/src/Monkey/WP/Hooks.php @@ -10,6 +10,7 @@ namespace Brain\Monkey\WP; +use Brain\Monkey\MockeryBridge; use Mockery; use Closure; use InvalidArgumentException; @@ -238,7 +239,7 @@ protected function runHook($type) if ($rawHook !== $hook && ! isset(self::$names[$hook])) { self::$names[$hook] = $rawHook; } - // returning value is always null for functions + // returning value is always null for actions $value = $type === self::FILTER && func_num_args() > 2 ? func_get_arg(2) : null; self::$current = $hook; $instance->done[] = $hook; @@ -366,6 +367,36 @@ private function callbackId(callable $callback) return [$id, $hash]; } + /** + * @param string $type + * @param string $hook + * @param string $action + * @return \Brain\Monkey\WP\MockeryHookBridge + */ + protected static function createBridgeFor($type, $hook, $action = 'add') + { + $hook = self::sanitizeHookName($hook); + /** @var static $instance */ + $instance = self::instance($type); + $prefix = $action; + ($action === 'run') and $prefix = $type === self::FILTER ? 'apply' : 'do'; + $method = "{$prefix}_{$type}_{$hook}"; + + $mock = null; + is_array($instance->mocks) or $instance->mocks = []; + if (! isset($instance->mocks[$hook]) || ! isset($instance->mocks[$hook][$action])) { + isset($instance->mocks[$hook]) or $instance->mocks[$hook] = []; + $mock = Mockery::mock("{$prefix}_{$hook}"); + $instance->mocks[$hook][$action] = $mock; + } + + $mock = $instance->mocks[$hook][$action]; + $expectation = $mock->shouldReceive($method); + $parent = $type === self::FILTER ? '\Brain\Monkey\WP\Filters' : '\Brain\Monkey\WP\Actions'; + + return new MockeryHookBridge(new MockeryBridge($expectation, $parent)); + } + /** * @param string $name * @return string @@ -377,7 +408,7 @@ protected static function sanitizeHookName($name) array_values(self::$sanitize_map), $name ); - $clean = preg_replace('/[^\w]/i', '__', $replaced); + $clean = preg_replace('/[^a-z0-9_]/i', '__', $replaced); if (is_numeric($clean[0])) { $clean = '_'.$clean; } diff --git a/tests/unit/FunctionsTest.php b/tests/unit/FunctionsTest.php index a4ccf6f..11ac825 100644 --- a/tests/unit/FunctionsTest.php +++ b/tests/unit/FunctionsTest.php @@ -22,7 +22,6 @@ */ class FunctionsTest extends PHPUnit_Framework_TestCase { - protected function tearDown() { Monkey::tearDown(); @@ -128,11 +127,13 @@ public function testSameFunctionDifferentArguments() Functions::expect('issue5') ->with(true) ->once() + ->ordered() ->andReturn('First!'); Functions::expect('issue5') ->with(false) ->once() + ->ordered() ->andReturn('Second!'); assertSame('First!', issue5(true)); @@ -153,7 +154,6 @@ public function testJustEchoEmptyString() i_do_not_exists(); } - /** * @expectedException \InvalidArgumentException * @expectedExceptionMessageRegExp /can't echo a var of type array/ @@ -183,7 +183,6 @@ public function testJustEchoObject() i_do_not_exists(); } - public function testEchoArg() { Functions::when('i_do_not_exists')->echoArg(2); diff --git a/tests/unit/WP/ActionAddTest.php b/tests/unit/WP/ActionAddTest.php index fbf2054..96c1901 100644 --- a/tests/unit/WP/ActionAddTest.php +++ b/tests/unit/WP/ActionAddTest.php @@ -142,6 +142,32 @@ public function testExpectAdded() assertTrue(Monkey::actions()->has('init', 'strtoupper', 20)); } + public function testAddedSameActionDifferentArguments() + { + $f1 = function () { + + }; + + $f2 = function () { + + }; + + Monkey::actions() + ->expectAdded('double_action') + ->once() + ->ordered() + ->with($f1); + + Monkey::actions() + ->expectAdded('double_action') + ->once() + ->ordered() + ->with($f2); + + add_action('double_action', $f1); + add_action('double_action', $f2); + } + public function testRemoveAction() { Actions::expectAdded('init')->once(); diff --git a/tests/unit/WP/ActionFireTest.php b/tests/unit/WP/ActionFireTest.php index b9f4663..1f5bc8f 100644 --- a/tests/unit/WP/ActionFireTest.php +++ b/tests/unit/WP/ActionFireTest.php @@ -122,6 +122,7 @@ public function testDoWithExpectationWhenHappen() ->whenHappen(function ($yes) use (&$works) { $works = $yes; }); + $sum = 0; Monkey::actions()->expectFired('sum') ->times(3) @@ -162,4 +163,22 @@ public function testDoWithExpectationFailIfTryToReturn() // well... that unicorns exist is a valid logic exception Monkey::actions()->expectFired('foo')->zeroOrMoreTimes()->andReturn('Unicorns exist!'); } + + public function testFiredSameActionDifferentArguments() + { + Monkey::actions() + ->expectFired('double_action') + ->once() + ->ordered() + ->with('arg_1'); + + Monkey::actions() + ->expectFired('double_action') + ->once() + ->ordered() + ->with('arg_2'); + + do_action('double_action', 'arg_1'); + do_action('double_action', 'arg_2'); + } } diff --git a/tests/unit/WP/FilterAddTest.php b/tests/unit/WP/FilterAddTest.php index 9642aae..e231559 100644 --- a/tests/unit/WP/FilterAddTest.php +++ b/tests/unit/WP/FilterAddTest.php @@ -148,6 +148,32 @@ public function testExpectAdded() add_filter('the_excerpt', [$this, __FUNCTION__], 30); } + public function testAddedSameFilterDifferentArguments() + { + $f1 = function () { + + }; + + $f2 = function () { + + }; + + Monkey::filters() + ->expectAdded('double_filter') + ->once() + ->ordered() + ->with($f1, 10); + + Monkey::filters() + ->expectAdded('double_filter') + ->once() + ->ordered() + ->with($f2, 20); + + add_filter('double_filter', $f1, 10); + add_filter('double_filter', $f2, 20); + } + public function testRemoveAction() { Filters::expectAdded('the_title')->once(); diff --git a/tests/unit/WP/FilterFireTest.php b/tests/unit/WP/FilterFireTest.php index f132627..44c0378 100644 --- a/tests/unit/WP/FilterFireTest.php +++ b/tests/unit/WP/FilterFireTest.php @@ -145,4 +145,31 @@ public function testApplyWithExpectationAndReturnCurrentFilter() assertSame('Great!', apply_filters('can_I_ask', 'How is Monkey?')); assertSame('Meh', apply_filters('can_I_ask', 'How is Milk?')); } + + public function testApplySameFilterDifferentArguments() + { + $obj = new \stdClass(); + + Monkey::filters() + ->expectApplied('double_filter') + ->once() + ->ordered() + ->with('x', $obj, 'x'); + + Monkey::filters() + ->expectApplied('double_filter') + ->once() + ->ordered() + ->with('x', $obj, 'y'); + + Monkey::filters() + ->expectApplied('double_filter') + ->once() + ->ordered() + ->with('x', $obj, 'x'); + + apply_filters('double_filter', 'x', $obj, 'x'); + apply_filters('double_filter', 'x', $obj, 'y'); + apply_filters('double_filter', 'x', $obj, 'x'); + } }