[DependencyInjection] Enhance tests for class Container

This commit is contained in:
Hany el-Kerdany 2014-08-25 15:14:37 +03:00 committed by Fabien Potencier
parent 1d7684ac3d
commit 6211205659
2 changed files with 194 additions and 73 deletions

View File

@ -217,11 +217,11 @@ class Container implements IntrospectableContainerInterface
$this->$method(); $this->$method();
} }
if (self::SCOPE_CONTAINER !== $scope && null === $service) { if (null === $service) {
if (self::SCOPE_CONTAINER !== $scope) {
unset($this->scopedServices[$scope][$id]); unset($this->scopedServices[$scope][$id]);
} }
if (null === $service) {
unset($this->services[$id]); unset($this->services[$id]);
} }
} }
@ -450,14 +450,15 @@ class Container implements IntrospectableContainerInterface
// the global service map // the global service map
$services = array($this->services, $this->scopedServices[$name]); $services = array($this->services, $this->scopedServices[$name]);
unset($this->scopedServices[$name]); unset($this->scopedServices[$name]);
foreach ($this->scopeChildren[$name] as $child) {
if (!isset($this->scopedServices[$child])) {
continue;
}
foreach ($this->scopeChildren[$name] as $child) {
if (isset($this->scopedServices[$child])) {
$services[] = $this->scopedServices[$child]; $services[] = $this->scopedServices[$child];
unset($this->scopedServices[$child]); unset($this->scopedServices[$child]);
} }
}
// update global map
$this->services = call_user_func_array('array_diff_key', $services); $this->services = call_user_func_array('array_diff_key', $services);
// check if we need to restore services of a previous scope of this type // check if we need to restore services of a previous scope of this type
@ -465,6 +466,10 @@ class Container implements IntrospectableContainerInterface
$services = $this->scopeStacks[$name]->pop(); $services = $this->scopeStacks[$name]->pop();
$this->scopedServices += $services; $this->scopedServices += $services;
if ($this->scopeStacks[$name]->isEmpty()) {
unset($this->scopeStacks[$name]);
}
foreach ($services as $array) { foreach ($services as $array) {
foreach ($array as $id => $service) { foreach ($array as $id => $service) {
$this->set($id, $service, $name); $this->set($id, $service, $name);

View File

@ -55,13 +55,35 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
); );
} }
/**
* @dataProvider dataForTestUnderscore
*/
public function testUnderscore($id, $expected)
{
$this->assertEquals($expected, Container::underscore($id), sprintf('Container::underscore("%s")', $id));
}
public function dataForTestUnderscore()
{
return array(
array('FooBar', 'foo_bar'),
array('Foo_Bar', 'foo.bar'),
array('Foo_BarBaz', 'foo.bar_baz'),
array('FooBar_BazQux', 'foo_bar.baz_qux'),
array('_Foo', '.foo'),
array('Foo_', 'foo.'),
);
}
/** /**
* @covers Symfony\Component\DependencyInjection\Container::compile * @covers Symfony\Component\DependencyInjection\Container::compile
*/ */
public function testCompile() public function testCompile()
{ {
$sc = new Container(new ParameterBag(array('foo' => 'bar'))); $sc = new Container(new ParameterBag(array('foo' => 'bar')));
$this->assertFalse($sc->getParameterBag()->isResolved(), '->compile() resolves the parameter bag');
$sc->compile(); $sc->compile();
$this->assertTrue($sc->getParameterBag()->isResolved(), '->compile() resolves the parameter bag');
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag', $sc->getParameterBag(), '->compile() changes the parameter bag to a FrozenParameterBag instance'); $this->assertInstanceOf('Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag', $sc->getParameterBag(), '->compile() changes the parameter bag to a FrozenParameterBag instance');
$this->assertEquals(array('foo' => 'bar'), $sc->getParameterBag()->all(), '->compile() copies the current parameters to the new parameter bag'); $this->assertEquals(array('foo' => 'bar'), $sc->getParameterBag()->all(), '->compile() copies the current parameters to the new parameter bag');
} }
@ -123,7 +145,8 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array('service_container', 'foo', 'bar'), $sc->getServiceIds(), '->getServiceIds() returns all defined service ids'); $this->assertEquals(array('service_container', 'foo', 'bar'), $sc->getServiceIds(), '->getServiceIds() returns all defined service ids');
$sc = new ProjectServiceContainer(); $sc = new ProjectServiceContainer();
$this->assertEquals(array('scoped', 'scoped_foo', 'inactive', 'bar', 'foo_bar', 'foo.baz', 'circular', 'throw_exception', 'throws_exception_on_service_configuration', 'service_container'), $sc->getServiceIds(), '->getServiceIds() returns defined service ids by getXXXService() methods'); $sc->set('foo', $obj = new \stdClass());
$this->assertEquals(array('scoped', 'scoped_foo', 'scoped_synchronized_foo', 'inactive', 'bar', 'foo_bar', 'foo.baz', 'circular', 'throw_exception', 'throws_exception_on_service_configuration', 'service_container', 'foo'), $sc->getServiceIds(), '->getServiceIds() returns defined service ids by getXXXService() methods, followed by service ids defined by set()');
} }
/** /**
@ -143,7 +166,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
{ {
$sc = new Container(); $sc = new Container();
$sc->set('foo', null); $sc->set('foo', null);
$this->assertFalse($sc->has('foo')); $this->assertFalse($sc->has('foo'), '->set() with null service resets the service');
} }
/** /**
@ -152,7 +175,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
public function testSetDoesNotAllowPrototypeScope() public function testSetDoesNotAllowPrototypeScope()
{ {
$c = new Container(); $c = new Container();
$c->set('foo', new \stdClass(), 'prototype'); $c->set('foo', new \stdClass(), Container::SCOPE_PROTOTYPE);
} }
/** /**
@ -172,9 +195,18 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$c->enterScope('foo'); $c->enterScope('foo');
$c->set('foo', $foo = new \stdClass(), 'foo'); $c->set('foo', $foo = new \stdClass(), 'foo');
$services = $this->getField($c, 'scopedServices'); $scoped = $this->getField($c, 'scopedServices');
$this->assertTrue(isset($services['foo']['foo'])); $this->assertTrue(isset($scoped['foo']['foo']), '->set() sets a scoped service');
$this->assertSame($foo, $services['foo']['foo']); $this->assertSame($foo, $scoped['foo']['foo'], '->set() sets a scoped service');
}
public function testSetAlsoCallsSynchronizeService()
{
$c = new ProjectServiceContainer();
$c->addScope(new Scope('foo'));
$c->enterScope('foo');
$c->set('scoped_synchronized_foo', $bar = new \stdClass(), 'foo');
$this->assertTrue($c->synchronized, '->set() calls synchronize*Service() if it is defined for the service');
} }
/** /**
@ -185,6 +217,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$sc = new ProjectServiceContainer(); $sc = new ProjectServiceContainer();
$sc->set('foo', $foo = new \stdClass()); $sc->set('foo', $foo = new \stdClass());
$this->assertEquals($foo, $sc->get('foo'), '->get() returns the service for the given id'); $this->assertEquals($foo, $sc->get('foo'), '->get() returns the service for the given id');
$this->assertEquals($foo, $sc->get('Foo'), '->get() returns the service for the given id, and converts id to lowercase');
$this->assertEquals($sc->__bar, $sc->get('bar'), '->get() returns the service for the given id'); $this->assertEquals($sc->__bar, $sc->get('bar'), '->get() returns the service for the given id');
$this->assertEquals($sc->__foo_bar, $sc->get('foo_bar'), '->get() returns the service if a get*Method() is defined'); $this->assertEquals($sc->__foo_bar, $sc->get('foo_bar'), '->get() returns the service if a get*Method() is defined');
$this->assertEquals($sc->__foo_baz, $sc->get('foo.baz'), '->get() returns the service if a get*Method() is defined'); $this->assertEquals($sc->__foo_baz, $sc->get('foo.baz'), '->get() returns the service if a get*Method() is defined');
@ -199,7 +232,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
} catch (\Exception $e) { } catch (\Exception $e) {
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws a ServiceNotFoundException exception if the service is empty'); $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws a ServiceNotFoundException exception if the service is empty');
} }
$this->assertNull($sc->get('', ContainerInterface::NULL_ON_INVALID_REFERENCE)); $this->assertNull($sc->get('', ContainerInterface::NULL_ON_INVALID_REFERENCE), '->get() returns null if the service is empty');
} }
public function testGetThrowServiceNotFoundException() public function testGetThrowServiceNotFoundException()
@ -317,16 +350,15 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$a = new \stdClass(); $a = new \stdClass();
$container->set('a', $a, 'bar'); $container->set('a', $a, 'bar');
$services = $this->getField($container, 'scopedServices'); $scoped = $this->getField($container, 'scopedServices');
$this->assertTrue(isset($services['bar']['a'])); $this->assertTrue(isset($scoped['bar']['a']));
$this->assertSame($a, $services['bar']['a']); $this->assertSame($a, $scoped['bar']['a']);
$this->assertTrue($container->has('a')); $this->assertTrue($container->has('a'));
$container->leaveScope('foo'); $container->leaveScope('foo');
$services = $this->getField($container, 'scopedServices'); $scoped = $this->getField($container, 'scopedServices');
$this->assertFalse(isset($services['bar'])); $this->assertFalse(isset($scoped['bar']));
$this->assertFalse($container->isScopeActive('foo')); $this->assertFalse($container->isScopeActive('foo'));
$this->assertFalse($container->has('a')); $this->assertFalse($container->has('a'));
} }
@ -348,19 +380,83 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$a = new \stdClass(); $a = new \stdClass();
$container->set('a', $a, 'foo'); $container->set('a', $a, 'foo');
$services = $this->getField($container, 'scopedServices'); $scoped = $this->getField($container, 'scopedServices');
$this->assertTrue(isset($services['foo']['a'])); $this->assertTrue(isset($scoped['foo']['a']));
$this->assertSame($a, $services['foo']['a']); $this->assertSame($a, $scoped['foo']['a']);
$this->assertTrue($container->has('a')); $this->assertTrue($container->has('a'));
$container->enterScope('foo'); $container->enterScope('foo');
$services = $this->getField($container, 'scopedServices'); $scoped = $this->getField($container, 'scopedServices');
$this->assertFalse(isset($services['a'])); $this->assertFalse(isset($scoped['a']));
$this->assertTrue($container->isScopeActive('foo')); $this->assertTrue($container->isScopeActive('foo'));
$this->assertFalse($container->isScopeActive('bar')); $this->assertFalse($container->isScopeActive('bar'));
$this->assertFalse($container->has('a')); $this->assertFalse($container->has('a'));
$container->enterScope('bar');
$this->assertTrue($container->isScopeActive('bar'));
$container->leaveScope('foo');
$this->assertTrue($container->isScopeActive('foo'));
$this->assertFalse($container->isScopeActive('bar'));
$this->assertTrue($container->has('a'));
}
public function testEnterChildScopeRecursively()
{
$container = new Container();
$container->addScope(new Scope('foo'));
$container->addScope(new Scope('bar', 'foo'));
$container->enterScope('foo');
$container->enterScope('bar');
$this->assertTrue($container->isScopeActive('bar'));
$this->assertFalse($container->has('a'));
$a = new \stdClass();
$container->set('a', $a, 'bar');
$scoped = $this->getField($container, 'scopedServices');
$this->assertTrue(isset($scoped['bar']['a']));
$this->assertSame($a, $scoped['bar']['a']);
$this->assertTrue($container->has('a'));
$container->enterScope('bar');
$scoped = $this->getField($container, 'scopedServices');
$this->assertFalse(isset($scoped['a']));
$this->assertTrue($container->isScopeActive('foo'));
$this->assertTrue($container->isScopeActive('bar'));
$this->assertFalse($container->has('a'));
$container->leaveScope('bar');
$this->assertTrue($container->isScopeActive('foo'));
$this->assertTrue($container->isScopeActive('bar'));
$this->assertTrue($container->has('a'));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testEnterScopeNotAdded()
{
$container = new Container();
$container->enterScope('foo');
}
/**
* @expectedException \RuntimeException
*/
public function testEnterScopeDoesNotAllowInactiveParentScope()
{
$container = new Container();
$container->addScope(new Scope('foo'));
$container->addScope(new Scope('bar', 'foo'));
$container->enterScope('bar');
} }
public function testLeaveScopeNotActive() public function testLeaveScopeNotActive()
@ -423,6 +519,11 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertSame(array('foo' => 'container', 'bar' => 'foo'), $this->getField($c, 'scopes')); $this->assertSame(array('foo' => 'container', 'bar' => 'foo'), $this->getField($c, 'scopes'));
$this->assertSame(array('foo' => array('bar'), 'bar' => array()), $this->getField($c, 'scopeChildren')); $this->assertSame(array('foo' => array('bar'), 'bar' => array()), $this->getField($c, 'scopeChildren'));
$c->addScope(new Scope('baz', 'bar'));
$this->assertSame(array('foo' => 'container', 'bar' => 'foo', 'baz' => 'bar'), $this->getField($c, 'scopes'));
$this->assertSame(array('foo' => array('bar', 'baz'), 'bar' => array('baz'), 'baz' => array()), $this->getField($c, 'scopeChildren'));
} }
public function testHasScope() public function testHasScope()
@ -434,6 +535,45 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($c->hasScope('foo')); $this->assertTrue($c->hasScope('foo'));
} }
/**
* @expectedException Exception
* @expectedExceptionMessage Something went terribly wrong!
*/
public function testGetThrowsException()
{
$c = new ProjectServiceContainer();
try {
$c->get('throw_exception');
} catch (\Exception $e) {
// Do nothing.
}
// Retry, to make sure that get*Service() will be called.
$c->get('throw_exception');
}
public function testGetThrowsExceptionOnServiceConfiguration()
{
$c = new ProjectServiceContainer();
try {
$c->get('throws_exception_on_service_configuration');
} catch (\Exception $e) {
// Do nothing.
}
$this->assertFalse($c->initialized('throws_exception_on_service_configuration'));
// Retry, to make sure that get*Service() will be called.
try {
$c->get('throws_exception_on_service_configuration');
} catch (\Exception $e) {
// Do nothing.
}
$this->assertFalse($c->initialized('throws_exception_on_service_configuration'));
}
public function testIsScopeActive() public function testIsScopeActive()
{ {
$c = new Container(); $c = new Container();
@ -450,46 +590,6 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($c->isScopeActive('foo')); $this->assertFalse($c->isScopeActive('foo'));
} }
public function testGetThrowsException()
{
$c = new ProjectServiceContainer();
try {
$c->get('throw_exception');
$this->fail();
} catch (\Exception $e) {
$this->assertEquals('Something went terribly wrong!', $e->getMessage());
}
try {
$c->get('throw_exception');
$this->fail();
} catch (\Exception $e) {
$this->assertEquals('Something went terribly wrong!', $e->getMessage());
}
}
public function testGetThrowsExceptionOnServiceConfiguration()
{
$c = new ProjectServiceContainer();
try {
$c->get('throws_exception_on_service_configuration');
$this->fail('The container can not contain invalid service!');
} catch (\Exception $e) {
$this->assertEquals('Something was terribly wrong while trying to configure the service!', $e->getMessage());
}
$this->assertFalse($c->initialized('throws_exception_on_service_configuration'));
try {
$c->get('throws_exception_on_service_configuration');
$this->fail('The container can not contain invalid service!');
} catch (\Exception $e) {
$this->assertEquals('Something was terribly wrong while trying to configure the service!', $e->getMessage());
}
$this->assertFalse($c->initialized('throws_exception_on_service_configuration'));
}
public function getInvalidParentScopes() public function getInvalidParentScopes()
{ {
return array( return array(
@ -526,6 +626,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
class ProjectServiceContainer extends Container class ProjectServiceContainer extends Container
{ {
public $__bar, $__foo_bar, $__foo_baz; public $__bar, $__foo_bar, $__foo_baz;
public $synchronized;
public function __construct() public function __construct()
{ {
@ -534,12 +635,13 @@ class ProjectServiceContainer extends Container
$this->__bar = new \stdClass(); $this->__bar = new \stdClass();
$this->__foo_bar = new \stdClass(); $this->__foo_bar = new \stdClass();
$this->__foo_baz = new \stdClass(); $this->__foo_baz = new \stdClass();
$this->synchronized = false;
$this->aliases = array('alias' => 'bar'); $this->aliases = array('alias' => 'bar');
} }
protected function getScopedService() protected function getScopedService()
{ {
if (!isset($this->scopedServices['foo'])) { if (!$this->isScopeActive('foo')) {
throw new \RuntimeException('Invalid call'); throw new \RuntimeException('Invalid call');
} }
@ -548,13 +650,27 @@ class ProjectServiceContainer extends Container
protected function getScopedFooService() protected function getScopedFooService()
{ {
if (!isset($this->scopedServices['foo'])) { if (!$this->isScopeActive('foo')) {
throw new \RuntimeException('invalid call'); throw new \RuntimeException('invalid call');
} }
return $this->services['scoped_foo'] = $this->scopedServices['foo']['scoped_foo'] = new \stdClass(); return $this->services['scoped_foo'] = $this->scopedServices['foo']['scoped_foo'] = new \stdClass();
} }
protected function getScopedSynchronizedFooService()
{
if (!$this->isScopeActive('foo')) {
throw new \RuntimeException('invalid call');
}
return $this->services['scoped_bar'] = $this->scopedServices['foo']['scoped_bar'] = new \stdClass();
}
protected function synchronizeScopedSynchronizedFooService()
{
$this->synchronized = true;
}
protected function getInactiveService() protected function getInactiveService()
{ {
throw new InactiveScopeException('request', 'request'); throw new InactiveScopeException('request', 'request');