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 }