Chris@0: machineFormat = TRUE; Chris@0: $this->containerClass = '\Drupal\Component\DependencyInjection\Container'; Chris@0: $this->containerDefinition = $this->getMockContainerDefinition(); Chris@0: $this->container = new $this->containerClass($this->containerDefinition); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that passing a non-supported format throws an InvalidArgumentException. Chris@0: * Chris@0: * @covers ::__construct Chris@0: */ Chris@0: public function testConstruct() { Chris@0: $container_definition = $this->getMockContainerDefinition(); Chris@0: $container_definition['machine_format'] = !$this->machineFormat; Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(InvalidArgumentException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(InvalidArgumentException::class); Chris@14: } Chris@0: $container = new $this->containerClass($container_definition); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::getParameter() works properly. Chris@0: * Chris@0: * @covers ::getParameter Chris@0: */ Chris@0: public function testGetParameter() { Chris@0: $this->assertEquals($this->containerDefinition['parameters']['some_config'], $this->container->getParameter('some_config'), 'Container parameter matches for %some_config%.'); Chris@0: $this->assertEquals($this->containerDefinition['parameters']['some_other_config'], $this->container->getParameter('some_other_config'), 'Container parameter matches for %some_other_config%.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::getParameter() works properly for non-existing Chris@0: * parameters. Chris@0: * Chris@0: * @covers ::getParameter Chris@0: * @covers ::getParameterAlternatives Chris@0: * @covers ::getAlternatives Chris@0: */ Chris@0: public function testGetParameterIfNotFound() { Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(ParameterNotFoundException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(ParameterNotFoundException::class); Chris@14: } Chris@0: $this->container->getParameter('parameter_that_does_not_exist'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::getParameter() works properly for NULL parameters. Chris@0: * Chris@0: * @covers ::getParameter Chris@0: */ Chris@0: public function testGetParameterIfNotFoundBecauseNull() { Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(ParameterNotFoundException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(ParameterNotFoundException::class); Chris@14: } Chris@0: $this->container->getParameter(NULL); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::hasParameter() works properly. Chris@0: * Chris@0: * @covers ::hasParameter Chris@0: */ Chris@0: public function testHasParameter() { Chris@0: $this->assertTrue($this->container->hasParameter('some_config'), 'Container parameters include %some_config%.'); Chris@0: $this->assertFalse($this->container->hasParameter('some_config_not_exists'), 'Container parameters do not include %some_config_not_exists%.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::setParameter() in an unfrozen case works properly. Chris@0: * Chris@0: * @covers ::setParameter Chris@0: */ Chris@0: public function testSetParameterWithUnfrozenContainer() { Chris@0: $container_definition = $this->containerDefinition; Chris@0: $container_definition['frozen'] = FALSE; Chris@0: $this->container = new $this->containerClass($container_definition); Chris@0: $this->container->setParameter('some_config', 'new_value'); Chris@0: $this->assertEquals('new_value', $this->container->getParameter('some_config'), 'Container parameters can be set.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::setParameter() in a frozen case works properly. Chris@0: * Chris@0: * @covers ::setParameter Chris@0: */ Chris@0: public function testSetParameterWithFrozenContainer() { Chris@0: $this->container = new $this->containerClass($this->containerDefinition); Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(LogicException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(LogicException::class); Chris@14: } Chris@0: $this->container->setParameter('some_config', 'new_value'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() works properly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGet() { Chris@0: $container = $this->container->get('service_container'); Chris@0: $this->assertSame($this->container, $container, 'Container can be retrieved from itself.'); Chris@0: Chris@0: // Retrieve services of the container. Chris@0: $other_service_class = $this->containerDefinition['services']['other.service']['class']; Chris@0: $other_service = $this->container->get('other.service'); Chris@0: $this->assertInstanceOf($other_service_class, $other_service, 'other.service has the right class.'); Chris@0: Chris@0: $some_parameter = $this->containerDefinition['parameters']['some_config']; Chris@0: $some_other_parameter = $this->containerDefinition['parameters']['some_other_config']; Chris@0: Chris@0: $service = $this->container->get('service.provider'); Chris@0: Chris@0: $this->assertEquals($other_service, $service->getSomeOtherService(), '@other.service was injected via constructor.'); Chris@0: $this->assertEquals($some_parameter, $service->getSomeParameter(), '%some_config% was injected via constructor.'); Chris@0: $this->assertEquals($this->container, $service->getContainer(), 'Container was injected via setter injection.'); Chris@0: $this->assertEquals($some_other_parameter, $service->getSomeOtherParameter(), '%some_other_config% was injected via setter injection.'); Chris@0: $this->assertEquals($service->_someProperty, 'foo', 'Service has added properties.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for non-shared services works properly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForNonSharedService() { Chris@0: $service = $this->container->get('non_shared_service'); Chris@0: $service2 = $this->container->get('non_shared_service'); Chris@0: Chris@0: $this->assertNotSame($service, $service2, 'Non shared services are always re-instantiated.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() works properly for class from parameters. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForClassFromParameter() { Chris@0: $container_definition = $this->containerDefinition; Chris@0: $container_definition['frozen'] = FALSE; Chris@0: $container = new $this->containerClass($container_definition); Chris@0: Chris@0: $other_service_class = $this->containerDefinition['parameters']['some_parameter_class']; Chris@0: $other_service = $container->get('other.service_class_from_parameter'); Chris@0: $this->assertInstanceOf($other_service_class, $other_service, 'other.service_class_from_parameter has the right class.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::set() works properly. Chris@0: * Chris@0: * @covers ::set Chris@0: */ Chris@0: public function testSet() { Chris@0: $this->assertNull($this->container->get('new_id', ContainerInterface::NULL_ON_INVALID_REFERENCE)); Chris@0: $mock_service = new MockService(); Chris@0: $this->container->set('new_id', $mock_service); Chris@0: Chris@0: $this->assertSame($mock_service, $this->container->get('new_id'), 'A manual set service works as expected.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::has() works properly. Chris@0: * Chris@0: * @covers ::has Chris@0: */ Chris@0: public function testHas() { Chris@0: $this->assertTrue($this->container->has('other.service')); Chris@0: $this->assertFalse($this->container->has('another.service')); Chris@0: Chris@0: // Set the service manually, ensure that its also respected. Chris@0: $mock_service = new MockService(); Chris@0: $this->container->set('another.service', $mock_service); Chris@0: $this->assertTrue($this->container->has('another.service')); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::has() for aliased services works properly. Chris@0: * Chris@0: * @covers ::has Chris@0: */ Chris@0: public function testHasForAliasedService() { Chris@0: $service = $this->container->has('service.provider'); Chris@0: $aliased_service = $this->container->has('service.provider_alias'); Chris@0: $this->assertSame($service, $aliased_service); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for circular dependencies works properly. Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForCircularServices() { Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(ServiceCircularReferenceException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(ServiceCircularReferenceException::class); Chris@14: } Chris@0: $this->container->get('circular_dependency'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for non-existent services works properly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::getAlternatives Chris@0: * @covers ::getServiceAlternatives Chris@0: */ Chris@0: public function testGetForNonExistantService() { Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(ServiceNotFoundException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(ServiceNotFoundException::class); Chris@14: } Chris@0: $this->container->get('service_not_exists'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for a serialized definition works properly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForSerializedServiceDefinition() { Chris@0: $container_definition = $this->containerDefinition; Chris@0: $container_definition['services']['other.service'] = serialize($container_definition['services']['other.service']); Chris@0: $container = new $this->containerClass($container_definition); Chris@0: Chris@0: // Retrieve services of the container. Chris@0: $other_service_class = $this->containerDefinition['services']['other.service']['class']; Chris@0: $other_service = $container->get('other.service'); Chris@0: $this->assertInstanceOf($other_service_class, $other_service, 'other.service has the right class.'); Chris@0: Chris@0: $service = $container->get('service.provider'); Chris@0: $this->assertEquals($other_service, $service->getSomeOtherService(), '@other.service was injected via constructor.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for non-existent parameters works properly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::resolveServicesAndParameters Chris@0: */ Chris@0: public function testGetForNonExistantParameterDependency() { Chris@0: $service = $this->container->get('service_parameter_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE); Chris@0: $this->assertNull($service, 'Service is NULL.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests Container::get() with an exception due to missing parameter on the second call. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::resolveServicesAndParameters Chris@0: */ Chris@0: public function testGetForParameterDependencyWithExceptionOnSecondCall() { Chris@0: $service = $this->container->get('service_parameter_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE); Chris@0: $this->assertNull($service, 'Service is NULL.'); Chris@0: Chris@0: // Reset the service. Chris@0: $this->container->set('service_parameter_not_exists', NULL); Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(InvalidArgumentException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(InvalidArgumentException::class); Chris@14: } Chris@0: $this->container->get('service_parameter_not_exists'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for non-existent parameters works properly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::resolveServicesAndParameters Chris@0: */ Chris@0: public function testGetForNonExistantParameterDependencyWithException() { Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(InvalidArgumentException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(InvalidArgumentException::class); Chris@14: } Chris@0: $this->container->get('service_parameter_not_exists'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for non-existent dependencies works properly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::resolveServicesAndParameters Chris@0: */ Chris@0: public function testGetForNonExistantServiceDependency() { Chris@0: $service = $this->container->get('service_dependency_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE); Chris@0: $this->assertNull($service, 'Service is NULL.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for non-existent dependencies works properly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::resolveServicesAndParameters Chris@0: * @covers ::getAlternatives Chris@0: */ Chris@0: public function testGetForNonExistantServiceDependencyWithException() { Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(ServiceNotFoundException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(ServiceNotFoundException::class); Chris@14: } Chris@0: $this->container->get('service_dependency_not_exists'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for non-existent services works properly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForNonExistantServiceWhenUsingNull() { Chris@0: $this->assertNull($this->container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does not throw exception.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for NULL service works properly. Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForNonExistantNULLService() { Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(ServiceNotFoundException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(ServiceNotFoundException::class); Chris@14: } Chris@0: $this->container->get(NULL); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests multiple Container::get() calls for non-existing dependencies work. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForNonExistantServiceMultipleTimes() { Chris@0: $container = new $this->containerClass(); Chris@0: Chris@0: $this->assertNull($container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does not throw exception.'); Chris@0: $this->assertNull($container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does not throw exception on second call.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests multiple Container::get() calls with exception on the second time. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::getAlternatives Chris@0: */ Chris@0: public function testGetForNonExistantServiceWithExceptionOnSecondCall() { Chris@0: $this->assertNull($this->container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does nto throw exception.'); Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(ServiceNotFoundException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(ServiceNotFoundException::class); Chris@14: } Chris@0: $this->container->get('service_not_exists'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for aliased services works properly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForAliasedService() { Chris@0: $service = $this->container->get('service.provider'); Chris@0: $aliased_service = $this->container->get('service.provider_alias'); Chris@0: $this->assertSame($service, $aliased_service); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for synthetic services works - if defined. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForSyntheticService() { Chris@0: $synthetic_service = new \stdClass(); Chris@0: $this->container->set('synthetic', $synthetic_service); Chris@0: $test_service = $this->container->get('synthetic'); Chris@0: $this->assertSame($synthetic_service, $test_service); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for synthetic services throws an Exception if not defined. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForSyntheticServiceWithException() { Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(RuntimeException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(RuntimeException::class); Chris@14: } Chris@0: $this->container->get('synthetic'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for services with file includes works. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetWithFileInclude() { Chris@0: $file_service = $this->container->get('container_test_file_service_test'); Chris@0: $this->assertTrue(function_exists('container_test_file_service_test_service_function')); Chris@0: $this->assertEquals('Hello Container', container_test_file_service_test_service_function()); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for various arguments lengths works. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::resolveServicesAndParameters Chris@0: */ Chris@0: public function testGetForInstantiationWithVariousArgumentLengths() { Chris@0: $args = []; Chris@0: for ($i = 0; $i < 12; $i++) { Chris@0: $instantiation_service = $this->container->get('service_test_instantiation_' . $i); Chris@0: $this->assertEquals($args, $instantiation_service->getArguments()); Chris@0: $args[] = 'arg_' . $i; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for wrong factories works correctly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForWrongFactory() { Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(RuntimeException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(RuntimeException::class); Chris@14: } Chris@0: $this->container->get('wrong_factory'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests Container::get() for factories via services (Symfony 2.7.0). Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForFactoryService() { Chris@0: $factory_service = $this->container->get('factory_service'); Chris@0: $factory_service_class = $this->container->getParameter('factory_service_class'); Chris@0: $this->assertInstanceOf($factory_service_class, $factory_service); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for factories via class works (Symfony 2.7.0). Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForFactoryClass() { Chris@0: $service = $this->container->get('service.provider'); Chris@0: $factory_service = $this->container->get('factory_class'); Chris@0: Chris@0: $this->assertInstanceOf(get_class($service), $factory_service); Chris@0: $this->assertEquals('bar', $factory_service->getSomeParameter(), 'Correct parameter was passed via the factory class instantiation.'); Chris@0: $this->assertEquals($this->container, $factory_service->getContainer(), 'Container was injected via setter injection.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for configurable services throws an Exception. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForConfiguratorWithException() { Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(InvalidArgumentException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(InvalidArgumentException::class); Chris@14: } Chris@0: $this->container->get('configurable_service_exception'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::get() for configurable services works. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: */ Chris@0: public function testGetForConfigurator() { Chris@0: $container = $this->container; Chris@0: Chris@0: // Setup a configurator. Chris@0: $configurator = $this->prophesize('\Drupal\Tests\Component\DependencyInjection\MockConfiguratorInterface'); Chris@0: $configurator->configureService(Argument::type('object')) Chris@0: ->shouldBeCalled(1) Chris@0: ->will(function ($args) use ($container) { Chris@0: $args[0]->setContainer($container); Chris@0: }); Chris@0: $container->set('configurator', $configurator->reveal()); Chris@0: Chris@0: // Test that the configurator worked. Chris@0: $service = $container->get('configurable_service'); Chris@0: $this->assertSame($container, $service->getContainer(), 'Container was injected via configurator.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that private services work correctly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::resolveServicesAndParameters Chris@0: */ Chris@0: public function testResolveServicesAndParametersForPrivateService() { Chris@0: $service = $this->container->get('service_using_private'); Chris@0: $private_service = $service->getSomeOtherService(); Chris@0: $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.'); Chris@0: Chris@0: // Test that sharing the same private services works. Chris@0: $service = $this->container->get('another_service_using_private'); Chris@0: $another_private_service = $service->getSomeOtherService(); Chris@0: $this->assertNotSame($private_service, $another_private_service, 'Private service is not shared.'); Chris@0: $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that private service sharing works correctly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::resolveServicesAndParameters Chris@0: */ Chris@0: public function testResolveServicesAndParametersForSharedPrivateService() { Chris@0: $service = $this->container->get('service_using_shared_private'); Chris@0: $private_service = $service->getSomeOtherService(); Chris@0: $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.'); Chris@0: Chris@0: // Test that sharing the same private services works. Chris@0: $service = $this->container->get('another_service_using_shared_private'); Chris@0: $same_private_service = $service->getSomeOtherService(); Chris@0: $this->assertSame($private_service, $same_private_service, 'Private service is shared.'); Chris@0: $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that services with an array of arguments work correctly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::resolveServicesAndParameters Chris@0: */ Chris@0: public function testResolveServicesAndParametersForArgumentsUsingDeepArray() { Chris@0: $service = $this->container->get('service_using_array'); Chris@0: $other_service = $this->container->get('other.service'); Chris@0: $this->assertEquals($other_service, $service->getSomeOtherService(), '@other.service was injected via constructor.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that services that are optional work correctly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::resolveServicesAndParameters Chris@0: */ Chris@0: public function testResolveServicesAndParametersForOptionalServiceDependencies() { Chris@0: $service = $this->container->get('service_with_optional_dependency'); Chris@0: $this->assertNull($service->getSomeOtherService(), 'other service was NULL was expected.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that an invalid argument throw an Exception. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::resolveServicesAndParameters Chris@0: */ Chris@0: public function testResolveServicesAndParametersForInvalidArgument() { Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(InvalidArgumentException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(InvalidArgumentException::class); Chris@14: } Chris@0: $this->container->get('invalid_argument_service'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that invalid arguments throw an Exception. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::resolveServicesAndParameters Chris@0: */ Chris@0: public function testResolveServicesAndParametersForInvalidArguments() { Chris@0: // In case the machine-optimized format is not used, we need to simulate the Chris@0: // test failure. Chris@14: if (method_exists($this, 'expectException')) { Chris@14: $this->expectException(InvalidArgumentException::class); Chris@14: } Chris@14: else { Chris@14: $this->setExpectedException(InvalidArgumentException::class); Chris@14: } Chris@0: if (!$this->machineFormat) { Chris@0: throw new InvalidArgumentException('Simulating the test failure.'); Chris@0: } Chris@0: $this->container->get('invalid_arguments_service'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that a parameter that points to a service works correctly. Chris@0: * Chris@0: * @covers ::get Chris@0: * @covers ::createService Chris@0: * @covers ::resolveServicesAndParameters Chris@0: */ Chris@0: public function testResolveServicesAndParametersForServiceInstantiatedFromParameter() { Chris@0: $service = $this->container->get('service.provider'); Chris@0: $test_service = $this->container->get('service_with_parameter_service'); Chris@0: $this->assertSame($service, $test_service->getSomeOtherService(), 'Service was passed via parameter.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::initialized works correctly. Chris@0: * Chris@0: * @covers ::initialized Chris@0: */ Chris@0: public function testInitialized() { Chris@0: $this->assertFalse($this->container->initialized('late.service'), 'Late service is not initialized.'); Chris@0: $this->container->get('late.service'); Chris@0: $this->assertTrue($this->container->initialized('late.service'), 'Late service is initialized after it was retrieved once.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::initialized works correctly for aliases. Chris@0: * Chris@0: * @covers ::initialized Chris@0: */ Chris@0: public function testInitializedForAliases() { Chris@0: $this->assertFalse($this->container->initialized('late.service_alias'), 'Late service is not initialized.'); Chris@0: $this->container->get('late.service'); Chris@0: $this->assertTrue($this->container->initialized('late.service_alias'), 'Late service is initialized after it was retrieved once.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that Container::getServiceIds() works properly. Chris@0: * Chris@0: * @covers ::getServiceIds Chris@0: */ Chris@0: public function testGetServiceIds() { Chris@0: $service_definition_keys = array_keys($this->containerDefinition['services']); Chris@0: $this->assertEquals($service_definition_keys, $this->container->getServiceIds(), 'Retrieved service IDs match definition.'); Chris@0: Chris@0: $mock_service = new MockService(); Chris@0: $this->container->set('bar', $mock_service); Chris@0: $this->container->set('service.provider', $mock_service); Chris@0: $service_definition_keys[] = 'bar'; Chris@0: Chris@0: $this->assertEquals($service_definition_keys, $this->container->getServiceIds(), 'Retrieved service IDs match definition after setting new services.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets a mock container definition. Chris@0: * Chris@0: * @return array Chris@0: * Associated array with parameters and services. Chris@0: */ Chris@0: protected function getMockContainerDefinition() { Chris@0: $fake_service = new \stdClass(); Chris@0: $parameters = []; Chris@0: $parameters['some_parameter_class'] = get_class($fake_service); Chris@0: $parameters['some_private_config'] = 'really_private_lama'; Chris@0: $parameters['some_config'] = 'foo'; Chris@0: $parameters['some_other_config'] = 'lama'; Chris@0: $parameters['factory_service_class'] = get_class($fake_service); Chris@0: // Also test alias resolving. Chris@0: $parameters['service_from_parameter'] = $this->getServiceCall('service.provider_alias'); Chris@0: Chris@0: $services = []; Chris@0: $services['service_container'] = [ Chris@0: 'class' => '\Drupal\service_container\DependencyInjection\Container', Chris@0: ]; Chris@0: $services['other.service'] = [ Chris@0: 'class' => get_class($fake_service), Chris@0: ]; Chris@0: Chris@0: $services['non_shared_service'] = [ Chris@0: 'class' => get_class($fake_service), Chris@0: 'shared' => FALSE, Chris@0: ]; Chris@0: Chris@0: $services['other.service_class_from_parameter'] = [ Chris@0: 'class' => $this->getParameterCall('some_parameter_class'), Chris@0: ]; Chris@0: $services['late.service'] = [ Chris@0: 'class' => get_class($fake_service), Chris@0: ]; Chris@0: $services['service.provider'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => $this->getCollection([ Chris@0: $this->getServiceCall('other.service'), Chris@0: $this->getParameterCall('some_config'), Chris@0: ]), Chris@0: 'properties' => $this->getCollection(['_someProperty' => 'foo']), Chris@0: 'calls' => [ Chris@0: [ Chris@0: 'setContainer', Chris@0: $this->getCollection([ Chris@0: $this->getServiceCall('service_container'), Chris@0: ]), Chris@0: ], Chris@0: [ Chris@0: 'setOtherConfigParameter', Chris@0: $this->getCollection([ Chris@0: $this->getParameterCall('some_other_config'), Chris@0: ]), Chris@0: ], Chris@0: ], Chris@0: 'priority' => 0, Chris@0: ]; Chris@0: Chris@0: // Test private services. Chris@0: $private_service = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => $this->getCollection([ Chris@0: $this->getServiceCall('other.service'), Chris@0: $this->getParameterCall('some_private_config'), Chris@0: ]), Chris@0: 'public' => FALSE, Chris@0: ]; Chris@0: Chris@0: $services['service_using_private'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => $this->getCollection([ Chris@0: $this->getPrivateServiceCall(NULL, $private_service), Chris@0: $this->getParameterCall('some_config'), Chris@0: ]), Chris@0: ]; Chris@0: $services['another_service_using_private'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => $this->getCollection([ Chris@0: $this->getPrivateServiceCall(NULL, $private_service), Chris@0: $this->getParameterCall('some_config'), Chris@0: ]), Chris@0: ]; Chris@0: Chris@0: // Test shared private services. Chris@0: $id = 'private_service_shared_1'; Chris@0: Chris@0: $services['service_using_shared_private'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => $this->getCollection([ Chris@0: $this->getPrivateServiceCall($id, $private_service, TRUE), Chris@0: $this->getParameterCall('some_config'), Chris@0: ]), Chris@0: ]; Chris@0: $services['another_service_using_shared_private'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => $this->getCollection([ Chris@0: $this->getPrivateServiceCall($id, $private_service, TRUE), Chris@0: $this->getParameterCall('some_config'), Chris@0: ]), Chris@0: ]; Chris@0: Chris@0: // Tests service with invalid argument. Chris@0: $services['invalid_argument_service'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => $this->getCollection([ Chris@0: // Test passing non-strings, too. Chris@0: 1, Chris@0: (object) [ Chris@0: 'type' => 'invalid', Chris@0: ], Chris@0: ]), Chris@0: ]; Chris@0: Chris@0: $services['invalid_arguments_service'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => (object) [ Chris@0: 'type' => 'invalid', Chris@0: ], Chris@0: ]; Chris@0: Chris@0: // Test service that needs deep-traversal. Chris@0: $services['service_using_array'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => $this->getCollection([ Chris@0: $this->getCollection([ Chris@0: $this->getServiceCall('other.service'), Chris@0: ]), Chris@0: $this->getParameterCall('some_private_config'), Chris@0: ]), Chris@0: ]; Chris@0: Chris@0: $services['service_with_optional_dependency'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => $this->getCollection([ Chris@0: $this->getServiceCall('service.does_not_exist', ContainerInterface::NULL_ON_INVALID_REFERENCE), Chris@0: $this->getParameterCall('some_private_config'), Chris@0: ]), Chris@0: Chris@0: ]; Chris@0: Chris@0: $services['factory_service'] = [ Chris@0: 'class' => '\Drupal\service_container\ServiceContainer\ControllerInterface', Chris@0: 'factory' => [ Chris@0: $this->getServiceCall('service.provider'), Chris@0: 'getFactoryMethod', Chris@0: ], Chris@0: 'arguments' => $this->getCollection([ Chris@0: $this->getParameterCall('factory_service_class'), Chris@0: ]), Chris@0: ]; Chris@0: $services['factory_class'] = [ Chris@0: 'class' => '\Drupal\service_container\ServiceContainer\ControllerInterface', Chris@0: 'factory' => '\Drupal\Tests\Component\DependencyInjection\MockService::getFactoryMethod', Chris@0: 'arguments' => [ Chris@0: '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: [NULL, 'bar'], Chris@0: ], Chris@0: 'calls' => [ Chris@0: [ Chris@0: 'setContainer', Chris@0: $this->getCollection([ Chris@0: $this->getServiceCall('service_container'), Chris@0: ]), Chris@0: ], Chris@0: ], Chris@0: ]; Chris@0: Chris@0: $services['wrong_factory'] = [ Chris@0: 'class' => '\Drupal\service_container\ServiceContainer\ControllerInterface', Chris@0: 'factory' => (object) ['I am not a factory, but I pretend to be.'], Chris@0: ]; Chris@0: Chris@0: $services['circular_dependency'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => $this->getCollection([ Chris@0: $this->getServiceCall('circular_dependency'), Chris@0: ]), Chris@0: ]; Chris@0: $services['synthetic'] = [ Chris@0: 'synthetic' => TRUE, Chris@0: ]; Chris@0: // The file could have been named as a .php file. The reason it is a .data Chris@0: // file is that SimpleTest tries to load it. SimpleTest does not like such Chris@0: // fixtures and hence we use a neutral name like .data. Chris@0: $services['container_test_file_service_test'] = [ Chris@0: 'class' => '\stdClass', Chris@0: 'file' => __DIR__ . '/Fixture/container_test_file_service_test_service_function.data', Chris@0: ]; Chris@0: Chris@0: // Test multiple arguments. Chris@0: $args = []; Chris@0: for ($i = 0; $i < 12; $i++) { Chris@0: $services['service_test_instantiation_' . $i] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockInstantiationService', Chris@0: // Also test a collection that does not need resolving. Chris@0: 'arguments' => $this->getCollection($args, FALSE), Chris@0: ]; Chris@0: $args[] = 'arg_' . $i; Chris@0: } Chris@0: Chris@0: $services['service_parameter_not_exists'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => $this->getCollection([ Chris@0: $this->getServiceCall('service.provider'), Chris@0: $this->getParameterCall('not_exists'), Chris@0: ]), Chris@0: ]; Chris@0: $services['service_dependency_not_exists'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => $this->getCollection([ Chris@0: $this->getServiceCall('service_not_exists'), Chris@0: $this->getParameterCall('some_config'), Chris@0: ]), Chris@0: ]; Chris@0: Chris@0: $services['service_with_parameter_service'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => $this->getCollection([ Chris@0: $this->getParameterCall('service_from_parameter'), Chris@0: // Also test deep collections that don't need resolving. Chris@0: $this->getCollection([ Chris@0: 1, Chris@0: ], FALSE), Chris@0: ]), Chris@0: ]; Chris@0: Chris@0: // To ensure getAlternatives() finds something. Chris@0: $services['service_not_exists_similar'] = [ Chris@0: 'synthetic' => TRUE, Chris@0: ]; Chris@0: Chris@0: // Test configurator. Chris@0: $services['configurator'] = [ Chris@0: 'synthetic' => TRUE, Chris@0: ]; Chris@0: $services['configurable_service'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => [], Chris@0: 'configurator' => [ Chris@0: $this->getServiceCall('configurator'), Chris@17: 'configureService', Chris@0: ], Chris@0: ]; Chris@0: $services['configurable_service_exception'] = [ Chris@0: 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService', Chris@0: 'arguments' => [], Chris@0: 'configurator' => 'configurator_service_test_does_not_exist', Chris@0: ]; Chris@0: Chris@0: $aliases = []; Chris@0: $aliases['service.provider_alias'] = 'service.provider'; Chris@0: $aliases['late.service_alias'] = 'late.service'; Chris@0: Chris@0: return [ Chris@0: 'aliases' => $aliases, Chris@0: 'parameters' => $parameters, Chris@0: 'services' => $services, Chris@0: 'frozen' => TRUE, Chris@0: 'machine_format' => $this->machineFormat, Chris@0: ]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Helper function to return a service definition. Chris@0: */ Chris@0: protected function getServiceCall($id, $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) { Chris@0: return (object) [ Chris@0: 'type' => 'service', Chris@0: 'id' => $id, Chris@0: 'invalidBehavior' => $invalid_behavior, Chris@0: ]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Helper function to return a service definition. Chris@0: */ Chris@0: protected function getParameterCall($name) { Chris@0: return (object) [ Chris@0: 'type' => 'parameter', Chris@0: 'name' => $name, Chris@0: ]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Helper function to return a private service definition. Chris@0: */ Chris@0: protected function getPrivateServiceCall($id, $service_definition, $shared = FALSE) { Chris@0: if (!$id) { Chris@0: $hash = Crypt::hashBase64(serialize($service_definition)); Chris@0: $id = 'private__' . $hash; Chris@0: } Chris@0: return (object) [ Chris@0: 'type' => 'private_service', Chris@0: 'id' => $id, Chris@0: 'value' => $service_definition, Chris@0: 'shared' => $shared, Chris@0: ]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Helper function to return a machine-optimized collection. Chris@0: */ Chris@0: protected function getCollection($collection, $resolve = TRUE) { Chris@0: return (object) [ Chris@0: 'type' => 'collection', Chris@0: 'value' => $collection, Chris@0: 'resolve' => $resolve, Chris@0: ]; Chris@0: } Chris@0: Chris@0: } Chris@0: Chris@0: /** Chris@0: * Helper interface to test Container::get() with configurator. Chris@0: * Chris@0: * @group DependencyInjection Chris@0: */ Chris@0: interface MockConfiguratorInterface { Chris@0: Chris@0: /** Chris@0: * Configures a service. Chris@0: * Chris@0: * @param object $service Chris@0: * The service to configure. Chris@0: */ Chris@0: public function configureService($service); Chris@0: Chris@0: } Chris@0: Chris@0: Chris@0: /** Chris@0: * Helper class to test Container::get() method for varying number of parameters. Chris@0: * Chris@0: * @group DependencyInjection Chris@0: */ Chris@0: class MockInstantiationService { Chris@0: Chris@0: /** Chris@0: * @var mixed[] Chris@0: */ Chris@0: protected $arguments; Chris@0: Chris@0: /** Chris@0: * Construct a mock instantiation service. Chris@0: */ Chris@0: public function __construct() { Chris@0: $this->arguments = func_get_args(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Return arguments injected into the service. Chris@0: * Chris@0: * @return mixed[] Chris@0: * Return the passed arguments. Chris@0: */ Chris@0: public function getArguments() { Chris@0: return $this->arguments; Chris@0: } Chris@0: Chris@0: } Chris@0: Chris@0: Chris@0: /** Chris@0: * Helper class to test Container::get() method. Chris@0: * Chris@0: * @group DependencyInjection Chris@0: */ Chris@0: class MockService { Chris@0: Chris@0: /** Chris@12: * @var \Symfony\Component\DependencyInjection\ContainerInterface Chris@0: */ Chris@0: protected $container; Chris@0: Chris@0: /** Chris@0: * @var object Chris@0: */ Chris@0: protected $someOtherService; Chris@0: Chris@0: /** Chris@0: * @var string Chris@0: */ Chris@0: protected $someParameter; Chris@0: Chris@0: /** Chris@0: * @var string Chris@0: */ Chris@0: protected $someOtherParameter; Chris@0: Chris@0: /** Chris@0: * Constructs a MockService object. Chris@0: * Chris@0: * @param object $some_other_service Chris@0: * (optional) Another injected service. Chris@0: * @param string $some_parameter Chris@0: * (optional) An injected parameter. Chris@0: */ Chris@0: public function __construct($some_other_service = NULL, $some_parameter = NULL) { Chris@0: if (is_array($some_other_service)) { Chris@0: $some_other_service = $some_other_service[0]; Chris@0: } Chris@0: $this->someOtherService = $some_other_service; Chris@0: $this->someParameter = $some_parameter; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets the container object. Chris@0: * Chris@12: * @param \Symfony\Component\DependencyInjection\ContainerInterface $container Chris@0: * The container to inject via setter injection. Chris@0: */ Chris@0: public function setContainer(ContainerInterface $container) { Chris@0: $this->container = $container; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the container object. Chris@0: * Chris@12: * @return \Symfony\Component\DependencyInjection\ContainerInterface Chris@0: * The internally set container. Chris@0: */ Chris@0: public function getContainer() { Chris@0: return $this->container; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the someOtherService object. Chris@0: * Chris@0: * @return object Chris@0: * The injected service. Chris@0: */ Chris@0: public function getSomeOtherService() { Chris@0: return $this->someOtherService; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the someParameter property. Chris@0: * Chris@0: * @return string Chris@0: * The injected parameter. Chris@0: */ Chris@0: public function getSomeParameter() { Chris@0: return $this->someParameter; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets the someOtherParameter property. Chris@0: * Chris@0: * @param string $some_other_parameter Chris@0: * The setter injected parameter. Chris@0: */ Chris@0: public function setOtherConfigParameter($some_other_parameter) { Chris@0: $this->someOtherParameter = $some_other_parameter; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the someOtherParameter property. Chris@0: * Chris@0: * @return string Chris@0: * The injected parameter. Chris@0: */ Chris@0: public function getSomeOtherParameter() { Chris@0: return $this->someOtherParameter; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Provides a factory method to get a service. Chris@0: * Chris@0: * @param string $class Chris@0: * The class name of the class to instantiate Chris@0: * @param array $arguments Chris@0: * (optional) Arguments to pass to the new class. Chris@0: * Chris@0: * @return object Chris@0: * The instantiated service object. Chris@0: */ Chris@0: public static function getFactoryMethod($class, $arguments = []) { Chris@0: $r = new \ReflectionClass($class); Chris@0: $service = ($r->getConstructor() === NULL) ? $r->newInstance() : $r->newInstanceArgs($arguments); Chris@0: Chris@0: return $service; Chris@0: } Chris@0: Chris@0: }