Passed
Push — 1.x ( 100d20...a08e8e )
by Kevin
11:25
created

can_replace_class_typehint_with_factory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 29
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 20
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 29
rs 9.6
1
<?php
2
3
namespace Zenstruck\Callback\Tests;
4
5
use PHPUnit\Framework\TestCase;
6
use Zenstruck\Callback;
7
8
/**
9
 * @author Kevin Bond <[email protected]>
10
 */
11
final class CallbackTest extends TestCase
12
{
13
    /**
14
     * @test
15
     */
16
    public function can_execute_string_callbacks(): void
17
    {
18
        $actual = Callback::createFor('strtoupper')
19
            ->minArguments(1)
20
            ->replaceUntypedArgument('foobar')
21
            ->execute()
22
        ;
23
24
        $this->assertSame('FOOBAR', $actual);
25
    }
26
27
    /**
28
     * @test
29
     */
30
    public function can_execute_closures(): void
31
    {
32
        $actual = Callback::createFor(function($string) { return \mb_strtoupper($string); })
33
            ->minArguments(1)
34
            ->replaceUntypedArgument('foobar')
35
            ->execute()
36
        ;
37
38
        $this->assertSame('FOOBAR', $actual);
39
    }
40
41
    /**
42
     * @test
43
     */
44
    public function can_enforce_min_arguments(): void
45
    {
46
        $callback = Callback::createFor(function() { return 'ret'; })
47
            ->minArguments(1)
48
        ;
49
50
        $this->expectException(\ArgumentCountError::class);
51
52
        $callback->execute();
53
    }
54
55
    /**
56
     * @test
57
     */
58
    public function can_replace_primitive_typehints(): void
59
    {
60
        $actual = Callback::createFor(function(string $string) { return \mb_strtoupper($string); })
61
            ->minArguments(1)
62
            ->replaceTypedArgument('string', 'foobar')
63
            ->execute()
64
        ;
65
66
        $this->assertSame('FOOBAR', $actual);
67
    }
68
69
    /**
70
     * @test
71
     */
72
    public function can_replace_class_argument(): void
73
    {
74
        $object = new Object2();
75
        $function = static function(Object1 $object1, Object2 $object2, $object3) {
76
            return [
77
                'object1' => $object1,
78
                'object2' => $object2,
79
                'object3' => $object3,
80
            ];
81
        };
82
83
        $actual = Callback::createFor($function)
84
            ->replaceTypedArgument(Object1::class, $object)
85
            ->replaceUntypedArgument($object)
86
            ->execute()
87
        ;
88
89
        $this->assertSame(
90
            [
91
                'object1' => $object,
92
                'object2' => $object,
93
                'object3' => $object,
94
            ],
95
            $actual
96
        );
97
    }
98
99
    /**
100
     * @test
101
     */
102
    public function can_replace_class_typehint_with_factory(): void
103
    {
104
        $function = static function(Object1 $object1, Object2 $object2, $object3) {
105
            return [
106
                'object1' => $object1,
107
                'object2' => $object2,
108
                'object3' => $object3,
109
            ];
110
        };
111
        $factoryArgs = [];
112
        $factory = static function($arg = null) use (&$factoryArgs) {
113
            $factoryArgs[] = $arg;
114
115
            return new Object2();
116
        };
117
118
        $ret = Callback::createFor($function)
119
            ->replaceTypedArgument(Object1::class, $factory)
120
            ->replaceUntypedArgument($factory)
121
            ->execute()
122
        ;
123
124
        $this->assertSame(['object1', 'object2', 'object3'], \array_keys($ret));
125
        $this->assertInstanceOf(Object2::class, $ret['object1']);
126
        $this->assertInstanceOf(Object2::class, $ret['object2']);
127
        $this->assertInstanceOf(Object2::class, $ret['object3']);
128
        $this->assertSame(
129
            [Object1::class, Object2::class, null],
130
            $factoryArgs
131
        );
132
    }
133
134
    /**
135
     * @test
136
     */
137
    public function type_error_thrown_if_no_untyped_argument_defined(): void
138
    {
139
        $callback = Callback::createFor(static function($arg) {});
0 ignored issues
show
Unused Code introduced by
The parameter $arg 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

139
        $callback = Callback::createFor(static function(/** @scrutinizer ignore-unused */ $arg) {});

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...
140
141
        $this->expectException(\TypeError::class);
142
        $this->expectExceptionMessage('No replaceUntypedArgument set');
143
144
        $callback->execute();
145
    }
146
147
    /**
148
     * @test
149
     */
150
    public function type_error_thrown_if_type_argument_not_defined(): void
151
    {
152
        $callback = Callback::createFor(static function(Object2 $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

152
        $callback = Callback::createFor(static function(/** @scrutinizer ignore-unused */ Object2 $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...
153
            ->replaceTypedArgument(\stdClass::class, new \stdClass())
154
        ;
155
156
        $this->expectException(\TypeError::class);
157
        $this->expectExceptionMessage('Unable to replace argument "object1"');
158
159
        $callback->execute();
160
    }
161
162
    /**
163
     * @test
164
     */
165
    public function create_must_be_callable(): void
166
    {
167
        $this->expectException(\InvalidArgumentException::class);
168
169
        Callback::createFor('not a callable');
170
    }
171
}
172
173
class Object1
174
{
175
}
176
177
class Object2 extends Object1
178
{
179
}
180