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