001 /*****************************************************************************
002 * Copyright (c) PicoContainer Organization. All rights reserved. *
003 * ------------------------------------------------------------------------- *
004 * The software in this package is published under the terms of the BSD *
005 * style license a copy of which has been included with this distribution in *
006 * the LICENSE.txt file. *
007 * *
008 * Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant *
009 *****************************************************************************/
010 package org.picocontainer;
011
012 import static org.picocontainer.Characteristics.CDI;
013 import static org.picocontainer.Characteristics.SDI;
014 import org.picocontainer.behaviors.Caching;
015 import org.picocontainer.containers.EmptyPicoContainer;
016 import org.picocontainer.injectors.AbstractInjector;
017 import org.picocontainer.injectors.ConstructorInjection;
018 import org.picocontainer.injectors.ConstructorInjector;
019 import org.picocontainer.lifecycle.NullLifecycleStrategy;
020 import org.picocontainer.monitors.NullComponentMonitor;
021 import org.picocontainer.monitors.WriterComponentMonitor;
022 import org.picocontainer.tck.AbstractPicoContainerTestCase;
023 import org.picocontainer.testmodel.DecoratedTouchable;
024 import org.picocontainer.testmodel.DependsOnTouchable;
025 import org.picocontainer.testmodel.SimpleTouchable;
026 import org.picocontainer.testmodel.Touchable;
027
028 import java.io.Serializable;
029 import java.io.StringWriter;
030 import java.lang.reflect.Member;
031 import java.util.ArrayList;
032 import java.util.Collection;
033 import java.util.HashMap;
034 import java.util.LinkedList;
035 import java.util.List;
036 import java.util.Properties;
037 import java.util.Map;
038
039 /**
040 * @author Aslak Hellesøy
041 * @author Paul Hammant
042 * @author Ward Cunningham
043 * @author Mauro Talevi
044 */
045 public final class DefaultPicoContainerTestCase extends AbstractPicoContainerTestCase {
046 protected MutablePicoContainer createPicoContainer(PicoContainer parent) {
047 return new DefaultPicoContainer(parent);
048 }
049
050 protected Properties[] getProperties() {
051 return new Properties[0];
052 }
053
054 public void testInstantiationWithNullComponentFactory() {
055 try {
056 new DefaultPicoContainer((ComponentFactory)null, null);
057 fail("NPE expected");
058 } catch (NullPointerException e) {
059 // expected
060 }
061 }
062
063 public void testUpDownDependenciesCannotBeFollowed() {
064 MutablePicoContainer parent = createPicoContainer(null);
065 MutablePicoContainer child = createPicoContainer(parent);
066
067 // ComponentF -> ComponentA -> ComponentB+C
068 child.addComponent(ComponentF.class);
069 parent.addComponent(ComponentA.class);
070 child.addComponent(ComponentB.class);
071 child.addComponent(ComponentC.class);
072
073 try {
074 child.getComponent(ComponentF.class);
075 fail("Thrown " + AbstractInjector.UnsatisfiableDependenciesException.class.getName() + " expected");
076 } catch (final AbstractInjector.UnsatisfiableDependenciesException e) {
077 assertEquals(ComponentB.class, e.getUnsatisfiedDependencyType());
078 }
079 }
080
081
082 public void testComponentsCanBeRemovedByInstance() {
083 MutablePicoContainer pico = createPicoContainer(null);
084 pico.addComponent(HashMap.class);
085 pico.addComponent(ArrayList.class);
086 List list = pico.getComponent(List.class);
087 pico.removeComponentByInstance(list);
088 assertEquals(1, pico.getComponentAdapters().size());
089 assertEquals(1, pico.getComponents().size());
090 assertEquals(HashMap.class, pico.getComponent(Serializable.class).getClass());
091 }
092
093 public void testComponentInstancesListIsReturnedForNullType() {
094 MutablePicoContainer pico = createPicoContainer(null);
095 List componentInstances = pico.getComponents(null);
096 assertNotNull(componentInstances);
097 assertEquals(0, componentInstances.size());
098 }
099
100 public void testComponentsWithCommonSupertypeWhichIsAConstructorArgumentCanBeLookedUpByConcreteType() {
101 MutablePicoContainer pico = createPicoContainer(null);
102 pico.addComponent(LinkedList.class, LinkedList.class, Parameter.ZERO);
103 pico.addComponent(ArrayList.class);
104 assertEquals(ArrayList.class, pico.getComponent((Class)ArrayList.class).getClass());
105 }
106
107 /*
108 When pico tries to resolve DecoratedTouchable it find as dependency itself and SimpleTouchable.
109 Problem is basically the same as above. Pico should not consider self as solution.
110
111 JS
112 fixed it ( PICO-222 )
113 KP
114 */
115 public void testUnambiguouSelfDependency() {
116 MutablePicoContainer pico = createPicoContainer(null);
117 pico.addComponent(SimpleTouchable.class);
118 pico.addComponent(DecoratedTouchable.class);
119 Touchable t = (Touchable)pico.getComponent((Object)DecoratedTouchable.class);
120 assertNotNull(t);
121 }
122
123
124 public void testPicoUsedInBuilderStyle() {
125 MutablePicoContainer pico = createPicoContainer(null);
126 Touchable t = pico.change(Characteristics.CACHE)
127 .addComponent(SimpleTouchable.class)
128 .addComponent(DecoratedTouchable.class)
129 .getComponent(DecoratedTouchable.class);
130 SimpleTouchable t2 = pico.getComponent(SimpleTouchable.class);
131 assertNotNull(t);
132 assertNotNull(t2);
133 t.touch();
134 assertTrue(t2.wasTouched);
135 }
136
137 public static class Thingie {
138 public Thingie(List c) {
139 assertNotNull(c);
140 }
141 }
142
143 public void testThangCanBeInstantiatedWithArrayList() {
144 MutablePicoContainer pico = new DefaultPicoContainer();
145 pico.addComponent(Thingie.class);
146 pico.addComponent(ArrayList.class);
147 assertNotNull(pico.getComponent(Thingie.class));
148 }
149
150 public void testGetComponentAdaptersOfTypeNullReturnsEmptyList() {
151 DefaultPicoContainer pico = new DefaultPicoContainer();
152 List adapters = pico.getComponentAdapters(null);
153 assertNotNull(adapters);
154 assertEquals(0, adapters.size());
155 }
156
157
158 public static class Service {
159 }
160
161 public static final class TransientComponent {
162 private final Service service;
163
164 public TransientComponent(Service service) {
165 this.service = service;
166 }
167 }
168
169 public void testDefaultPicoContainerReturnsNewInstanceForEachCallWhenUsingTransientComponentAdapter() {
170
171
172 DefaultPicoContainer picoContainer =
173 new DefaultPicoContainer(new Caching().wrap(new ConstructorInjection()));
174
175 picoContainer.addComponent(Service.class);
176 picoContainer.as(Characteristics.NO_CACHE)
177 .addAdapter(new ConstructorInjector(TransientComponent.class,
178 TransientComponent.class,
179 null,
180 new NullComponentMonitor(),
181 new NullLifecycleStrategy()));
182 TransientComponent c1 = picoContainer.getComponent(TransientComponent.class);
183 TransientComponent c2 = picoContainer.getComponent(TransientComponent.class);
184 assertNotSame(c1, c2);
185 assertSame(c1.service, c2.service);
186 }
187
188 public static class DependsOnCollection {
189 public DependsOnCollection(Collection c) {
190 }
191 }
192
193 public void testShouldProvideInfoAboutDependingWhenAmbiguityHappens() {
194 MutablePicoContainer pico = this.createPicoContainer(null);
195 pico.addComponent(new ArrayList());
196 pico.addComponent(new LinkedList());
197 pico.addComponent(DependsOnCollection.class);
198 try {
199 pico.getComponent(DependsOnCollection.class);
200 fail();
201 } catch (AbstractInjector.AmbiguousComponentResolutionException expected) {
202 String doc = DependsOnCollection.class.getName();
203 assertEquals("class " + doc +
204 " needs a 'java.util.Collection' injected, but there are too many choices to inject. These:[class java.util.ArrayList, class java.util.LinkedList], refer http://picocontainer.org/ambiguous-injectable-help.html",
205 expected.getMessage());
206 }
207 }
208
209 public void testInstantiationWithMonitorAndParent() {
210 StringWriter writer = new StringWriter();
211 ComponentMonitor monitor = new WriterComponentMonitor(writer);
212 DefaultPicoContainer parent = new DefaultPicoContainer();
213 DefaultPicoContainer child = new DefaultPicoContainer(monitor, parent);
214 parent.addComponent("st", SimpleTouchable.class);
215 child.addComponent("dot", DependsOnTouchable.class);
216 DependsOnTouchable dot = (DependsOnTouchable)child.getComponent("dot");
217 assertNotNull(dot);
218 assertTrue("writer not empty", writer.toString().length() > 0);
219 }
220
221 public void testStartCapturedByMonitor() {
222 final StringBuffer sb = new StringBuffer();
223 DefaultPicoContainer dpc = new DefaultPicoContainer(new NullComponentMonitor() {
224 public void invoking(PicoContainer container,
225 ComponentAdapter componentAdapter,
226 Member member,
227 Object instance)
228 {
229 sb.append(member.toString());
230 }
231 });
232 dpc.as(Characteristics.CACHE).addComponent(DefaultPicoContainer.class);
233 dpc.start();
234 assertEquals("ComponentMonitor should have been notified that the component had been started",
235 "public abstract void org.picocontainer.Startable.start()", sb.toString());
236 }
237
238 public static class StartableClazz implements Startable {
239 private MutablePicoContainer _pico;
240
241 public void start() {
242 List<SimpleTouchable> cps = _pico
243 .getComponents(SimpleTouchable.class);
244 assertNotNull(cps);
245 }
246
247 public void stop() {
248 }
249
250 }
251
252 public void testListComponentsOnStart() {
253
254 // This is really discouraged. Breaks basic principals of IoC - components should not refer
255 // to their containers
256 //
257 // Might be deleted in due coure, along with adaptersClone stuff in DPC
258
259 DefaultPicoContainer dpc = new DefaultPicoContainer();
260 dpc.addComponent(SimpleTouchable.class);
261 StartableClazz cl = new StartableClazz();
262 cl._pico = dpc;
263 dpc.addComponent(cl);
264 dpc.start();
265 }
266
267 public void testCanChangeMonitor() {
268 StringWriter writer1 = new StringWriter();
269 ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
270 DefaultPicoContainer pico = new DefaultPicoContainer(monitor1);
271 pico.addComponent("t1", SimpleTouchable.class);
272 pico.addComponent("t3", SimpleTouchable.class);
273 Touchable t1 = (Touchable)pico.getComponent("t1");
274 assertNotNull(t1);
275 final String s = writer1.toString();
276 assertTrue("writer not empty", s.length() > 0);
277 StringWriter writer2 = new StringWriter();
278 ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
279 pico.changeMonitor(monitor2);
280 pico.addComponent("t2", SimpleTouchable.class);
281 Touchable t2 = (Touchable)pico.getComponent("t2");
282 assertNotNull(t2);
283 final String s2 = writer2.toString();
284 assertTrue("writer not empty", s2.length() > 0);
285 assertTrue("writers of same length", writer1.toString().length() == writer2.toString().length());
286 Touchable t3 = (Touchable)pico.getComponent("t3");
287 assertNotNull(t3);
288 assertTrue("old writer was used", writer1.toString().length() < writer2.toString().length());
289 }
290
291 public void testCanChangeMonitorOfChildContainers() {
292 StringWriter writer1 = new StringWriter();
293 ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
294 DefaultPicoContainer parent = new DefaultPicoContainer();
295 DefaultPicoContainer child = new DefaultPicoContainer(monitor1);
296 parent.addChildContainer(child);
297 child.addComponent("t1", SimpleTouchable.class);
298 child.addComponent("t3", SimpleTouchable.class);
299 Touchable t1 = (Touchable)child.getComponent("t1");
300 assertNotNull(t1);
301 assertTrue("writer not empty", writer1.toString().length() > 0);
302 StringWriter writer2 = new StringWriter();
303 ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
304 parent.changeMonitor(monitor2);
305 child.addComponent("t2", SimpleTouchable.class);
306 Touchable t2 = (Touchable)child.getComponent("t2");
307 assertNotNull(t2);
308 assertTrue("writer not empty", writer2.toString().length() > 0);
309 String s1 = writer1.toString();
310 String s2 = writer2.toString();
311 assertTrue("writers of same length", s1.length() == s2.length());
312 Touchable t3 = (Touchable)child.getComponent("t3");
313 assertNotNull(t3);
314 assertTrue("old writer was used", writer1.toString().length() < writer2.toString().length());
315 }
316
317 public void testChangeMonitorIsIgnoredIfNotSupportingStrategy() {
318 StringWriter writer = new StringWriter();
319 ComponentMonitor monitor = new WriterComponentMonitor(writer);
320 DefaultPicoContainer parent =
321 new DefaultPicoContainer(new ComponentFactoryWithNoMonitor(new ComponentAdapterWithNoMonitor(new SimpleTouchable())));
322 parent.addChildContainer(new EmptyPicoContainer());
323 parent.addComponent("t1", SimpleTouchable.class);
324 parent.changeMonitor(monitor);
325 assertTrue("writer empty", writer.toString().length() == 0);
326 }
327
328 public void testCanReturnCurrentMonitorFromComponentFactory() {
329 StringWriter writer1 = new StringWriter();
330 ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
331 DefaultPicoContainer pico = new DefaultPicoContainer(monitor1);
332 assertEquals(monitor1, pico.currentMonitor());
333 StringWriter writer2 = new StringWriter();
334 ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
335 pico.changeMonitor(monitor2);
336 assertEquals(monitor2, pico.currentMonitor());
337 }
338
339 private static final class ComponentFactoryWithNoMonitor implements ComponentFactory {
340 private final ComponentAdapter adapter;
341
342 public ComponentFactoryWithNoMonitor(ComponentAdapter adapter) {
343 this.adapter = adapter;
344 }
345
346 public ComponentAdapter createComponentAdapter(ComponentMonitor componentMonitor,
347 LifecycleStrategy lifecycleStrategy,
348 Properties componentProperties,
349 Object componentKey,
350 Class componentImplementation,
351 Parameter... parameters) throws PicoCompositionException
352 {
353 return adapter;
354 }
355 }
356
357 private static final class ComponentAdapterWithNoMonitor implements ComponentAdapter {
358 private final Object instance;
359
360 public ComponentAdapterWithNoMonitor(Object instance) {
361 this.instance = instance;
362 }
363
364 public Object getComponentKey() {
365 return instance.getClass();
366 }
367
368 public Class getComponentImplementation() {
369 return instance.getClass();
370 }
371
372 public Object getComponentInstance(PicoContainer container) throws PicoCompositionException {
373 return instance;
374 }
375
376 public void verify(PicoContainer container) throws PicoCompositionException {
377 }
378
379 public void accept(PicoVisitor visitor) {
380 }
381
382 public ComponentAdapter getDelegate() {
383 return null;
384 }
385
386 public ComponentAdapter findAdapterOfType(Class componentAdapterType) {
387 return null;
388 }
389 }
390
391 public void testMakeChildContainer() {
392 MutablePicoContainer parent = new DefaultPicoContainer();
393 parent.addComponent("t1", SimpleTouchable.class);
394 MutablePicoContainer child = parent.makeChildContainer();
395 Object t1 = child.getParent().getComponent("t1");
396 assertNotNull(t1);
397 assertTrue(t1 instanceof SimpleTouchable);
398 }
399
400 public void testCanUseCustomLifecycleStrategyForClassRegistrations() {
401 DefaultPicoContainer dpc = new DefaultPicoContainer(new FailingLifecycleStrategy(), null);
402 dpc.as(Characteristics.CACHE).addComponent(Startable.class, MyStartable.class);
403 try {
404 dpc.start();
405 fail("should have barfed");
406 } catch (RuntimeException e) {
407 assertEquals("foo", e.getMessage());
408 }
409 }
410
411 public void testCanUseCustomLifecycleStrategyForInstanceRegistrations() {
412 DefaultPicoContainer dpc = new DefaultPicoContainer(new FailingLifecycleStrategy(), null);
413 Startable myStartable = new MyStartable();
414 dpc.addComponent(Startable.class, myStartable);
415 try {
416 dpc.start();
417 fail("should have barfed");
418 } catch (RuntimeException e) {
419 assertEquals("foo", e.getMessage());
420 }
421 }
422
423 public static class FailingLifecycleStrategy implements LifecycleStrategy {
424 public void start(Object component) {
425 throw new RuntimeException("foo");
426 }
427
428 public void stop(Object component) {
429 }
430
431 public void dispose(Object component) {
432 }
433
434 public boolean hasLifecycle(Class type) {
435 return true;
436 }
437
438 }
439
440 public static class MyStartable implements Startable {
441 public MyStartable() {
442 }
443
444 public void start() {
445 }
446
447 public void stop() {
448 }
449 }
450
451 public static interface A {
452
453 }
454
455 public static class SimpleA implements A {
456
457 }
458
459 public static class WrappingA implements A {
460 private final A wrapped;
461
462 public WrappingA(A wrapped) {
463 this.wrapped = wrapped;
464 }
465 }
466
467 public void testCanRegisterTwoComponentsImplementingSameInterfaceOneWithInterfaceAsKey() throws Exception {
468 MutablePicoContainer container = createPicoContainer(null);
469
470 container.addComponent(SimpleA.class);
471 container.addComponent(A.class, WrappingA.class);
472
473 container.start();
474
475 assertEquals(WrappingA.class, container.getComponent(A.class).getClass());
476 }
477
478 public void testCanRegisterTwoComponentsWithSameImplementionAndDifferentKey() throws Exception {
479 MutablePicoContainer container = createPicoContainer(null);
480
481 container.addComponent(SimpleA.class);
482 container.addComponent("A", SimpleA.class);
483
484 container.start();
485
486 assertNotNull(container.getComponent("A"));
487 assertNotNull(container.getComponent(SimpleA.class));
488 assertNotSame(container.getComponent("A"), container.getComponent(SimpleA.class));
489 }
490
491 public void testPicoCanDifferentiateBetweenNamedStringsThatWouldOtherwiseBeAmbiguous() {
492 MutablePicoContainer mpc = createPicoContainer(null);
493 mpc.addComponent("greeting", "1");
494 mpc.addComponent("message", "2");
495 mpc.addComponent(PicoCompositionException.class, PicoCompositionException.class);
496 assertEquals("2", mpc.getComponent(PicoCompositionException.class).getMessage());
497 }
498
499 public void testPicoCanDifferentiateBetweenNamedObjectsThatWouldOtherwiseBeAmbiguous() {
500 MutablePicoContainer mpc = createPicoContainer(null);
501 Horse dobbin = new Horse();
502 Horse redRum = new Horse();
503 mpc.addComponent("dobbin", dobbin);
504 mpc.addComponent("horse", redRum);
505 mpc.addComponent(CdiTurtle.class);
506 assertEquals(redRum, mpc.getComponent(CdiTurtle.class).horse);
507 }
508
509 public void testPicoCanDifferentiateBetweenNamedIntsThatWouldOtherwiseBeAmbiguous() {
510 MutablePicoContainer mpc = createPicoContainer(null);
511 mpc.addComponent("one", 1);
512 mpc.addComponent("two", 2);
513 mpc.addComponent(NeedsTwo.class);
514 assertEquals(2, mpc.getComponent(NeedsTwo.class).two);
515 }
516
517 public static class NeedsTwo {
518 private final int two;
519
520 public NeedsTwo(Integer two) {
521 this.two = two;
522 }
523 }
524
525 public static class Horse {
526 }
527
528 public static class CdiTurtle {
529 public final Horse horse;
530
531 public CdiTurtle(Horse horse) {
532 this.horse = horse;
533 }
534 }
535
536 public static class SdiDonkey {
537 public Horse horse;
538
539 public void setHorse(Horse horse) {
540 this.horse = horse;
541 }
542 }
543
544 public static class SdiRabbit {
545 public Horse horse;
546
547 public void setHorse(Horse horse) {
548 this.horse = horse;
549 }
550 }
551
552 public void testMixingOfSDIandCDI() {
553
554 MutablePicoContainer container = createPicoContainer(null).change(Characteristics.CACHE);
555 container.addComponent(Horse.class);
556 container.change(SDI);
557 container.addComponent(SdiDonkey.class);
558 container.addComponent(SdiRabbit.class);
559 container.change(CDI);
560 container.addComponent(CdiTurtle.class);
561
562 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
563 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
564 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
565
566 assertions(donkey, rabbit, turtle);
567 }
568
569 public void testMixingOfSDIandCDIDifferently() {
570
571 MutablePicoContainer container = createPicoContainer(null).change(Characteristics.CACHE);
572 container.addComponent(Horse.class);
573 container.addComponent(CdiTurtle.class);
574 container.change(SDI);
575 container.addComponent(SdiDonkey.class);
576 container.addComponent(SdiRabbit.class);
577
578 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
579 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
580 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
581
582 assertions(donkey, rabbit, turtle);
583 }
584
585 public void testMixingOfSDIandCDIInBuilderStyle() {
586
587 MutablePicoContainer container = createPicoContainer(null).change(Characteristics.CACHE);
588 container.addComponent(Horse.class).change(SDI)
589 .addComponent(SdiDonkey.class).addComponent(SdiRabbit.class).change(CDI).addComponent(CdiTurtle.class);
590
591 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
592 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
593 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
594
595 assertions(donkey, rabbit, turtle);
596 }
597
598 private void assertions(SdiDonkey donkey, SdiRabbit rabbit, CdiTurtle turtle) {
599 assertNotNull(rabbit);
600 assertNotNull(donkey);
601 assertNotNull(turtle);
602 assertNotNull(turtle.horse);
603 assertNotNull(donkey.horse);
604 assertNotNull(rabbit.horse);
605 assertSame(donkey.horse, turtle.horse);
606 assertSame(rabbit.horse, turtle.horse);
607 }
608
609 public void testMixingOfSDIandCDIWithTemporaryCharacterizations() {
610
611 MutablePicoContainer container = createPicoContainer(null).change(Characteristics.CACHE);
612 container.addComponent(Horse.class);
613 container.addComponent(CdiTurtle.class);
614 container.as(SDI).addComponent(SdiDonkey.class);
615 container.as(SDI).addComponent(SdiRabbit.class);
616
617 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
618 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
619 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
620
621 assertions(donkey, rabbit, turtle);
622 }
623
624 public void testMixingOfSDIandCDIWithTemporaryCharacterizationsDifferently() {
625
626 MutablePicoContainer container = createPicoContainer(null).change(Characteristics.CACHE);
627 container.as(SDI).addComponent(SdiDonkey.class);
628 container.as(SDI).addComponent(SdiRabbit.class);
629 container.addComponent(Horse.class);
630 container.addComponent(CdiTurtle.class);
631
632 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
633 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
634 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
635
636 assertions(donkey, rabbit, turtle);
637 }
638
639 public void testNoComponentIsMonitoredAndPotentiallyLateProvided() {
640 final String[] missingKey = new String[1];
641
642 String foo = (String)new DefaultPicoContainer(new NullComponentMonitor() {
643 public Object noComponentFound(MutablePicoContainer container, Object componentKey) {
644 missingKey[0] = (String)componentKey;
645 return "foo";
646 }
647 }).getComponent("missingKey");
648
649 assertNotNull(missingKey[0]);
650 assertEquals("missingKey", missingKey[0]);
651 assertEquals("foo", foo);
652
653 }
654
655 public void testThatComponentCannotBeRemovedFromStartedContainer() {
656 MutablePicoContainer container = createPicoContainer(null);
657 container.addComponent(Map.class, HashMap.class);
658 container.start();
659 try {
660 container.removeComponent(Map.class);
661 fail("should have barfed");
662 } catch (PicoCompositionException e) {
663 }
664 }
665 }