2 use MediaWiki\Services\ServiceContainer
;
5 * @covers MediaWiki\Services\ServiceContainer
9 class ServiceContainerTest
extends PHPUnit_Framework_TestCase
{
11 private function newServiceContainer( $extraArgs = [] ) {
12 return new ServiceContainer( $extraArgs );
15 public function testGetServiceNames() {
16 $services = $this->newServiceContainer();
17 $names = $services->getServiceNames();
19 $this->assertInternalType( 'array', $names );
20 $this->assertEmpty( $names );
22 $name = 'TestService92834576';
23 $services->defineService( $name, function() {
27 $names = $services->getServiceNames();
28 $this->assertContains( $name, $names );
31 public function testHasService() {
32 $services = $this->newServiceContainer();
34 $name = 'TestService92834576';
35 $this->assertFalse( $services->hasService( $name ) );
37 $services->defineService( $name, function() {
41 $this->assertTrue( $services->hasService( $name ) );
44 public function testGetService() {
45 $services = $this->newServiceContainer( [ 'Foo' ] );
47 $theService = new stdClass();
48 $name = 'TestService92834576';
51 $services->defineService(
53 function( $actualLocator, $extra ) use ( $services, $theService, &$count ) {
55 PHPUnit_Framework_Assert
::assertSame( $services, $actualLocator );
56 PHPUnit_Framework_Assert
::assertSame( $extra, 'Foo' );
61 $this->assertSame( $theService, $services->getService( $name ) );
63 $services->getService( $name );
64 $this->assertSame( 1, $count, 'instantiator should be called exactly once!' );
67 public function testGetService_fail_unknown() {
68 $services = $this->newServiceContainer();
70 $name = 'TestService92834576';
72 $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
74 $services->getService( $name );
77 public function testPeekService() {
78 $services = $this->newServiceContainer();
80 $services->defineService(
83 return new stdClass();
87 $services->defineService(
90 return new stdClass();
94 // trigger instantiation of Foo
95 $services->getService( 'Foo' );
97 $this->assertInternalType(
99 $services->peekService( 'Foo' ),
100 'Peek should return the service object if it had been accessed before.'
104 $services->peekService( 'Bar' ),
105 'Peek should return null if the service was never accessed.'
109 public function testPeekService_fail_unknown() {
110 $services = $this->newServiceContainer();
112 $name = 'TestService92834576';
114 $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
116 $services->peekService( $name );
119 public function testDefineService() {
120 $services = $this->newServiceContainer();
122 $theService = new stdClass();
123 $name = 'TestService92834576';
125 $services->defineService( $name, function( $actualLocator ) use ( $services, $theService ) {
126 PHPUnit_Framework_Assert
::assertSame( $services, $actualLocator );
130 $this->assertTrue( $services->hasService( $name ) );
131 $this->assertSame( $theService, $services->getService( $name ) );
134 public function testDefineService_fail_duplicate() {
135 $services = $this->newServiceContainer();
137 $theService = new stdClass();
138 $name = 'TestService92834576';
140 $services->defineService( $name, function() use ( $theService ) {
144 $this->setExpectedException( 'MediaWiki\Services\ServiceAlreadyDefinedException' );
146 $services->defineService( $name, function() use ( $theService ) {
151 public function testApplyWiring() {
152 $services = $this->newServiceContainer();
155 'Foo' => function() {
158 'Bar' => function() {
163 $services->applyWiring( $wiring );
165 $this->assertSame( 'Foo!', $services->getService( 'Foo' ) );
166 $this->assertSame( 'Bar!', $services->getService( 'Bar' ) );
169 public function testLoadWiringFiles() {
170 $services = $this->newServiceContainer();
173 __DIR__
. '/TestWiring1.php',
174 __DIR__
. '/TestWiring2.php',
177 $services->loadWiringFiles( $wiringFiles );
179 $this->assertSame( 'Foo!', $services->getService( 'Foo' ) );
180 $this->assertSame( 'Bar!', $services->getService( 'Bar' ) );
183 public function testLoadWiringFiles_fail_duplicate() {
184 $services = $this->newServiceContainer();
187 __DIR__
. '/TestWiring1.php',
188 __DIR__
. '/./TestWiring1.php',
191 // loading the same file twice should fail, because
192 $this->setExpectedException( 'MediaWiki\Services\ServiceAlreadyDefinedException' );
194 $services->loadWiringFiles( $wiringFiles );
197 public function testRedefineService() {
198 $services = $this->newServiceContainer( [ 'Foo' ] );
200 $theService1 = new stdClass();
201 $name = 'TestService92834576';
203 $services->defineService( $name, function() {
204 PHPUnit_Framework_Assert
::fail(
205 'The original instantiator function should not get called'
209 // redefine before instantiation
210 $services->redefineService(
212 function( $actualLocator, $extra ) use ( $services, $theService1 ) {
213 PHPUnit_Framework_Assert
::assertSame( $services, $actualLocator );
214 PHPUnit_Framework_Assert
::assertSame( 'Foo', $extra );
219 // force instantiation, check result
220 $this->assertSame( $theService1, $services->getService( $name ) );
223 public function testRedefineService_fail_undefined() {
224 $services = $this->newServiceContainer();
226 $theService = new stdClass();
227 $name = 'TestService92834576';
229 $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
231 $services->redefineService( $name, function() use ( $theService ) {
236 public function testRedefineService_fail_in_use() {
237 $services = $this->newServiceContainer( [ 'Foo' ] );
239 $theService = new stdClass();
240 $name = 'TestService92834576';
242 $services->defineService( $name, function() {
246 // create the service, so it can no longer be redefined
247 $services->getService( $name );
249 $this->setExpectedException( 'MediaWiki\Services\CannotReplaceActiveServiceException' );
251 $services->redefineService( $name, function() use ( $theService ) {
256 public function testDisableService() {
257 $services = $this->newServiceContainer( [ 'Foo' ] );
259 $destructible = $this->getMock( 'MediaWiki\Services\DestructibleService' );
260 $destructible->expects( $this->once() )
261 ->method( 'destroy' );
263 $services->defineService( 'Foo', function() use ( $destructible ) {
264 return $destructible;
266 $services->defineService( 'Bar', function() {
267 return new stdClass();
269 $services->defineService( 'Qux', function() {
270 return new stdClass();
273 // instantiate Foo and Bar services
274 $services->getService( 'Foo' );
275 $services->getService( 'Bar' );
277 // disable service, should call destroy() once.
278 $services->disableService( 'Foo' );
280 // disabled service should still be listed
281 $this->assertContains( 'Foo', $services->getServiceNames() );
283 // getting other services should still work
284 $services->getService( 'Bar' );
286 // disable non-destructible service, and not-yet-instantiated service
287 $services->disableService( 'Bar' );
288 $services->disableService( 'Qux' );
290 $this->assertNull( $services->peekService( 'Bar' ) );
291 $this->assertNull( $services->peekService( 'Qux' ) );
293 // disabled service should still be listed
294 $this->assertContains( 'Bar', $services->getServiceNames() );
295 $this->assertContains( 'Qux', $services->getServiceNames() );
297 // re-enable Bar service
298 $services->redefineService( 'Bar', function() {
299 return new stdClass();
302 $services->getService( 'Bar' );
304 $this->setExpectedException( 'MediaWiki\Services\ServiceDisabledException' );
305 $services->getService( 'Qux' );
308 public function testDisableService_fail_undefined() {
309 $services = $this->newServiceContainer();
311 $theService = new stdClass();
312 $name = 'TestService92834576';
314 $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
316 $services->redefineService( $name, function() use ( $theService ) {
321 public function testDestroy() {
322 $services = $this->newServiceContainer();
324 $destructible = $this->getMock( 'MediaWiki\Services\DestructibleService' );
325 $destructible->expects( $this->once() )
326 ->method( 'destroy' );
328 $services->defineService( 'Foo', function() use ( $destructible ) {
329 return $destructible;
332 $services->defineService( 'Bar', function() {
333 return new stdClass();
336 // create the service
337 $services->getService( 'Foo' );
339 // destroy the container
340 $services->destroy();
342 $this->setExpectedException( 'MediaWiki\Services\ContainerDisabledException' );
343 $services->getService( 'Bar' );