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