Skip to content

Commit

Permalink
Update WP_Mock::expectHookNotAdded() with new params (#234)
Browse files Browse the repository at this point in the history
<!--
Filling out the required portions of this template is mandatory. 
Any PR that does not include enough information to be reviewed may be
closed at a maintainers' discretion.
All new code requires associated documentation and unit tests.
-->

# Summary <!-- Required -->

Adds method params to `expectHookNotAdded` for priority and allowed
arguments that are symmetrical to `expectHookAdded` - and carries them
over the aliased functions for filter and action hooks.

This way, we can set more specific expectations than assuming hooks will
always have `10, 1` as priority/args allowed.

The PR also improves the WP_Mock hook methods phpdocs and types to match
current standards.

### Closes: #233 

## Contributor checklist <!-- Required -->

<!--- Go over all the following points, and put an `x` in all the boxes
that apply. -->
<!--- If you are unsure about any of these, please ask for
clarification. We are here to help! -->

- [x] I agree to follow this project's [**Code of
Conduct**](https://github.com/10up/.github/blob/trunk/CODE_OF_CONDUCT.md).
- [x] I have updated the documentation accordingly 
- [x] I have added tests to cover changes introduced by this pull
request
- [x] All new and existing tests pass

### Reviewer checklist <!-- Required -->

<!-- The following checklist is for the reviewer: add any steps that may
be relevant while reviewing this pull request -->

- [x] Code changes review
- [ ] Documentation changes review
- [x] Unit tests pass
- [x] Static analysis passes
  • Loading branch information
unfulvio-godaddy authored Aug 16, 2023
1 parent de812e4 commit e9e421c
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 170 deletions.
155 changes: 83 additions & 72 deletions php/WP_Mock.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,163 +224,174 @@ public static function addHook($hook, $type = 'filter')
}

/**
* Set up the expectation that an action will be called during the test.
* Adds an expectation that an action will be called during the test.
*
* Mock a WordPress action, regardless of the parameters used. This call merely
* verifies that the action is invoked by the tested method.
*
* @param string $action Action we expect the method to call
* @param string $action expected action
* @returnv oid
*/
public static function expectAction($action)
public static function expectAction(string $action) : void
{
$intercept = \Mockery::mock('intercept');
$intercept = Mockery::mock('intercept');
$intercept->shouldReceive('intercepted')->atLeast()->once();
$args = func_get_args();
$args = count($args) > 1 ? array_slice($args, 1) : array( null );

$mocked_action = self::onAction($action);
$responder = call_user_func_array(array( $mocked_action, 'with' ), $args);
$responder->perform(array( $intercept, 'intercepted' ));
$responder->perform([$intercept, 'intercepted']);
}

/**
* Set up the expectation that a filter will be applied during the test.
*
* Mock a WordPress filter with specific arguments. You need all arguments that you expect
* in order to fulfill the expectation.
* Adds an expectation that a filter will be applied during the test.
*
* @param string $filter
* @param string $filter expected filter
* @return void
*/
public static function expectFilter($filter)
public static function expectFilter(string $filter) : void
{
$intercept = \Mockery::mock('intercept');
$intercept = Mockery::mock('intercept');
$intercept->shouldReceive('intercepted')->atLeast()->once()->andReturnUsing(function ($value) {
return $value;
});
$args = func_num_args() > 1 ? array_slice(func_get_args(), 1) : array( null );

$mocked_filter = self::onFilter($filter);
$responder = call_user_func_array(array( $mocked_filter, 'with' ), $args);
$responder->reply(new \WP_Mock\InvokedFilterValue(array( $intercept, 'intercepted' )));
$responder->reply(new WP_Mock\InvokedFilterValue(array( $intercept, 'intercepted' )));
}

/**
* Assert that all actions are called.
* Asserts that all actions are called.
*
* @return void
*/
public static function assertActionsCalled()
public static function assertActionsCalled() : void
{
$allActionsCalled = self::$event_manager->allActionsCalled();
$failed = implode(', ', self::$event_manager->expectedActions());
\PHPUnit\Framework\Assert::assertTrue($allActionsCalled, 'Method failed to invoke actions: ' . $failed);
PHPUnit\Framework\Assert::assertTrue($allActionsCalled, 'Method failed to invoke actions: ' . $failed);
}

/**
* Assert that all filters are called.
* Asserts that all filters are called.
*
* @return void
*/
public static function assertFiltersCalled()
public static function assertFiltersCalled() : void
{
$allFiltersCalled = self::$event_manager->allFiltersCalled();
$failed = implode(', ', self::$event_manager->expectedFilters());
\PHPUnit\Framework\Assert::assertTrue($allFiltersCalled, 'Method failed to invoke filters: ' . $failed);
PHPUnit\Framework\Assert::assertTrue($allFiltersCalled, 'Method failed to invoke filters: ' . $failed);
}

/**
* Add an expectation that an action should be added
*
* Really just a wrapper function for expectHookAdded()
* Adds an expectation that an action hook should be added.
*
* @param string $action The action name
* @param callable|Type $callback The callback that should be registered
* @param int $priority The priority it should be registered at
* @param int $args The number of arguments that should be allowed
* @param string $action the action hook name
* @param string|callable-string|callable|Type $callback the callback that should be registered
* @param int $priority the priority it should be registered at
* @param int $args the number of arguments that should be allowed
* @return void
*/
public static function expectActionAdded($action, $callback, $priority = 10, $args = 1)
public static function expectActionAdded(string $action, $callback, int $priority = 10, int $args = 1) : void
{
self::expectHookAdded('action', $action, $callback, $priority, $args);
}

/**
* Add an expection that an action should not be added. A wrapper
* around the expectHookNotAdded function.
* Adds an expectation that an action hook should not be added.
*
* @param string $action The action hook name
* @param callable|Type $callback The action callback
* @param string $action the action hook name
* @param string|callable-string|callable|Type $callback the callback that should be registered
* @param int $priority the priority it should be registered at
* @param int $args the number of arguments that should be allowed
* @return void
*/
public static function expectActionNotAdded($action, $callback)
public static function expectActionNotAdded(string $action, $callback, int $priority = 10, int $args = 1) : void
{
self::expectHookNotAdded('action', $action, $callback);
self::expectHookNotAdded('action', $action, $callback, $priority, $args);
}

/**
* Add an expectation that a filter should be added
* Add an expectation that a filter hook should be added.
*
* Really just a wrapper function for expectHookAdded()
*
* @param string $filter The action name
* @param callable|Type $callback The callback that should be registered
* @param int $priority The priority it should be registered at
* @param int $args The number of arguments that should be allowed
* @param string $filter the filter hook name
* @param string|callable-string|callable|Type $callback the callback that should be registered
* @param int $priority the priority it should be registered at
* @param int $args the number of arguments that should be allowed
* @return void
*/
public static function expectFilterAdded($filter, $callback, $priority = 10, $args = 1)
public static function expectFilterAdded(string $filter, $callback, int $priority = 10, int $args = 1) : void
{
self::expectHookAdded('filter', $filter, $callback, $priority, $args);
}

/**
* Adds an expectation that a filter will not be added. A wrapper
* around the expectHookNotAdded function.
* Adds an expectation that a filter hook should not be added.
*
* @param string $filter The filter hook name
* @param callable|Type $callback The filter callback
* @param string $filter the filter hook name
* @param string|callable-string|callable|Type $callback the callback that should be registered
* @param int $priority the priority it should be registered at
* @param int $args the number of arguments that should be allowed
* @return void
*/
public static function expectFilterNotAdded($filter, $callback)
public static function expectFilterNotAdded(string $filter, $callback, int $priority = 10, int $args = 10) : void
{
self::expectHookNotAdded('filter', $filter, $callback);
self::expectHookNotAdded('filter', $filter, $callback, $priority, $args);
}

/**
* Add an expectation that a hook should be added
* Adds an expectation that a hook should be added.
*
* @param string $type The type of hook being added
* @param string $action The action name
* @param callable|Type $callback The callback that should be registered
* @param int $priority The priority it should be registered at
* @param int $args The number of arguments that should be allowed
* Based {@see Mockery\MockInterface::shouldReceive()}.
*
* @param string $type the type of hook being added ('action' or 'filter')
* @param string $hook the hook name
* @param string|callable-string|callable|Type $callback the callback that should be registered
* @param int $priority the priority it should be registered at
* @param int $args the number of arguments that should be allowed
* @return void
*/
public static function expectHookAdded($type, $action, $callback, $priority = 10, $args = 1)
public static function expectHookAdded(string $type, string $hook, $callback, int $priority = 10, int $args = 1) : void
{
$intercept = \Mockery::mock('intercept');
$intercept = Mockery::mock('intercept');
$intercept->shouldReceive('intercepted')->atLeast()->once();

/** @var WP_Mock\HookedCallbackResponder $responder */
$responder = self::onHookAdded($action, $type)
$responder = self::onHookAdded($hook, $type)
->with($callback, $priority, $args);
$responder->perform(array( $intercept, 'intercepted' ));
$responder->perform([$intercept, 'intercepted']);
}

/**
* Adds an expectation that a hook should not be added. Based on the
* shouldNotReceive API of Mocker.
* Adds an expectation that a hook should not be added.
*
* @param string $type The hook type, 'action' or 'filter'
* @param string $action The name of the hook
* @param callable|Type $callback The hooks callback handler.
* Based {@see Mockery\MockInterface::shouldNotReceive()}.
*
* @param string $type the type of hook being added ('action' or 'filter')
* @param string $hook the hook name
* @param string|callable-string|callable|Type $callback the callback that should be registered
* @param int $priority the priority it should be registered at
* @param int $args the number of arguments that should be allowed
* @return void
*/
public static function expectHookNotAdded($type, $action, $callback)
public static function expectHookNotAdded(string $type, string $hook, $callback, int $priority = 10, int $args = 1) : void
{
$intercept = \Mockery::mock('intercept');
$intercept = Mockery::mock('intercept');
$intercept->shouldNotReceive('intercepted');

/** @var WP_Mock\HookedCallbackResponder $responder */
$responder = self::onHookAdded($action, $type)
->with($callback, 10, 1);
$responder->perform(array( $intercept, 'intercepted' ));
$responder = self::onHookAdded($hook, $type)
->with($callback, $priority, $args);
$responder->perform([$intercept, 'intercepted']);
}

/**
* Assert that all hooks are added.
* Asserts that all hooks are added.
*
* @return void
*/
public static function assertHooksAdded()
public static function assertHooksAdded() : void
{
$allHooksAdded = self::$event_manager->allHooksAdded();
$failed = implode(', ', self::$event_manager->expectedHooks());
Expand Down
36 changes: 23 additions & 13 deletions php/WP_Mock/API/function-mocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@
/**
* Hooks a function on to a specific action.
*
* Actions are the hooks that the WordPress core launches at specific points
* during execution, or when specific events occur. Plugins can specify that
* one or more of its PHP functions are executed at these points, using the
* Action API.
* Actions are the hooks that WordPress launches at specific points during execution, or when specific events occur.
* Plugins can specify that one or more of its PHP functions are executed at these points, using the Action API.
*
* @param string $tag The name of the action to which the $function_to_add is hooked.
* @param callback $function_to_add The name of the function you wish to be called.
* @param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.
* @param int $accepted_args optional. The number of arguments the function accept (default 1).
* @link https://developer.wordpress.org/plugins/hooks/actions/
*
* @param string $tag the name of the action to which the $function_to_add is hooked
* @param string|callable-string|callable $functionToAdd the name of the function you wish to be called
* @param int $priority optional, used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action
* @param int $acceptedArgs the number of arguments the function accept (default 1)
*/
function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1)
function add_action(string $tag, $functionToAdd, int $priority = 10, int $acceptedArgs = 1)
{
\WP_Mock::onActionAdded($tag)->react($function_to_add, (int) $priority, (int) $accepted_args);
\WP_Mock::onActionAdded($tag)->react($functionToAdd, $priority, $acceptedArgs);
}
}

Expand All @@ -43,11 +43,21 @@ function do_action($tag, $arg = '')

if (! function_exists('add_filter')) {
/**
* Dummy method to prevent filter hooks in constructor from failing.
* Hooks a function on to a specific filter.
*
* Filters are the hooks that WordPress uses to alter the value of a variable at specific points during execution.
* Plugins can specify that one or more of its PHP functions are executed at these points, using the Filter API, to change the value of that variable.
*
* @link https://developer.wordpress.org/plugins/hooks/filters/
*
* @param string $tag the name of the action to which the $function_to_add is hooked
* @param string|callable-string|callable $functionToAdd the name of the function you wish to be called
* @param int $priority optional, used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action
* @param int $acceptedArgs the number of arguments the function accept (default 1)
*/
function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1)
function add_filter(string $tag, $functionToAdd, int $priority = 10, int $acceptedArgs = 1)
{
\WP_Mock::onFilterAdded($tag)->react($function_to_add, (int) $priority, (int) $accepted_args);
\WP_Mock::onFilterAdded($tag)->react($functionToAdd, $priority, $acceptedArgs);
}
}

Expand Down
10 changes: 5 additions & 5 deletions php/WP_Mock/Hook.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,19 @@ protected function safe_offset($value): string
if ($value instanceof Closure || Closure::class === $value || (is_string($value) && '<CLOSURE>' === strtoupper($value)) || ($value instanceof Type && $value->match($closure))){
return '__CLOSURE__';
}

if (is_scalar($value)){
return (string) $value;
}

if ($value instanceof AnyInstance){
return (string) $value;
}

if (is_object($value)){
return spl_object_hash($value);
}

if (is_array($value)) {
$parsed = '';

Expand All @@ -79,7 +79,7 @@ protected function safe_offset($value): string
return '';
}

/** @return Action_Responder|Filter_Responder */
/** @return Action_Responder|Filter_Responder|HookedCallbackResponder */
public function with()
{
$args = func_get_args();
Expand Down
Loading

0 comments on commit e9e421c

Please sign in to comment.