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 }