Completed
Pull Request — master (#5)
by mw
01:35
created

testRecursiveBuildToLoadParameterizedCallbackHandler()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 28
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 16
nc 1
nop 0
1
<?php
2
3
namespace Onoi\CallbackContainer\Tests;
4
5
use Onoi\CallbackContainer\CallbackContainerBuilder;
6
use Onoi\CallbackContainer\Fixtures\FakeCallbackContainer;
7
8
/**
9
 * @covers \Onoi\CallbackContainer\CallbackContainerBuilder
10
 * @group onoi-callback-container
11
 *
12
 * @license GNU GPL v2+
13
 * @since 1.2
14
 *
15
 * @author mwjames
16
 */
17
class CallbackContainerBuilderTest extends \PHPUnit_Framework_TestCase {
18
19
	public function testCanConstruct() {
20
21
		$this->assertInstanceOf(
22
			'\Onoi\CallbackContainer\CallbackContainerBuilder',
23
			new CallbackContainerBuilder()
24
		);
25
	}
26
27
	public function testCanConstructWithCallbackContainer() {
28
29
		$callbackContainer = $this->getMockBuilder( '\Onoi\CallbackContainer\CallbackContainer' )
30
			->disableOriginalConstructor()
31
			->getMock();
32
33
		$callbackContainer->expects( $this->once() )
34
			->method( 'register' );
35
36
		$this->assertInstanceOf(
37
			'\Onoi\CallbackContainer\CallbackContainerBuilder',
38
			new CallbackContainerBuilder( $callbackContainer )
39
		);
40
	}
41
42
	public function testRegisterCallback() {
43
44
		$instance = new CallbackContainerBuilder();
45
46
		$instance->registerCallback( 'Foo', function() {
47
			return new \stdClass;
48
		} );
49
50
		$this->assertEquals(
51
			new \stdClass,
52
			$instance->create( 'Foo' )
53
		);
54
55
		$this->assertEquals(
56
			new \stdClass,
57
			$instance->singleton( 'Foo' )
58
		);
59
60
		$this->assertTrue(
61
			$instance->isRegistered( 'Foo' )
62
		);
63
	}
64
65
	public function testDeregisterCallback() {
66
67
		$instance = new CallbackContainerBuilder();
68
69
		$instance->registerCallback( 'Foo', function() {
70
			return 'abc';
71
		} );
72
73
		$this->assertEquals(
74
			'abc',
75
			$instance->create( 'Foo' )
76
		);
77
78
		$instance->deregister( 'Foo' );
79
	}
80
81
	public function testLoadCallbackHandlerWithExpectedReturnType() {
82
83
		$instance = new CallbackContainerBuilder();
84
85
		$instance->registerCallback( 'Foo', function() {
86
			return new \stdClass;
87
		} );
88
89
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
90
91
		$this->assertEquals(
92
			new \stdClass,
93
			$instance->create( 'Foo' )
94
		);
95
	}
96
97
	public function testLoadCallbackHandlerWithoutExpectedReturnType() {
98
99
		$instance = new CallbackContainerBuilder();
100
101
		$instance->registerCallback( 'Foo', function() {
102
			return 'abc';
103
		} );
104
105
		$this->assertEquals(
106
			'abc',
107
			$instance->create( 'Foo' )
108
		);
109
	}
110
111
	public function testRegisterCallbackContainer() {
112
113
		$instance = new CallbackContainerBuilder();
114
		$instance->registerCallbackContainer( new FakeCallbackContainer() );
115
116
		$this->assertEquals(
117
			new \stdClass,
118
			$instance->create( 'Foo' )
119
		);
120
121
		$this->assertEquals(
122
			new \stdClass,
123
			$instance->singleton( 'Foo' )
124
		);
125
	}
126
127
	public function testRegisterFromFile() {
128
129
		$instance = new CallbackContainerBuilder();
130
		$instance->registerFromFile( __DIR__ . '/../Fixtures/fakeCallbackFromFile.php' );
131
132
		$this->assertEquals(
133
			new \stdClass,
134
			$instance->create( 'SomeStdClassFromFile' )
135
		);
136
	}
137
138
	public function testRegisterFromFileWithInterFactory() {
139
140
		$instance = new CallbackContainerBuilder();
141
		$instance->registerFromFile( __DIR__ . '/../Fixtures/fakeCallbackFromFile.php' );
142
143
		$this->assertEquals(
144
			new \stdClass,
145
			$instance->create( 'AnotherStdClassFromFileWithInterFactory' )
146
		);
147
	}
148
149
	public function testRegisterFromFileWithInterFactoryAndArgument() {
150
151
		$instance = new CallbackContainerBuilder();
152
		$instance->registerFromFile( __DIR__ . '/../Fixtures/fakeCallbackFromFile.php' );
153
154
		$this->assertEquals(
155
			123,
156
			$instance->create( 'AnotherStdClassFromFileWithInterFactoryAndArgument', 123 )->argument
157
		);
158
	}
159
160
	public function testRegisterFromFileWithCircularReferenceThrowsException() {
161
162
		$instance = new CallbackContainerBuilder();
163
		$instance->registerFromFile( __DIR__ . '/../Fixtures/fakeCallbackFromFile.php' );
164
165
		$this->setExpectedException( 'Onoi\CallbackContainer\Exception\ServiceCircularReferenceException' );
166
		$instance->create( 'serviceFromFileWithForcedCircularReference' );
167
	}
168
169
	public function testRegisterObject() {
170
171
		$expected = new \stdClass;
172
173
		$instance = new CallbackContainerBuilder();
174
175
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
176
		$instance->registerObject( 'Foo', $expected );
177
178
		$this->assertEquals(
179
			$expected,
180
			$instance->create( 'Foo' )
181
		);
182
183
		$this->assertEquals(
184
			$expected,
185
			$instance->singleton( 'Foo' )
186
		);
187
	}
188
189
	public function testInjectInstanceForExistingRegisteredCallbackHandler() {
190
191
		$stdClass = $this->getMockBuilder( '\stdClass' )
192
			->disableOriginalConstructor()
193
			->getMock();
194
195
		$instance = new CallbackContainerBuilder( new FakeCallbackContainer() );
196
		$instance->singleton( 'Foo' );
197
198
		$instance->registerObject( 'Foo', $stdClass );
199
200
		$this->assertSame(
201
			$stdClass,
202
			$instance->create( 'Foo' )
203
		);
204
205
		$this->assertSame(
206
			$stdClass,
207
			$instance->singleton( 'Foo' )
208
		);
209
	}
210
211
	public function testOverrideSingletonInstanceOnRegisteredCallbackHandlerWithArguments() {
212
213
		$argument = $this->getMockBuilder( '\stdClass' )
214
			->disableOriginalConstructor()
215
			->getMock();
216
217
		$instance = new CallbackContainerBuilder(
218
			new FakeCallbackContainer()
219
		);
220
221
		$instance->singleton( 'FooWithNullArgument', $argument );
222
		$override = $instance->singleton( 'FooWithNullArgument', null );
223
224
		$this->assertNotSame(
225
			$override,
226
			$instance->singleton( 'FooWithNullArgument', $argument )
227
		);
228
229
		$instance->registerObject( 'FooWithNullArgument', $override );
230
231
		$this->assertSame(
232
			$override,
233
			$instance->singleton( 'FooWithNullArgument', $argument )
234
		);
235
236
		$this->assertSame(
237
			$override,
238
			$instance->singleton( 'FooWithNullArgument', null )
239
		);
240
	}
241
242
	public function testLoadParameterizedCallbackHandler() {
243
244
		$instance = new CallbackContainerBuilder();
245
246
		$instance->registerCallback( 'Foo', function( $containerBuilder, $a, $b, $c ) {
247
			$stdClass = new \stdClass;
248
			$stdClass->a = $a;
249
			$stdClass->b = $b;
250
			$stdClass->c = $c;
251
252
			return $stdClass;
253
		} );
254
255
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
256
257
		$object = new \stdClass;
258
		$object->extra = 123;
259
260
		$this->assertEquals(
261
			'abc',
262
			$instance->create( 'Foo', 'abc', 123, $object )->a
263
		);
264
265
		$this->assertEquals(
266
			$object,
267
			$instance->create( 'Foo', 'abc', 123, $object )->c
268
		);
269
	}
270
271
	public function testRecursiveBuildToLoadParameterizedCallbackHandler() {
272
273
		$instance = new CallbackContainerBuilder();
274
275
		$instance->registerCallback( 'Foo', function( $containerBuilder, $a, $b = null, $c ) {
276
			$stdClass = new \stdClass;
277
			$stdClass->a = $a;
278
			$stdClass->c = $c;
279
280
			return $stdClass;
281
		} );
282
283
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
284
285
		$instance->registerCallback( 'Bar', function( $containerBuilder, $a, $b, $c ) use( $instance ) {
286
			return $instance->create( 'Foo', $a, $b, $c );
287
		} );
288
289
		$instance->registerExpectedReturnType( 'Bar', '\stdClass' );
290
291
		$object = new \stdClass;
292
		$object->extra = 123;
293
294
		$this->assertSame(
295
			$object,
296
			$instance->create( 'Bar', 'abc', null, $object )->c
297
		);
298
	}
299
300
	public function testSingleton() {
301
302
		$instance = new CallbackContainerBuilder();
303
304
		$instance->registerCallback( 'Foo', function() {
305
			return new \stdClass;
306
		} );
307
308
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
309
310
		$singleton = $instance->singleton( 'Foo' );
311
312
		$this->assertSame(
313
			$singleton,
314
			$instance->singleton( 'Foo' )
315
		);
316
	}
317
318
	public function testFingerprintedParameterizedSingletonCallbackHandler() {
319
320
		$instance = new CallbackContainerBuilder();
321
322
		$instance->registerCallback( 'Foo', function( $containerBuilder, $a, array $b ) {
323
			$stdClass = new \stdClass;
324
			$stdClass->a = $a;
325
			$stdClass->b = $b;
326
327
			return $stdClass;
328
		} );
329
330
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
331
332
		$this->assertSame(
333
			$instance->singleton( 'Foo', 'abc', array( 'def' ) ),
334
			$instance->singleton( 'Foo', 'abc', array( 'def' ) )
335
		);
336
337
		$this->assertNotSame(
338
			$instance->singleton( 'Foo', 'abc', array( '123' ) ),
339
			$instance->singleton( 'Foo', 'abc', array( 'def' ) )
340
		);
341
	}
342
343
	public function testUnregisteredServiceOnCreateThrowsException() {
344
345
		$instance = new CallbackContainerBuilder();
346
347
		$this->setExpectedException( '\Onoi\CallbackContainer\Exception\ServiceNotFoundException' );
348
		$instance->create( 'Foo' );
349
	}
350
351
	public function testUnregisteredServiceOnSingletonThrowsException() {
352
353
		$instance = new CallbackContainerBuilder();
354
355
		$this->setExpectedException( '\Onoi\CallbackContainer\Exception\ServiceNotFoundException' );
356
		$instance->singleton( 'Foo' );
357
	}
358
359
	public function testCreateFromCallbackWithTypeMismatchThrowsException() {
360
361
		$instance = new CallbackContainerBuilder();
362
363
		$instance->registerCallback( 'Foo', function() {
364
			return new \stdClass;
365
		} );
366
367
		$instance->registerExpectedReturnType( 'Foo', 'Bar' );
368
369
		$this->setExpectedException( 'RuntimeException' );
370
		$instance->create( 'Foo' );
371
	}
372
373
	public function testCreateWithInvalidNameForCallbackHandlerOnLoadThrowsException() {
374
375
		$instance = new CallbackContainerBuilder();
376
377
		$this->setExpectedException( 'InvalidArgumentException' );
378
		$instance->create( new \stdClass );
379
	}
380
381
	public function testSingletonWithInvalidNameForCallbackHandlerOnSingletonThrowsException() {
382
383
		$instance = new CallbackContainerBuilder();
384
385
		$this->setExpectedException( 'InvalidArgumentException' );
386
		$instance->singleton( new \stdClass );
387
	}
388
389
	public function testCreateOnCallbackHandlerWithCircularReferenceThrowsException() {
390
391
		$instance = new CallbackContainerBuilder();
392
393
		$this->setExpectedException( 'RuntimeException' );
394
395
		$instance->registerCallback( 'Foo', function() use ( $instance ) {
396
			return $instance->create( 'Foo' );
397
		} );
398
399
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
400
		$instance->create( 'Foo' );
401
	}
402
403
	public function testSingletonOnCallbackHandlerWithCircularReferenceThrowsException() {
404
405
		$instance = new CallbackContainerBuilder();
406
407
		$this->setExpectedException( 'RuntimeException' );
408
409
		$instance->registerCallback( 'Foo', function() use ( $instance ) {
410
			return $instance->singleton( 'Foo' );
411
		} );
412
413
		$instance->singleton( 'Foo' );
414
	}
415
416
	public function testRegisterCallbackWithInvalidNameThrowsException() {
417
418
		$instance = new CallbackContainerBuilder();
419
420
		$this->setExpectedException( 'InvalidArgumentException' );
421
		$instance->registerCallback( new \stdClass, function() {
0 ignored issues
show
Documentation introduced by
new \stdClass() is of type object<stdClass>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
422
			return new \stdClass;
423
		} );
424
	}
425
426
	public function testRegisterObjectWithInvalidNameThrowsException() {
427
428
		$instance = new CallbackContainerBuilder();
429
430
		$this->setExpectedException( 'InvalidArgumentException' );
431
		$instance->registerObject( new \stdClass, new \stdClass );
0 ignored issues
show
Documentation introduced by
new \stdClass() is of type object<stdClass>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
432
	}
433
434
	public function testRegisterExpectedReturnTypeWithInvalidTypeThrowsException() {
435
436
		$instance = new CallbackContainerBuilder();
437
438
		$this->setExpectedException( 'InvalidArgumentException' );
439
		$instance->registerExpectedReturnType( new \stdClass, 'Bar' );
0 ignored issues
show
Documentation introduced by
new \stdClass() is of type object<stdClass>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
440
	}
441
442
	public function testRegisterFromWithInvalidFileThrowsException() {
443
444
		$instance = new CallbackContainerBuilder();
445
446
		$this->setExpectedException( 'RuntimeException' );
447
		$instance->registerFromFile( 'Foo' );
448
	}
449
450
}
451