001    package org.picocontainer.defaults;
002    
003    import org.picocontainer.ComponentAdapter;
004    import org.picocontainer.MutablePicoContainer;
005    import org.picocontainer.Parameter;
006    import org.picocontainer.PicoContainer;
007    import org.picocontainer.PicoIntrospectionException;
008    import org.picocontainer.testmodel.SimpleTouchable;
009    import org.picocontainer.testmodel.Touchable;
010    
011    import org.jmock.Mock;
012    import org.jmock.MockObjectTestCase;
013    
014    import java.util.Arrays;
015    import java.util.Collection;
016    import java.util.Collections;
017    import java.util.HashSet;
018    import java.util.List;
019    import java.util.Map;
020    import java.util.Set;
021    import java.util.SortedMap;
022    import java.util.SortedSet;
023    
024    
025    /**
026     * @author Aslak Hellesøy
027     * @author Jörg Schaible
028     * @version $Revision: 2789 $
029     */
030    public class CollectionComponentParameterTestCase
031            extends MockObjectTestCase {
032    
033        public void testShouldInstantiateArrayOfStrings() {
034            CollectionComponentParameter ccp = new CollectionComponentParameter();
035    
036            Mock componentAdapterMock = mock(ComponentAdapter.class);
037            componentAdapterMock.expects(atLeastOnce()).method("getComponentKey").will(returnValue("x"));
038            Mock containerMock = mock(PicoContainer.class);
039            containerMock.expects(once()).method("getComponentAdapters").withNoArguments().will(returnValue(new HashSet()));
040            containerMock.expects(once()).method("getComponentAdaptersOfType").with(eq(String.class)).will(
041                    returnValue(Arrays.asList(new ComponentAdapter[]{
042                            new InstanceComponentAdapter("y", "Hello"), new InstanceComponentAdapter("z", "World")})));
043            containerMock.expects(once()).method("getComponentInstance").with(eq("z")).will(returnValue("World"));
044            containerMock.expects(once()).method("getComponentInstance").with(eq("y")).will(returnValue("Hello"));
045            containerMock.expects(once()).method("getParent").withNoArguments().will(returnValue(null));
046    
047            List expected = Arrays.asList(new String[]{"Hello", "World"});
048            Collections.sort(expected);
049            List actual = Arrays.asList((Object[]) ccp.resolveInstance(
050                    (PicoContainer) containerMock.proxy(), (ComponentAdapter) componentAdapterMock.proxy(), String[].class));
051            Collections.sort(actual);
052            assertEquals(expected, actual);
053        }
054    
055        static public interface Fish {
056        }
057    
058        static public class Cod
059                implements Fish {
060            public String toString() {
061                return "Cod";
062            }
063        }
064    
065        static public class Shark
066                implements Fish {
067            public String toString() {
068                return "Shark";
069            }
070        }
071    
072        static public class Bowl {
073            private final Cod[] cods;
074            private final Fish[] fishes;
075    
076            public Bowl(Cod cods[], Fish fishes[]) {
077                this.cods = cods;
078                this.fishes = fishes;
079            }
080        }
081    
082        private MutablePicoContainer getDefaultPicoContainer() {
083            MutablePicoContainer mpc = new DefaultPicoContainer();
084            mpc.registerComponentImplementation(Bowl.class);
085            mpc.registerComponentImplementation(Cod.class);
086            mpc.registerComponentImplementation(Shark.class);
087            return mpc;
088        }
089    
090        public void testNativeArrays() {
091            MutablePicoContainer mpc = getDefaultPicoContainer();
092            Cod cod = (Cod) mpc.getComponentInstanceOfType(Cod.class);
093            Bowl bowl = (Bowl) mpc.getComponentInstance(Bowl.class);
094            assertEquals(1, bowl.cods.length);
095            assertEquals(2, bowl.fishes.length);
096            assertSame(cod, bowl.cods[0]);
097            assertNotSame(bowl.fishes[0], bowl.fishes[1]);
098        }
099    
100        public void testCollectionsAreGeneratedOnTheFly() {
101            MutablePicoContainer mpc = new DefaultPicoContainer();
102            mpc.registerComponent(new ConstructorInjectionComponentAdapter(Bowl.class, Bowl.class));
103            mpc.registerComponentImplementation(Cod.class);
104            Bowl bowl = (Bowl) mpc.getComponentInstance(Bowl.class);
105            assertEquals(1, bowl.cods.length);
106            mpc.registerComponentInstance("Nemo", new Cod());
107            bowl = (Bowl) mpc.getComponentInstance(Bowl.class);
108            assertEquals(2, bowl.cods.length);
109            assertNotSame(bowl.cods[0], bowl.cods[1]);
110        }
111    
112        static public class CollectedBowl {
113            private final Cod[] cods;
114            private final Fish[] fishes;
115    
116            public CollectedBowl(Collection cods, Collection fishes) {
117                this.cods = (Cod[]) cods.toArray(new Cod[cods.size()]);
118                this.fishes = (Fish[]) fishes.toArray(new Fish[fishes.size()]);
119            }
120        }
121    
122        public void testCollections() {
123            MutablePicoContainer mpc = new DefaultPicoContainer();
124            mpc.registerComponentImplementation(CollectedBowl.class, CollectedBowl.class, new Parameter[]{
125                    new ComponentParameter(Cod.class, false), new ComponentParameter(Fish.class, false)});
126            mpc.registerComponentImplementation(Cod.class);
127            mpc.registerComponentImplementation(Shark.class);
128            Cod cod = (Cod) mpc.getComponentInstanceOfType(Cod.class);
129            CollectedBowl bowl = (CollectedBowl) mpc.getComponentInstance(CollectedBowl.class);
130            assertEquals(1, bowl.cods.length);
131            assertEquals(2, bowl.fishes.length);
132            assertSame(cod, bowl.cods[0]);
133            assertNotSame(bowl.fishes[0], bowl.fishes[1]);
134        }
135    
136        static public class MappedBowl {
137            private final Fish[] fishes;
138    
139            public MappedBowl(Map map) {
140                Collection collection = map.values();
141                this.fishes = (Fish[]) collection.toArray(new Fish[collection.size()]);
142            }
143        }
144    
145        public void testMaps() {
146            MutablePicoContainer mpc = new DefaultPicoContainer();
147            mpc.registerComponentImplementation(MappedBowl.class, MappedBowl.class, new Parameter[]{new ComponentParameter(
148                    Fish.class, false)});
149            mpc.registerComponentImplementation(Cod.class);
150            mpc.registerComponentImplementation(Shark.class);
151            MappedBowl bowl = (MappedBowl) mpc.getComponentInstance(MappedBowl.class);
152            assertEquals(2, bowl.fishes.length);
153            assertNotSame(bowl.fishes[0], bowl.fishes[1]);
154        }
155    
156        public static class UngenericCollectionBowl {
157            public UngenericCollectionBowl(Collection fish) {
158            }
159        }
160    
161        public void testShouldNotInstantiateCollectionForUngenericCollectionParameters() {
162            MutablePicoContainer pico = getDefaultPicoContainer();
163            pico.registerComponentImplementation(UngenericCollectionBowl.class);
164            try {
165                pico.getComponentInstance(UngenericCollectionBowl.class);
166                fail();
167            } catch (UnsatisfiableDependenciesException e) {
168                // expected
169            }
170        }
171    
172        public static class AnotherGenericCollectionBowl {
173            private final String[] strings;
174    
175            public AnotherGenericCollectionBowl(String[] strings) {
176                this.strings = strings;
177            }
178    
179            public String[] getStrings() {
180                return strings;
181            }
182        }
183    
184        public void testShouldFailWhenThereAreNoComponentsToPutInTheArray() {
185            MutablePicoContainer pico = getDefaultPicoContainer();
186            pico.registerComponentImplementation(AnotherGenericCollectionBowl.class);
187            try {
188                pico.getComponentInstance(AnotherGenericCollectionBowl.class);
189                fail();
190            } catch (UnsatisfiableDependenciesException e) {
191                // expected
192            }
193        }
194    
195        public void testAllowsEmptyArraysIfEspeciallySet() {
196            MutablePicoContainer pico = getDefaultPicoContainer();
197            pico.registerComponentImplementation(
198                    AnotherGenericCollectionBowl.class, AnotherGenericCollectionBowl.class,
199                    new Parameter[]{ComponentParameter.ARRAY_ALLOW_EMPTY});
200            AnotherGenericCollectionBowl bowl = (AnotherGenericCollectionBowl) pico
201                    .getComponentInstance(AnotherGenericCollectionBowl.class);
202            assertNotNull(bowl);
203            assertEquals(0, bowl.strings.length);
204        }
205    
206        public static class TouchableObserver
207                implements Touchable {
208            private final Touchable[] touchables;
209    
210            public TouchableObserver(Touchable[] touchables) {
211                this.touchables = touchables;
212    
213            }
214    
215            public void touch() {
216                for (int i = 0; i < touchables.length; i++) {
217                    touchables[i].touch();
218                }
219            }
220        }
221    
222        public void testWillOmitSelfFromCollection() {
223            MutablePicoContainer pico = getDefaultPicoContainer();
224            pico.registerComponentImplementation(SimpleTouchable.class);
225            pico.registerComponentImplementation(TouchableObserver.class);
226            Touchable observer = (Touchable) pico.getComponentInstanceOfType(TouchableObserver.class);
227            assertNotNull(observer);
228            observer.touch();
229            SimpleTouchable touchable = (SimpleTouchable) pico.getComponentInstanceOfType(SimpleTouchable.class);
230            assertTrue(touchable.wasTouched);
231        }
232    
233        public void testWillRemoveComponentsWithMatchingKeyFromParent() {
234            MutablePicoContainer parent = new DefaultPicoContainer();
235            parent.registerComponentImplementation("Tom", Cod.class);
236            parent.registerComponentImplementation("Dick", Cod.class);
237            parent.registerComponentImplementation("Harry", Cod.class);
238            MutablePicoContainer child = new DefaultPicoContainer(parent);
239            child.registerComponentImplementation("Dick", Shark.class);
240            child.registerComponentImplementation(Bowl.class);
241            Bowl bowl = (Bowl) child.getComponentInstance(Bowl.class);
242            assertEquals(3, bowl.fishes.length);
243            assertEquals(2, bowl.cods.length);
244        }
245    
246        public void testBowlWithoutTom() {
247            MutablePicoContainer mpc = new DefaultPicoContainer();
248            mpc.registerComponentImplementation("Tom", Cod.class);
249            mpc.registerComponentImplementation("Dick", Cod.class);
250            mpc.registerComponentImplementation("Harry", Cod.class);
251            mpc.registerComponentImplementation(Shark.class);
252            mpc.registerComponentImplementation(CollectedBowl.class, CollectedBowl.class, new Parameter[]{
253                new CollectionComponentParameter(Cod.class, false) {
254                    protected boolean evaluate(ComponentAdapter adapter) {
255                        return !"Tom".equals(adapter.getComponentKey());
256                    }
257                },
258                new CollectionComponentParameter(Fish.class, false)
259            });
260            CollectedBowl bowl = (CollectedBowl) mpc.getComponentInstance(CollectedBowl.class);
261            Cod tom = (Cod) mpc.getComponentInstance("Tom");
262            assertEquals(4, bowl.fishes.length);
263            assertEquals(2, bowl.cods.length);
264            assertFalse(Arrays.asList(bowl.cods).contains(tom));
265        }
266    
267        public static class DependsOnAll {
268            public DependsOnAll(Set set, SortedSet sortedSet, Collection collection, List list, SortedMap sortedMap, Map map
269            // , ConcurrentMap concurrentMap, Queue queue, BlockingQueue blockingQueue
270            ) {
271                assertNotNull(set);
272                assertNotNull(sortedSet);
273                assertNotNull(collection);
274                assertNotNull(list);
275                assertNotNull(sortedMap);
276                assertNotNull(map);
277                //            assertNotNull(concurrentMap);
278                //            assertNotNull(queue);
279                //            assertNotNull(blockingQueue);
280            }
281        }
282    
283        public void testDifferentCollectiveTypesAreResolved() {
284            MutablePicoContainer pico = new DefaultPicoContainer();
285            CollectionComponentParameter parameter = new CollectionComponentParameter(Fish.class, true);
286            pico.registerComponentImplementation(DependsOnAll.class, DependsOnAll.class, new Parameter[]{
287                    parameter, parameter, parameter, parameter, parameter, parameter,
288            // parameter, parameter, parameter,
289                    });
290            assertNotNull(pico.getComponentInstance(DependsOnAll.class));
291        }
292    
293        public void testVerify() {
294            MutablePicoContainer pico = new DefaultPicoContainer();
295            CollectionComponentParameter parameterNonEmpty = CollectionComponentParameter.ARRAY;
296            pico.registerComponentImplementation(Shark.class);
297            parameterNonEmpty.verify(pico, null, Fish[].class);
298            try {
299                parameterNonEmpty.verify(pico, null, Cod[].class);
300                fail("(PicoIntrospectionException expected");
301            } catch (PicoIntrospectionException e) {
302                assertTrue(e.getMessage().indexOf(Cod.class.getName())>0);
303            }
304            CollectionComponentParameter parameterEmpty = CollectionComponentParameter.ARRAY_ALLOW_EMPTY;
305            parameterEmpty.verify(pico, null, Fish[].class);
306            parameterEmpty.verify(pico, null, Cod[].class);
307        }
308    
309        // PICO-243 : this test will fail if executed on jdk1.3 without commons-collections
310        public void testOrderOfElementsOfAnArrayDependencyIsPreserved() {
311            MutablePicoContainer pico = new DefaultPicoContainer();
312            pico.registerComponentInstance("first", "first");
313            pico.registerComponentInstance("second", "second");
314            pico.registerComponentInstance("third", "third");
315            pico.registerComponentInstance("fourth", "fourth");
316            pico.registerComponentInstance("fifth", "fifth");
317            pico.registerComponentImplementation(Truc.class);
318    
319            final List strings = pico.getComponentInstancesOfType(String.class);
320            assertEquals("first", strings.get(0));
321            assertEquals("second", strings.get(1));
322            assertEquals("third", strings.get(2));
323            assertEquals("fourth", strings.get(3));
324            assertEquals("fifth", strings.get(4));
325    
326            pico.getComponentInstanceOfType(Truc.class);
327        }
328    
329        public static final class Truc {
330            public Truc(String[] s) {
331                assertEquals("first", s[0]);
332                assertEquals("second", s[1]);
333                assertEquals("third", s[2]);
334                assertEquals("fourth", s[3]);
335                assertEquals("fifth", s[4]);
336            }
337        }
338    
339    }