Completed
Push — master ( 3de977...cf3a23 )
by mw
9s
created

testOverrideSingletonInstanceOnRegisteredCallbackHandlerWithArguments()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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