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 }