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(),
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 }