Skip to content

Commit

Permalink
v2.3.0
Browse files Browse the repository at this point in the history
API:
- Added `Functions\stubWpTranslationFunctions()`
- Added `Functions\stubWpEscapeFunctions()`
- Make sure default params are used and checked when adding or removing hooks
- Added `Actions\expectRemoved` and `Filters\expectRemoved` (see #45)

Tests:
- re-structured tests folder and test suites
- deleted bootstrap file and rely on autoload-dev only
- improced
- fixed minor tests issues
- added basic functional tests
- added tests for new features

Docs:
- some improvements in various files (ses #49)
- added docs for new features

Others:
- Improved some doc blocks and removed all `@throws` occurrences
- Fixed some end-of-line inconsistencies
  • Loading branch information
gmazzap committed Jul 22, 2019
1 parent 9d25c58 commit e19ad8f
Show file tree
Hide file tree
Showing 51 changed files with 1,591 additions and 528 deletions.
13 changes: 7 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
335 changes: 200 additions & 135 deletions docs/functions-stubs.md
Original file line number Diff line number Diff line change
@@ -1,135 +1,200 @@
<!--
currentMenu: "functionsstubs"
currentSection: "PHP Functions"
title: "Bulk patching with stubs()"
-->
# 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' ] );
```
<!--
currentMenu: "functionsstubs"
currentSection: "PHP Functions"
title: "Bulk patching with stubs()"
-->
# 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')
```
2 changes: 1 addition & 1 deletion docs/wordpress-hooks-added.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) {
Expand Down
Loading

0 comments on commit e19ad8f

Please sign in to comment.