testLoadCallbackHandlerWithExpectedReturnType()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 8
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
		$instance->registerAlias( 'Foo', 'Foobar' );
74
75
		$this->assertTrue(
76
			$instance->isRegistered( 'Foo' )
77
		);
78
79
		$instance->deregister( 'Foo' );
80
81
		$this->assertFalse(
82
			$instance->isRegistered( 'Foo' )
83
		);
84
85
		$this->assertFalse(
86
			$instance->isRegistered( 'Foobar' )
87
		);
88
	}
89
90
	public function testLoadCallbackHandlerWithExpectedReturnType() {
91
92
		$instance = new CallbackContainerBuilder();
93
94
		$instance->registerCallback( 'Foo', function() {
95
			return new \stdClass;
96
		} );
97
98
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
99
100
		$this->assertEquals(
101
			new \stdClass,
102
			$instance->create( 'Foo' )
103
		);
104
	}
105
106
	public function testLoadCallbackHandlerWithoutExpectedReturnType() {
107
108
		$instance = new CallbackContainerBuilder();
109
110
		$instance->registerCallback( 'Foo', function() {
111
			return 'abc';
112
		} );
113
114
		$this->assertEquals(
115
			'abc',
116
			$instance->create( 'Foo' )
117
		);
118
	}
119
120
	public function testRegisterCallbackContainer() {
121
122
		$instance = new CallbackContainerBuilder();
123
		$instance->registerCallbackContainer( new FakeCallbackContainer() );
124
125
		$this->assertEquals(
126
			new \stdClass,
127
			$instance->create( 'Foo' )
128
		);
129
130
		$this->assertEquals(
131
			new \stdClass,
132
			$instance->singleton( 'Foo' )
133
		);
134
	}
135
136
	public function testRegisterFromFile() {
137
138
		$instance = new CallbackContainerBuilder();
139
		$instance->registerFromFile( __DIR__ . '/../Fixtures/fakeCallbackFromFile.php' );
140
141
		$this->assertEquals(
142
			new \stdClass,
143
			$instance->create( 'SomeStdClassFromFile' )
144
		);
145
	}
146
147
	public function testRegisterFromFileWithInterFactory() {
148
149
		$instance = new CallbackContainerBuilder();
150
		$instance->registerFromFile( __DIR__ . '/../Fixtures/fakeCallbackFromFile.php' );
151
152
		$this->assertEquals(
153
			new \stdClass,
154
			$instance->create( 'AnotherStdClassFromFileWithInterFactory' )
155
		);
156
	}
157
158
	public function testRegisterFromFileWithInterFactoryAndArgument() {
159
160
		$instance = new CallbackContainerBuilder();
161
		$instance->registerFromFile( __DIR__ . '/../Fixtures/fakeCallbackFromFile.php' );
162
163
		$this->assertEquals(
164
			123,
165
			$instance->create( 'AnotherStdClassFromFileWithInterFactoryAndArgument', 123 )->argument
166
		);
167
	}
168
169
	public function testRegisterFromFileWithCircularReferenceThrowsException() {
170
171
		$instance = new CallbackContainerBuilder();
172
		$instance->registerFromFile( __DIR__ . '/../Fixtures/fakeCallbackFromFile.php' );
173
174
		$this->setExpectedException( 'Onoi\CallbackContainer\Exception\ServiceCircularReferenceException' );
175
		$instance->create( 'serviceFromFileWithForcedCircularReference' );
176
	}
177
178
	public function testRegisterObject() {
179
180
		$expected = new \stdClass;
181
182
		$instance = new CallbackContainerBuilder();
183
184
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
185
		$instance->registerObject( 'Foo', $expected );
186
187
		$this->assertEquals(
188
			$expected,
189
			$instance->create( 'Foo' )
190
		);
191
192
		$this->assertEquals(
193
			$expected,
194
			$instance->singleton( 'Foo' )
195
		);
196
	}
197
198
	public function testInjectInstanceForExistingRegisteredCallbackHandler() {
199
200
		$stdClass = $this->getMockBuilder( '\stdClass' )
201
			->disableOriginalConstructor()
202
			->getMock();
203
204
		$instance = new CallbackContainerBuilder( new FakeCallbackContainer() );
205
		$instance->singleton( 'Foo' );
206
207
		$instance->registerObject( 'Foo', $stdClass );
208
209
		$this->assertSame(
210
			$stdClass,
211
			$instance->create( 'Foo' )
212
		);
213
214
		$this->assertSame(
215
			$stdClass,
216
			$instance->singleton( 'Foo' )
217
		);
218
	}
219
220
	public function testOverrideSingletonInstanceOnRegisteredCallbackHandlerWithArguments() {
221
222
		$argument = $this->getMockBuilder( '\stdClass' )
223
			->disableOriginalConstructor()
224
			->getMock();
225
226
		$instance = new CallbackContainerBuilder(
227
			new FakeCallbackContainer()
228
		);
229
230
		$this->assertSame(
231
			$instance->singleton( 'FooWithNullArgument', $argument ),
232
			$instance->singleton( 'service.one', $argument )
233
		);
234
235
		$override = $instance->singleton( 'FooWithNullArgument', null );
236
237
		$this->assertNotSame(
238
			$override,
239
			$instance->singleton( 'FooWithNullArgument', $argument )
240
		);
241
242
		$instance->registerObject( 'FooWithNullArgument', $override );
243
244
		$this->assertSame(
245
			$override,
246
			$instance->singleton( 'FooWithNullArgument', $argument )
247
		);
248
249
		$this->assertSame(
250
			$override,
251
			$instance->singleton( 'FooWithNullArgument', null )
252
		);
253
	}
254
255
	public function testLoadParameterizedCallbackHandler() {
256
257
		$instance = new CallbackContainerBuilder();
258
259
		$instance->registerCallback( 'Foo', function( $containerBuilder, $a, $b, $c ) {
260
			$stdClass = new \stdClass;
261
			$stdClass->a = $a;
262
			$stdClass->b = $b;
263
			$stdClass->c = $c;
264
265
			return $stdClass;
266
		} );
267
268
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
269
270
		$object = new \stdClass;
271
		$object->extra = 123;
272
273
		$this->assertEquals(
274
			'abc',
275
			$instance->create( 'Foo', 'abc', 123, $object )->a
276
		);
277
278
		$this->assertEquals(
279
			$object,
280
			$instance->create( 'Foo', 'abc', 123, $object )->c
281
		);
282
	}
283
284
	public function testRecursiveBuildToLoadParameterizedCallbackHandler() {
285
286
		$instance = new CallbackContainerBuilder();
287
288
		$instance->registerCallback( 'Foo', function( $containerBuilder, $a, $b = null, $c ) {
289
			$stdClass = new \stdClass;
290
			$stdClass->a = $a;
291
			$stdClass->c = $c;
292
293
			return $stdClass;
294
		} );
295
296
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
297
298
		$instance->registerCallback( 'Bar', function( $containerBuilder, $a, $b, $c ) use( $instance ) {
299
			return $instance->create( 'Foo', $a, $b, $c );
300
		} );
301
302
		$instance->registerExpectedReturnType( 'Bar', '\stdClass' );
303
304
		$object = new \stdClass;
305
		$object->extra = 123;
306
307
		$this->assertSame(
308
			$object,
309
			$instance->create( 'Bar', 'abc', null, $object )->c
310
		);
311
	}
312
313
	public function testSingleton() {
314
315
		$instance = new CallbackContainerBuilder();
316
317
		$instance->registerCallback( 'Foo', function() {
318
			return new \stdClass;
319
		} );
320
321
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
322
323
		$singleton = $instance->singleton( 'Foo' );
324
325
		$this->assertSame(
326
			$singleton,
327
			$instance->singleton( 'Foo' )
328
		);
329
	}
330
331
	public function testFingerprintedParameterizedSingletonCallbackHandler() {
332
333
		$instance = new CallbackContainerBuilder();
334
335
		$instance->registerCallback( 'Foo', function( $containerBuilder, $a, array $b ) {
336
			$stdClass = new \stdClass;
337
			$stdClass->a = $a;
338
			$stdClass->b = $b;
339
340
			return $stdClass;
341
		} );
342
343
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
344
345
		$this->assertSame(
346
			$instance->singleton( 'Foo', 'abc', array( 'def' ) ),
347
			$instance->singleton( 'Foo', 'abc', array( 'def' ) )
348
		);
349
350
		$this->assertNotSame(
351
			$instance->singleton( 'Foo', 'abc', array( '123' ) ),
352
			$instance->singleton( 'Foo', 'abc', array( 'def' ) )
353
		);
354
	}
355
356
	public function testRegisterAlias() {
357
358
		$instance = new CallbackContainerBuilder();
359
360
		$instance->registerCallback( 'Foo', function( $containerBuilder ) {
0 ignored issues
show
Unused Code introduced by
The parameter $containerBuilder is not used and could be removed.

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

Loading history...
361
			return new \stdClass;
362
		} );
363
364
		$instance->registerAlias( 'Foo', 'Foobar' );
365
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
366
367
		$this->assertTrue(
368
			$instance->isRegistered( 'Foobar' )
369
		);
370
371
		$this->assertInstanceOf(
372
			'\stdClass',
373
			$instance->create( 'Foobar' )
374
		);
375
376
		$this->assertInstanceOf(
377
			'\stdClass',
378
			$instance->singleton( 'Foobar' )
379
		);
380
	}
381
382
	public function testRegisterAliasOnExistingServiceNameThrowsException() {
383
384
		$instance = new CallbackContainerBuilder();
385
386
		$this->setExpectedException( '\Onoi\CallbackContainer\Exception\InvalidParameterTypeException' );
387
		$instance->registerAlias( 'Foo', 123 );
388
	}
389
390
	public function testRegisterAliasOnInvalidNameThrowsException() {
391
392
		$instance = new CallbackContainerBuilder();
393
394
		$instance->registerCallback( 'Foo', function() {
395
			return new \stdClass;
396
		} );
397
398
		$this->setExpectedException( '\Onoi\CallbackContainer\Exception\ServiceAliasAssignmentException' );
399
		$instance->registerAlias( 'Foo', 'Foo' );
400
	}
401
402
	public function testRegisterAliasOnCrossedServiceAssignmentThrowsException() {
403
404
		$instance = new CallbackContainerBuilder();
405
406
		$instance->registerCallback( 'Foo', function() {
407
			return new \stdClass;
408
		} );
409
410
		$instance->registerAlias( 'Foo', 'Foobar' );
411
412
		$this->setExpectedException( '\Onoi\CallbackContainer\Exception\ServiceAliasCrossAssignmentException' );
413
		$instance->registerAlias( 'Foo2', 'Foobar' );
414
	}
415
416
	public function testRegisterObjectWithAliasThrowsException() {
417
418
		$instance = new CallbackContainerBuilder();
419
420
		$instance->registerAlias( 'Foo', 'Foobar' );
421
422
		$this->setExpectedException( '\Onoi\CallbackContainer\Exception\ServiceAliasMismatchException' );
423
		$instance->registerObject( 'Foobar', new \stdClass );
424
	}
425
426
	public function testUnregisteredServiceOnCreateThrowsException() {
427
428
		$instance = new CallbackContainerBuilder();
429
430
		$this->setExpectedException( '\Onoi\CallbackContainer\Exception\ServiceNotFoundException' );
431
		$instance->create( 'Foo' );
432
	}
433
434
	public function testUnregisteredServiceOnSingletonThrowsException() {
435
436
		$instance = new CallbackContainerBuilder();
437
438
		$this->setExpectedException( '\Onoi\CallbackContainer\Exception\ServiceNotFoundException' );
439
		$instance->singleton( 'Foo' );
440
	}
441
442
	public function testCreateFromCallbackWithTypeMismatchThrowsException() {
443
444
		$instance = new CallbackContainerBuilder();
445
446
		$instance->registerCallback( 'Foo', function() {
447
			return new \stdClass;
448
		} );
449
450
		$instance->registerExpectedReturnType( 'Foo', 'Bar' );
451
452
		$this->setExpectedException( 'RuntimeException' );
453
		$instance->create( 'Foo' );
454
	}
455
456
	public function testCreateWithInvalidNameForCallbackHandlerOnLoadThrowsException() {
457
458
		$instance = new CallbackContainerBuilder();
459
460
		$this->setExpectedException( 'InvalidArgumentException' );
461
		$instance->create( new \stdClass );
462
	}
463
464
	public function testSingletonWithInvalidNameForCallbackHandlerOnSingletonThrowsException() {
465
466
		$instance = new CallbackContainerBuilder();
467
468
		$this->setExpectedException( 'InvalidArgumentException' );
469
		$instance->singleton( new \stdClass );
470
	}
471
472
	public function testCreateOnCallbackHandlerWithCircularReferenceThrowsException() {
473
474
		$instance = new CallbackContainerBuilder();
475
476
		$this->setExpectedException( 'RuntimeException' );
477
478
		$instance->registerCallback( 'Foo', function() use ( $instance ) {
479
			return $instance->create( 'Foo' );
480
		} );
481
482
		$instance->registerExpectedReturnType( 'Foo', '\stdClass' );
483
		$instance->create( 'Foo' );
484
	}
485
486
	public function testSingletonOnCallbackHandlerWithCircularReferenceThrowsException() {
487
488
		$instance = new CallbackContainerBuilder();
489
490
		$this->setExpectedException( 'RuntimeException' );
491
492
		$instance->registerCallback( 'Foo', function() use ( $instance ) {
493
			return $instance->singleton( 'Foo' );
494
		} );
495
496
		$instance->singleton( 'Foo' );
497
	}
498
499
	public function testRegisterCallbackWithInvalidNameThrowsException() {
500
501
		$instance = new CallbackContainerBuilder();
502
503
		$this->setExpectedException( 'InvalidArgumentException' );
504
		$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...
505
			return new \stdClass;
506
		} );
507
	}
508
509
	public function testRegisterObjectWithInvalidNameThrowsException() {
510
511
		$instance = new CallbackContainerBuilder();
512
513
		$this->setExpectedException( 'InvalidArgumentException' );
514
		$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...
515
	}
516
517
	public function testRegisterExpectedReturnTypeWithInvalidTypeThrowsException() {
518
519
		$instance = new CallbackContainerBuilder();
520
521
		$this->setExpectedException( 'InvalidArgumentException' );
522
		$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...
523
	}
524
525
	public function testRegisterFromWithInvalidFileThrowsException() {
526
527
		$instance = new CallbackContainerBuilder();
528
529
		$this->setExpectedException( 'RuntimeException' );
530
		$instance->registerFromFile( 'Foo' );
531
	}
532
533
}
534