Mercurial > hg > isophonics-drupal-site
comparison core/tests/Drupal/Tests/Component/DependencyInjection/ContainerTest.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 7a779792577d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 /** | |
4 * @file | |
5 * Contains \Drupal\Tests\Component\DependencyInjection\ContainerTest. | |
6 */ | |
7 | |
8 namespace Drupal\Tests\Component\DependencyInjection; | |
9 | |
10 use Drupal\Component\Utility\Crypt; | |
11 use PHPUnit\Framework\TestCase; | |
12 use Symfony\Component\DependencyInjection\ContainerInterface; | |
13 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; | |
14 use Symfony\Component\DependencyInjection\Exception\LogicException; | |
15 use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; | |
16 use Symfony\Component\DependencyInjection\Exception\RuntimeException; | |
17 use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; | |
18 use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; | |
19 use Prophecy\Argument; | |
20 | |
21 /** | |
22 * @coversDefaultClass \Drupal\Component\DependencyInjection\Container | |
23 * @group DependencyInjection | |
24 */ | |
25 class ContainerTest extends TestCase { | |
26 | |
27 /** | |
28 * The tested container. | |
29 * | |
30 * @var \Symfony\Component\DependencyInjection\ContainerInterface | |
31 */ | |
32 protected $container; | |
33 | |
34 /** | |
35 * The container definition used for the test. | |
36 * | |
37 * @var array | |
38 */ | |
39 protected $containerDefinition; | |
40 | |
41 /** | |
42 * The container class to be tested. | |
43 * | |
44 * @var bool | |
45 */ | |
46 protected $containerClass; | |
47 | |
48 /** | |
49 * Whether the container uses the machine-optimized format or not. | |
50 * | |
51 * @var bool | |
52 */ | |
53 protected $machineFormat; | |
54 | |
55 /** | |
56 * {@inheritdoc} | |
57 */ | |
58 protected function setUp() { | |
59 $this->machineFormat = TRUE; | |
60 $this->containerClass = '\Drupal\Component\DependencyInjection\Container'; | |
61 $this->containerDefinition = $this->getMockContainerDefinition(); | |
62 $this->container = new $this->containerClass($this->containerDefinition); | |
63 } | |
64 | |
65 /** | |
66 * Tests that passing a non-supported format throws an InvalidArgumentException. | |
67 * | |
68 * @covers ::__construct | |
69 */ | |
70 public function testConstruct() { | |
71 $container_definition = $this->getMockContainerDefinition(); | |
72 $container_definition['machine_format'] = !$this->machineFormat; | |
73 $this->setExpectedException(InvalidArgumentException::class); | |
74 $container = new $this->containerClass($container_definition); | |
75 } | |
76 | |
77 /** | |
78 * Tests that Container::getParameter() works properly. | |
79 * | |
80 * @covers ::getParameter | |
81 */ | |
82 public function testGetParameter() { | |
83 $this->assertEquals($this->containerDefinition['parameters']['some_config'], $this->container->getParameter('some_config'), 'Container parameter matches for %some_config%.'); | |
84 $this->assertEquals($this->containerDefinition['parameters']['some_other_config'], $this->container->getParameter('some_other_config'), 'Container parameter matches for %some_other_config%.'); | |
85 } | |
86 | |
87 /** | |
88 * Tests that Container::getParameter() works properly for non-existing | |
89 * parameters. | |
90 * | |
91 * @covers ::getParameter | |
92 * @covers ::getParameterAlternatives | |
93 * @covers ::getAlternatives | |
94 */ | |
95 public function testGetParameterIfNotFound() { | |
96 $this->setExpectedException(ParameterNotFoundException::class); | |
97 $this->container->getParameter('parameter_that_does_not_exist'); | |
98 } | |
99 | |
100 /** | |
101 * Tests that Container::getParameter() works properly for NULL parameters. | |
102 * | |
103 * @covers ::getParameter | |
104 */ | |
105 public function testGetParameterIfNotFoundBecauseNull() { | |
106 $this->setExpectedException(ParameterNotFoundException::class); | |
107 $this->container->getParameter(NULL); | |
108 } | |
109 | |
110 /** | |
111 * Tests that Container::hasParameter() works properly. | |
112 * | |
113 * @covers ::hasParameter | |
114 */ | |
115 public function testHasParameter() { | |
116 $this->assertTrue($this->container->hasParameter('some_config'), 'Container parameters include %some_config%.'); | |
117 $this->assertFalse($this->container->hasParameter('some_config_not_exists'), 'Container parameters do not include %some_config_not_exists%.'); | |
118 } | |
119 | |
120 /** | |
121 * Tests that Container::setParameter() in an unfrozen case works properly. | |
122 * | |
123 * @covers ::setParameter | |
124 */ | |
125 public function testSetParameterWithUnfrozenContainer() { | |
126 $container_definition = $this->containerDefinition; | |
127 $container_definition['frozen'] = FALSE; | |
128 $this->container = new $this->containerClass($container_definition); | |
129 $this->container->setParameter('some_config', 'new_value'); | |
130 $this->assertEquals('new_value', $this->container->getParameter('some_config'), 'Container parameters can be set.'); | |
131 } | |
132 | |
133 /** | |
134 * Tests that Container::setParameter() in a frozen case works properly. | |
135 * | |
136 * @covers ::setParameter | |
137 */ | |
138 public function testSetParameterWithFrozenContainer() { | |
139 $this->container = new $this->containerClass($this->containerDefinition); | |
140 $this->setExpectedException(LogicException::class); | |
141 $this->container->setParameter('some_config', 'new_value'); | |
142 } | |
143 | |
144 /** | |
145 * Tests that Container::get() works properly. | |
146 * | |
147 * @covers ::get | |
148 * @covers ::createService | |
149 */ | |
150 public function testGet() { | |
151 $container = $this->container->get('service_container'); | |
152 $this->assertSame($this->container, $container, 'Container can be retrieved from itself.'); | |
153 | |
154 // Retrieve services of the container. | |
155 $other_service_class = $this->containerDefinition['services']['other.service']['class']; | |
156 $other_service = $this->container->get('other.service'); | |
157 $this->assertInstanceOf($other_service_class, $other_service, 'other.service has the right class.'); | |
158 | |
159 $some_parameter = $this->containerDefinition['parameters']['some_config']; | |
160 $some_other_parameter = $this->containerDefinition['parameters']['some_other_config']; | |
161 | |
162 $service = $this->container->get('service.provider'); | |
163 | |
164 $this->assertEquals($other_service, $service->getSomeOtherService(), '@other.service was injected via constructor.'); | |
165 $this->assertEquals($some_parameter, $service->getSomeParameter(), '%some_config% was injected via constructor.'); | |
166 $this->assertEquals($this->container, $service->getContainer(), 'Container was injected via setter injection.'); | |
167 $this->assertEquals($some_other_parameter, $service->getSomeOtherParameter(), '%some_other_config% was injected via setter injection.'); | |
168 $this->assertEquals($service->_someProperty, 'foo', 'Service has added properties.'); | |
169 } | |
170 | |
171 /** | |
172 * Tests that Container::get() for non-shared services works properly. | |
173 * | |
174 * @covers ::get | |
175 * @covers ::createService | |
176 */ | |
177 public function testGetForNonSharedService() { | |
178 $service = $this->container->get('non_shared_service'); | |
179 $service2 = $this->container->get('non_shared_service'); | |
180 | |
181 $this->assertNotSame($service, $service2, 'Non shared services are always re-instantiated.'); | |
182 } | |
183 | |
184 /** | |
185 * Tests that Container::get() works properly for class from parameters. | |
186 * | |
187 * @covers ::get | |
188 * @covers ::createService | |
189 */ | |
190 public function testGetForClassFromParameter() { | |
191 $container_definition = $this->containerDefinition; | |
192 $container_definition['frozen'] = FALSE; | |
193 $container = new $this->containerClass($container_definition); | |
194 | |
195 $other_service_class = $this->containerDefinition['parameters']['some_parameter_class']; | |
196 $other_service = $container->get('other.service_class_from_parameter'); | |
197 $this->assertInstanceOf($other_service_class, $other_service, 'other.service_class_from_parameter has the right class.'); | |
198 } | |
199 | |
200 /** | |
201 * Tests that Container::set() works properly. | |
202 * | |
203 * @covers ::set | |
204 */ | |
205 public function testSet() { | |
206 $this->assertNull($this->container->get('new_id', ContainerInterface::NULL_ON_INVALID_REFERENCE)); | |
207 $mock_service = new MockService(); | |
208 $this->container->set('new_id', $mock_service); | |
209 | |
210 $this->assertSame($mock_service, $this->container->get('new_id'), 'A manual set service works as expected.'); | |
211 } | |
212 | |
213 /** | |
214 * Tests that Container::has() works properly. | |
215 * | |
216 * @covers ::has | |
217 */ | |
218 public function testHas() { | |
219 $this->assertTrue($this->container->has('other.service')); | |
220 $this->assertFalse($this->container->has('another.service')); | |
221 | |
222 // Set the service manually, ensure that its also respected. | |
223 $mock_service = new MockService(); | |
224 $this->container->set('another.service', $mock_service); | |
225 $this->assertTrue($this->container->has('another.service')); | |
226 } | |
227 | |
228 /** | |
229 * Tests that Container::has() for aliased services works properly. | |
230 * | |
231 * @covers ::has | |
232 */ | |
233 public function testHasForAliasedService() { | |
234 $service = $this->container->has('service.provider'); | |
235 $aliased_service = $this->container->has('service.provider_alias'); | |
236 $this->assertSame($service, $aliased_service); | |
237 } | |
238 | |
239 /** | |
240 * Tests that Container::get() for circular dependencies works properly. | |
241 * @covers ::get | |
242 * @covers ::createService | |
243 */ | |
244 public function testGetForCircularServices() { | |
245 $this->setExpectedException(ServiceCircularReferenceException::class); | |
246 $this->container->get('circular_dependency'); | |
247 } | |
248 | |
249 /** | |
250 * Tests that Container::get() for non-existent services works properly. | |
251 * | |
252 * @covers ::get | |
253 * @covers ::createService | |
254 * @covers ::getAlternatives | |
255 * @covers ::getServiceAlternatives | |
256 */ | |
257 public function testGetForNonExistantService() { | |
258 $this->setExpectedException(ServiceNotFoundException::class); | |
259 $this->container->get('service_not_exists'); | |
260 } | |
261 | |
262 /** | |
263 * Tests that Container::get() for a serialized definition works properly. | |
264 * | |
265 * @covers ::get | |
266 * @covers ::createService | |
267 */ | |
268 public function testGetForSerializedServiceDefinition() { | |
269 $container_definition = $this->containerDefinition; | |
270 $container_definition['services']['other.service'] = serialize($container_definition['services']['other.service']); | |
271 $container = new $this->containerClass($container_definition); | |
272 | |
273 // Retrieve services of the container. | |
274 $other_service_class = $this->containerDefinition['services']['other.service']['class']; | |
275 $other_service = $container->get('other.service'); | |
276 $this->assertInstanceOf($other_service_class, $other_service, 'other.service has the right class.'); | |
277 | |
278 $service = $container->get('service.provider'); | |
279 $this->assertEquals($other_service, $service->getSomeOtherService(), '@other.service was injected via constructor.'); | |
280 } | |
281 | |
282 /** | |
283 * Tests that Container::get() for non-existent parameters works properly. | |
284 * | |
285 * @covers ::get | |
286 * @covers ::createService | |
287 * @covers ::resolveServicesAndParameters | |
288 */ | |
289 public function testGetForNonExistantParameterDependency() { | |
290 $service = $this->container->get('service_parameter_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE); | |
291 $this->assertNull($service, 'Service is NULL.'); | |
292 } | |
293 | |
294 /** | |
295 * Tests Container::get() with an exception due to missing parameter on the second call. | |
296 * | |
297 * @covers ::get | |
298 * @covers ::createService | |
299 * @covers ::resolveServicesAndParameters | |
300 */ | |
301 public function testGetForParameterDependencyWithExceptionOnSecondCall() { | |
302 $service = $this->container->get('service_parameter_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE); | |
303 $this->assertNull($service, 'Service is NULL.'); | |
304 | |
305 // Reset the service. | |
306 $this->container->set('service_parameter_not_exists', NULL); | |
307 $this->setExpectedException(InvalidArgumentException::class); | |
308 $this->container->get('service_parameter_not_exists'); | |
309 } | |
310 | |
311 /** | |
312 * Tests that Container::get() for non-existent parameters works properly. | |
313 * | |
314 * @covers ::get | |
315 * @covers ::createService | |
316 * @covers ::resolveServicesAndParameters | |
317 */ | |
318 public function testGetForNonExistantParameterDependencyWithException() { | |
319 $this->setExpectedException(InvalidArgumentException::class); | |
320 $this->container->get('service_parameter_not_exists'); | |
321 } | |
322 | |
323 /** | |
324 * Tests that Container::get() for non-existent dependencies works properly. | |
325 * | |
326 * @covers ::get | |
327 * @covers ::createService | |
328 * @covers ::resolveServicesAndParameters | |
329 */ | |
330 public function testGetForNonExistantServiceDependency() { | |
331 $service = $this->container->get('service_dependency_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE); | |
332 $this->assertNull($service, 'Service is NULL.'); | |
333 } | |
334 | |
335 /** | |
336 * Tests that Container::get() for non-existent dependencies works properly. | |
337 * | |
338 * @covers ::get | |
339 * @covers ::createService | |
340 * @covers ::resolveServicesAndParameters | |
341 * @covers ::getAlternatives | |
342 */ | |
343 public function testGetForNonExistantServiceDependencyWithException() { | |
344 $this->setExpectedException(ServiceNotFoundException::class); | |
345 $this->container->get('service_dependency_not_exists'); | |
346 } | |
347 | |
348 /** | |
349 * Tests that Container::get() for non-existent services works properly. | |
350 * | |
351 * @covers ::get | |
352 * @covers ::createService | |
353 */ | |
354 public function testGetForNonExistantServiceWhenUsingNull() { | |
355 $this->assertNull($this->container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does not throw exception.'); | |
356 } | |
357 | |
358 /** | |
359 * Tests that Container::get() for NULL service works properly. | |
360 * @covers ::get | |
361 * @covers ::createService | |
362 */ | |
363 public function testGetForNonExistantNULLService() { | |
364 $this->setExpectedException(ServiceNotFoundException::class); | |
365 $this->container->get(NULL); | |
366 } | |
367 | |
368 /** | |
369 * Tests multiple Container::get() calls for non-existing dependencies work. | |
370 * | |
371 * @covers ::get | |
372 * @covers ::createService | |
373 */ | |
374 public function testGetForNonExistantServiceMultipleTimes() { | |
375 $container = new $this->containerClass(); | |
376 | |
377 $this->assertNull($container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does not throw exception.'); | |
378 $this->assertNull($container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does not throw exception on second call.'); | |
379 } | |
380 | |
381 /** | |
382 * Tests multiple Container::get() calls with exception on the second time. | |
383 * | |
384 * @covers ::get | |
385 * @covers ::createService | |
386 * @covers ::getAlternatives | |
387 */ | |
388 public function testGetForNonExistantServiceWithExceptionOnSecondCall() { | |
389 $this->assertNull($this->container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does nto throw exception.'); | |
390 $this->setExpectedException(ServiceNotFoundException::class); | |
391 $this->container->get('service_not_exists'); | |
392 } | |
393 | |
394 /** | |
395 * Tests that Container::get() for aliased services works properly. | |
396 * | |
397 * @covers ::get | |
398 * @covers ::createService | |
399 */ | |
400 public function testGetForAliasedService() { | |
401 $service = $this->container->get('service.provider'); | |
402 $aliased_service = $this->container->get('service.provider_alias'); | |
403 $this->assertSame($service, $aliased_service); | |
404 } | |
405 | |
406 /** | |
407 * Tests that Container::get() for synthetic services works - if defined. | |
408 * | |
409 * @covers ::get | |
410 * @covers ::createService | |
411 */ | |
412 public function testGetForSyntheticService() { | |
413 $synthetic_service = new \stdClass(); | |
414 $this->container->set('synthetic', $synthetic_service); | |
415 $test_service = $this->container->get('synthetic'); | |
416 $this->assertSame($synthetic_service, $test_service); | |
417 } | |
418 | |
419 /** | |
420 * Tests that Container::get() for synthetic services throws an Exception if not defined. | |
421 * | |
422 * @covers ::get | |
423 * @covers ::createService | |
424 */ | |
425 public function testGetForSyntheticServiceWithException() { | |
426 $this->setExpectedException(RuntimeException::class); | |
427 $this->container->get('synthetic'); | |
428 } | |
429 | |
430 /** | |
431 * Tests that Container::get() for services with file includes works. | |
432 * | |
433 * @covers ::get | |
434 * @covers ::createService | |
435 */ | |
436 public function testGetWithFileInclude() { | |
437 $file_service = $this->container->get('container_test_file_service_test'); | |
438 $this->assertTrue(function_exists('container_test_file_service_test_service_function')); | |
439 $this->assertEquals('Hello Container', container_test_file_service_test_service_function()); | |
440 } | |
441 | |
442 /** | |
443 * Tests that Container::get() for various arguments lengths works. | |
444 * | |
445 * @covers ::get | |
446 * @covers ::createService | |
447 * @covers ::resolveServicesAndParameters | |
448 */ | |
449 public function testGetForInstantiationWithVariousArgumentLengths() { | |
450 $args = []; | |
451 for ($i = 0; $i < 12; $i++) { | |
452 $instantiation_service = $this->container->get('service_test_instantiation_' . $i); | |
453 $this->assertEquals($args, $instantiation_service->getArguments()); | |
454 $args[] = 'arg_' . $i; | |
455 } | |
456 } | |
457 | |
458 /** | |
459 * Tests that Container::get() for wrong factories works correctly. | |
460 * | |
461 * @covers ::get | |
462 * @covers ::createService | |
463 */ | |
464 public function testGetForWrongFactory() { | |
465 $this->setExpectedException(RuntimeException::class); | |
466 $this->container->get('wrong_factory'); | |
467 } | |
468 | |
469 /** | |
470 * Tests Container::get() for factories via services (Symfony 2.7.0). | |
471 * | |
472 * @covers ::get | |
473 * @covers ::createService | |
474 */ | |
475 public function testGetForFactoryService() { | |
476 $factory_service = $this->container->get('factory_service'); | |
477 $factory_service_class = $this->container->getParameter('factory_service_class'); | |
478 $this->assertInstanceOf($factory_service_class, $factory_service); | |
479 } | |
480 | |
481 /** | |
482 * Tests that Container::get() for factories via class works (Symfony 2.7.0). | |
483 * | |
484 * @covers ::get | |
485 * @covers ::createService | |
486 */ | |
487 public function testGetForFactoryClass() { | |
488 $service = $this->container->get('service.provider'); | |
489 $factory_service = $this->container->get('factory_class'); | |
490 | |
491 $this->assertInstanceOf(get_class($service), $factory_service); | |
492 $this->assertEquals('bar', $factory_service->getSomeParameter(), 'Correct parameter was passed via the factory class instantiation.'); | |
493 $this->assertEquals($this->container, $factory_service->getContainer(), 'Container was injected via setter injection.'); | |
494 } | |
495 | |
496 /** | |
497 * Tests that Container::get() for configurable services throws an Exception. | |
498 * | |
499 * @covers ::get | |
500 * @covers ::createService | |
501 */ | |
502 public function testGetForConfiguratorWithException() { | |
503 $this->setExpectedException(InvalidArgumentException::class); | |
504 $this->container->get('configurable_service_exception'); | |
505 } | |
506 | |
507 /** | |
508 * Tests that Container::get() for configurable services works. | |
509 * | |
510 * @covers ::get | |
511 * @covers ::createService | |
512 */ | |
513 public function testGetForConfigurator() { | |
514 $container = $this->container; | |
515 | |
516 // Setup a configurator. | |
517 $configurator = $this->prophesize('\Drupal\Tests\Component\DependencyInjection\MockConfiguratorInterface'); | |
518 $configurator->configureService(Argument::type('object')) | |
519 ->shouldBeCalled(1) | |
520 ->will(function ($args) use ($container) { | |
521 $args[0]->setContainer($container); | |
522 }); | |
523 $container->set('configurator', $configurator->reveal()); | |
524 | |
525 // Test that the configurator worked. | |
526 $service = $container->get('configurable_service'); | |
527 $this->assertSame($container, $service->getContainer(), 'Container was injected via configurator.'); | |
528 } | |
529 | |
530 /** | |
531 * Tests that private services work correctly. | |
532 * | |
533 * @covers ::get | |
534 * @covers ::createService | |
535 * @covers ::resolveServicesAndParameters | |
536 */ | |
537 public function testResolveServicesAndParametersForPrivateService() { | |
538 $service = $this->container->get('service_using_private'); | |
539 $private_service = $service->getSomeOtherService(); | |
540 $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.'); | |
541 | |
542 // Test that sharing the same private services works. | |
543 $service = $this->container->get('another_service_using_private'); | |
544 $another_private_service = $service->getSomeOtherService(); | |
545 $this->assertNotSame($private_service, $another_private_service, 'Private service is not shared.'); | |
546 $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.'); | |
547 } | |
548 | |
549 /** | |
550 * Tests that private service sharing works correctly. | |
551 * | |
552 * @covers ::get | |
553 * @covers ::createService | |
554 * @covers ::resolveServicesAndParameters | |
555 */ | |
556 public function testResolveServicesAndParametersForSharedPrivateService() { | |
557 $service = $this->container->get('service_using_shared_private'); | |
558 $private_service = $service->getSomeOtherService(); | |
559 $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.'); | |
560 | |
561 // Test that sharing the same private services works. | |
562 $service = $this->container->get('another_service_using_shared_private'); | |
563 $same_private_service = $service->getSomeOtherService(); | |
564 $this->assertSame($private_service, $same_private_service, 'Private service is shared.'); | |
565 $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.'); | |
566 } | |
567 | |
568 /** | |
569 * Tests that services with an array of arguments work correctly. | |
570 * | |
571 * @covers ::get | |
572 * @covers ::createService | |
573 * @covers ::resolveServicesAndParameters | |
574 */ | |
575 public function testResolveServicesAndParametersForArgumentsUsingDeepArray() { | |
576 $service = $this->container->get('service_using_array'); | |
577 $other_service = $this->container->get('other.service'); | |
578 $this->assertEquals($other_service, $service->getSomeOtherService(), '@other.service was injected via constructor.'); | |
579 } | |
580 | |
581 /** | |
582 * Tests that services that are optional work correctly. | |
583 * | |
584 * @covers ::get | |
585 * @covers ::createService | |
586 * @covers ::resolveServicesAndParameters | |
587 */ | |
588 public function testResolveServicesAndParametersForOptionalServiceDependencies() { | |
589 $service = $this->container->get('service_with_optional_dependency'); | |
590 $this->assertNull($service->getSomeOtherService(), 'other service was NULL was expected.'); | |
591 } | |
592 | |
593 /** | |
594 * Tests that an invalid argument throw an Exception. | |
595 * | |
596 * @covers ::get | |
597 * @covers ::createService | |
598 * @covers ::resolveServicesAndParameters | |
599 */ | |
600 public function testResolveServicesAndParametersForInvalidArgument() { | |
601 $this->setExpectedException(InvalidArgumentException::class); | |
602 $this->container->get('invalid_argument_service'); | |
603 } | |
604 | |
605 /** | |
606 * Tests that invalid arguments throw an Exception. | |
607 * | |
608 * @covers ::get | |
609 * @covers ::createService | |
610 * @covers ::resolveServicesAndParameters | |
611 */ | |
612 public function testResolveServicesAndParametersForInvalidArguments() { | |
613 // In case the machine-optimized format is not used, we need to simulate the | |
614 // test failure. | |
615 $this->setExpectedException(InvalidArgumentException::class); | |
616 if (!$this->machineFormat) { | |
617 throw new InvalidArgumentException('Simulating the test failure.'); | |
618 } | |
619 $this->container->get('invalid_arguments_service'); | |
620 } | |
621 | |
622 /** | |
623 * Tests that a parameter that points to a service works correctly. | |
624 * | |
625 * @covers ::get | |
626 * @covers ::createService | |
627 * @covers ::resolveServicesAndParameters | |
628 */ | |
629 public function testResolveServicesAndParametersForServiceInstantiatedFromParameter() { | |
630 $service = $this->container->get('service.provider'); | |
631 $test_service = $this->container->get('service_with_parameter_service'); | |
632 $this->assertSame($service, $test_service->getSomeOtherService(), 'Service was passed via parameter.'); | |
633 } | |
634 | |
635 /** | |
636 * Tests that Container::initialized works correctly. | |
637 * | |
638 * @covers ::initialized | |
639 */ | |
640 public function testInitialized() { | |
641 $this->assertFalse($this->container->initialized('late.service'), 'Late service is not initialized.'); | |
642 $this->container->get('late.service'); | |
643 $this->assertTrue($this->container->initialized('late.service'), 'Late service is initialized after it was retrieved once.'); | |
644 } | |
645 | |
646 /** | |
647 * Tests that Container::initialized works correctly for aliases. | |
648 * | |
649 * @covers ::initialized | |
650 */ | |
651 public function testInitializedForAliases() { | |
652 $this->assertFalse($this->container->initialized('late.service_alias'), 'Late service is not initialized.'); | |
653 $this->container->get('late.service'); | |
654 $this->assertTrue($this->container->initialized('late.service_alias'), 'Late service is initialized after it was retrieved once.'); | |
655 } | |
656 | |
657 /** | |
658 * Tests that Container::getServiceIds() works properly. | |
659 * | |
660 * @covers ::getServiceIds | |
661 */ | |
662 public function testGetServiceIds() { | |
663 $service_definition_keys = array_keys($this->containerDefinition['services']); | |
664 $this->assertEquals($service_definition_keys, $this->container->getServiceIds(), 'Retrieved service IDs match definition.'); | |
665 | |
666 $mock_service = new MockService(); | |
667 $this->container->set('bar', $mock_service); | |
668 $this->container->set('service.provider', $mock_service); | |
669 $service_definition_keys[] = 'bar'; | |
670 | |
671 $this->assertEquals($service_definition_keys, $this->container->getServiceIds(), 'Retrieved service IDs match definition after setting new services.'); | |
672 } | |
673 | |
674 /** | |
675 * Gets a mock container definition. | |
676 * | |
677 * @return array | |
678 * Associated array with parameters and services. | |
679 */ | |
680 protected function getMockContainerDefinition() { | |
681 $fake_service = new \stdClass(); | |
682 $parameters = []; | |
683 $parameters['some_parameter_class'] = get_class($fake_service); | |
684 $parameters['some_private_config'] = 'really_private_lama'; | |
685 $parameters['some_config'] = 'foo'; | |
686 $parameters['some_other_config'] = 'lama'; | |
687 $parameters['factory_service_class'] = get_class($fake_service); | |
688 // Also test alias resolving. | |
689 $parameters['service_from_parameter'] = $this->getServiceCall('service.provider_alias'); | |
690 | |
691 $services = []; | |
692 $services['service_container'] = [ | |
693 'class' => '\Drupal\service_container\DependencyInjection\Container', | |
694 ]; | |
695 $services['other.service'] = [ | |
696 'class' => get_class($fake_service), | |
697 ]; | |
698 | |
699 $services['non_shared_service'] = [ | |
700 'class' => get_class($fake_service), | |
701 'shared' => FALSE, | |
702 ]; | |
703 | |
704 $services['other.service_class_from_parameter'] = [ | |
705 'class' => $this->getParameterCall('some_parameter_class'), | |
706 ]; | |
707 $services['late.service'] = [ | |
708 'class' => get_class($fake_service), | |
709 ]; | |
710 $services['service.provider'] = [ | |
711 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
712 'arguments' => $this->getCollection([ | |
713 $this->getServiceCall('other.service'), | |
714 $this->getParameterCall('some_config'), | |
715 ]), | |
716 'properties' => $this->getCollection(['_someProperty' => 'foo']), | |
717 'calls' => [ | |
718 [ | |
719 'setContainer', | |
720 $this->getCollection([ | |
721 $this->getServiceCall('service_container'), | |
722 ]), | |
723 ], | |
724 [ | |
725 'setOtherConfigParameter', | |
726 $this->getCollection([ | |
727 $this->getParameterCall('some_other_config'), | |
728 ]), | |
729 ], | |
730 ], | |
731 'priority' => 0, | |
732 ]; | |
733 | |
734 // Test private services. | |
735 $private_service = [ | |
736 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
737 'arguments' => $this->getCollection([ | |
738 $this->getServiceCall('other.service'), | |
739 $this->getParameterCall('some_private_config'), | |
740 ]), | |
741 'public' => FALSE, | |
742 ]; | |
743 | |
744 $services['service_using_private'] = [ | |
745 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
746 'arguments' => $this->getCollection([ | |
747 $this->getPrivateServiceCall(NULL, $private_service), | |
748 $this->getParameterCall('some_config'), | |
749 ]), | |
750 ]; | |
751 $services['another_service_using_private'] = [ | |
752 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
753 'arguments' => $this->getCollection([ | |
754 $this->getPrivateServiceCall(NULL, $private_service), | |
755 $this->getParameterCall('some_config'), | |
756 ]), | |
757 ]; | |
758 | |
759 // Test shared private services. | |
760 $id = 'private_service_shared_1'; | |
761 | |
762 $services['service_using_shared_private'] = [ | |
763 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
764 'arguments' => $this->getCollection([ | |
765 $this->getPrivateServiceCall($id, $private_service, TRUE), | |
766 $this->getParameterCall('some_config'), | |
767 ]), | |
768 ]; | |
769 $services['another_service_using_shared_private'] = [ | |
770 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
771 'arguments' => $this->getCollection([ | |
772 $this->getPrivateServiceCall($id, $private_service, TRUE), | |
773 $this->getParameterCall('some_config'), | |
774 ]), | |
775 ]; | |
776 | |
777 // Tests service with invalid argument. | |
778 $services['invalid_argument_service'] = [ | |
779 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
780 'arguments' => $this->getCollection([ | |
781 // Test passing non-strings, too. | |
782 1, | |
783 (object) [ | |
784 'type' => 'invalid', | |
785 ], | |
786 ]), | |
787 ]; | |
788 | |
789 $services['invalid_arguments_service'] = [ | |
790 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
791 'arguments' => (object) [ | |
792 'type' => 'invalid', | |
793 ], | |
794 ]; | |
795 | |
796 // Test service that needs deep-traversal. | |
797 $services['service_using_array'] = [ | |
798 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
799 'arguments' => $this->getCollection([ | |
800 $this->getCollection([ | |
801 $this->getServiceCall('other.service'), | |
802 ]), | |
803 $this->getParameterCall('some_private_config'), | |
804 ]), | |
805 ]; | |
806 | |
807 $services['service_with_optional_dependency'] = [ | |
808 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
809 'arguments' => $this->getCollection([ | |
810 $this->getServiceCall('service.does_not_exist', ContainerInterface::NULL_ON_INVALID_REFERENCE), | |
811 $this->getParameterCall('some_private_config'), | |
812 ]), | |
813 | |
814 ]; | |
815 | |
816 $services['factory_service'] = [ | |
817 'class' => '\Drupal\service_container\ServiceContainer\ControllerInterface', | |
818 'factory' => [ | |
819 $this->getServiceCall('service.provider'), | |
820 'getFactoryMethod', | |
821 ], | |
822 'arguments' => $this->getCollection([ | |
823 $this->getParameterCall('factory_service_class'), | |
824 ]), | |
825 ]; | |
826 $services['factory_class'] = [ | |
827 'class' => '\Drupal\service_container\ServiceContainer\ControllerInterface', | |
828 'factory' => '\Drupal\Tests\Component\DependencyInjection\MockService::getFactoryMethod', | |
829 'arguments' => [ | |
830 '\Drupal\Tests\Component\DependencyInjection\MockService', | |
831 [NULL, 'bar'], | |
832 ], | |
833 'calls' => [ | |
834 [ | |
835 'setContainer', | |
836 $this->getCollection([ | |
837 $this->getServiceCall('service_container'), | |
838 ]), | |
839 ], | |
840 ], | |
841 ]; | |
842 | |
843 $services['wrong_factory'] = [ | |
844 'class' => '\Drupal\service_container\ServiceContainer\ControllerInterface', | |
845 'factory' => (object) ['I am not a factory, but I pretend to be.'], | |
846 ]; | |
847 | |
848 $services['circular_dependency'] = [ | |
849 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
850 'arguments' => $this->getCollection([ | |
851 $this->getServiceCall('circular_dependency'), | |
852 ]), | |
853 ]; | |
854 $services['synthetic'] = [ | |
855 'synthetic' => TRUE, | |
856 ]; | |
857 // The file could have been named as a .php file. The reason it is a .data | |
858 // file is that SimpleTest tries to load it. SimpleTest does not like such | |
859 // fixtures and hence we use a neutral name like .data. | |
860 $services['container_test_file_service_test'] = [ | |
861 'class' => '\stdClass', | |
862 'file' => __DIR__ . '/Fixture/container_test_file_service_test_service_function.data', | |
863 ]; | |
864 | |
865 // Test multiple arguments. | |
866 $args = []; | |
867 for ($i = 0; $i < 12; $i++) { | |
868 $services['service_test_instantiation_' . $i] = [ | |
869 'class' => '\Drupal\Tests\Component\DependencyInjection\MockInstantiationService', | |
870 // Also test a collection that does not need resolving. | |
871 'arguments' => $this->getCollection($args, FALSE), | |
872 ]; | |
873 $args[] = 'arg_' . $i; | |
874 } | |
875 | |
876 $services['service_parameter_not_exists'] = [ | |
877 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
878 'arguments' => $this->getCollection([ | |
879 $this->getServiceCall('service.provider'), | |
880 $this->getParameterCall('not_exists'), | |
881 ]), | |
882 ]; | |
883 $services['service_dependency_not_exists'] = [ | |
884 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
885 'arguments' => $this->getCollection([ | |
886 $this->getServiceCall('service_not_exists'), | |
887 $this->getParameterCall('some_config'), | |
888 ]), | |
889 ]; | |
890 | |
891 $services['service_with_parameter_service'] = [ | |
892 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
893 'arguments' => $this->getCollection([ | |
894 $this->getParameterCall('service_from_parameter'), | |
895 // Also test deep collections that don't need resolving. | |
896 $this->getCollection([ | |
897 1, | |
898 ], FALSE), | |
899 ]), | |
900 ]; | |
901 | |
902 // To ensure getAlternatives() finds something. | |
903 $services['service_not_exists_similar'] = [ | |
904 'synthetic' => TRUE, | |
905 ]; | |
906 | |
907 // Test configurator. | |
908 $services['configurator'] = [ | |
909 'synthetic' => TRUE, | |
910 ]; | |
911 $services['configurable_service'] = [ | |
912 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
913 'arguments' => [], | |
914 'configurator' => [ | |
915 $this->getServiceCall('configurator'), | |
916 'configureService' | |
917 ], | |
918 ]; | |
919 $services['configurable_service_exception'] = [ | |
920 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', | |
921 'arguments' => [], | |
922 'configurator' => 'configurator_service_test_does_not_exist', | |
923 ]; | |
924 | |
925 $aliases = []; | |
926 $aliases['service.provider_alias'] = 'service.provider'; | |
927 $aliases['late.service_alias'] = 'late.service'; | |
928 | |
929 return [ | |
930 'aliases' => $aliases, | |
931 'parameters' => $parameters, | |
932 'services' => $services, | |
933 'frozen' => TRUE, | |
934 'machine_format' => $this->machineFormat, | |
935 ]; | |
936 } | |
937 | |
938 /** | |
939 * Helper function to return a service definition. | |
940 */ | |
941 protected function getServiceCall($id, $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) { | |
942 return (object) [ | |
943 'type' => 'service', | |
944 'id' => $id, | |
945 'invalidBehavior' => $invalid_behavior, | |
946 ]; | |
947 } | |
948 | |
949 /** | |
950 * Helper function to return a service definition. | |
951 */ | |
952 protected function getParameterCall($name) { | |
953 return (object) [ | |
954 'type' => 'parameter', | |
955 'name' => $name, | |
956 ]; | |
957 } | |
958 | |
959 /** | |
960 * Helper function to return a private service definition. | |
961 */ | |
962 protected function getPrivateServiceCall($id, $service_definition, $shared = FALSE) { | |
963 if (!$id) { | |
964 $hash = Crypt::hashBase64(serialize($service_definition)); | |
965 $id = 'private__' . $hash; | |
966 } | |
967 return (object) [ | |
968 'type' => 'private_service', | |
969 'id' => $id, | |
970 'value' => $service_definition, | |
971 'shared' => $shared, | |
972 ]; | |
973 } | |
974 | |
975 /** | |
976 * Helper function to return a machine-optimized collection. | |
977 */ | |
978 protected function getCollection($collection, $resolve = TRUE) { | |
979 return (object) [ | |
980 'type' => 'collection', | |
981 'value' => $collection, | |
982 'resolve' => $resolve, | |
983 ]; | |
984 } | |
985 | |
986 } | |
987 | |
988 /** | |
989 * Helper interface to test Container::get() with configurator. | |
990 * | |
991 * @group DependencyInjection | |
992 */ | |
993 interface MockConfiguratorInterface { | |
994 | |
995 /** | |
996 * Configures a service. | |
997 * | |
998 * @param object $service | |
999 * The service to configure. | |
1000 */ | |
1001 public function configureService($service); | |
1002 | |
1003 } | |
1004 | |
1005 | |
1006 /** | |
1007 * Helper class to test Container::get() method for varying number of parameters. | |
1008 * | |
1009 * @group DependencyInjection | |
1010 */ | |
1011 class MockInstantiationService { | |
1012 | |
1013 /** | |
1014 * @var mixed[] | |
1015 */ | |
1016 protected $arguments; | |
1017 | |
1018 /** | |
1019 * Construct a mock instantiation service. | |
1020 */ | |
1021 public function __construct() { | |
1022 $this->arguments = func_get_args(); | |
1023 } | |
1024 | |
1025 /** | |
1026 * Return arguments injected into the service. | |
1027 * | |
1028 * @return mixed[] | |
1029 * Return the passed arguments. | |
1030 */ | |
1031 public function getArguments() { | |
1032 return $this->arguments; | |
1033 } | |
1034 | |
1035 } | |
1036 | |
1037 | |
1038 /** | |
1039 * Helper class to test Container::get() method. | |
1040 * | |
1041 * @group DependencyInjection | |
1042 */ | |
1043 class MockService { | |
1044 | |
1045 /** | |
1046 * @var ContainerInterface | |
1047 */ | |
1048 protected $container; | |
1049 | |
1050 /** | |
1051 * @var object | |
1052 */ | |
1053 protected $someOtherService; | |
1054 | |
1055 /** | |
1056 * @var string | |
1057 */ | |
1058 protected $someParameter; | |
1059 | |
1060 /** | |
1061 * @var string | |
1062 */ | |
1063 protected $someOtherParameter; | |
1064 | |
1065 /** | |
1066 * Constructs a MockService object. | |
1067 * | |
1068 * @param object $some_other_service | |
1069 * (optional) Another injected service. | |
1070 * @param string $some_parameter | |
1071 * (optional) An injected parameter. | |
1072 */ | |
1073 public function __construct($some_other_service = NULL, $some_parameter = NULL) { | |
1074 if (is_array($some_other_service)) { | |
1075 $some_other_service = $some_other_service[0]; | |
1076 } | |
1077 $this->someOtherService = $some_other_service; | |
1078 $this->someParameter = $some_parameter; | |
1079 } | |
1080 | |
1081 /** | |
1082 * Sets the container object. | |
1083 * | |
1084 * @param ContainerInterface $container | |
1085 * The container to inject via setter injection. | |
1086 */ | |
1087 public function setContainer(ContainerInterface $container) { | |
1088 $this->container = $container; | |
1089 } | |
1090 | |
1091 /** | |
1092 * Gets the container object. | |
1093 * | |
1094 * @return ContainerInterface | |
1095 * The internally set container. | |
1096 */ | |
1097 public function getContainer() { | |
1098 return $this->container; | |
1099 } | |
1100 | |
1101 /** | |
1102 * Gets the someOtherService object. | |
1103 * | |
1104 * @return object | |
1105 * The injected service. | |
1106 */ | |
1107 public function getSomeOtherService() { | |
1108 return $this->someOtherService; | |
1109 } | |
1110 | |
1111 /** | |
1112 * Gets the someParameter property. | |
1113 * | |
1114 * @return string | |
1115 * The injected parameter. | |
1116 */ | |
1117 public function getSomeParameter() { | |
1118 return $this->someParameter; | |
1119 } | |
1120 | |
1121 /** | |
1122 * Sets the someOtherParameter property. | |
1123 * | |
1124 * @param string $some_other_parameter | |
1125 * The setter injected parameter. | |
1126 */ | |
1127 public function setOtherConfigParameter($some_other_parameter) { | |
1128 $this->someOtherParameter = $some_other_parameter; | |
1129 } | |
1130 | |
1131 /** | |
1132 * Gets the someOtherParameter property. | |
1133 * | |
1134 * @return string | |
1135 * The injected parameter. | |
1136 */ | |
1137 public function getSomeOtherParameter() { | |
1138 return $this->someOtherParameter; | |
1139 } | |
1140 | |
1141 /** | |
1142 * Provides a factory method to get a service. | |
1143 * | |
1144 * @param string $class | |
1145 * The class name of the class to instantiate | |
1146 * @param array $arguments | |
1147 * (optional) Arguments to pass to the new class. | |
1148 * | |
1149 * @return object | |
1150 * The instantiated service object. | |
1151 */ | |
1152 public static function getFactoryMethod($class, $arguments = []) { | |
1153 $r = new \ReflectionClass($class); | |
1154 $service = ($r->getConstructor() === NULL) ? $r->newInstance() : $r->newInstanceArgs($arguments); | |
1155 | |
1156 return $service; | |
1157 } | |
1158 | |
1159 } |