Passed
Push — 1.x ( 44281e...e2dae5 )
by Kevin
02:12
created

CallbackTest   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 248
Duplicated Lines 0 %

Importance

Changes 5
Bugs 1 Features 1
Metric Value
eloc 105
c 5
b 1
f 1
dl 0
loc 248
rs 10
wmc 14

13 Methods

Rating   Name   Duplication   Size   Complexity  
A invoke_with_unresolvable_argument() 0 14 1
A invoke_all_class_arguments() 0 25 1
A invoke_all_unresolvable_parameter() 0 10 1
A invoke_all_with_no_arguments() 0 7 1
A invoke_all_class_arguments_value_factories() 0 34 2
A invoke_with_not_enough_required_arguments() 0 14 1
A invoke_all_primitive_typed_argument() 0 7 1
A invoke_all_untyped_argument() 0 7 1
A create_must_be_callable() 0 5 1
A invoke_all_with_string_callable() 0 11 1
A invoke_with_no_args() 0 7 1
A invoke_with_resolvable_args() 0 29 1
A invoke_all_can_enforce_min_arguments() 0 7 1
1
<?php
2
3
namespace Zenstruck\Callback\Tests;
4
5
use PHPUnit\Framework\TestCase;
6
use Zenstruck\Callback;
7
use Zenstruck\Callback\Exception\UnresolveableArgument;
8
use Zenstruck\Callback\Parameter;
9
use Zenstruck\Callback\ValueFactory;
10
11
/**
12
 * @author Kevin Bond <[email protected]>
13
 */
14
final class CallbackTest extends TestCase
15
{
16
    /**
17
     * @test
18
     */
19
    public function create_must_be_callable(): void
20
    {
21
        $this->expectException(\InvalidArgumentException::class);
22
23
        Callback::createFor('not a callable');
24
    }
25
26
    /**
27
     * @test
28
     */
29
    public function invoke_all_can_enforce_min_arguments(): void
30
    {
31
        $callback = Callback::createFor(function() { return 'ret'; });
32
33
        $this->expectException(\ArgumentCountError::class);
34
35
        $callback->invokeAll(Parameter::untyped('foo'), 1);
36
    }
37
38
    /**
39
     * @test
40
     */
41
    public function invoke_all_with_no_arguments(): void
42
    {
43
        $actual = Callback::createFor(function() { return 'ret'; })
44
            ->invokeAll(Parameter::untyped('foo'))
45
        ;
46
47
        $this->assertSame('ret', $actual);
48
    }
49
50
    /**
51
     * @test
52
     */
53
    public function invoke_all_with_string_callable(): void
54
    {
55
        $actual = Callback::createFor('strtoupper')
56
            ->invokeAll(Parameter::union(
57
                Parameter::untyped('foobar'),
58
                Parameter::typed('string', 'foobar')
59
            )
60
        )
61
        ;
62
63
        $this->assertSame('FOOBAR', $actual);
64
    }
65
66
    /**
67
     * @test
68
     */
69
    public function invoke_all_untyped_argument(): void
70
    {
71
        $actual = Callback::createFor(function($string) { return \mb_strtoupper($string); })
72
            ->invokeAll(Parameter::untyped('foobar'))
73
        ;
74
75
        $this->assertSame('FOOBAR', $actual);
76
    }
77
78
    /**
79
     * @test
80
     */
81
    public function invoke_all_primitive_typed_argument(): void
82
    {
83
        $actual = Callback::createFor(function(string $string) { return \mb_strtoupper($string); })
84
            ->invokeAll(Parameter::typed('string', 'foobar'))
85
        ;
86
87
        $this->assertSame('FOOBAR', $actual);
88
    }
89
90
    /**
91
     * @test
92
     */
93
    public function invoke_all_class_arguments(): void
94
    {
95
        $object = new Object2();
96
        $function = static function(Object1 $object1, Object2 $object2, $object3) {
97
            return [
98
                'object1' => $object1,
99
                'object2' => $object2,
100
                'object3' => $object3,
101
            ];
102
        };
103
104
        $actual = Callback::createFor($function)
105
            ->invokeAll(Parameter::union(
106
                Parameter::untyped($object),
107
                Parameter::typed(Object1::class, $object)
108
            ))
109
        ;
110
111
        $this->assertSame(
112
            [
113
                'object1' => $object,
114
                'object2' => $object,
115
                'object3' => $object,
116
            ],
117
            $actual
118
        );
119
    }
120
121
    /**
122
     * @test
123
     */
124
    public function invoke_all_class_arguments_value_factories(): void
125
    {
126
        $function = static function(Object1 $object1, Object2 $object2, $object3) {
127
            return [
128
                'object1' => $object1,
129
                'object2' => $object2,
130
                'object3' => $object3,
131
            ];
132
        };
133
        $factoryArgs = [];
134
        $factory = new ValueFactory(static function($arg) use (&$factoryArgs) {
135
            $factoryArgs[] = $arg;
136
137
            if ($arg) {
138
                return new $arg();
139
            }
140
141
            return new Object1();
142
        });
143
144
        $ret = Callback::createFor($function)
145
            ->invokeAll(Parameter::union(
146
                Parameter::untyped($factory),
147
                Parameter::typed(Object1::class, $factory)
148
            ))
149
        ;
150
151
        $this->assertSame(['object1', 'object2', 'object3'], \array_keys($ret));
152
        $this->assertInstanceOf(Object1::class, $ret['object1']);
153
        $this->assertInstanceOf(Object2::class, $ret['object2']);
154
        $this->assertInstanceOf(Object1::class, $ret['object3']);
155
        $this->assertSame(
156
            [Object1::class, Object2::class, null],
157
            $factoryArgs
158
        );
159
    }
160
161
    /**
162
     * @test
163
     */
164
    public function invoke_all_unresolvable_parameter(): void
165
    {
166
        $callback = Callback::createFor(static function(Object1 $object1, Object2 $object2, Object3 $object3) {});
0 ignored issues
show
Unused Code introduced by
The parameter $object1 is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

166
        $callback = Callback::createFor(static function(/** @scrutinizer ignore-unused */ Object1 $object1, Object2 $object2, Object3 $object3) {});

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $object2 is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

166
        $callback = Callback::createFor(static function(Object1 $object1, /** @scrutinizer ignore-unused */ Object2 $object2, Object3 $object3) {});

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $object3 is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

166
        $callback = Callback::createFor(static function(Object1 $object1, Object2 $object2, /** @scrutinizer ignore-unused */ Object3 $object3) {});

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
167
168
        $this->expectException(UnresolveableArgument::class);
169
        $this->expectExceptionMessage('Unable to resolve argument 3 for callback. Expected type: "mixed|Zenstruck\Callback\Tests\Object1"');
170
171
        $callback->invokeAll(Parameter::union(
172
            Parameter::untyped(new Object1()),
173
            Parameter::typed(Object1::class, new Object1())
174
        ));
175
    }
176
177
    /**
178
     * @test
179
     */
180
    public function invoke_with_no_args(): void
181
    {
182
        $actual = Callback::createFor(function() { return 'ret'; })
183
            ->invoke()
184
        ;
185
186
        $this->assertSame('ret', $actual);
187
    }
188
189
    /**
190
     * @test
191
     */
192
    public function invoke_with_resolvable_args(): void
193
    {
194
        $object = new Object2();
195
        $function = static function(Object1 $object1, Object2 $object2, $object3, $extra) {
196
            return [
197
                'object1' => $object1,
198
                'object2' => $object2,
199
                'object3' => $object3,
200
                'extra' => $extra,
201
            ];
202
        };
203
204
        $actual = Callback::createFor($function)
205
            ->invoke(
206
                Parameter::typed(Object1::class, $object),
207
                Parameter::typed(Object2::class, $object),
208
                Parameter::untyped($object),
209
                'value'
210
            )
211
        ;
212
213
        $this->assertSame(
214
            [
215
                'object1' => $object,
216
                'object2' => $object,
217
                'object3' => $object,
218
                'extra' => 'value',
219
            ],
220
            $actual
221
        );
222
    }
223
224
    /**
225
     * @test
226
     */
227
    public function invoke_with_unresolvable_argument(): void
228
    {
229
        $object = new Object2();
230
        $function = static function(Object1 $object1, $object2, $object3, $extra) {};
0 ignored issues
show
Unused Code introduced by
The parameter $object3 is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

230
        $function = static function(Object1 $object1, $object2, /** @scrutinizer ignore-unused */ $object3, $extra) {};

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $object1 is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

230
        $function = static function(/** @scrutinizer ignore-unused */ Object1 $object1, $object2, $object3, $extra) {};

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $extra is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

230
        $function = static function(Object1 $object1, $object2, $object3, /** @scrutinizer ignore-unused */ $extra) {};

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $object2 is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

230
        $function = static function(Object1 $object1, /** @scrutinizer ignore-unused */ $object2, $object3, $extra) {};

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
231
232
        $this->expectException(UnresolveableArgument::class);
233
        $this->expectExceptionMessage('Unable to resolve argument 2 for callback. Expected type: "Zenstruck\Callback\Tests\Object2"');
234
235
        Callback::createFor($function)
236
            ->invoke(
237
                Parameter::typed(Object1::class, $object),
238
                Parameter::typed(Object2::class, $object),
239
                Parameter::untyped($object),
240
                'value'
241
            )
242
        ;
243
    }
244
245
    /**
246
     * @test
247
     */
248
    public function invoke_with_not_enough_required_arguments(): void
249
    {
250
        $object = new Object2();
251
        $function = static function(Object1 $object1) {};
0 ignored issues
show
Unused Code introduced by
The parameter $object1 is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

251
        $function = static function(/** @scrutinizer ignore-unused */ Object1 $object1) {};

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
252
253
        $this->expectException(\ArgumentCountError::class);
254
        $this->expectExceptionMessage('No argument 2 for callable. Expected type: "Zenstruck\Callback\Tests\Object2"');
255
256
        Callback::createFor($function)
257
            ->invoke(
258
                Parameter::typed(Object1::class, $object),
259
                Parameter::typed(Object2::class, $object),
260
                Parameter::untyped($object),
261
                'value'
262
            )
263
        ;
264
    }
265
}
266
267
class Object1
268
{
269
}
270
271
class Object2 extends Object1
272
{
273
}
274
275
class Object3
276
{
277
}
278