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