    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     * Original code by                                                          *
    009     *****************************************************************************/
    010    package org.picocontainer.defaults;
    011
    012    import static org.junit.Assert.assertEquals;
    013    import static org.junit.Assert.assertFalse;
    014    import static org.junit.Assert.assertNotNull;
    015    import static org.junit.Assert.assertNotSame;
    016    import static org.junit.Assert.assertSame;
    017    import static org.junit.Assert.assertTrue;
    018    import static org.junit.Assert.fail;
    019    import static org.picocontainer.tck.MockFactory.mockeryWithCountingNamingScheme;
    020
    021    import java.util.Arrays;
    022    import java.util.Collection;
    023    import java.util.Collections;
    024    import java.util.HashSet;
    025    import java.util.List;
    026    import java.util.Map;
    027    import java.util.Set;
    028    import java.util.SortedMap;
    029    import java.util.SortedSet;
    030
    031    import org.jmock.Expectations;
    032    import org.jmock.Mockery;
    033    import org.jmock.integration.junit4.JMock;
    034    import org.junit.Test;
    035    import org.junit.runner.RunWith;
    036    import org.picocontainer.ComponentAdapter;
    037    import org.picocontainer.DefaultPicoContainer;
    038    import org.picocontainer.MutablePicoContainer;
    039    import org.picocontainer.PicoCompositionException;
    040    import org.picocontainer.PicoContainer;
    041    import org.picocontainer.adapters.InstanceAdapter;
    042    import org.picocontainer.behaviors.Caching;
    043    import org.picocontainer.injectors.AbstractInjector;
    044    import org.picocontainer.injectors.ConstructorInjector;
    045    import org.picocontainer.lifecycle.NullLifecycleStrategy;
    046    import org.picocontainer.monitors.NullComponentMonitor;
    047    import org.picocontainer.parameters.CollectionComponentParameter;
    048    import org.picocontainer.parameters.ComponentParameter;
    049    import org.picocontainer.testmodel.SimpleTouchable;
    050    import org.picocontainer.testmodel.Touchable;
    051
    052    /**
    053     * @author Aslak Helles&oslash;y
    054     * @author J&ouml;rg Schaible
    055     * @author Mauro Talevi
    056     */
    057    @SuppressWarnings("serial")
    058    @RunWith(JMock.class)
    059    public class CollectionComponentParameterTestCase {
    060
    061            private Mockery mockery = mockeryWithCountingNamingScheme();
    062
    063            @Test
    064            public void testShouldInstantiateArrayOfStrings() {
    065                    CollectionComponentParameter ccp = new CollectionComponentParameter();
    066                    final ComponentAdapter componentAdapter = mockery
    067                                    .mock(ComponentAdapter.class);
    068                    final PicoContainer picoContainer = mockery.mock(PicoContainer.class);
    069                    mockery.checking(new Expectations() {
    070                            {
    071                                    atLeast(1).of(componentAdapter).getComponentKey();
    072                                    will(returnValue("x"));
    073                                    one(picoContainer).getComponentAdapters();
    074                                    will(returnValue(new HashSet()));
    075                                    one(picoContainer).getComponentAdapters(
    076                                                    with(equal(String.class)));
    077                                    will(returnValue(Arrays.asList(new InstanceAdapter("y",
    078                                                    "Hello", new NullLifecycleStrategy(),
    079                                                    new NullComponentMonitor()), new InstanceAdapter("z",
    080                                                    "World", new NullLifecycleStrategy(),
    081                                                    new NullComponentMonitor()))));
    082                                    one(picoContainer).getComponent(with(equal("z")));
    083                                    will(returnValue("World"));
    084                                    one(picoContainer).getComponent(with(equal("y")));
    085                                    will(returnValue("Hello"));
    086                                    one(picoContainer).getParent();
    087                                    will(returnValue(null));
    088                            }
    089                    });
    090                    List expected = Arrays.asList("Hello", "World");
    091                    Collections.sort(expected);
    092                    List actual = Arrays.asList((Object[]) ccp.resolveInstance(
    093                                    picoContainer, componentAdapter, String[].class,
    094                                    null, false, null));
    095                    Collections.sort(actual);
    096                    assertEquals(expected, actual);
    097            }
    098
    099            static public interface Fish {
    100            }
    101
    102            static public class Cod implements Fish {
    103                    public String toString() {
    104                            return "Cod";
    105                    }
    106            }
    107
    108            static public class Shark implements Fish {
    109                    public String toString() {
    110                            return "Shark";
    111                    }
    112            }
    113
    114            static public class Bowl {
    115                    private final Cod[] cods;
    116                    private final Fish[] fishes;
    117
    118                    public Bowl(Cod cods[], Fish fishes[]) {
    119                            this.cods = cods;
    120                            this.fishes = fishes;
    121                    }
    122            }
    123
    124            private MutablePicoContainer getDefaultPicoContainer() {
    125                    MutablePicoContainer mpc = new DefaultPicoContainer(new Caching());
    126                    mpc.addComponent(Bowl.class);
    127                    mpc.addComponent(Cod.class);
    128                    mpc.addComponent(Shark.class);
    129                    return mpc;
    130            }
    131
    132            @Test
    133            public void testNativeArrays() {
    134                    MutablePicoContainer mpc = getDefaultPicoContainer();
    135                    Cod cod = mpc.getComponent(Cod.class);
    136                    Bowl bowl = mpc.getComponent(Bowl.class);
    137                    assertEquals(1, bowl.cods.length);
    138                    assertEquals(2, bowl.fishes.length);
    139                    assertSame(cod, bowl.cods[0]);
    140                    assertNotSame(bowl.fishes[0], bowl.fishes[1]);
    141            }
    142
    143            @Test
    144            public void testCollectionsAreGeneratedOnTheFly() {
    145                    MutablePicoContainer mpc = new DefaultPicoContainer();
    146                    mpc.addAdapter(new ConstructorInjector(Bowl.class, Bowl.class,
    147                                                    null, new NullComponentMonitor(),
    148                                                    new NullLifecycleStrategy(), false));
    149                    mpc.addComponent(Cod.class);
    150                    Bowl bowl = mpc.getComponent(Bowl.class);
    151                    assertEquals(1, bowl.cods.length);
    152                    mpc.addComponent("Nemo", new Cod());
    153                    bowl = mpc.getComponent(Bowl.class);
    154                    assertEquals(2, bowl.cods.length);
    155                    assertNotSame(bowl.cods[0], bowl.cods[1]);
    156            }
    157
    158            static public class CollectedBowl {
    159                    private final Cod[] cods;
    160                    private final Fish[] fishes;
    161
    162                    public CollectedBowl(Collection cods, Collection fishes) {
    163                            this.cods = (Cod[]) cods.toArray(new Cod[cods.size()]);
    164                            this.fishes = (Fish[]) fishes.toArray(new Fish[fishes.size()]);
    165                    }
    166            }
    167
    168            static public class GenericCollectedBowl extends CollectedBowl {
    169
    170                    public GenericCollectedBowl(Collection<Cod> cods, Collection<Fish> fishes) {
    171                super(cods, fishes);
    172            }
    173            }
    174
    175            @Test
    176            public void testCollections() {
    177                    MutablePicoContainer mpc = new DefaultPicoContainer(new Caching());
    178                    mpc.addComponent(CollectedBowl.class, CollectedBowl.class,
    179                                    new ComponentParameter(Cod.class, false),
    180                                    new ComponentParameter(Fish.class, false));
    181                    mpc.addComponent(Cod.class);
    182                    mpc.addComponent(Shark.class);
    183                    Cod cod = mpc.getComponent(Cod.class);
    184                    CollectedBowl bowl = mpc.getComponent(CollectedBowl.class);
    185                    assertEquals(1, bowl.cods.length);
    186                    assertEquals(2, bowl.fishes.length);
    187                    assertSame(cod, bowl.cods[0]);
    188                    assertNotSame(bowl.fishes[0], bowl.fishes[1]);
    189            }
    190
    191            @Test
    192            public void testGenericCollections() {
    193                    MutablePicoContainer mpc = new DefaultPicoContainer(new Caching());
    194                    mpc.addComponent(GenericCollectedBowl.class);
    195                    mpc.addComponent(Cod.class);
    196                    mpc.addComponent(Shark.class);
    197                    Cod cod = mpc.getComponent(Cod.class);
    198                    CollectedBowl bowl = mpc.getComponent(CollectedBowl.class);
    199                    assertEquals(1, bowl.cods.length);
    200                    assertEquals(2, bowl.fishes.length);
    201                    assertSame(cod, bowl.cods[0]);
    202                    assertNotSame(bowl.fishes[0], bowl.fishes[1]);
    203            }
    204
    205            static public class MappedBowl {
    206                    private final Fish[] fishes;
    207
    208                    public MappedBowl(Map map) {
    209                            Collection collection = map.values();
    210                            this.fishes = (Fish[]) collection.toArray(new Fish[collection
    211                                            .size()]);
    212                    }
    213            }
    214
    215            @Test
    216            public void testMaps() {
    217                    MutablePicoContainer mpc = new DefaultPicoContainer();
    218                    mpc.addComponent(MappedBowl.class, MappedBowl.class,
    219                                    new ComponentParameter(Fish.class, false));
    220                    mpc.addComponent(Cod.class);
    221                    mpc.addComponent(Shark.class);
    222                    MappedBowl bowl = mpc.getComponent(MappedBowl.class);
    223                    assertEquals(2, bowl.fishes.length);
    224                    assertNotSame(bowl.fishes[0], bowl.fishes[1]);
    225            }
    226
    227            public static class UngenericCollectionBowl {
    228                    public UngenericCollectionBowl(Collection fish) {
    229                    }
    230            }
    231
    232            @Test
    233            public void testShouldNotInstantiateCollectionForUngenericCollectionParameters() {
    234                    MutablePicoContainer pico = getDefaultPicoContainer();
    235                    pico.addComponent(UngenericCollectionBowl.class);
    236                    try {
    237                            pico.getComponent(UngenericCollectionBowl.class);
    238                            fail();
    239                    } catch (AbstractInjector.UnsatisfiableDependenciesException e) {
    240                            // expected
    241                    }
    242            }
    243
    244            public static class AnotherGenericCollectionBowl {
    245                    private final String[] strings;
    246
    247                    public AnotherGenericCollectionBowl(String[] strings) {
    248                            this.strings = strings;
    249                    }
    250
    251                    public String[] getStrings() {
    252                            return strings;
    253                    }
    254            }
    255
    256            @Test
    257            public void testShouldFailWhenThereAreNoComponentsToPutInTheArray() {
    258                    MutablePicoContainer pico = getDefaultPicoContainer();
    259                    pico.addComponent(AnotherGenericCollectionBowl.class);
    260                    try {
    261                            pico.getComponent(AnotherGenericCollectionBowl.class);
    262                            fail();
    263                    } catch (AbstractInjector.UnsatisfiableDependenciesException e) {
    264                            // expected
    265                    }
    266            }
    267
    268            @Test
    269            public void testAllowsEmptyArraysIfEspeciallySet() {
    270                    MutablePicoContainer pico = getDefaultPicoContainer();
    271                    pico.addComponent(AnotherGenericCollectionBowl.class,
    272                                    AnotherGenericCollectionBowl.class,
    273                                    ComponentParameter.ARRAY_ALLOW_EMPTY);
    274                    AnotherGenericCollectionBowl bowl = pico
    275                                    .getComponent(AnotherGenericCollectionBowl.class);
    276                    assertNotNull(bowl);
    277                    assertEquals(0, bowl.strings.length);
    278            }
    279
    280            public static class TouchableObserver implements Touchable {
    281                    private final Touchable[] touchables;
    282
    283                    public TouchableObserver(Touchable[] touchables) {
    284                            this.touchables = touchables;
    285
    286                    }
    287
    288                    public void touch() {
    289                            for (Touchable touchable : touchables) {
    290                                    touchable.touch();
    291                            }
    292                    }
    293            }
    294
    295            @Test
    296            public void testWillOmitSelfFromCollection() {
    297                    MutablePicoContainer pico = getDefaultPicoContainer();
    298                    pico.addComponent(SimpleTouchable.class);
    299                    pico.addComponent(TouchableObserver.class);
    300                    Touchable observer = pico.getComponent(TouchableObserver.class);
    301                    assertNotNull(observer);
    302                    observer.touch();
    303                    SimpleTouchable touchable = pico.getComponent(SimpleTouchable.class);
    304                    assertTrue(touchable.wasTouched);
    305            }
    306
    307            @Test
    308            public void testWillRemoveComponentsWithMatchingKeyFromParent() {
    309                    MutablePicoContainer parent = new DefaultPicoContainer();
    310                    parent.addComponent("Tom", Cod.class);
    311                    parent.addComponent("Dick", Cod.class);
    312                    parent.addComponent("Harry", Cod.class);
    313                    MutablePicoContainer child = new DefaultPicoContainer(parent);
    314                    child.addComponent("Dick", Shark.class);
    315                    child.addComponent(Bowl.class);
    316                    Bowl bowl = child.getComponent(Bowl.class);
    317                    assertEquals(3, bowl.fishes.length);
    318                    assertEquals(2, bowl.cods.length);
    319            }
    320
    321            @Test
    322            public void testBowlWithoutTom() {
    323                    MutablePicoContainer mpc = new DefaultPicoContainer();
    324                    mpc.addComponent("Tom", Cod.class);
    325                    mpc.addComponent("Dick", Cod.class);
    326                    mpc.addComponent("Harry", Cod.class);
    327                    mpc.addComponent(Shark.class);
    328                    mpc.addComponent(CollectedBowl.class, CollectedBowl.class,
    329                                    new CollectionComponentParameter(Cod.class, false) {
    330                                            protected boolean evaluate(ComponentAdapter adapter) {
    331                                                    return !"Tom".equals(adapter.getComponentKey());
    332                                            }
    333                                    }, new CollectionComponentParameter(Fish.class, false));
    334                    CollectedBowl bowl = mpc.getComponent(CollectedBowl.class);
    335                    Cod tom = (Cod) mpc.getComponent("Tom");
    336                    assertEquals(4, bowl.fishes.length);
    337                    assertEquals(2, bowl.cods.length);
    338                    assertFalse(Arrays.asList(bowl.cods).contains(tom));
    339            }
    340
    341            public static class DependsOnAll {
    342                    public DependsOnAll(Set set, SortedSet sortedSet,
    343                                    Collection collection, List list, SortedMap sortedMap, Map map
    344                    // , ConcurrentMap concurrentMap, Queue queue, BlockingQueue
    345                    // blockingQueue
    346                    ) {
    347                            assertNotNull(set);
    348                            assertNotNull(sortedSet);
    349                            assertNotNull(collection);
    350                            assertNotNull(list);
    351                            assertNotNull(sortedMap);
    352                            assertNotNull(map);
    353                            // assertNotNull(concurrentMap);
    354                            // assertNotNull(queue);
    355                            // assertNotNull(blockingQueue);
    356                    }
    357            }
    358
    359            @Test
    360            public void testDifferentCollectiveTypesAreResolved() {
    361                    MutablePicoContainer pico = new DefaultPicoContainer();
    362                    CollectionComponentParameter parameter = new CollectionComponentParameter(
    363                                    Fish.class, true);
    364                    pico.addComponent(DependsOnAll.class, DependsOnAll.class, parameter,
    365                                    parameter, parameter, parameter, parameter, parameter);
    366                    assertNotNull(pico.getComponent(DependsOnAll.class));
    367            }
    368
    369            @Test
    370            public void testVerify() {
    371                    MutablePicoContainer pico = new DefaultPicoContainer();
    372                    CollectionComponentParameter parameterNonEmpty = CollectionComponentParameter.ARRAY;
    373                    pico.addComponent(Shark.class);
    374                    parameterNonEmpty.verify(pico, null, Fish[].class, null, false, null);
    375                    try {
    376                            parameterNonEmpty
    377                                            .verify(pico, null, Cod[].class, null, false, null);
    378                            fail("(PicoCompositionException expected");
    379                    } catch (PicoCompositionException e) {
    380                            assertTrue(e.getMessage().indexOf(Cod.class.getName()) > 0);
    381                    }
    382                    CollectionComponentParameter parameterEmpty = CollectionComponentParameter.ARRAY_ALLOW_EMPTY;
    383                    parameterEmpty.verify(pico, null, Fish[].class, null, false, null);
    384                    parameterEmpty.verify(pico, null, Cod[].class, null, false, null);
    385            }
    386
    387            // PICO-243 : this test will fail if executed on jdk1.3 without
    388            // commons-collections
    389            @Test
    390            public void testOrderOfElementsOfAnArrayDependencyIsPreserved() {
    391                    MutablePicoContainer pico = new DefaultPicoContainer();
    392                    pico.addComponent("first", "first");
    393                    pico.addComponent("second", "second");
    394                    pico.addComponent("third", "third");
    395                    pico.addComponent("fourth", "fourth");
    396                    pico.addComponent("fifth", "fifth");
    397                    pico.addComponent(Truc.class);
    398
    399                    final List strings = pico.getComponents(String.class);
    400                    assertEquals("first", strings.get(0));
    401                    assertEquals("second", strings.get(1));
    402                    assertEquals("third", strings.get(2));
    403                    assertEquals("fourth", strings.get(3));
    404                    assertEquals("fifth", strings.get(4));
    405
    406                    pico.getComponent(Truc.class);
    407            }
    408
    409            public static final class Truc {
    410                    public Truc(String[] s) {
    411                            assertEquals("first", s[0]);
    412                            assertEquals("second", s[1]);
    413                            assertEquals("third", s[2]);
    414                            assertEquals("fourth", s[3]);
    415                            assertEquals("fifth", s[4]);
    416                    }
    417            }
    418
    419    }