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