• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

10up / wp_mock / 13901966852

17 Mar 2025 02:27PM UTC coverage: 66.142% (+0.1%) from 66.01%
13901966852

push

github

web-flow
Fix: Multiple `onFilter` call issues related to the `withAnyArgs` method (#259)

# Summary <!-- Required -->

This PR implements a fix for an issue I discovered when using multiple
`onFilter` calls with the `withAnyArgs` method.

<img width="807" alt="Screenshot 2025-03-12 at 18 47 52"
src="https://github.com/user-attachments/assets/3c1bb38a-830a-4a4a-907c-a61b7f0d8e11"
/>

### Closes: #258 

## Details <!-- Optional -->

While writing some unit test cases using the `withAnyArgs` method, I
came across issues for multiple `onFilter` calls introduced into the
tests. At the moment, if a single `onFilter` call is used alongside
`withAnyArgs`, it works correctly, but for multiple cases, it doesn't
correctly pass the tests. The expected behaviour should be that this
works for both single and multiple use cases using the `withAnyArgs`.

This PR fixes this issue correctly.

<img width="587" alt="Screenshot 2025-03-12 at 19 42 19"
src="https://github.com/user-attachments/assets/46cfd651-62a7-455b-9b58-257d38a78b84"
/>

---

Run tests:

```php
vendor/bin/phpunit ./tests/Unit/WP_MockTest.php 
```

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

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

## Testing <!-- Required -->

```php
public function testMultipleOnFilterPassesWithAnyArgs(): void
{
    WP_Mock::bootstrap();

    /** @phpstan-ignore-next-line */
    WP_Mock::onFilter('testFilter1')
        ->withAnyArgs()
        ->reply('Filtered value 1');

    /** @phpstan-ignore-next-line */
    WP_Mock::onFilter('testFilter2')
        ->withAnyArgs()
        ->reply('Filtered value 2');

    /** @phpstan-ignore-next-line */
    WP_Mock::onFilter('testFilter3')
        ->withAnyArgs()
        ->reply('Filtered value 3');

    $filter... (continued)

0 of 2 new or added lines in 1 file covered. (0.0%)

504 of 762 relevant lines covered (66.14%)

2.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/php/WP_Mock/Filter.php
1
<?php
2

3
namespace WP_Mock;
4

5
/**
6
 * Mock representation of a WordPress filter as an object.
7
 *
8
 * Mocks WordPress filters by substituting each filter with an object capable of intercepting calls and returning predictable behavior.
9
 */
10
class Filter extends Hook
11
{
12
    /** @var array<string, array<int>> Collection of filter names mapped to random integers. */
13
    protected static array $filtersWithAnyArgs = [];
14

15
    /**
16
     * Apply the stored filter.
17
     *
18
     * @param array $args Arguments passed to apply_filters()
19
     *
20
     * @return mixed
21
     */
22
    public function apply($args)
23
    {
24
        if (isset(static::$filtersWithAnyArgs[ $this->name ])) {
×
NEW
25
            $args = static::$filtersWithAnyArgs[ $this->name ];
×
26
        }
27

28
        if ($args[0] === null && count($args) === 1) {
×
29
            if (isset($this->processors['argsnull'])) {
×
30
                return $this->processors['argsnull']->send();
×
31
            }
32
            $this->strict_check();
×
33

34
            return null;
×
35
        }
36

37
        $processors = $this->processors;
×
38
        foreach ($args as $arg) {
×
39
            $key = $this->safe_offset($arg);
×
40
            if (! is_array($processors) || ! isset($processors[ $key ])) {
×
41
                $this->strict_check();
×
42

43
                return $arg;
×
44
            }
45

46
            $processors = $processors[ $key ];
×
47
        }
48

49
        return call_user_func_array(array($processors, 'send'), $args);
×
50
    }
51

52
    /**
53
     * @return Filter_Responder
54
     */
55
    protected function new_responder()
56
    {
57
        return new Filter_Responder();
×
58
    }
59

60
    /**
61
     * @return string
62
     */
63
    protected function get_strict_mode_message()
64
    {
65
        return sprintf('Unexpected use of apply_filters for filter %s', $this->name);
×
66
    }
67

68
    /**
69
     * @return Action_Responder|Filter_Responder|HookedCallbackResponder
70
     */
71
    public function withAnyArgs()
72
    {
73
        $random_value = mt_rand();
×
NEW
74
        static::$filtersWithAnyArgs[ $this->name ] = [ $random_value ];
×
75

76
        return $this->with($random_value);
×
77
    }
78
}
79

80
class Filter_Responder
81
{
82
    /**
83
     * @var mixed
84
     */
85
    protected $value;
86

87
    public function reply($value)
88
    {
89
        $this->value = $value;
×
90
    }
91

92
    public function send()
93
    {
94
        if ($this->value instanceof InvokedFilterValue) {
×
95
            return call_user_func_array($this->value, func_get_args());
×
96
        }
97

98
        return $this->value;
×
99
    }
100
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc