Security update for Core, with self-updated composer
[yaffs-website] / vendor / symfony / dependency-injection / Tests / ContainerTest.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\DependencyInjection\Tests;
13
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\DependencyInjection\Container;
16 use Symfony\Component\DependencyInjection\ContainerInterface;
17 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
18
19 class ContainerTest extends TestCase
20 {
21     public function testConstructor()
22     {
23         $sc = new Container();
24         $this->assertSame($sc, $sc->get('service_container'), '__construct() automatically registers itself as a service');
25
26         $sc = new Container(new ParameterBag(array('foo' => 'bar')));
27         $this->assertEquals(array('foo' => 'bar'), $sc->getParameterBag()->all(), '__construct() takes an array of parameters as its first argument');
28     }
29
30     /**
31      * @dataProvider dataForTestCamelize
32      */
33     public function testCamelize($id, $expected)
34     {
35         $this->assertEquals($expected, Container::camelize($id), sprintf('Container::camelize("%s")', $id));
36     }
37
38     public function dataForTestCamelize()
39     {
40         return array(
41             array('foo_bar', 'FooBar'),
42             array('foo.bar', 'Foo_Bar'),
43             array('foo.bar_baz', 'Foo_BarBaz'),
44             array('foo._bar', 'Foo_Bar'),
45             array('foo_.bar', 'Foo_Bar'),
46             array('_foo', 'Foo'),
47             array('.foo', '_Foo'),
48             array('foo_', 'Foo'),
49             array('foo.', 'Foo_'),
50             array('foo\bar', 'Foo_Bar'),
51         );
52     }
53
54     /**
55      * @dataProvider dataForTestUnderscore
56      */
57     public function testUnderscore($id, $expected)
58     {
59         $this->assertEquals($expected, Container::underscore($id), sprintf('Container::underscore("%s")', $id));
60     }
61
62     public function dataForTestUnderscore()
63     {
64         return array(
65             array('FooBar', 'foo_bar'),
66             array('Foo_Bar', 'foo.bar'),
67             array('Foo_BarBaz', 'foo.bar_baz'),
68             array('FooBar_BazQux', 'foo_bar.baz_qux'),
69             array('_Foo', '.foo'),
70             array('Foo_', 'foo.'),
71         );
72     }
73
74     public function testCompile()
75     {
76         $sc = new Container(new ParameterBag(array('foo' => 'bar')));
77         $this->assertFalse($sc->getParameterBag()->isResolved(), '->compile() resolves the parameter bag');
78         $sc->compile();
79         $this->assertTrue($sc->getParameterBag()->isResolved(), '->compile() resolves the parameter bag');
80         $this->assertInstanceOf('Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag', $sc->getParameterBag(), '->compile() changes the parameter bag to a FrozenParameterBag instance');
81         $this->assertEquals(array('foo' => 'bar'), $sc->getParameterBag()->all(), '->compile() copies the current parameters to the new parameter bag');
82     }
83
84     public function testIsFrozen()
85     {
86         $sc = new Container(new ParameterBag(array('foo' => 'bar')));
87         $this->assertFalse($sc->isFrozen(), '->isFrozen() returns false if the parameters are not frozen');
88         $sc->compile();
89         $this->assertTrue($sc->isFrozen(), '->isFrozen() returns true if the parameters are frozen');
90     }
91
92     public function testGetParameterBag()
93     {
94         $sc = new Container();
95         $this->assertEquals(array(), $sc->getParameterBag()->all(), '->getParameterBag() returns an empty array if no parameter has been defined');
96     }
97
98     public function testGetSetParameter()
99     {
100         $sc = new Container(new ParameterBag(array('foo' => 'bar')));
101         $sc->setParameter('bar', 'foo');
102         $this->assertEquals('foo', $sc->getParameter('bar'), '->setParameter() sets the value of a new parameter');
103
104         $sc->setParameter('foo', 'baz');
105         $this->assertEquals('baz', $sc->getParameter('foo'), '->setParameter() overrides previously set parameter');
106
107         $sc->setParameter('Foo', 'baz1');
108         $this->assertEquals('baz1', $sc->getParameter('foo'), '->setParameter() converts the key to lowercase');
109         $this->assertEquals('baz1', $sc->getParameter('FOO'), '->getParameter() converts the key to lowercase');
110
111         try {
112             $sc->getParameter('baba');
113             $this->fail('->getParameter() thrown an \InvalidArgumentException if the key does not exist');
114         } catch (\Exception $e) {
115             $this->assertInstanceOf('\InvalidArgumentException', $e, '->getParameter() thrown an \InvalidArgumentException if the key does not exist');
116             $this->assertEquals('You have requested a non-existent parameter "baba".', $e->getMessage(), '->getParameter() thrown an \InvalidArgumentException if the key does not exist');
117         }
118     }
119
120     public function testGetServiceIds()
121     {
122         $sc = new Container();
123         $sc->set('foo', $obj = new \stdClass());
124         $sc->set('bar', $obj = new \stdClass());
125         $this->assertEquals(array('service_container', 'foo', 'bar'), $sc->getServiceIds(), '->getServiceIds() returns all defined service ids');
126
127         $sc = new ProjectServiceContainer();
128         $sc->set('foo', $obj = new \stdClass());
129         $this->assertEquals(array('service_container', 'internal', 'bar', 'foo_bar', 'foo.baz', 'circular', 'throw_exception', 'throws_exception_on_service_configuration', 'internal_dependency', 'foo'), $sc->getServiceIds(), '->getServiceIds() returns defined service ids by factory methods in the method map, followed by service ids defined by set()');
130     }
131
132     /**
133      * @group legacy
134      * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.
135      */
136     public function testGetLegacyServiceIds()
137     {
138         $sc = new LegacyProjectServiceContainer();
139         $sc->set('foo', $obj = new \stdClass());
140
141         $this->assertEquals(array('internal', '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()');
142     }
143
144     public function testSet()
145     {
146         $sc = new Container();
147         $sc->set('._. \\o/', $foo = new \stdClass());
148         $this->assertSame($foo, $sc->get('._. \\o/'), '->set() sets a service');
149     }
150
151     public function testSetWithNullResetTheService()
152     {
153         $sc = new Container();
154         $sc->set('foo', null);
155         $this->assertFalse($sc->has('foo'), '->set() with null service resets the service');
156     }
157
158     public function testSetReplacesAlias()
159     {
160         $c = new ProjectServiceContainer();
161
162         $c->set('alias', $foo = new \stdClass());
163         $this->assertSame($foo, $c->get('alias'), '->set() replaces an existing alias');
164     }
165
166     public function testGet()
167     {
168         $sc = new ProjectServiceContainer();
169         $sc->set('foo', $foo = new \stdClass());
170         $this->assertSame($foo, $sc->get('foo'), '->get() returns the service for the given id');
171         $this->assertSame($foo, $sc->get('Foo'), '->get() returns the service for the given id, and converts id to lowercase');
172         $this->assertSame($sc->__bar, $sc->get('bar'), '->get() returns the service for the given id');
173         $this->assertSame($sc->__foo_bar, $sc->get('foo_bar'), '->get() returns the service if a get*Method() is defined');
174         $this->assertSame($sc->__foo_baz, $sc->get('foo.baz'), '->get() returns the service if a get*Method() is defined');
175
176         $sc->set('bar', $bar = new \stdClass());
177         $this->assertSame($bar, $sc->get('bar'), '->get() prefers to return a service defined with set() than one defined with a getXXXMethod()');
178
179         try {
180             $sc->get('');
181             $this->fail('->get() throws a \InvalidArgumentException exception if the service is empty');
182         } catch (\Exception $e) {
183             $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws a ServiceNotFoundException exception if the service is empty');
184         }
185         $this->assertNull($sc->get('', ContainerInterface::NULL_ON_INVALID_REFERENCE), '->get() returns null if the service is empty');
186     }
187
188     /**
189      * @group legacy
190      * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.
191      * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.
192      * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.
193      * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.
194      */
195     public function testLegacyGet()
196     {
197         $sc = new LegacyProjectServiceContainer();
198         $sc->set('foo', $foo = new \stdClass());
199
200         $this->assertSame($foo, $sc->get('foo'), '->get() returns the service for the given id');
201         $this->assertSame($foo, $sc->get('Foo'), '->get() returns the service for the given id, and converts id to lowercase');
202         $this->assertSame($sc->__bar, $sc->get('bar'), '->get() returns the service for the given id');
203         $this->assertSame($sc->__foo_bar, $sc->get('foo_bar'), '->get() returns the service if a get*Method() is defined');
204         $this->assertSame($sc->__foo_baz, $sc->get('foo.baz'), '->get() returns the service if a get*Method() is defined');
205         $this->assertSame($sc->__foo_baz, $sc->get('foo\\baz'), '->get() returns the service if a get*Method() is defined');
206
207         $sc->set('bar', $bar = new \stdClass());
208         $this->assertSame($bar, $sc->get('bar'), '->get() prefers to return a service defined with set() than one defined with a getXXXMethod()');
209
210         try {
211             $sc->get('');
212             $this->fail('->get() throws a \InvalidArgumentException exception if the service is empty');
213         } catch (\Exception $e) {
214             $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws a ServiceNotFoundException exception if the service is empty');
215         }
216         $this->assertNull($sc->get('', ContainerInterface::NULL_ON_INVALID_REFERENCE), '->get() returns null if the service is empty');
217     }
218
219     public function testGetThrowServiceNotFoundException()
220     {
221         $sc = new ProjectServiceContainer();
222         $sc->set('foo', $foo = new \stdClass());
223         $sc->set('baz', $foo = new \stdClass());
224
225         try {
226             $sc->get('foo1');
227             $this->fail('->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException if the key does not exist');
228         } catch (\Exception $e) {
229             $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException if the key does not exist');
230             $this->assertEquals('You have requested a non-existent service "foo1". Did you mean this: "foo"?', $e->getMessage(), '->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException with some advices');
231         }
232
233         try {
234             $sc->get('bag');
235             $this->fail('->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException if the key does not exist');
236         } catch (\Exception $e) {
237             $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException if the key does not exist');
238             $this->assertEquals('You have requested a non-existent service "bag". Did you mean one of these: "bar", "baz"?', $e->getMessage(), '->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException with some advices');
239         }
240     }
241
242     public function testGetCircularReference()
243     {
244         $sc = new ProjectServiceContainer();
245         try {
246             $sc->get('circular');
247             $this->fail('->get() throws a ServiceCircularReferenceException if it contains circular reference');
248         } catch (\Exception $e) {
249             $this->assertInstanceOf('\Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException', $e, '->get() throws a ServiceCircularReferenceException if it contains circular reference');
250             $this->assertStringStartsWith('Circular reference detected for service "circular"', $e->getMessage(), '->get() throws a \LogicException if it contains circular reference');
251         }
252     }
253
254     /**
255      * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
256      * @expectedExceptionMessage You have requested a synthetic service ("request"). The DIC does not know how to construct this service.
257      */
258     public function testGetSyntheticServiceAlwaysThrows()
259     {
260         require_once __DIR__.'/Fixtures/php/services9.php';
261
262         $container = new \ProjectServiceContainer();
263         $container->get('request', ContainerInterface::NULL_ON_INVALID_REFERENCE);
264     }
265
266     public function testHas()
267     {
268         $sc = new ProjectServiceContainer();
269         $sc->set('foo', new \stdClass());
270         $this->assertFalse($sc->has('foo1'), '->has() returns false if the service does not exist');
271         $this->assertTrue($sc->has('foo'), '->has() returns true if the service exists');
272         $this->assertTrue($sc->has('bar'), '->has() returns true if a get*Method() is defined');
273         $this->assertTrue($sc->has('foo_bar'), '->has() returns true if a get*Method() is defined');
274         $this->assertTrue($sc->has('foo.baz'), '->has() returns true if a get*Method() is defined');
275     }
276
277     /**
278      * @group legacy
279      * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.
280      * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.
281      * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.
282      * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.
283      */
284     public function testLegacyHas()
285     {
286         $sc = new LegacyProjectServiceContainer();
287         $sc->set('foo', new \stdClass());
288
289         $this->assertFalse($sc->has('foo1'), '->has() returns false if the service does not exist');
290         $this->assertTrue($sc->has('foo'), '->has() returns true if the service exists');
291         $this->assertTrue($sc->has('bar'), '->has() returns true if a get*Method() is defined');
292         $this->assertTrue($sc->has('foo_bar'), '->has() returns true if a get*Method() is defined');
293         $this->assertTrue($sc->has('foo.baz'), '->has() returns true if a get*Method() is defined');
294         $this->assertTrue($sc->has('foo\\baz'), '->has() returns true if a get*Method() is defined');
295     }
296
297     public function testInitialized()
298     {
299         $sc = new ProjectServiceContainer();
300         $sc->set('foo', new \stdClass());
301         $this->assertTrue($sc->initialized('foo'), '->initialized() returns true if service is loaded');
302         $this->assertFalse($sc->initialized('foo1'), '->initialized() returns false if service is not loaded');
303         $this->assertFalse($sc->initialized('bar'), '->initialized() returns false if a service is defined, but not currently loaded');
304         $this->assertFalse($sc->initialized('alias'), '->initialized() returns false if an aliased service is not initialized');
305
306         $sc->set('bar', new \stdClass());
307         $this->assertTrue($sc->initialized('alias'), '->initialized() returns true for alias if aliased service is initialized');
308     }
309
310     public function testReset()
311     {
312         $c = new Container();
313         $c->set('bar', new \stdClass());
314
315         $c->reset();
316
317         $this->assertNull($c->get('bar', ContainerInterface::NULL_ON_INVALID_REFERENCE));
318     }
319
320     /**
321      * @expectedException \Exception
322      * @expectedExceptionMessage Something went terribly wrong!
323      */
324     public function testGetThrowsException()
325     {
326         $c = new ProjectServiceContainer();
327
328         try {
329             $c->get('throw_exception');
330         } catch (\Exception $e) {
331             // Do nothing.
332         }
333
334         // Retry, to make sure that get*Service() will be called.
335         $c->get('throw_exception');
336     }
337
338     public function testGetThrowsExceptionOnServiceConfiguration()
339     {
340         $c = new ProjectServiceContainer();
341
342         try {
343             $c->get('throws_exception_on_service_configuration');
344         } catch (\Exception $e) {
345             // Do nothing.
346         }
347
348         $this->assertFalse($c->initialized('throws_exception_on_service_configuration'));
349
350         // Retry, to make sure that get*Service() will be called.
351         try {
352             $c->get('throws_exception_on_service_configuration');
353         } catch (\Exception $e) {
354             // Do nothing.
355         }
356         $this->assertFalse($c->initialized('throws_exception_on_service_configuration'));
357     }
358
359     protected function getField($obj, $field)
360     {
361         $reflection = new \ReflectionProperty($obj, $field);
362         $reflection->setAccessible(true);
363
364         return $reflection->getValue($obj);
365     }
366
367     public function testAlias()
368     {
369         $c = new ProjectServiceContainer();
370
371         $this->assertTrue($c->has('alias'));
372         $this->assertSame($c->get('alias'), $c->get('bar'));
373     }
374
375     public function testThatCloningIsNotSupported()
376     {
377         $class = new \ReflectionClass('Symfony\Component\DependencyInjection\Container');
378         $clone = $class->getMethod('__clone');
379         $this->assertFalse($class->isCloneable());
380         $this->assertTrue($clone->isPrivate());
381     }
382
383     /**
384      * @group legacy
385      * @expectedDeprecation Unsetting the "internal" private service is deprecated since Symfony 3.2 and won't be supported anymore in Symfony 4.0.
386      */
387     public function testUnsetInternalPrivateServiceIsDeprecated()
388     {
389         $c = new ProjectServiceContainer();
390         $c->set('internal', null);
391     }
392
393     /**
394      * @group legacy
395      * @expectedDeprecation Setting the "internal" private service is deprecated since Symfony 3.2 and won't be supported anymore in Symfony 4.0. A new public service will be created instead.
396      */
397     public function testChangeInternalPrivateServiceIsDeprecated()
398     {
399         $c = new ProjectServiceContainer();
400         $c->set('internal', $internal = new \stdClass());
401         $this->assertSame($c->get('internal'), $internal);
402     }
403
404     /**
405      * @group legacy
406      * @expectedDeprecation Checking for the existence of the "internal" private service is deprecated since Symfony 3.2 and won't be supported anymore in Symfony 4.0.
407      */
408     public function testCheckExistenceOfAnInternalPrivateServiceIsDeprecated()
409     {
410         $c = new ProjectServiceContainer();
411         $c->get('internal_dependency');
412         $this->assertTrue($c->has('internal'));
413     }
414
415     /**
416      * @group legacy
417      * @expectedDeprecation Requesting the "internal" private service is deprecated since Symfony 3.2 and won't be supported anymore in Symfony 4.0.
418      */
419     public function testRequestAnInternalSharedPrivateServiceIsDeprecated()
420     {
421         $c = new ProjectServiceContainer();
422         $c->get('internal_dependency');
423         $c->get('internal');
424     }
425 }
426
427 class ProjectServiceContainer extends Container
428 {
429     public $__bar;
430     public $__foo_bar;
431     public $__foo_baz;
432     public $__internal;
433     protected $methodMap = array(
434         'internal' => 'getInternalService',
435         'bar' => 'getBarService',
436         'foo_bar' => 'getFooBarService',
437         'foo.baz' => 'getFoo_BazService',
438         'circular' => 'getCircularService',
439         'throw_exception' => 'getThrowExceptionService',
440         'throws_exception_on_service_configuration' => 'getThrowsExceptionOnServiceConfigurationService',
441         'internal_dependency' => 'getInternalDependencyService',
442     );
443
444     public function __construct()
445     {
446         parent::__construct();
447
448         $this->__bar = new \stdClass();
449         $this->__foo_bar = new \stdClass();
450         $this->__foo_baz = new \stdClass();
451         $this->__internal = new \stdClass();
452         $this->privates = array('internal' => true);
453         $this->aliases = array('alias' => 'bar');
454     }
455
456     protected function getInternalService()
457     {
458         return $this->services['internal'] = $this->__internal;
459     }
460
461     protected function getBarService()
462     {
463         return $this->__bar;
464     }
465
466     protected function getFooBarService()
467     {
468         return $this->__foo_bar;
469     }
470
471     protected function getFoo_BazService()
472     {
473         return $this->__foo_baz;
474     }
475
476     protected function getCircularService()
477     {
478         return $this->get('circular');
479     }
480
481     protected function getThrowExceptionService()
482     {
483         throw new \Exception('Something went terribly wrong!');
484     }
485
486     protected function getThrowsExceptionOnServiceConfigurationService()
487     {
488         $this->services['throws_exception_on_service_configuration'] = $instance = new \stdClass();
489
490         throw new \Exception('Something was terribly wrong while trying to configure the service!');
491     }
492
493     protected function getInternalDependencyService()
494     {
495         $this->services['internal_dependency'] = $instance = new \stdClass();
496
497         $instance->internal = isset($this->services['internal']) ? $this->services['internal'] : $this->getInternalService();
498
499         return $instance;
500     }
501 }
502
503 class LegacyProjectServiceContainer extends Container
504 {
505     public $__bar;
506     public $__foo_bar;
507     public $__foo_baz;
508     public $__internal;
509
510     public function __construct()
511     {
512         parent::__construct();
513
514         $this->__bar = new \stdClass();
515         $this->__foo_bar = new \stdClass();
516         $this->__foo_baz = new \stdClass();
517         $this->__internal = new \stdClass();
518         $this->privates = array('internal' => true);
519         $this->aliases = array('alias' => 'bar');
520     }
521
522     protected function getInternalService()
523     {
524         return $this->__internal;
525     }
526
527     protected function getBarService()
528     {
529         return $this->__bar;
530     }
531
532     protected function getFooBarService()
533     {
534         return $this->__foo_bar;
535     }
536
537     protected function getFoo_BazService()
538     {
539         return $this->__foo_baz;
540     }
541
542     protected function getCircularService()
543     {
544         return $this->get('circular');
545     }
546
547     protected function getThrowExceptionService()
548     {
549         throw new \Exception('Something went terribly wrong!');
550     }
551
552     protected function getThrowsExceptionOnServiceConfigurationService()
553     {
554         $this->services['throws_exception_on_service_configuration'] = $instance = new \stdClass();
555
556         throw new \Exception('Something was terribly wrong while trying to configure the service!');
557     }
558 }