diff --git a/composer.json b/composer.json index 146a43c..62d7f67 100644 --- a/composer.json +++ b/composer.json @@ -43,13 +43,14 @@ ] }, "autoload-dev": { - "psr-4": { - "Brain\\Monkey\\Tests\\": "tests/src/" - }, "files": [ - "inc/wp-helper-functions.php", - "inc/wp-hook-functions.php" - ] + "vendor/antecedent/patchwork/Patchwork.php" + ], + "psr-4": { + "Brain\\Monkey\\Tests\\": "tests/src/", + "Brain\\Monkey\\Tests\\Unit\\": "tests/cases/unit/", + "Brain\\Monkey\\Tests\\Functional\\": "tests/cases/functional/" + } }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/docs/functions-stubs.md b/docs/functions-stubs.md index f359687..9b9220c 100644 --- a/docs/functions-stubs.md +++ b/docs/functions-stubs.md @@ -1,135 +1,200 @@ - -# Bulk patching with stubs() - -`when()` and its related functions are quite simple and straightforward. - -However, it can be quite verbose when multiple functions needed to be patched. - -When one uses `when()` they are not interested in adding expectations but usually are -interested in ensuring the target function is defined, and maybe its return value. - -For this reason, version 2.1 introduced a new API function to define multiple functions in bulk: `stubs()` - -## `stubs()` - -`Functions\stubs()` accepts an array of functions to be defined. - -The function names can be passed as array item _keys_ or as array item _values_ and no key. - -When the function name is the item key, the item value can be either: - -- a `callable`, in which case the function will be aliased to it -- anything else, in which case a stub returning a given value will be created for the function - -Example: - -```php -Functions\stubs([ - 'is_user_logged_in' => true, - 'current_user_can' => true, - 'wp_get_current_user' => function() { - return \Mockery::mock('\WP_User'); - } -]); -``` - -When the function name is the array item value, and no item key is used, the behavior will change -based on the second argument passed to `stubs()`: - -- when the second argument is `null` (default), the created stub will return the first parameter it would receive -- when the second argument is anything else, the created stub will use it as its return value - - -Example: - -```php -// Given functions will return `true` -Functions\stubs( - [ - 'is_user_logged_in', - 'current_user_can', - ], - true -); - -// Given functions will return the first argument they would receive, -// just like `when( $function_name )->justReturnArg()` was used for all of them. -Functions\stubs( - [ - 'esc_attr', - 'esc_html', - 'esc_textarea', - '__', - '_x', - 'esc_html__', - 'esc_html_x', - 'esc_attr_x', - ] -); -``` - -### Gotcha - -When passing a function name as an array item key and a `callable` as the value, the function -will be aliased to that callable. That means it is **not** possible to create a stub -for a function that returns a callback, by doing something like: - -```php -Functions\stubs( - [ - 'function_that_returns_a_callback' => 'the_expected_returned_callback' - ] -); -``` - -But this will work: - -```php -Functions\stubs( - [ - 'function_that_returns_a_callback' => function() { - return 'the_expected_returned_callback'; - } - ] -); -``` - -Moreover, when doing something like this: - -```php -Functions\stubs( - [ 'function_that_returns_null' => null ] -); -``` - -or like this: - -```php -Functions\stubs( - [ 'function_that_returns_null' ], - null -); -``` - - -the return value of the stub will **not** be `null`, because when return value is set to `null` -Brain Monkey will make the function stub return the first received value. - -The only way to use `stubs()` for creating a stub that returns `null` is: - -```php -Functions\stubs( - [ 'function_that_returns_null' => function() { return null; } ] -); -``` - -or the equivalent but more concise: - -```php -// __return_null is defined by Brain Monkey since version 2 -Functions\stubs( [ 'function_that_returns_null' => '__return_null' ] ); -``` + +# Bulk patching with stubs() + +`when()` and its related functions are quite simple and straightforward. + +However, it can be quite verbose when multiple functions needs to be patched. + +For this reason, version 2.1 introduced a new API function to define multiple functions in bulk: `stubs()` + +## `stubs()` + +`Functions\stubs()` accepts an array of functions to be defined. + +The first way to use it is to pass function names as array item _keys_ and the wanted return values +as array _values_: + +```php +Functions\stubs( + [ + 'is_user_logged_in' => true, + 'current_user_can' => false, + ] +); +``` + +There are two special cases: + +- when the array item value is a `callable`, the function given as array item key is _aliased_ to + the given callback instead of returning the callback itself; + +- when the array item value is `null`, the function given as array item key will return the first + argument received, just like `when( $function_name )->justReturnArg()` was used for it + +```php +Functions\stubs( + [ + 'is_user_logged_in' => true, // will return `true` as provided + 'wp_get_current_user' => function () { // will return the WP_User mock + return \Mockery::mock(\WP_User::class); + }, + '__' => null, // will return the 1st argument received + ] +); +``` + +Another way to use `stubs`, useful to stub many function with same return value, is to pass +to a non-associative array of function names as first argument, and the wanted return +value for all of them as second argument. + +For example, the snippet below will create a stub that returns `true` for all the given functions: + +```php +Functions\stubs( + [ + 'is_user_logged_in', + 'current_user_can', + 'is_multisite', + 'is_admin', + ], + true +); +``` + +Please note that the default value for the second argument, being it optional, is `null`, and because +using `null` as value means _"return first received argument"_ it is possible to stub many functions +that have to return first received argument, by passing their names as first argument to `stubs()` +(and no second argument), like this: + +```php +Functions\stubs( + [ + 'esc_attr', + 'esc_html', + '__', + '_x', + 'esc_attr__', + 'esc_html__', + ] +); +``` + +(Even if there's a simpler way to stub escaping and translation WP functions, more on this below). + +It worth noting that the two ways of using `stubs()` can be mixed together, for example like this: + +```php +Functions\stubs( + [ + // will both return 1st argument received, because `stubs` 2nd param defaults to `null` + 'esc_attr', + 'esc_html', + + // will all return what is given as array item value + 'is_user_logged_in' => true, + 'current_user_can' => false, + 'get_current_user_id' => 1, + ] +); +``` + + + +## Pre-defined stubs for escaping functions + +To stub WordPress escaping functions is a very common usage for `Functions\stubs`. + +This is why, since version 2.3, Brain Monkey introduced a new API function: + +- **`Functions\stubEscapeFunctions()`** + +When called, it will create a stub for each of the following functions: + +- `esc_js()` +- `esc_sql()` +- `esc_attr()` +- `esc_html()` +- `esc_textarea()` +- `esc_url()` +- `esc_url_raw()` + +By calling `Functions\stubEscapeFunctions()`, for _all_ of the functions listed above a stub will +be created that will do some very basic escaping on the received first argument before returning it. + +It will *not* be the exact same escape mechanism that WordPress would apply, but "similar enough" +for unit tests purpose and could still be helpful to discover some bugs. + + +## Pre-defined stubs for translation functions + +Another common usage for `Functions\stubs`, since its introduction, has been to stub translation +functions. + +Since version 2.3, this has became much easier thanks to the introduction of a new API function: + +- **`Functions\stubTranslationFunctions()`** + +When called, it will create a stub for _all_ the following functions: + +- `__()` +- `_x()` +- `translate()` +- `esc_html__()` +- `esc_html_x()` +- `esc_attr__()` +- `esc_attr_x()` +- `esc_html_e()` +- `esc_attr_e()` + +The created stub will not attempt any translation, but will return (or echo) the first received argument. + +Only for functions that both translate and escape (`esc_html__()`, `esc_html_x()`...) the same +escaping mechanism used by the pre-defined escaping functions stubs (see above) is applied before +returning first received argument. + +Please note how `Functions\stubTranslationFunctions()` creates stubs for functions that _echo_ +translated text, something not easily doable with `Functions\stubs()` alone. + + +## Gotcha for `Functions\stubs` + +### Functions that returns null + +When using `stubs()`, passing `null` as the "value" of the function to stub, the return value of the +stub will **not** be `null`, but the first received value. + +To use `stubs()` to stub functions that return `null` it is possible to do something like this: + +```php +Functions\stubs( [ 'function_that_returns_null' => '__return_null' ] ); +``` + +It works because `__return_null` is a WP function that Brain Monkey also defines since version 2.0. + +### Functions that returns callbacks + +When using `stubs`, passing a `callable` as the "value" of the function to stub, the created stub +will be an _alias_ of the given callable, will **not** return it. + +If one want to use `stubs` to stub a function that returns a callable, a way to do it would be +something like this: + +```php +Functions\stubs( + [ + 'function_that_returns_a_callback' => function() { + return 'the_expected_returned_callback'; + } + ] +); +``` + +but it is probably simpler to use the "usual" `when` + `justReturn`: + +```php +when('function_that_returns_a_callback')->justReturn('the_expected_returned_callback') +``` diff --git a/docs/wordpress-hooks-added.md b/docs/wordpress-hooks-added.md index cca4f0b..7233614 100644 --- a/docs/wordpress-hooks-added.md +++ b/docs/wordpress-hooks-added.md @@ -165,7 +165,7 @@ Just note how classes used in type-hints were using _relative_ namespace on decl PHP 7+ scalar type hints are perfectly supported. -The serialization also recognizes `static `closures. Following closure: +The serialization also recognizes `static` closures. Following closure: ```php static function( int $foo, Bar ...$bar ) { diff --git a/docs/wordpress-tools.md b/docs/wordpress-tools.md index 147a632..4ab903b 100644 --- a/docs/wordpress-tools.md +++ b/docs/wordpress-tools.md @@ -1,85 +1,92 @@ - -# WordPress Testing Tools - -The sole ability to mocking functions is a great help on testing WordPress code. - -All WordPress functions can be mocked and tested using the techniques described in the *PHP Functions* section, they are PHP functions, after all. - -However, to test WordPress code in isolation, without a bunch of bootstrap code for every test, a more fine grained control of plugin API functions is required. - -This is exactly what Brain Monkey offers. - - - -## Defined functions - -Following functions are defined by Brain Monkey when it is loaded for tests: - - - -**Hook-related functions:** - - - `add_action()` - - `remove_action()` - - `do_action()` - - `do_action_ref_array()` - - `did_action()` - - `doing_action()` - - `has_action()` - - `add_filter()` - - `remove_filter()` - - `apply_filters()` - - `apply_filters_ref_array()` - - `has_filter()` - - `current_filter()` - -**Generic functions:** - - - `__return_true()` - - `__return_false()` - - `__return_null()` - - `__return_empty_array()` - - `__return_empty_string()` - - `trailingslashit()` - - `untrailingslashit()` - - - -If your code uses any of these functions, and very likely it does, you don't need to define (or mock) them -to avoid fatal errors during tests. - -Note that the returning value of those functions (most of the times) will work out of the box as you might expect. - -For example, if your code contains: - -```php -do_action('my_custom_action'); - -// something in the middle -$did = did_action('my_custom_action'); -``` -the value of `$did` will be correctly `1` (`did_action()` in WordPress returns the number an action was *done*). - -Or if your code contains: - -```php -$post = [ 'post_title' => 'My Title' ]; - -$title = apply_filters('the_title', $post['post_title']); -``` -the value of `$title` will be `'My Title'`, without the need of any intervention. - -But, of course, that's not enough. To proper test WordPress code you will probably desire to: - - - test if an action or a filter has been added, how many times that happen and with which arguments - - test if an action or a filter has been fired, how many times that happen and with which arguments - - perform some callback when an action is fired, being able to access passed arguments - - perform some callback when an filter is applied, being able to access passed arguments and to return specific values - -Guess what, Brain Monkey allows to do all of this and even more. - -And it does that using its straightforward and human readable syntax. \ No newline at end of file + +# WordPress Testing Tools + +The sole ability to mocking functions is a great help on testing WordPress code. + +All WordPress functions can be mocked and tested using the techniques described in the *PHP Functions* section, they are PHP functions, after all. + +However, to test WordPress code in isolation, without a bunch of bootstrap code for every test, a more fine grained control of plugin API functions is required. + +This is exactly what Brain Monkey offers. + + + +## Defined functions + +Following functions are defined by Brain Monkey when it is loaded for tests: + + + +**Hook-related functions:** + + - `add_action()` + - `remove_action()` + - `do_action()` + - `do_action_ref_array()` + - `did_action()` + - `doing_action()` + - `has_action()` + - `add_filter()` + - `remove_filter()` + - `apply_filters()` + - `apply_filters_ref_array()` + - `has_filter()` + - `current_filter()` + +**Generic functions:** + + - `__return_true()` + - `__return_false()` + - `__return_null()` + - `__return_empty_array()` + - `__return_empty_string()` + - `trailingslashit()` + - `untrailingslashit()` + - `absint()` (since 2.3) + - `is_wp_error()` (since 2.3) + + + +If your code uses any of these functions, and very likely it does, you don't need to define (or mock) them +to avoid fatal errors during tests. + +Note that the returning value of those functions (_most of the times_) will work out of the box as you might expect. + +For example, if your code contains: + +```php +do_action('my_custom_action'); + +// something in the middle +$did = did_action('my_custom_action'); +``` +the value of `$did` will be correctly `1` (`did_action()` in WordPress returns the number an action was *done*). + +Or if your code contains: + +```php +$post = [ 'post_title' => 'My Title' ]; + +$title = apply_filters('the_title', $post['post_title']); +``` +the value of `$title` will be `'My Title'`, without the need of any intervention. + +This works as long as there's no code that actually adds filters to `"the_title"` hook, so we expect +that the title stay unchanged. And that's what happen. + +If in the code under test there's something that adds filters (i.e. calls `add_filter`), the +_Brain Monkey version_ of `apply_filters` will still return the value unchanged, but will allow to +test that `apply_filters` has been called, how many times, with which callbacks and arguments are used. + +More generally, in the regards of WP hook API, Brain Monkey allow to: + + - test if an action or a filter has been added, how many times that happen and with which arguments + - test if an action or a filter has been fired, how many times that happen and with which arguments + - perform some callback when an action is fired, being able to access passed arguments + - perform some callback when an filter is applied, being able to access passed arguments and to return specific values + +And it does that using its straightforward and human-readable syntax. \ No newline at end of file diff --git a/inc/api.php b/inc/api.php index 7e90e5e..83d652d 100644 --- a/inc/api.php +++ b/inc/api.php @@ -43,16 +43,17 @@ function tearDown() namespace Brain\Monkey\Functions { use Brain\Monkey\Container; + use Brain\Monkey\Expectation\EscapeHelper; use Brain\Monkey\Expectation\FunctionStubFactory; use Brain\Monkey\Name\FunctionName; /** - * API entrypoint for plain functions stub. + * API entry-point for plain functions stub. * * Factory method: receives the name of the function to mock and returns an instance of * FunctionStub. * - * @param string $function_name the name of the function to mock + * @param string $function_name the name of the function to mock * @return \Brain\Monkey\Expectation\FunctionStub */ function when($function_name) @@ -67,18 +68,21 @@ function when($function_name) * * It does not allow to add expectations. * - * The function name to create stub for can be passed as array key or as array value (with no key). + * The function name to create stub for can be passed as array key or as array value (with no + * key). * * When the function name is in the key, the value can be: * - a callable, in which case the function will be aliased to it - * - anything else, in which case a stub returning given value will be created for the function - * + * - anything else, in which case a stub returning given value will be created for the + * function + * * When the function name is in the value, and no key is set, the behavior will change based on * the second param: - * - when 2nd param is `null` (default) the created stub will return the 1st param it will receive + * - when 2nd param is `null` (default) the created stub will return the 1st param it will + * receive * - when 2nd param is anything else the created stub will return it * - * + * * @param array $functions * @param mixed|null $default_return */ @@ -102,7 +106,7 @@ function stubs(array $functions, $default_return = null) } /** - * API entrypoint for plain functions expectations. + * API entry-point for plain functions expectations. * * Returns a Mockery Expectation object, where is possible to set all the expectations, using * Mockery methods. @@ -126,6 +130,51 @@ function expect($function_name) return $expectation; } + + /** + * Stub translation functions. + * + * @see EscapeHelper + */ + function stubTranslationFunctions() + { + stubs( + [ + '__', + '_x', + 'translate', + 'esc_html__' => [EscapeHelper::class, 'esc'], + 'esc_html_x' => [EscapeHelper::class, 'esc'], + 'esc_attr__' => [EscapeHelper::class, 'esc'], + 'esc_attr_x' => [EscapeHelper::class, 'esc'], + 'esc_html_e' => [EscapeHelper::class, 'escAndEcho'], + 'esc_attr_e' => [EscapeHelper::class, 'escAndEcho'], + ] + ); + + when('_e')->echoArg(); + when('_ex')->echoArg(); + } + + /** + * Stub escape functions with default behavior. + * + * @see EscapeHelper + */ + function stubEscapeFunctions() + { + stubs( + [ + 'esc_js' => [EscapeHelper::class, 'esc'], + 'esc_sql' => 'addslashes', + 'esc_attr' => [EscapeHelper::class, 'esc'], + 'esc_html' => [EscapeHelper::class, 'esc'], + 'esc_textarea' => [EscapeHelper::class, 'esc'], + 'esc_url' => [EscapeHelper::class, 'escUrl'], + 'esc_url_raw' => [EscapeHelper::class, 'escUrlRaw'], + ] + ); + } } namespace Brain\Monkey\Actions { @@ -134,7 +183,7 @@ function expect($function_name) use Brain\Monkey\Hook; /** - * API entrypoint for added action expectations. + * API entry-point for added action expectations. * * Takes the action name and returns a Mockery Expectation object, where is possible to set all * the expectations, using Mockery methods. @@ -150,7 +199,7 @@ function expectAdded($action) } /** - * API entrypoint for fired action expectations. + * API entry-point for fired action expectations. * * Takes the action name and returns a Mockery Expectation object, where is possible to set all * the expectations, using Mockery methods. @@ -210,6 +259,22 @@ function doing($action) ->hookRunningStack() ->has($action); } + + /** + * API entry-point for removed action expectations. + * + * Takes the action name and returns a Mockery Expectation object, where is possible to set all + * the expectations, using Mockery methods. + * + * @param string $action + * @return \Brain\Monkey\Expectation\Expectation + */ + function expectRemoved($action) + { + return Container::instance() + ->expectationFactory() + ->forActionRemoved($action); + } } namespace Brain\Monkey\Filters { @@ -218,7 +283,7 @@ function doing($action) use Brain\Monkey\Hook; /** - * API entrypoint for added filter expectations. + * API entry-point for added filter expectations. * * Takes the filter name and returns a Mockery Expectation object, where is possible to set all * the expectations, using Mockery methods. @@ -234,7 +299,7 @@ function expectAdded($filter) } /** - * API entrypoint for applied filter expectations. + * API entry-point for applied filter expectations. * * Takes the filter name and returns a Mockery Expectation object, where is possible to set all * the expectations, using Mockery methods. @@ -294,5 +359,21 @@ function doing($filter) ->hookRunningStack() ->has($filter); } + + /** + * API entry-point for removed action expectations. + * + * Takes the action name and returns a Mockery Expectation object, where is possible to set all + * the expectations, using Mockery methods. + * + * @param string $filter + * @return \Brain\Monkey\Expectation\Expectation + */ + function expectRemoved($filter) + { + return Container::instance() + ->expectationFactory() + ->forFilterRemoved($filter); + } } diff --git a/inc/patchwork-loader.php b/inc/patchwork-loader.php index 22562bf..adb3f17 100644 --- a/inc/patchwork-loader.php +++ b/inc/patchwork-loader.php @@ -17,10 +17,8 @@ } if (file_exists(dirname(dirname(dirname(__DIR__)))."/antecedent/patchwork/Patchwork.php")) { - /** @noinspection PhpIncludeInspection */ @require_once dirname(dirname(dirname(__DIR__)))."/antecedent/patchwork/Patchwork.php"; } elseif (file_exists(dirname(__DIR__)."/vendor/antecedent/patchwork/Patchwork.php")) { - /** @noinspection PhpIncludeInspection */ @require_once dirname(__DIR__)."/vendor/antecedent/patchwork/Patchwork.php"; } diff --git a/inc/wp-helper-functions.php b/inc/wp-helper-functions.php index d5383da..0398f51 100644 --- a/inc/wp-helper-functions.php +++ b/inc/wp-helper-functions.php @@ -66,4 +66,18 @@ function trailingslashit($string) { return rtrim($string, '/\\').'/'; } +} + +if ( ! function_exists('absint')) { + function absint($number) + { + return abs((int)$number); + } +} + +if ( ! function_exists('is_wp_error')) { + function is_wp_error($thing) + { + return $thing instanceof \WP_Error; + } } \ No newline at end of file diff --git a/inc/wp-hook-functions.php b/inc/wp-hook-functions.php index ecf3379..89401bc 100644 --- a/inc/wp-hook-functions.php +++ b/inc/wp-hook-functions.php @@ -15,8 +15,9 @@ use Brain\Monkey; if ( ! function_exists('add_action')) { - function add_action($action, ...$args) + function add_action($action, $function, $priority = 10, $accepted_args = 1) { + $args = [$function, $priority, $accepted_args]; $container = Monkey\Container::instance(); $container->hookStorage()->pushToAdded(Monkey\Hook\HookStorage::ACTIONS, $action, $args); $container->hookExpectationExecutor()->executeAddAction($action, $args); @@ -26,8 +27,9 @@ function add_action($action, ...$args) } if ( ! function_exists('add_filter')) { - function add_filter($filter, ...$args) + function add_filter($filter, $function, $priority = 10, $accepted_args = 1) { + $args = [$function, $priority, $accepted_args]; $container = Monkey\Container::instance(); $container->hookStorage()->pushToAdded(Monkey\Hook\HookStorage::FILTERS, $filter, $args); $container->hookExpectationExecutor()->executeAddFilter($filter, $args); @@ -96,20 +98,28 @@ function did_action($action) } if ( ! function_exists('remove_action')) { - function remove_action($action, ...$args) + function remove_action($action, $function, $priority = 10) { - return Monkey\Container::instance() - ->hookStorage() - ->removeFromAdded(Monkey\Hook\HookStorage::ACTIONS, $action, $args); + $container = Monkey\Container::instance(); + $storage = $container->hookStorage(); + $args = [$function, $priority]; + + $container->hookExpectationExecutor()->executeRemoveAction($action, $args); + + return $storage->removeFromAdded(Monkey\Hook\HookStorage::ACTIONS, $action, $args); } } if ( ! function_exists('remove_filter')) { - function remove_filter($filter, ...$args) + function remove_filter($filter, $function, $priority = 10) { - return Monkey\Container::instance() - ->hookStorage() - ->removeFromAdded(Monkey\Hook\HookStorage::FILTERS, $filter, $args); + $container = Monkey\Container::instance(); + $storage = $container->hookStorage(); + $args = [$function, $priority]; + + $container->hookExpectationExecutor()->executeRemoveFilter($filter, $args); + + return $storage->removeFromAdded(Monkey\Hook\HookStorage::FILTERS, $filter, $args); } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 0a6fdd6..9f01eea 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,6 +1,5 @@ - - tests/src/Api + + tests/cases/unit - - tests/src/Expectation + + tests/cases/unit/Api - - tests/src/Name + + tests/cases/unit/Expectation - - tests/src/Hook + + tests/cases/unit/Name + + + tests/cases/unit/Hook + + + tests/cases/functional diff --git a/src/Expectation/EscapeHelper.php b/src/Expectation/EscapeHelper.php new file mode 100644 index 0000000..456d3cc --- /dev/null +++ b/src/Expectation/EscapeHelper.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Brain\Monkey\Expectation; + +/** + * Helper functions used to get an escaping that is "similar enough" to WordPress functions, + * without adding too much complexity. + * + * For edge cases consumers can either override the downstream functions that make use of this, or + * tests in integration. + */ +class EscapeHelper +{ + + /** + * @param $text + * @return string + */ + public static function esc($text) + { + return htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); + } + + /** + * @param string $text + * @return void + */ + public static function escAndEcho($text) + { + print static::esc($text); + + } + + /** + * @param string $url + * @return string + */ + public static function escUrlRaw($url) + { + if (!parse_url($url, PHP_URL_SCHEME)) { + $url = "http://{$url}"; + } + + return $url; + } + + /** + * @param string $url + * @return string + */ + public static function escUrl($url) + { + return str_replace(['&', "'"], ['&', '''], static::escUrlRaw($url)); + } +} \ No newline at end of file diff --git a/src/Expectation/Expectation.php b/src/Expectation/Expectation.php index df02049..278bc47 100644 --- a/src/Expectation/Expectation.php +++ b/src/Expectation/Expectation.php @@ -34,7 +34,6 @@ * @method Expectation ordered() * @method Expectation between(int $min, int $max) * @method Expectation zeroOrMoreTimes() - * @method Expectation with(...$args) * @method Expectation withArgs($args) * @method Expectation withAnyArgs() * @method Expectation andReturn(...$args) @@ -51,6 +50,16 @@ class Expectation ExpectationTarget::TYPE_FUNCTION ]; + const ADDING_TYPES = [ + ExpectationTarget::TYPE_ACTION_ADDED, + ExpectationTarget::TYPE_FILTER_ADDED + ]; + + const REMOVING_TYPES = [ + ExpectationTarget::TYPE_ACTION_REMOVED, + ExpectationTarget::TYPE_FILTER_REMOVED + ]; + const NO_ARGS_EXPECTATION_TYPES = [ ExpectationTarget::TYPE_ACTION_DONE, ExpectationTarget::TYPE_FUNCTION @@ -118,7 +127,6 @@ public function __clone() * @param string $name * @param array $arguments * @return static - * @throws \Brain\Monkey\Expectation\Exception\NotAllowedMethod */ public function __call($name, array $arguments = []) { @@ -182,7 +190,6 @@ public function andAlsoExpectIt() * and setting an expectation of no arguments for those triggers an error in Brain Monkey. * * @return static - * @throws \Brain\Monkey\Expectation\Exception\ExpectationArgsRequired */ public function withNoArgs() { @@ -195,6 +202,34 @@ public function withNoArgs() return $this; } + /** + * @param mixed ...$args + * @return static + */ + public function with(...$args) + { + $argsNum = count($args); + + if ( ! $argsNum && + ! in_array($this->target->type(), self::NO_ARGS_EXPECTATION_TYPES, true) + ) { + throw Exception\ExpectationArgsRequired::forExpectationType($this->target); + } + + if (in_array($this->target->type(), self::ADDING_TYPES, true) && $argsNum < 3) { + $argsNum < 2 and $args[] = 10; + $args[] = 1; + } + + if (in_array($this->target->type(), self::REMOVING_TYPES, true) && $argsNum === 1) { + $args[] = 10; + } + + $this->expectation = $this->expectation->with(...$args); + + return $this; + } + /** * Brain Monkey doesn't allow return expectation for actions (added/done) nor for added * filters. @@ -216,7 +251,6 @@ public function withNoArgs() * * @param callable $callback * @return static - * @throws \Brain\Monkey\Expectation\Exception\NotAllowedMethod */ public function whenHappen(callable $callback) { @@ -231,7 +265,6 @@ public function whenHappen(callable $callback) /** * @return static - * @throws \Brain\Monkey\Expectation\Exception\NotAllowedMethod */ public function andReturnFirstArg() { diff --git a/src/Expectation/ExpectationFactory.php b/src/Expectation/ExpectationFactory.php index 9575f88..90c3674 100644 --- a/src/Expectation/ExpectationFactory.php +++ b/src/Expectation/ExpectationFactory.php @@ -70,6 +70,17 @@ public function forActionDone($action) ); } + /** + * @param string $action + * @return \Brain\Monkey\Expectation\Expectation; + */ + public function forActionRemoved($action) + { + return $this->create( + new ExpectationTarget(ExpectationTarget::TYPE_ACTION_REMOVED, $action) + ); + } + /** * @param string $filter * @return \Brain\Monkey\Expectation\Expectation; @@ -92,6 +103,17 @@ public function forFilterApplied($filter) ); } + /** + * @param string $filter + * @return \Brain\Monkey\Expectation\Expectation; + */ + public function forFilterRemoved($filter) + { + return $this->create( + new ExpectationTarget(ExpectationTarget::TYPE_FILTER_REMOVED, $filter) + ); + } + /** * @param \Brain\Monkey\Expectation\ExpectationTarget $target * @return \Mockery\MockInterface|mixed diff --git a/src/Expectation/ExpectationTarget.php b/src/Expectation/ExpectationTarget.php index 13a7c90..dfbcc08 100644 --- a/src/Expectation/ExpectationTarget.php +++ b/src/Expectation/ExpectationTarget.php @@ -29,8 +29,10 @@ final class ExpectationTarget const TYPE_ACTION_ADDED = 'add_action'; const TYPE_ACTION_DONE = 'do_action'; + const TYPE_ACTION_REMOVED = 'remove_action'; const TYPE_FILTER_ADDED = 'add_filter'; const TYPE_FILTER_APPLIED = 'apply_filters'; + const TYPE_FILTER_REMOVED = 'remove_filter'; const TYPE_FUNCTION = 'function'; const TYPE_NULL = ''; @@ -38,8 +40,10 @@ final class ExpectationTarget self::TYPE_FUNCTION, self::TYPE_ACTION_ADDED, self::TYPE_ACTION_DONE, + self::TYPE_ACTION_REMOVED, self::TYPE_FILTER_ADDED, self::TYPE_FILTER_APPLIED, + self::TYPE_FILTER_REMOVED, ]; const HOOK_SANITIZE_MAP = [ @@ -93,8 +97,6 @@ final class ExpectationTarget /** * @param string $type * @param string $name - * @throws \Brain\Monkey\Expectation\Exception\InvalidExpectationName - * @throws \Brain\Monkey\Expectation\Exception\InvalidExpectationType */ public function __construct($type, $name) { @@ -157,12 +159,18 @@ public function mockMethodName() case ExpectationTarget::TYPE_ACTION_DONE: $name = "do_action_{$name}"; break; + case ExpectationTarget::TYPE_ACTION_REMOVED: + $name = "remove_action_{$name}"; + break; case ExpectationTarget::TYPE_FILTER_ADDED: $name = "add_filter_{$name}"; break; case ExpectationTarget::TYPE_FILTER_APPLIED: $name = "apply_filters_{$name}"; break; + case ExpectationTarget::TYPE_FILTER_REMOVED: + $name = "remove_filter_{$name}"; + break; default : throw new \UnexpectedValueException(sprintf('Unexpected %s type.', __CLASS__)); } diff --git a/src/Expectation/FunctionStub.php b/src/Expectation/FunctionStub.php index 3d8b5b0..6fc8330 100644 --- a/src/Expectation/FunctionStub.php +++ b/src/Expectation/FunctionStub.php @@ -112,7 +112,6 @@ public function justReturn($return = null) * Redefine target function making it echo an arbitrary value. * * @param mixed $value - * @throws \Brain\Monkey\Expectation\Exception\InvalidArgumentForStub */ public function justEcho($value = null) { @@ -159,7 +158,6 @@ public function returnArg($arg_num = 1) * Redefined function will throw an exception if the function does not receive desired argument. * * @param int $arg_num The position (1-based) of the argument to echo - * @throws \Brain\Monkey\Expectation\Exception\InvalidArgumentForStub */ public function echoArg($arg_num = 1) { @@ -189,7 +187,6 @@ public function echoArg($arg_num = 1) /** * @param int $arg_num * @return bool - * @throws \Brain\Monkey\Expectation\Exception\InvalidArgumentForStub */ private function assertValidArgNum($arg_num) { @@ -204,7 +201,6 @@ private function assertValidArgNum($arg_num) /** * @param string $function_name - * @throws \Brain\Monkey\Expectation\Exception\MissedPatchworkReplace */ private function assertRedefined($function_name) { @@ -216,7 +212,6 @@ private function assertRedefined($function_name) /** * @param $value * @param string $coming - * @throws \Brain\Monkey\Expectation\Exception\InvalidArgumentForStub */ private function assertPrintable($value, $coming = '') { diff --git a/src/Expectation/FunctionStubFactory.php b/src/Expectation/FunctionStubFactory.php index 8bc0747..73ad60c 100644 --- a/src/Expectation/FunctionStubFactory.php +++ b/src/Expectation/FunctionStubFactory.php @@ -32,7 +32,6 @@ class FunctionStubFactory * @param \Brain\Monkey\Name\FunctionName $name * @param string $scope * @return \Brain\Monkey\Expectation\FunctionStub - * @throws \Brain\Monkey\Expectation\Exception\Exception */ public function create(FunctionName $name, $scope) { diff --git a/src/Hook/HookExpectationExecutor.php b/src/Hook/HookExpectationExecutor.php index 2f7b13c..291c73f 100644 --- a/src/Hook/HookExpectationExecutor.php +++ b/src/Hook/HookExpectationExecutor.php @@ -10,6 +10,7 @@ namespace Brain\Monkey\Hook; +use Brain\Monkey\Expectation\Expectation; use Brain\Monkey\Expectation\ExpectationTarget; use Brain\Monkey\Expectation\ExpectationFactory; @@ -91,6 +92,26 @@ public function executeApplyFilters($filter, array $args) return $return; } + /** + * @param string $action + * @param array $args + * @return mixed + */ + public function executeRemoveAction($action, array $args) + { + return $this->execute(ExpectationTarget::TYPE_ACTION_REMOVED, $action, $args); + } + + /** + * @param string $filter + * @param array $args + * @return mixed + */ + public function executeRemoveFilter($filter, array $args) + { + return $this->execute(ExpectationTarget::TYPE_FILTER_REMOVED, $filter, $args); + } + /** * @param string $type * @param string $hook diff --git a/src/Hook/HookStorage.php b/src/Hook/HookStorage.php index bbb188f..1015b29 100644 --- a/src/Hook/HookStorage.php +++ b/src/Hook/HookStorage.php @@ -137,7 +137,6 @@ public function isHookDone($type, $hook) * @param string $hook * @param array $args * @return static - * @throws \Brain\Monkey\Hook\Exception\InvalidHookArgument */ private function pushToStorage($key, $type, $hook, array $args) { @@ -174,7 +173,6 @@ private function pushToStorage($key, $type, $hook, array $args) * @param string $hook * @param callable|null $function * @return int|bool - * @throws \Brain\Monkey\Hook\Exception\InvalidHookArgument */ private function isInStorage($key, $type, $hook, $function = null) { @@ -206,7 +204,6 @@ private function isInStorage($key, $type, $hook, $function = null) * @param string $key * @param string $type * @return array - * @throws \Brain\Monkey\Hook\Exception\InvalidHookArgument */ private function parseArgsToAdd(array $args, $key, $type) { diff --git a/src/Name/CallbackStringForm.php b/src/Name/CallbackStringForm.php index 6f3f4c2..dc1f574 100644 --- a/src/Name/CallbackStringForm.php +++ b/src/Name/CallbackStringForm.php @@ -50,7 +50,6 @@ public function equals(CallbackStringForm $callback) /** * @return string - * @throws \Brain\Monkey\Name\Exception\NotInvokableObjectAsCallback */ public function __toString() { @@ -60,8 +59,6 @@ public function __toString() /** * @param $callback * @return string - * @throws \Brain\Monkey\Name\Exception\InvalidCallable - * @throws \Brain\Monkey\Name\Exception\NotInvokableObjectAsCallback */ private function parseCallback($callback) { @@ -109,8 +106,6 @@ private function parseCallback($callback) /** * @param string $callback * @return bool|string - * @throws \Brain\Monkey\Name\Exception\InvalidCallable - * @throws \Brain\Monkey\Name\Exception\NotInvokableObjectAsCallback */ private function parseString($callback) { @@ -173,8 +168,6 @@ private function parseString($callback) * @param string $class_name * @param string $method * @param string|array $callable - * @throws \Brain\Monkey\Name\Exception\InvalidCallable - * @throws \Brain\Monkey\Name\Exception\NotInvokableObjectAsCallback */ private function assertMethodCallable($class_name, $method, $callable) { diff --git a/src/Name/ClassName.php b/src/Name/ClassName.php index 22653d9..107dc4e 100644 --- a/src/Name/ClassName.php +++ b/src/Name/ClassName.php @@ -26,7 +26,6 @@ final class ClassName /** * @param string $class_name - * @throws \Brain\Monkey\Name\Exception\InvalidName */ public function __construct($class_name) { diff --git a/src/Name/ClosureParamStringForm.php b/src/Name/ClosureParamStringForm.php index 3ab23e0..728d15e 100644 --- a/src/Name/ClosureParamStringForm.php +++ b/src/Name/ClosureParamStringForm.php @@ -36,7 +36,6 @@ class ClosureParamStringForm /** * @param string $param * @return static - * @throws \Brain\Monkey\Name\Exception\InvalidClosureParam */ public static function fromString($param) { @@ -85,7 +84,6 @@ public static function fromReflectionParameter(\ReflectionParameter $parameter) * @param string $param_name * @param string $type_name * @param bool $variadic - * @throws \Brain\Monkey\Name\Exception\InvalidClosureParam */ private function __construct($param_name, $type_name = '', $variadic = false) { diff --git a/src/Name/ClosureStringForm.php b/src/Name/ClosureStringForm.php index 0db51d2..de32169 100644 --- a/src/Name/ClosureStringForm.php +++ b/src/Name/ClosureStringForm.php @@ -32,8 +32,6 @@ final class ClosureStringForm /** * @param string $closure_string * @return string - * @throws \Brain\Monkey\Name\Exception\InvalidCallable - * @throws \Brain\Monkey\Name\Exception\NotInvokableObjectAsCallback */ public static function normalizeString($closure_string) { diff --git a/src/Name/FunctionName.php b/src/Name/FunctionName.php index 71fe648..f8dc4dc 100644 --- a/src/Name/FunctionName.php +++ b/src/Name/FunctionName.php @@ -77,8 +77,7 @@ public function equals(FunctionName $name) * When name is valid returns an array of the name itself and its namespace parts. * * @param string $function_name - * @return \string[] - * @throws \Brain\Monkey\Name\Exception\InvalidName + * @return string[] */ private function parseName($function_name) { diff --git a/src/Name/MethodName.php b/src/Name/MethodName.php index abe9bdb..72bfd88 100644 --- a/src/Name/MethodName.php +++ b/src/Name/MethodName.php @@ -26,7 +26,6 @@ final class MethodName /** * @param string $method_name - * @throws \Brain\Monkey\Name\Exception\InvalidName */ public function __construct($method_name) { diff --git a/tests/boot.php b/tests/boot.php deleted file mode 100644 index 2513e86..0000000 --- a/tests/boot.php +++ /dev/null @@ -1,21 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - * - * @author Giuseppe Mazzapica - * @license http://opensource.org/licenses/MIT MIT - * @package BrainMonkey - */ - -$autoload_path = dirname(__DIR__).'/vendor/'; -if (! file_exists($autoload_path.'autoload.php')) { - die('Please install via Composer before running tests.'); -} - -require_once $autoload_path.'autoload.php'; -unset($autoload_path); diff --git a/tests/cases/functional/ActionsTest.php b/tests/cases/functional/ActionsTest.php new file mode 100644 index 0000000..774d685 --- /dev/null +++ b/tests/cases/functional/ActionsTest.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Brain\Monkey\Tests\Functional; + +use Brain\Monkey; + +/** + * @author Giuseppe Mazzapica + * @license http://opensource.org/licenses/MIT MIT + * @package BrainMonkey + */ +class ActionsTest extends Monkey\Tests\FunctionalTestCase +{ + public function testExpectAdded() + { + $this->expectOutputString('Hello'); + + Monkey\Actions\expectAdded('init') + ->with(\Mockery::type('callable'), 1, 2) + ->whenHappen( + function (callable $callback) { + $callback(); + } + ); + + add_action( + 'init', + function () { + echo "Hello"; + }, + 1, + 2 + ); + } + + public function testExpectDone() + { + $this->expectOutputString('Hello World'); + + Monkey\Actions\expectDone('my_hook') + ->with(\Mockery::type('string'), \Mockery::type('string')) + ->whenHappen( + function ($a, $b) { + echo "{$a} {$b}"; + } + ); + + do_action('my_hook', 'Hello', 'World'); + } + + public function testRemove() + { + Monkey\Actions\expectRemoved('my_hook') + ->once() + ->with('my_callback', 30); + + add_action('my_hook', 'my_callback', 30); + + $removed = remove_action('my_hook', 'my_callback', 30); + + static::assertTrue($removed); + } + + public function testExpectAppliedThenDone() + { + $this->expectOutputString('Hello World'); + + /** @var callable|null $on_my_hook */ + $on_my_hook = null; + + Monkey\Actions\expectAdded('my_hook') + ->with(\Mockery::type('callable'), \Mockery::type('int'), 2) + ->whenHappen( + static function (callable $callback) use (&$on_my_hook) { + $on_my_hook = $callback; + } + ); + + Monkey\Actions\expectDone('my_hook') + ->whenHappen( + static function (...$args) use (&$on_my_hook) { + $on_my_hook(...$args); + } + ); + + add_action( + 'my_hook', + function ($a, $b) { + echo "{$a} {$b}"; + }, + 1, + 2 + ); + + do_action('my_hook', 'Hello', 'World'); + } +} diff --git a/tests/cases/functional/FiltersTest.php b/tests/cases/functional/FiltersTest.php new file mode 100644 index 0000000..266253d --- /dev/null +++ b/tests/cases/functional/FiltersTest.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Brain\Monkey\Tests\Functional; + +use Brain\Monkey; + +/** + * @author Giuseppe Mazzapica + * @license http://opensource.org/licenses/MIT MIT + * @package BrainMonkey + */ +class FiltersTest extends Monkey\Tests\FunctionalTestCase +{ + public function testExpectAdded() + { + Monkey\Filters\expectAdded('my_filter')->once(); + + add_filter( + 'my_filter', + function ($thing) { + return $thing; + }, + 1, + 2 + ); + } + + public function testExpectApplied() + { + Monkey\Filters\expectApplied('the_title') + ->once() + ->with(\Mockery::type('string')) + ->andReturnUsing( + function ($title) { + return strtoupper($title); + } + ); + + $title = apply_filters('the_title', 'Hello World'); + + static::assertSame('HELLO WORLD', $title); + } + + public function testRemove() + { + Monkey\Filters\expectRemoved('my_hook') + ->once() + ->with('my_callback', 10); + + add_filter('my_hook', 'my_callback'); + + $removed = remove_filter('my_hook', 'my_callback'); + + static::assertTrue($removed); + } + + + public function testExpectAppliedThenDone() + { + /** @var callable|null $on_my_hook */ + $on_my_hook = null; + + Monkey\Filters\expectAdded('my_hook') + ->with(\Mockery::type('callable'), 1, 2) + ->once() + ->whenHappen( + static function (callable $callback) use (&$on_my_hook) { + $on_my_hook = $callback; + } + ); + + Monkey\Filters\expectApplied('my_hook') + ->once() + ->with(\Mockery::type('string'), \Mockery::type('string')) + ->andReturnUsing( + static function ($a, $b) use (&$on_my_hook) { + return $on_my_hook($a, $b); + } + ); + + add_filter( + 'my_hook', + function ($a, $b) { + return strtoupper("{$a} {$b}"); + }, + 1, + 2 + ); + + $hello = apply_filters('my_hook', 'Hello', 'World'); + + static::assertSame('HELLO WORLD', $hello); + } +} diff --git a/tests/cases/functional/FunctionsTest.php b/tests/cases/functional/FunctionsTest.php new file mode 100644 index 0000000..c4186dd --- /dev/null +++ b/tests/cases/functional/FunctionsTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Brain\Monkey\Tests\Functional; + +use Brain\Monkey; + +/** + * @author Giuseppe Mazzapica + * @license http://opensource.org/licenses/MIT MIT + * @package BrainMonkey + */ +class FunctionsTest extends Monkey\Tests\FunctionalTestCase +{ + public function testWhen() + { + Monkey\Functions\when('get_post')->justReturn(false); + + static::assertFalse(get_post(1)); + static::assertFalse(get_post(2)); + } + + public function testExpect() + { + $post = \Mockery::mock(\WP_Post::class); + + Monkey\Functions\expect('get_post') + ->once() + ->with(1) + ->andReturn(false) + ->andAlsoExpectIt() + ->twice() + ->with(2) + ->andReturn($post); + + static::assertFalse(get_post(1)); + static::assertSame($post, get_post(2)); + static::assertSame($post, get_post(2)); + } + + public function testPredefinedStubs() + { + $error = \Mockery::mock(\WP_Error::class); + + static::assertTrue(is_wp_error($error)); + static::assertFalse(is_wp_error('x')); + } + + public function testReDefinePredefinedStubsWithWhen() + { + Monkey\Functions\when('is_wp_error')->alias('ctype_alpha'); + + static::assertTrue(is_wp_error('xyz')); + static::assertFalse(is_wp_error(123)); + } + + public function testReDefinePredefinedStubsWithExpect() + { + Monkey\Functions\expect('is_wp_error') + ->atLeast() + ->twice() + ->andReturnUsing( + function ($thing) { + return $thing !== 42; + } + ); + + static::assertTrue(is_wp_error(123)); + static::assertFalse(is_wp_error(42)); + static::assertTrue(is_wp_error('xyz')); + } +} diff --git a/tests/src/Api/AddActionTest.php b/tests/cases/unit/Api/AddActionTest.php similarity index 94% rename from tests/src/Api/AddActionTest.php rename to tests/cases/unit/Api/AddActionTest.php index c6c73bd..511c54f 100644 --- a/tests/src/Api/AddActionTest.php +++ b/tests/cases/unit/Api/AddActionTest.php @@ -1,147 +1,147 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Brain\Monkey\Tests\Api; - -use Brain\Monkey; -use Brain\Monkey\Actions; -use Mockery\Exception\InvalidCountException; - -/** - * @author Giuseppe Mazzapica - * @license http://opensource.org/licenses/MIT MIT - * @package BrainMonkey - */ -class AddActionTest extends Monkey\Tests\TestCase -{ - public function testAddNull() - { - add_action('init', 'strtolower', 20, 2); - // just want to see that when called properly nothing bad happen - static::assertTrue(true); - } - - public function testAddReturnsTrue() - { - static::assertTrue(add_action('init', 'strtolower', 20, 2)); - } - - public function testAddAndHas() - { - add_action('init', 'strtolower', 30, 1); - add_action('init', function ( $x, ...$y ) { return true; }); - add_action('init', [new \ArrayObject(), 'getArrayCopy'], 5); - add_action('init', 'SomeClass\To\Test::method', 1); - - static::assertTrue(has_action('init', 'strtolower')); - static::assertTrue(has_action('init', 'function( $x, ...$y )')); - static::assertTrue(has_action('init', 'ArrayObject->getArrayCopy()')); - static::assertTrue(has_action('init', 'SomeClass\To\Test::method')); - static::assertTrue(has_action('init', 'SomeClass\To\Test::method()')); - - static::assertFalse(has_action('pre_get_posts', 'strtolower')); - static::assertFalse(has_action('foo', 'function()')); - static::assertFalse(has_action('baz', 'ArrayObject->getArrayCopy()')); - static::assertFalse(has_action('baz', 'SomeClass\To\Test->method()')); - } - - public function testAddAndHasWithoutCallback() - { - static::assertFalse(has_action('init')); - add_action('init', [$this, __FUNCTION__], 20); - static::assertTrue(has_action('init')); - } - - public function testExpectAdded() - { - Actions\expectAdded('init')->times(3)->with( - \Mockery::anyOf('strtolower', 'strtoupper', [$this, __FUNCTION__]), - \Mockery::type('int') - ); - Actions\expectAdded('foo')->never(); - Actions\expectAdded('wp_footer')->once(); - - add_action('init', 'strtolower', 30); - add_action('init', 'strtoupper', 20); - add_action('init', [$this, __FUNCTION__], 20); - add_action('wp_footer', function () { - return 'baz'; - }); - - static::assertTrue(has_action('init', 'strtolower')); - static::assertTrue(has_action('init', 'strtoupper')); - } - - public function testAddedSameActionDifferentArguments() - { - Actions\expectAdded('double_action') - ->once() - ->ordered() - ->with('a_function_name'); - - Actions\expectAdded('double_action') - ->once() - ->ordered() - ->with('another_function_name'); - - add_action('double_action', 'a_function_name'); - add_action('double_action', 'another_function_name'); - } - - public function testRemoveAction() - { - Actions\expectAdded('init')->once(); - - add_action('init', [$this, __FUNCTION__], 20); - - static::assertTrue(has_action('init', [$this, __FUNCTION__])); - - remove_action('init', [$this, __FUNCTION__], 20); - - static::assertFalse(has_action('init', [$this, __FUNCTION__])); - } - - public function testAddActionWhenHappen() - { - Actions\expectAdded('foo')->once()->whenHappen(function($callable, $priority, $args) { - $callable(); - static::assertSame(20, $priority); - static::assertSame(2, $args); - }); - - $this->expectOutputString('Foo!'); - - add_action( 'foo', function() { - echo 'Foo!'; - }, 20, 2); - } - - public function testAndAlsoExpect() - { - Actions\expectAdded('foo') - ->once() - ->ordered() - ->with('__return_true', 10) - ->andAlsoExpectIt() - ->once() - ->ordered() - ->with('__return_false', 20); - - add_action('foo', '__return_true', 10); - add_action('foo', '__return_false', 20); - } - - public function testExpectWithNoArgsFailsIfNotAdded() - { - $this->expectMockeryException(InvalidCountException::class); - - Actions\expectAdded('init'); - } -} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Brain\Monkey\Tests\Unit\Api; + +use Brain\Monkey\Actions; +use Brain\Monkey\Tests\UnitTestCase; +use Mockery\Exception\InvalidCountException; + +/** + * @author Giuseppe Mazzapica + * @license http://opensource.org/licenses/MIT MIT + * @package BrainMonkey + */ +class AddActionTest extends UnitTestCase +{ + public function testAddNull() + { + add_action('init', 'strtolower', 20, 2); + // just want to see that when called properly nothing bad happen + static::assertTrue(true); + } + + public function testAddReturnsTrue() + { + static::assertTrue(add_action('init', 'strtolower', 20, 2)); + } + + public function testAddAndHas() + { + add_action('init', 'strtolower', 30, 1); + add_action('init', function ( $x, ...$y ) { return true; }); + add_action('init', [new \ArrayObject(), 'getArrayCopy'], 5); + add_action('init', 'SomeClass\To\Test::method', 1); + + static::assertTrue(has_action('init', 'strtolower')); + static::assertTrue(has_action('init', 'function( $x, ...$y )')); + static::assertTrue(has_action('init', 'ArrayObject->getArrayCopy()')); + static::assertTrue(has_action('init', 'SomeClass\To\Test::method')); + static::assertTrue(has_action('init', 'SomeClass\To\Test::method()')); + + static::assertFalse(has_action('pre_get_posts', 'strtolower')); + static::assertFalse(has_action('foo', 'function()')); + static::assertFalse(has_action('baz', 'ArrayObject->getArrayCopy()')); + static::assertFalse(has_action('baz', 'SomeClass\To\Test->method()')); + } + + public function testAddAndHasWithoutCallback() + { + static::assertFalse(has_action('init')); + add_action('init', [$this, __FUNCTION__], 20); + static::assertTrue(has_action('init')); + } + + public function testExpectAdded() + { + Actions\expectAdded('init')->times(3)->with( + \Mockery::anyOf('strtolower', 'strtoupper', [$this, __FUNCTION__]), + \Mockery::type('int') + ); + Actions\expectAdded('foo')->never(); + Actions\expectAdded('wp_footer')->once(); + + add_action('init', 'strtolower', 30); + add_action('init', 'strtoupper', 20); + add_action('init', [$this, __FUNCTION__], 20); + add_action('wp_footer', function () { + return 'baz'; + }); + + static::assertTrue(has_action('init', 'strtolower')); + static::assertTrue(has_action('init', 'strtoupper')); + } + + public function testAddedSameActionDifferentArguments() + { + Actions\expectAdded('double_action') + ->once() + ->ordered() + ->with('a_function_name'); + + Actions\expectAdded('double_action') + ->once() + ->ordered() + ->with('another_function_name'); + + add_action('double_action', 'a_function_name'); + add_action('double_action', 'another_function_name'); + } + + public function testRemoveAction() + { + Actions\expectAdded('init')->once(); + + add_action('init', [$this, __FUNCTION__], 20); + + static::assertTrue(has_action('init', [$this, __FUNCTION__])); + + remove_action('init', [$this, __FUNCTION__], 20); + + static::assertFalse(has_action('init', [$this, __FUNCTION__])); + } + + public function testAddActionWhenHappen() + { + Actions\expectAdded('foo')->once()->whenHappen(function($callable, $priority, $args) { + $callable(); + static::assertSame(20, $priority); + static::assertSame(2, $args); + }); + + $this->expectOutputString('Foo!'); + + add_action( 'foo', function() { + echo 'Foo!'; + }, 20, 2); + } + + public function testAndAlsoExpect() + { + Actions\expectAdded('foo') + ->once() + ->ordered() + ->with('__return_true', 10) + ->andAlsoExpectIt() + ->once() + ->ordered() + ->with('__return_false', 20); + + add_action('foo', '__return_true', 10); + add_action('foo', '__return_false', 20); + } + + public function testExpectWithNoArgsFailsIfNotAdded() + { + $this->expectMockeryException(InvalidCountException::class); + + Actions\expectAdded('init'); + } +} diff --git a/tests/src/Api/AddFiltersTest.php b/tests/cases/unit/Api/AddFiltersTest.php similarity index 97% rename from tests/src/Api/AddFiltersTest.php rename to tests/cases/unit/Api/AddFiltersTest.php index f195f4a..f5139f3 100644 --- a/tests/src/Api/AddFiltersTest.php +++ b/tests/cases/unit/Api/AddFiltersTest.php @@ -8,10 +8,10 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Api; +namespace Brain\Monkey\Tests\Unit\Api; use Brain\Monkey\Filters; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; use Mockery\Exception\InvalidCountException; /** @@ -19,7 +19,7 @@ * @license http://opensource.org/licenses/MIT MIT * @package BrainMonkey */ -class AddFiltersTest extends TestCase +class AddFiltersTest extends UnitTestCase { public function testAddNull() diff --git a/tests/src/Api/ApplyFiltersTest.php b/tests/cases/unit/Api/ApplyFiltersTest.php similarity index 98% rename from tests/src/Api/ApplyFiltersTest.php rename to tests/cases/unit/Api/ApplyFiltersTest.php index 6842f61..2d8c873 100644 --- a/tests/src/Api/ApplyFiltersTest.php +++ b/tests/cases/unit/Api/ApplyFiltersTest.php @@ -8,10 +8,10 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Api; +namespace Brain\Monkey\Tests\Unit\Api; use Brain\Monkey\Filters; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; use Mockery\Exception\InvalidCountException; /** @@ -19,7 +19,7 @@ * @license http://opensource.org/licenses/MIT MIT * @package BrainMonkey */ -class ApplyFiltersTest extends TestCase +class ApplyFiltersTest extends UnitTestCase { public function testApplyNull() diff --git a/tests/src/Api/DoActionTest.php b/tests/cases/unit/Api/DoActionTest.php similarity index 98% rename from tests/src/Api/DoActionTest.php rename to tests/cases/unit/Api/DoActionTest.php index 54b2972..c06d8b5 100644 --- a/tests/src/Api/DoActionTest.php +++ b/tests/cases/unit/Api/DoActionTest.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Api; +namespace Brain\Monkey\Tests\Unit\Api; use Brain\Monkey; use Brain\Monkey\Actions; @@ -19,7 +19,7 @@ * @license http://opensource.org/licenses/MIT MIT * @package BrainMonkey */ -class DoActionTest extends Monkey\Tests\TestCase +class DoActionTest extends Monkey\Tests\UnitTestCase { public function testDoNull() diff --git a/tests/src/Api/FunctionsTest.php b/tests/cases/unit/Api/FunctionsTest.php similarity index 79% rename from tests/src/Api/FunctionsTest.php rename to tests/cases/unit/Api/FunctionsTest.php index c6b9c2e..acc4924 100644 --- a/tests/src/Api/FunctionsTest.php +++ b/tests/cases/unit/Api/FunctionsTest.php @@ -8,10 +8,10 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Api; +namespace Brain\Monkey\Tests\Unit\Api; use Brain\Monkey\Functions; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; use Mockery\Exception\InvalidCountException; /** @@ -19,7 +19,7 @@ * @license http://opensource.org/licenses/MIT MIT * @package BrainMonkey */ -class FunctionsTest extends TestCase +class FunctionsTest extends UnitTestCase { public function testJustReturn() @@ -229,7 +229,7 @@ public function testStubsReturnValue() ]); static::assertTrue(is_user_logged_in()); - static::assertTrue(current_user_can()); + static::assertTrue(current_user_can('x')); Functions\stubs([ 'is_user_logged_in' => 1, @@ -237,7 +237,7 @@ public function testStubsReturnValue() ]); static::assertSame(1, is_user_logged_in()); - static::assertSame(2, current_user_can()); + static::assertSame(2, current_user_can('y')); } public function testStubsCallable() @@ -284,7 +284,7 @@ public function testStubsAll() ]); static::assertSame('a', is_user_logged_in()); - static::assertSame(123, current_user_can()); + static::assertSame(123, current_user_can('xy')); static::assertSame(['ID' => 456], wp_get_current_user()->to_array()); static::assertSame('!', esc_attr('!')); static::assertSame('?', esc_html('?')); @@ -307,9 +307,70 @@ public function testStubsEdgeCases() ] ); + /** @noinspection PhpUndefinedFunctionInspection */ static::assertNull(i_return_null()); + /** @noinspection PhpUndefinedFunctionInspection */ static::assertNull(i_return_null_too()); + /** @noinspection PhpUndefinedFunctionInspection */ $cb = i_return_a_callback(); static::assertSame('yes', $cb()); } + + public function testStubsTranslationsReturn() + { + Functions\stubTranslationFunctions(); + + static::assertSame('Foo', __('Foo', 'my-txt-domain')); + static::assertSame('Foo!', _x('Foo!', 'context', 'my-txt-domain')); + static::assertSame('Bar!', esc_html__('Bar!', 'my-txt-domain')); + static::assertSame('Baz!', esc_attr__('Baz!', 'my-txt-domain')); + static::assertSame('Foo bar', esc_attr_x('Foo bar', 'context', 'my-txt-domain')); + } + + public function testStubsTranslationsEcho() + { + Functions\stubTranslationFunctions(); + + $this->expectOutputString('ABCD'); + + static::assertNull(_e('A', 'my-txt-domain')); + static::assertNull(_ex('B', 'context', 'my-txt-domain')); + static::assertNull(esc_html_e('C', 'my-txt-domain')); + static::assertNull(esc_attr_e('D', 'my-txt-domain')); + } + + public function testStubsEscapeFunctionsNoUrlNoSql() + { + Functions\stubEscapeFunctions(); + + $lorem = 'Lorem ipsum'; + $escaped = htmlspecialchars($lorem); + + static::assertSame($escaped, esc_html($lorem)); + static::assertSame($escaped, esc_attr($lorem)); + static::assertSame($escaped, esc_js($lorem)); + static::assertSame($escaped, esc_textarea($lorem)); + } + + public function testStubsEscapeUrl() + { + Functions\stubEscapeFunctions(); + + static::assertSame('http://www.example.com', esc_url('http://www.example.com')); + static::assertSame('https://www.example.com', esc_url('https://www.example.com')); + static::assertSame('http://no-schema', esc_url('no-schema')); + static::assertSame('http://www.example.com?f&b=x', esc_url_raw('www.example.com?f&b=x')); + static::assertSame( + 'http://example.com?f&b=x'y&', + esc_url('http://example.com?f&b=x\'y&') + ); + } + + public function testStubsEscapeSql() + { + Functions\stubEscapeFunctions(); + + static::assertSame("hello, \\'world\\'", esc_sql("hello, 'world'")); + static::assertSame('hello world', esc_sql('hello world')); + } } diff --git a/tests/cases/unit/Api/RemoveActionTest.php b/tests/cases/unit/Api/RemoveActionTest.php new file mode 100644 index 0000000..33b7ff4 --- /dev/null +++ b/tests/cases/unit/Api/RemoveActionTest.php @@ -0,0 +1,187 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Brain\Monkey\Tests\Unit\Api; + +use Brain\Monkey; +use Mockery\Exception\InvalidCountException; +use Mockery\Exception\InvalidOrderException; + +/** + * @author Giuseppe Mazzapica + * @license http://opensource.org/licenses/MIT MIT + * @package BrainMonkey + */ +class RemoveActionTest extends Monkey\Tests\UnitTestCase +{ + public function testRemoveActionNotAdded() + { + static::assertFalse(remove_action('init', 'my_callback')); + } + + public function testRemoveActionAddedWithDifferentCallback() + { + add_action('init', 'one_callback'); + + static::assertFalse(remove_action('init', 'another_callback')); + } + + public function testRemoveActionAddedWithSameCallbackDifferentPriority() + { + add_action('init', 'my_callback', 10); + + static::assertFalse(remove_action('init', 'my_callback', 20)); + } + + public function testRemoveActionAddedWithSameCallbackDifferentPriorityBecauseDefaultOnAdd() + { + add_action('init', 'my_callback'); + + static::assertFalse(remove_action('init', 'my_callback', 20)); + } + + public function testRemoveActionAddedWithSameCallbackDifferentPriorityBecauseDefaultOnRemove() + { + add_action('init', 'my_callback', 20); + + static::assertFalse(remove_action('init', 'my_callback')); + } + + public function testRemoveActionAddedWithSameCallbackAndSamePriority() + { + add_action('init', 'my_callback', 30); + + static::assertTrue(remove_action('init', 'my_callback', 30)); + } + + public function testRemoveActionAddedWithSameCallbackAndSamePriorityBecauseDefaultOnAdd() + { + add_action('init', 'my_callback'); + + static::assertTrue(remove_action('init', 'my_callback', 10)); + } + + public function testRemoveActionAddedWithSameCallbackAndSamePriorityBecauseDefaultOnRemove() + { + add_action('init', 'my_callback', 10); + + static::assertTrue(remove_action('init', 'my_callback')); + } + + public function testRemoveActionAddedWithSameCallbackAndSamePriorityBecauseDefault() + { + add_action('init', 'my_callback'); + + static::assertTrue(remove_action('init', 'my_callback')); + } + + public function testRemoveAssertionFailedWithNoCallbackAndNoPriority() + { + $this->expectMockeryException(InvalidCountException::class); + + Monkey\Actions\expectRemoved('init'); + } + + public function testRemoveAssertionFailedWithNoPriority() + { + $this->expectMockeryException(InvalidCountException::class); + + Monkey\Actions\expectRemoved('init')->with('my_callback'); + } + + public function testRemoveAssertionFailedWrongCount() + { + $this->expectMockeryException(InvalidCountException::class); + + Monkey\Actions\expectRemoved('init')->twice()->with('my_callback'); + + remove_action('init', 'my_callback'); + } + + public function testRemoveAssertionSuccessWithNoPriority() + { + Monkey\Actions\expectRemoved('init')->twice()->with('my_callback'); + + remove_action('init', 'my_callback'); + remove_action('init', 'my_callback'); + } + + public function testRemoveManyAssertionSuccessWithDifferentPriority() + { + Monkey\Actions\expectRemoved('init') + ->once() + ->with('my_callback') + ->andAlsoExpectIt() + ->once() + ->with('my_callback', 42); + + remove_action('init', 'my_callback', 42); + remove_action('init', 'my_callback'); + } + + public function testRemoveManyAssertionFailsWithDifferentPriorityOrdered() + { + $this->expectException(InvalidOrderException::class); + $this->expectMockeryException(InvalidCountException::class); + + Monkey\Actions\expectRemoved('init') + ->once() + ->with('my_callback') + ->ordered() + ->andAlsoExpectIt() + ->once() + ->with('my_callback', 42) + ->ordered(); + + remove_action('init', 'my_callback', 42); + remove_action('init', 'my_callback'); + } + + public function testRemoveManyAssertionSuccessWithDifferentPriorityOrdered() + { + Monkey\Actions\expectRemoved('init') + ->once() + ->with('my_callback') + ->ordered() + ->andAlsoExpectIt() + ->once() + ->with('my_callback', 42) + ->ordered(); + + remove_action('init', 'my_callback'); + remove_action('init', 'my_callback', 42); + } + + public function testRemoveManyAssertionSuccessWithDifferentCallbacksAndPriorities() + { + $cb1 = static function () { + return 1; + }; + + $cb2 = static function ($x) { + return $x; + }; + + Monkey\Actions\expectRemoved('my_hook') + ->once() + ->with($cb1, 10); + + Monkey\Actions\expectRemoved('my_hook') + ->once() + ->with($cb2, 22); + + add_action('my_hook', $cb1); + add_action('my_hook', $cb2, 22); + + static::assertTrue(remove_action('my_hook', $cb1)); + static::assertTrue(remove_action('my_hook', $cb2, 22)); + static::assertFalse(remove_action('my_hook', $cb2)); + } +} diff --git a/tests/cases/unit/Api/RemoveFilterTest.php b/tests/cases/unit/Api/RemoveFilterTest.php new file mode 100644 index 0000000..9594fa7 --- /dev/null +++ b/tests/cases/unit/Api/RemoveFilterTest.php @@ -0,0 +1,187 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Brain\Monkey\Tests\Unit\Api; + +use Brain\Monkey; +use Mockery\Exception\InvalidCountException; +use Mockery\Exception\InvalidOrderException; + +/** + * @author Giuseppe Mazzapica + * @license http://opensource.org/licenses/MIT MIT + * @package BrainMonkey + */ +class RemoveFilterTest extends Monkey\Tests\UnitTestCase +{ + public function testRemoveFilterNotAdded() + { + static::assertFalse(remove_filter('the_title', 'my_callback')); + } + + public function testRemoveActionAddedWithDifferentCallback() + { + add_filter('the_title', 'one_callback'); + + static::assertFalse(remove_filter('the_title', 'another_callback')); + } + + public function testRemoveActionAddedWithSameCallbackDifferentPriority() + { + add_filter('the_title', 'my_callback', 10); + + static::assertFalse(remove_filter('the_title', 'my_callback', 20)); + } + + public function testRemoveActionAddedWithSameCallbackDifferentPriorityBecauseDefaultOnAdd() + { + add_filter('the_title', 'my_callback'); + + static::assertFalse(remove_filter('the_title', 'my_callback', 20)); + } + + public function testRemoveActionAddedWithSameCallbackDifferentPriorityBecauseDefaultOnRemove() + { + add_filter('the_title', 'my_callback', 20); + + static::assertFalse(remove_filter('the_title', 'my_callback')); + } + + public function testRemoveActionAddedWithSameCallbackAndSamePriority() + { + add_filter('the_title', 'my_callback', 30); + + static::assertTrue(remove_filter('the_title', 'my_callback', 30)); + } + + public function testRemoveActionAddedWithSameCallbackAndSamePriorityBecauseDefaultOnAdd() + { + add_filter('the_title', 'my_callback'); + + static::assertTrue(remove_filter('the_title', 'my_callback', 10)); + } + + public function testRemoveActionAddedWithSameCallbackAndSamePriorityBecauseDefaultOnRemove() + { + add_filter('the_title', 'my_callback', 10); + + static::assertTrue(remove_filter('the_title', 'my_callback')); + } + + public function testRemoveActionAddedWithSameCallbackAndSamePriorityBecauseDefault() + { + add_filter('the_title', 'my_callback'); + + static::assertTrue(remove_filter('the_title', 'my_callback')); + } + + public function testRemoveAssertionFailedWithNoCallbackAndNoPriority() + { + $this->expectMockeryException(InvalidCountException::class); + + Monkey\Filters\expectRemoved('the_title'); + } + + public function testRemoveAssertionFailedWithNoPriority() + { + $this->expectMockeryException(InvalidCountException::class); + + Monkey\Filters\expectRemoved('the_title')->with('my_callback'); + } + + public function testRemoveAssertionFailedWrongCount() + { + $this->expectMockeryException(InvalidCountException::class); + + Monkey\Filters\expectRemoved('the_title')->twice()->with('my_callback'); + + remove_filter('the_title', 'my_callback'); + } + + public function testRemoveAssertionSuccessWithNoPriority() + { + Monkey\Filters\expectRemoved('the_title')->twice()->with('my_callback'); + + remove_filter('the_title', 'my_callback'); + remove_filter('the_title', 'my_callback'); + } + + public function testRemoveManyAssertionSuccessWithDifferentPriority() + { + Monkey\Filters\expectRemoved('the_title') + ->once() + ->with('my_callback') + ->andAlsoExpectIt() + ->once() + ->with('my_callback', 42); + + remove_filter('the_title', 'my_callback', 42); + remove_filter('the_title', 'my_callback'); + } + + public function testRemoveManyAssertionFailsWithDifferentPriorityOrdered() + { + $this->expectException(InvalidOrderException::class); + $this->expectMockeryException(InvalidCountException::class); + + Monkey\Filters\expectRemoved('the_title') + ->once() + ->with('my_callback') + ->ordered() + ->andAlsoExpectIt() + ->once() + ->with('my_callback', 42) + ->ordered(); + + remove_filter('the_title', 'my_callback', 42); + remove_filter('the_title', 'my_callback'); + } + + public function testRemoveManyAssertionSuccessWithDifferentPriorityOrdered() + { + Monkey\Filters\expectRemoved('the_title') + ->once() + ->with('my_callback') + ->ordered() + ->andAlsoExpectIt() + ->once() + ->with('my_callback', 42) + ->ordered(); + + remove_filter('the_title', 'my_callback'); + remove_filter('the_title', 'my_callback', 42); + } + + public function testRemoveManyAssertionSuccessWithDifferentCallbacksAndPriorities() + { + $cb1 = static function () { + return 1; + }; + + $cb2 = static function ($x) { + return $x; + }; + + Monkey\Filters\expectRemoved('my_hook') + ->once() + ->with($cb1, 10); + + Monkey\Filters\expectRemoved('my_hook') + ->once() + ->with($cb2, 22); + + add_filter('my_hook', $cb1); + add_filter('my_hook', $cb2, 22); + + static::assertTrue(remove_filter('my_hook', $cb1)); + static::assertTrue(remove_filter('my_hook', $cb2, 22)); + static::assertFalse(remove_filter('my_hook', $cb2)); + } +} diff --git a/tests/src/Expectation/Exception/ExceptionTest.php b/tests/cases/unit/Expectation/Exception/ExceptionTest.php similarity index 83% rename from tests/src/Expectation/Exception/ExceptionTest.php rename to tests/cases/unit/Expectation/Exception/ExceptionTest.php index 6cfb961..7ecaf43 100644 --- a/tests/src/Expectation/Exception/ExceptionTest.php +++ b/tests/cases/unit/Expectation/Exception/ExceptionTest.php @@ -8,13 +8,13 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Expectation\Exception; +namespace Brain\Monkey\Tests\Unit\Expectation\Exception; use Brain\Monkey\Expectation\Exception\Exception; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; -class ExceptionTest extends TestCase +class ExceptionTest extends UnitTestCase { public function testBecauseOf() diff --git a/tests/src/Expectation/Exception/ExpectationArgsRequiredTest.php b/tests/cases/unit/Expectation/Exception/ExpectationArgsRequiredTest.php similarity index 88% rename from tests/src/Expectation/Exception/ExpectationArgsRequiredTest.php rename to tests/cases/unit/Expectation/Exception/ExpectationArgsRequiredTest.php index eb0c7fd..83a72a3 100644 --- a/tests/src/Expectation/Exception/ExpectationArgsRequiredTest.php +++ b/tests/cases/unit/Expectation/Exception/ExpectationArgsRequiredTest.php @@ -8,14 +8,14 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Expectation\Exception; +namespace Brain\Monkey\Tests\Unit\Expectation\Exception; use Brain\Monkey\Expectation\Exception\ExpectationArgsRequired; use Brain\Monkey\Expectation\ExpectationTarget; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; -class ExpectationArgsRequiredTest extends TestCase +class ExpectationArgsRequiredTest extends UnitTestCase { /** diff --git a/tests/src/Expectation/ExpectationFactoryTest.php b/tests/cases/unit/Expectation/ExpectationFactoryTest.php similarity index 97% rename from tests/src/Expectation/ExpectationFactoryTest.php rename to tests/cases/unit/Expectation/ExpectationFactoryTest.php index c233d79..e4a15c0 100644 --- a/tests/src/Expectation/ExpectationFactoryTest.php +++ b/tests/cases/unit/Expectation/ExpectationFactoryTest.php @@ -8,15 +8,15 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Expectation; +namespace Brain\Monkey\Tests\Unit\Expectation; use Brain\Monkey\Expectation\Expectation; use Brain\Monkey\Expectation\ExpectationFactory; use Brain\Monkey\Expectation\ExpectationTarget; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; use Mockery\Exception\InvalidCountException; -class ExpectationFactoryTest extends TestCase +class ExpectationFactoryTest extends UnitTestCase { public function testForFunctionExecuted() diff --git a/tests/src/Expectation/ExpectationTargetTest.php b/tests/cases/unit/Expectation/ExpectationTargetTest.php similarity index 96% rename from tests/src/Expectation/ExpectationTargetTest.php rename to tests/cases/unit/Expectation/ExpectationTargetTest.php index 44ffaf5..4141a8f 100644 --- a/tests/src/Expectation/ExpectationTargetTest.php +++ b/tests/cases/unit/Expectation/ExpectationTargetTest.php @@ -8,15 +8,15 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Expectation; +namespace Brain\Monkey\Tests\Unit\Expectation; use Brain\Monkey\Exception; use Brain\Monkey\Expectation\Exception\InvalidExpectationName; use Brain\Monkey\Expectation\Exception\InvalidExpectationType; use Brain\Monkey\Expectation\ExpectationTarget; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; -class ExpectationTargetTest extends TestCase +class ExpectationTargetTest extends UnitTestCase { public function testConstructorThrowExceptionIfInvalidType() diff --git a/tests/src/Expectation/ExpectationTest.php b/tests/cases/unit/Expectation/ExpectationTest.php similarity index 95% rename from tests/src/Expectation/ExpectationTest.php rename to tests/cases/unit/Expectation/ExpectationTest.php index da34b5f..ff245a3 100644 --- a/tests/src/Expectation/ExpectationTest.php +++ b/tests/cases/unit/Expectation/ExpectationTest.php @@ -8,16 +8,16 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Expectation; +namespace Brain\Monkey\Tests\Unit\Expectation; use Brain\Monkey\Expectation\Exception\ExpectationArgsRequired; use Brain\Monkey\Expectation\Exception\NotAllowedMethod; use Brain\Monkey\Expectation\Expectation; use Brain\Monkey\Expectation\ExpectationTarget; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; use Mockery\ExpectationInterface; -class ExpectationTest extends TestCase +class ExpectationTest extends UnitTestCase { public function testNotAllowedMethodsThrowException() diff --git a/tests/src/Expectation/FunctionStubFactoryTest.php b/tests/cases/unit/Expectation/FunctionStubFactoryTest.php similarity index 92% rename from tests/src/Expectation/FunctionStubFactoryTest.php rename to tests/cases/unit/Expectation/FunctionStubFactoryTest.php index 6ad960d..3f2e893 100644 --- a/tests/src/Expectation/FunctionStubFactoryTest.php +++ b/tests/cases/unit/Expectation/FunctionStubFactoryTest.php @@ -8,14 +8,14 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Expectation; +namespace Brain\Monkey\Tests\Unit\Expectation; use Brain\Monkey\Expectation\Exception\Exception; use Brain\Monkey\Expectation\FunctionStubFactory; use Brain\Monkey\Name\FunctionName; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; -class FunctionStubFactoryTest extends TestCase +class FunctionStubFactoryTest extends UnitTestCase { public function testCreateReturnSameStubWhenCalledMoreTimes() diff --git a/tests/src/Expectation/FunctionStubTest.php b/tests/cases/unit/Expectation/FunctionStubTest.php similarity index 95% rename from tests/src/Expectation/FunctionStubTest.php rename to tests/cases/unit/Expectation/FunctionStubTest.php index 5329a73..9c9dfcd 100644 --- a/tests/src/Expectation/FunctionStubTest.php +++ b/tests/cases/unit/Expectation/FunctionStubTest.php @@ -8,17 +8,17 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Expectation; +namespace Brain\Monkey\Tests\Unit\Expectation; use Brain\Monkey\Expectation\Exception\InvalidArgumentForStub; use Brain\Monkey\Expectation\FunctionStub; use Brain\Monkey\Name\FunctionName; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; /** * @runTestsInSeparateProcesses */ -class FunctionStubTest extends TestCase +class FunctionStubTest extends UnitTestCase { public function testConstructorDeclareFunction() diff --git a/tests/src/Hook/HookRunningStackTest.php b/tests/cases/unit/Hook/HookRunningStackTest.php similarity index 94% rename from tests/src/Hook/HookRunningStackTest.php rename to tests/cases/unit/Hook/HookRunningStackTest.php index 562d5f4..7c10a6f 100644 --- a/tests/src/Hook/HookRunningStackTest.php +++ b/tests/cases/unit/Hook/HookRunningStackTest.php @@ -8,10 +8,10 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Hook; +namespace Brain\Monkey\Tests\Unit\Hook; use Brain\Monkey\Hook\HookRunningStack; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; /** @@ -19,7 +19,7 @@ * @package BrainMonkey * @license http://opensource.org/licenses/MIT MIT */ -class HookRunningStackTest extends TestCase +class HookRunningStackTest extends UnitTestCase { public function testPushAndLast() diff --git a/tests/src/Hook/HookStorageTest.php b/tests/cases/unit/Hook/HookStorageTest.php similarity index 97% rename from tests/src/Hook/HookStorageTest.php rename to tests/cases/unit/Hook/HookStorageTest.php index 670a47c..fbfc4ef 100644 --- a/tests/src/Hook/HookStorageTest.php +++ b/tests/cases/unit/Hook/HookStorageTest.php @@ -8,11 +8,11 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Hook; +namespace Brain\Monkey\Tests\Unit\Hook; use Brain\Monkey\Hook\Exception\InvalidHookArgument; use Brain\Monkey\Hook\HookStorage; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; /** @@ -20,7 +20,7 @@ * @package BrainMonkey * @license http://opensource.org/licenses/MIT MIT */ -class HookStorageTest extends TestCase +class HookStorageTest extends UnitTestCase { public function testPushToAddedThrowsIfBadType() diff --git a/tests/src/Name/CallbackStringFormTest.php b/tests/cases/unit/Name/CallbackStringFormTest.php similarity index 94% rename from tests/src/Name/CallbackStringFormTest.php rename to tests/cases/unit/Name/CallbackStringFormTest.php index d712bc5..49e9146 100644 --- a/tests/src/Name/CallbackStringFormTest.php +++ b/tests/cases/unit/Name/CallbackStringFormTest.php @@ -8,18 +8,18 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Name; +namespace Brain\Monkey\Tests\Unit\Name; use Brain\Monkey\Name\CallbackStringForm; use Brain\Monkey\Name\Exception\InvalidCallable; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; /** * @author Giuseppe Mazzapica * @package BrainMonkey * @license http://opensource.org/licenses/MIT MIT */ -class CallbackStringFormTest extends TestCase +class CallbackStringFormTest extends UnitTestCase { public function testClosureToString() @@ -123,4 +123,4 @@ public function testFromStringThrowForMalformedClosureArgs() $this->expectException(InvalidCallable::class); new CallbackStringForm($closure); } -} \ No newline at end of file +} diff --git a/tests/src/Name/ClassNameTest.php b/tests/cases/unit/Name/ClassNameTest.php similarity index 90% rename from tests/src/Name/ClassNameTest.php rename to tests/cases/unit/Name/ClassNameTest.php index b3e844e..f95050b 100644 --- a/tests/src/Name/ClassNameTest.php +++ b/tests/cases/unit/Name/ClassNameTest.php @@ -8,18 +8,18 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Name; +namespace Brain\Monkey\Tests\Unit\Name; use Brain\Monkey\Name\ClassName; use Brain\Monkey\Name\Exception\InvalidName; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; /** * @author Giuseppe Mazzapica * @package BrainMonkey * @license http://opensource.org/licenses/MIT MIT */ -class ClassNameTest extends TestCase +class ClassNameTest extends UnitTestCase { public function testConstructorThrowsIfBadName() @@ -58,7 +58,7 @@ public function testNamespace() public function testEquals() { $class_a = new ClassName(__CLASS__); - $class_b = new ClassName('\Brain\Monkey\Tests\Name\ClassNameTest'); + $class_b = new ClassName(ClassNameTest::class); static::assertTrue($class_a->equals($class_b)); static::assertTrue($class_b->equals($class_a)); diff --git a/tests/src/Name/ClosureParamStringFormTest.php b/tests/cases/unit/Name/ClosureParamStringFormTest.php similarity index 97% rename from tests/src/Name/ClosureParamStringFormTest.php rename to tests/cases/unit/Name/ClosureParamStringFormTest.php index 49e4786..f0b8aef 100644 --- a/tests/src/Name/ClosureParamStringFormTest.php +++ b/tests/cases/unit/Name/ClosureParamStringFormTest.php @@ -8,18 +8,18 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Name; +namespace Brain\Monkey\Tests\Unit\Name; use Brain\Monkey\Name\ClosureParamStringForm; use Brain\Monkey\Name\Exception\InvalidClosureParam; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; /** * @author Giuseppe Mazzapica * @package BrainMonkey * @license http://opensource.org/licenses/MIT MIT */ -class ClosureParamStringFormTest extends TestCase +class ClosureParamStringFormTest extends UnitTestCase { public function testFromStringThrowsForTooManyParameters() diff --git a/tests/src/Name/ClosureStringFormTest.php b/tests/cases/unit/Name/ClosureStringFormTest.php similarity index 97% rename from tests/src/Name/ClosureStringFormTest.php rename to tests/cases/unit/Name/ClosureStringFormTest.php index 8e47b3e..c660e5f 100644 --- a/tests/src/Name/ClosureStringFormTest.php +++ b/tests/cases/unit/Name/ClosureStringFormTest.php @@ -8,18 +8,18 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Name; +namespace Brain\Monkey\Tests\Unit\Name; use Brain\Monkey\Name\ClosureStringForm; use Brain\Monkey\Name\Exception\InvalidCallable; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; /** * @author Giuseppe Mazzapica * @package BrainMonkey * @license http://opensource.org/licenses/MIT MIT */ -class ClosureStringFormTest extends TestCase +class ClosureStringFormTest extends UnitTestCase { public function testNoArg() diff --git a/tests/src/Name/FunctionNameTest.php b/tests/cases/unit/Name/FunctionNameTest.php similarity index 90% rename from tests/src/Name/FunctionNameTest.php rename to tests/cases/unit/Name/FunctionNameTest.php index 6f25ed5..44ad5f3 100644 --- a/tests/src/Name/FunctionNameTest.php +++ b/tests/cases/unit/Name/FunctionNameTest.php @@ -8,18 +8,18 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Name; +namespace Brain\Monkey\Tests\Unit\Name; use Brain\Monkey\Name\Exception\InvalidName; use Brain\Monkey\Name\FunctionName; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; /** * @author Giuseppe Mazzapica * @package BrainMonkey * @license http://opensource.org/licenses/MIT MIT */ -class FunctionNameTest extends TestCase +class FunctionNameTest extends UnitTestCase { public function testConstructorThrowsIfBadName() @@ -59,7 +59,7 @@ public function testNamespace() public function testEquals() { $function_a = new FunctionName(__NAMESPACE__.'\\'.__FUNCTION__); - $function_b = new FunctionName('\\Brain\\Monkey\\Tests\Name\\testEquals'); + $function_b = new FunctionName('\\Brain\\Monkey\\Tests\\Unit\\Name\\testEquals'); static::assertTrue($function_a->equals($function_b)); static::assertTrue($function_b->equals($function_a)); diff --git a/tests/src/Name/MethodNameTest.php b/tests/cases/unit/Name/MethodNameTest.php similarity index 91% rename from tests/src/Name/MethodNameTest.php rename to tests/cases/unit/Name/MethodNameTest.php index f0bae55..875c55d 100644 --- a/tests/src/Name/MethodNameTest.php +++ b/tests/cases/unit/Name/MethodNameTest.php @@ -8,18 +8,18 @@ * file that was distributed with this source code. */ -namespace Brain\Monkey\Tests\Name; +namespace Brain\Monkey\Tests\Unit\Name; use Brain\Monkey\Name\Exception\InvalidName; use Brain\Monkey\Name\MethodName; -use Brain\Monkey\Tests\TestCase; +use Brain\Monkey\Tests\UnitTestCase; /** * @author Giuseppe Mazzapica * @package BrainMonkey * @license http://opensource.org/licenses/MIT MIT */ -class MethodNameTest extends TestCase +class MethodNameTest extends UnitTestCase { public function testConstructorThrowsIfBadName() diff --git a/tests/src/FunctionalTestCase.php b/tests/src/FunctionalTestCase.php new file mode 100644 index 0000000..a652250 --- /dev/null +++ b/tests/src/FunctionalTestCase.php @@ -0,0 +1,33 @@ + + * @package BrainMonkey + * @license http://opensource.org/licenses/MIT MIT + */ +class FunctionalTestCase extends \PHPUnit_Framework_TestCase +{ + protected function setUp() + { + parent::setUp(); + Monkey\setUp(); + } + + protected function tearDown() + { + Monkey\tearDown(); + parent::tearDown(); + } +} \ No newline at end of file diff --git a/tests/src/TestCase.php b/tests/src/UnitTestCase.php similarity index 60% rename from tests/src/TestCase.php rename to tests/src/UnitTestCase.php index d8b9ab5..9f935b0 100644 --- a/tests/src/TestCase.php +++ b/tests/src/UnitTestCase.php @@ -17,11 +17,19 @@ * @package BrainMonkey * @license http://opensource.org/licenses/MIT MIT */ -class TestCase extends \PHPUnit_Framework_TestCase +class UnitTestCase extends \PHPUnit_Framework_TestCase { - private $expect_mockery_exception = null; + protected function setUp() + { + $this->expect_mockery_exception = null; + $libPath = explode('/tests/src/', str_replace('\\', '/', __FILE__))[0]; + + require_once "{$libPath}/inc/wp-helper-functions.php"; + require_once "{$libPath}/inc/wp-hook-functions.php"; + } + protected function tearDown() { if ( ! $this->expect_mockery_exception) { @@ -30,8 +38,24 @@ protected function tearDown() return; } + $this->tearDownMakingSureExpectedExceptionIsThrown(); + } + + /** + * We can't use PHPUnit expectException() because we need to wait for `Monkey\tearDown` and that + * does not work for `expectException()`. + * + * So we let tests use TestCase::expectMockeryException() to set the expectation on thrown + * exception, and when that is thrown we do nothing, but we throw PHPUnit exception in case it + * is not thrown and we expected it. + * + * @return void + */ + protected function tearDownMakingSureExpectedExceptionIsThrown() + { try { Monkey\tearDown(); + throw new \PHPUnit_Framework_ExpectationFailedException( sprintf( 'Failed asserting that Mockery exception %s is thrown.', @@ -46,8 +70,6 @@ protected function tearDown() if (get_class($e) !== $this->expect_mockery_exception) { throw $e; } - } finally { - $this->expect_mockery_exception = null; } } @@ -58,8 +80,11 @@ protected function expectMockeryException($class) { if ( ! class_exists($class) || ! is_subclass_of($class, \Exception::class, true)) { throw new \PHPUnit_Framework_Exception( - sprintf('%s is not a valid Mockery exception class name.'), - $class + sprintf( + '%s is not a valid Mockery exception class name.', + $class + ) + ); }