Completed
Branch 6.0 (d30585)
by yun
02:10
created

ContainerTest::testInvoke()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 43
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 25
c 2
b 0
f 0
nc 1
nop 0
dl 0
loc 43
rs 9.52
1
<?php
2
3
namespace think\tests;
4
5
use PHPUnit\Framework\TestCase;
6
use ReflectionMethod;
7
use stdClass;
8
use think\Container;
9
use think\exception\ClassNotFoundException;
10
use think\exception\FuncNotFoundException;
11
12
class Taylor
13
{
14
    public $name;
15
16
    public function __construct($name)
17
    {
18
        $this->name = $name;
19
    }
20
21
    public function some(Container $container)
22
    {
23
    }
24
25
    protected function protectionFun()
26
    {
27
        return true;
28
    }
29
30
    public static function test(Container $container)
31
    {
32
        return $container;
33
    }
34
35
    public static function __make()
36
    {
37
        return new self('Taylor');
38
    }
39
}
40
41
class SomeClass
42
{
43
    public $container;
44
45
    public $count = 0;
46
47
    public function __construct(Container $container)
48
    {
49
        $this->container = $container;
50
    }
51
}
52
53
class ContainerTest extends TestCase
54
{
55
    protected function tearDown(): void
56
    {
57
        Container::setInstance(null);
58
    }
59
60
    public function testClosureResolution()
61
    {
62
        $container = new Container;
63
64
        Container::setInstance($container);
65
66
        $container->bind('name', function () {
67
            return 'Taylor';
68
        });
69
70
        $this->assertEquals('Taylor', $container->make('name'));
71
72
        $this->assertEquals('Taylor', Container::pull('name'));
73
    }
74
75
    public function testGet()
76
    {
77
        $container = new Container;
78
79
        $this->expectException(ClassNotFoundException::class);
80
        $this->expectExceptionMessage('class not exists: name');
81
        $container->get('name');
82
83
        $container->bind('name', function () {
84
            return 'Taylor';
85
        });
86
87
        $this->assertSame('Taylor', $container->get('name'));
88
    }
89
90
    public function testExist()
91
    {
92
        $container = new Container;
93
94
        $container->bind('name', function () {
95
            return 'Taylor';
96
        });
97
98
        $this->assertFalse($container->exists("name"));
99
100
        $container->make('name');
101
102
        $this->assertTrue($container->exists('name'));
103
    }
104
105
    public function testInstance()
106
    {
107
        $container = new Container;
108
109
        $container->bind('name', function () {
110
            return 'Taylor';
111
        });
112
113
        $this->assertEquals('Taylor', $container->get('name'));
114
115
        $container->bind('name2', Taylor::class);
116
117
        $object = new stdClass();
118
119
        $this->assertFalse($container->exists('name2'));
120
121
        $container->instance('name2', $object);
122
123
        $this->assertTrue($container->exists('name2'));
124
125
        $this->assertTrue($container->exists(Taylor::class));
126
127
        $this->assertEquals($object, $container->make(Taylor::class));
128
129
        unset($container->name1);
130
131
        $this->assertFalse($container->exists('name1'));
132
133
        $container->delete('name2');
134
135
        $this->assertFalse($container->exists('name2'));
136
137
        foreach ($container as $class => $instance) {
138
139
        }
140
    }
141
142
    public function testBind()
143
    {
144
        $container = new Container;
145
146
        $object = new stdClass();
147
148
        $container->bind(['name' => Taylor::class]);
149
150
        $container->bind('name2', $object);
151
152
        $container->bind('name3', Taylor::class);
153
154
        $container->name4 = $object;
155
156
        $container['name5'] = $object;
157
158
        $this->assertTrue(isset($container->name4));
159
160
        $this->assertTrue(isset($container['name5']));
161
162
        $this->assertInstanceOf(Taylor::class, $container->get('name'));
163
164
        $this->assertSame($object, $container->get('name2'));
165
166
        $this->assertSame($object, $container->name4);
167
168
        $this->assertSame($object, $container['name5']);
169
170
        $this->assertInstanceOf(Taylor::class, $container->get('name3'));
171
172
        unset($container['name']);
173
174
        $this->assertFalse(isset($container['name']));
175
176
        unset($container->name3);
177
178
        $this->assertFalse(isset($container->name3));
179
    }
180
181
    public function testAutoConcreteResolution()
182
    {
183
        $container = new Container;
184
185
        $taylor = $container->make(Taylor::class);
186
187
        $this->assertInstanceOf(Taylor::class, $taylor);
188
        $this->assertAttributeSame('Taylor', 'name', $taylor);
189
    }
190
191
    public function testGetAndSetInstance()
192
    {
193
        $this->assertInstanceOf(Container::class, Container::getInstance());
194
195
        $object = new stdClass();
196
197
        Container::setInstance($object);
198
199
        $this->assertSame($object, Container::getInstance());
200
201
        Container::setInstance(function () {
202
            return $this;
203
        });
204
205
        $this->assertSame($this, Container::getInstance());
206
    }
207
208
    public function testResolving()
209
    {
210
        $container = new Container();
211
        $container->bind(Container::class, $container);
212
213
        $container->resolving(function (SomeClass $taylor, Container $container) {
214
            $taylor->count++;
215
        });
216
        $container->resolving(SomeClass::class, function (SomeClass $taylor, Container $container) {
217
            $taylor->count++;
218
        });
219
220
        /** @var SomeClass $someClass */
221
        $someClass = $container->invokeClass(SomeClass::class);
222
        $this->assertEquals(2, $someClass->count);
223
    }
224
225
    public function testInvokeFunctionWithoutMethodThrowsException()
226
    {
227
        $this->expectException(FuncNotFoundException::class);
228
        $this->expectExceptionMessage('function not exists: ContainerTestCallStub()');
229
        $container = new Container();
230
        $container->invokeFunction('ContainerTestCallStub', []);
231
    }
232
233
    public function testInvokeProtectionMethod()
234
    {
235
        $container = new Container();
236
        $this->assertTrue($container->invokeMethod([Taylor::class, 'protectionFun'], [], true));
237
    }
238
239
    public function testInvoke()
240
    {
241
        $container = new Container();
242
243
        Container::setInstance($container);
244
245
        $container->bind(Container::class, $container);
246
247
        $stub = $this->createMock(Taylor::class);
248
249
        $stub->expects($this->once())->method('some')->with($container)->will($this->returnSelf());
250
251
        $container->invokeMethod([$stub, 'some']);
252
253
        $this->assertEquals('48', $container->invoke('ord', ['0']));
254
255
        $this->assertSame($container, $container->invoke(Taylor::class . '::test', []));
256
257
        $this->assertSame($container, $container->invokeMethod(Taylor::class . '::test'));
258
259
        $reflect = new ReflectionMethod($container, 'exists');
260
261
        $this->assertTrue($container->invokeReflectMethod($container, $reflect, [Container::class]));
262
263
        $this->assertSame($container, $container->invoke(function (Container $container) {
264
            return $container;
265
        }));
266
267
        $this->assertSame($container, $container->invoke(Taylor::class . '::test'));
268
269
        $object = $container->invokeClass(SomeClass::class);
270
        $this->assertInstanceOf(SomeClass::class, $object);
271
        $this->assertSame($container, $object->container);
272
273
        $stdClass = new stdClass();
274
275
        $container->invoke(function (Container $container, stdClass $stdObject, $key1, $lowKey, $key2 = 'default') use ($stdClass) {
276
            $this->assertEquals('value1', $key1);
277
            $this->assertEquals('default', $key2);
278
            $this->assertEquals('value2', $lowKey);
279
            $this->assertSame($stdClass, $stdObject);
280
            return $container;
281
        }, ['some' => $stdClass, 'key1' => 'value1', 'low_key' => 'value2']);
282
    }
283
284
    public function testInvokeMethodNotExists()
285
    {
286
        $container = $this->resolveContainer();
287
        $this->expectException(FuncNotFoundException::class);
288
289
        $container->invokeMethod([SomeClass::class, 'any']);
290
    }
291
292
    public function testInvokeClassNotExists()
293
    {
294
        $container = new Container();
295
296
        Container::setInstance($container);
297
298
        $container->bind(Container::class, $container);
299
300
        $this->expectExceptionObject(new ClassNotFoundException('class not exists: SomeClass'));
301
302
        $container->invokeClass('SomeClass');
303
    }
304
305
    protected function resolveContainer()
306
    {
307
        $container = new Container();
308
309
        Container::setInstance($container);
310
        return $container;
311
    }
312
313
}
314