1 /******************************************************************************
2 * Copyright (C) PicoContainer Organization. All rights reserved. *
3 * ------------------------------------------------------------------------- *
4 * The software in this package is published under the terms of the BSD *
5 * style license a copy of which has been included with this distribution in *
6 * the LICENSE.txt file. *
7 * *
8 * Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant *
9 *****************************************************************************/
10
11 package picocontainer.hierarchical;
12
13 import junit.framework.TestCase;
14
15 import java.io.Serializable;
16 import java.lang.reflect.Constructor;
17 import java.util.List;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Vector;
21
22 import picocontainer.testmodel.FlintstonesImpl;
23 import picocontainer.testmodel.FredImpl;
24 import picocontainer.testmodel.Wilma;
25 import picocontainer.testmodel.WilmaImpl;
26 import picocontainer.testmodel.Dictionary;
27 import picocontainer.testmodel.Webster;
28 import picocontainer.testmodel.Thesaurus;
29 import picocontainer.PicoInitializationException;
30 import picocontainer.PicoRegistrationException;
31 import picocontainer.ClassRegistrationPicoContainer;
32 import picocontainer.PicoContainer;
33 import picocontainer.ComponentFactory;
34 import picocontainer.PicoInvocationTargetInitailizationException;
35 import picocontainer.defaults.DefaultComponentFactory;
36 import picocontainer.defaults.NullContainer;
37
38 public class HierarchicalPicoContainerTestCase extends TestCase {
39
40 public void testBasicContainerAsserts() {
41 try {
42 new HierarchicalPicoContainer(new DefaultComponentFactory(), null);
43 fail("Should have had NPE)");
44 } catch (NullPointerException npe) {
45 // expected
46 }
47 try {
48 new HierarchicalPicoContainer(null, new NullContainer());
49 fail("Should have had NPE)");
50 } catch (NullPointerException npe) {
51 // expected
52 }
53 }
54
55 public void testBasicRegAndStart() throws PicoInitializationException, PicoRegistrationException {
56 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
57
58 pico.registerComponent(FredImpl.class);
59 pico.registerComponent(WilmaImpl.class);
60
61 pico.instantiateComponents();
62
63 assertEquals("There should be two comps in the container", 2, pico.getComponents().length);
64
65 assertTrue("There should have been a Fred in the container", pico.hasComponent(FredImpl.class));
66 assertTrue("There should have been a Wilma in the container", pico.hasComponent(WilmaImpl.class));
67 }
68
69 public void testTooFewComponents() throws PicoInitializationException, PicoRegistrationException {
70 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
71
72 pico.registerComponent(FredImpl.class);
73
74 try {
75 pico.instantiateComponents();
76 fail("should need a wilma");
77 } catch (UnsatisfiedDependencyStartupException e) {
78 // expected
79 assertTrue(e.getClassThatNeedsDeps() == FredImpl.class);
80 assertTrue(e.getMessage().indexOf(FredImpl.class.getName()) > 0);
81
82 }
83 }
84
85 public void testDupeImplementationsOfComponents() throws PicoInitializationException {
86
87 List messages = new ArrayList();
88 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
89 try {
90 pico.registerComponent(List.class, messages);
91 pico.registerComponent(Dictionary.class, Webster.class);
92 pico.registerComponent(Thesaurus.class, Webster.class);
93 pico.instantiateComponents();
94
95 assertEquals("Should only have one instance of Webster", 1, messages.size());
96 Object dictionary = pico.getComponent(Dictionary.class);
97 Object thesaurus = pico.getComponent(Thesaurus.class);
98 assertSame("The dictionary and the thesaurus should heve been the same object", dictionary, thesaurus);
99
100 } catch (PicoRegistrationException e) {
101 fail("Should not have barfed with dupe registration");
102 }
103 }
104
105 public void testDupeTypesWithClass() throws PicoInitializationException, PicoRegistrationException {
106 ClassRegistrationPicoContainer pico = new HierarchicalPicoContainer.Default();
107
108 pico.registerComponent(WilmaImpl.class);
109 try {
110 pico.registerComponent(WilmaImpl.class);
111 fail("Should have barfed with dupe registration");
112 } catch (DuplicateComponentTypeRegistrationException e) {
113 // expected
114 assertTrue(e.getDuplicateClass() == WilmaImpl.class);
115 assertTrue(e.getMessage().indexOf(WilmaImpl.class.getName()) > 0);
116 }
117 }
118
119 public void testDupeTypesWithObject() throws PicoInitializationException, PicoRegistrationException {
120 ClassRegistrationPicoContainer pico = new HierarchicalPicoContainer.Default();
121
122 pico.registerComponent(WilmaImpl.class);
123 try {
124 pico.registerComponent(WilmaImpl.class, new WilmaImpl());
125 fail("Should have barfed with dupe registration");
126 } catch (DuplicateComponentTypeRegistrationException e) {
127 // expected
128 assertTrue(e.getDuplicateClass() == WilmaImpl.class);
129 assertTrue(e.getMessage().indexOf(WilmaImpl.class.getName()) > 0);
130 }
131 }
132
133 public static class DerivedWilma extends WilmaImpl {
134 public DerivedWilma() {
135 }
136 }
137
138 public void testAmbiguousHierarchy() throws PicoRegistrationException, PicoInitializationException {
139
140 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
141
142 // Register two Wilmas that Fred will be confused about
143 pico.registerComponent(WilmaImpl.class);
144 pico.registerComponent(DerivedWilma.class);
145
146 // Register a confused Fred
147 pico.registerComponent(FredImpl.class);
148
149 try {
150 pico.instantiateComponents();
151 fail("Fred should have been confused about the two Wilmas");
152 } catch (AmbiguousComponentResolutionException e) {
153 // expected
154
155 List ambiguous = Arrays.asList(e.getAmbiguousClasses());
156 assertTrue(ambiguous.contains(DerivedWilma.class));
157 assertTrue(ambiguous.contains(WilmaImpl.class));
158 assertTrue(e.getMessage().indexOf(WilmaImpl.class.getName()) > 0);
159 assertTrue(e.getMessage().indexOf(DerivedWilma.class.getName()) > 0);
160 }
161 }
162
163 public void testRegisterComponentWithObject() throws PicoRegistrationException, PicoInitializationException {
164 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
165
166 pico.registerComponent(FredImpl.class);
167 pico.registerComponent(new WilmaImpl());
168
169 pico.instantiateComponents();
170
171 assertTrue("There should have been a Fred in the container", pico.hasComponent(FredImpl.class));
172 assertTrue("There should have been a Wilma in the container", pico.hasComponent(WilmaImpl.class));
173 }
174
175 public void testRegisterComponentWithObjectBadType() {
176 ClassRegistrationPicoContainer pico = new HierarchicalPicoContainer.Default();
177
178 try {
179 pico.registerComponent(Serializable.class, new Object());
180 fail("Shouldn't be able to register an Object as Serializable");
181 } catch (PicoRegistrationException e) {
182
183 }
184
185 }
186
187 public void testComponentRegistrationMismatch() throws PicoInitializationException, PicoRegistrationException {
188 ClassRegistrationPicoContainer pico = new HierarchicalPicoContainer.Default();
189
190
191 try {
192 pico.registerComponent(List.class, WilmaImpl.class);
193 } catch (AssignabilityRegistrationException e) {
194 // not worded in message
195 assertTrue(e.getMessage().indexOf(List.class.getName()) > 0);
196 assertTrue(e.getMessage().indexOf(WilmaImpl.class.getName()) > 0);
197 }
198
199 }
200
201 public void testMultipleArgumentConstructor() throws Throwable /* fixme */ {
202 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
203
204 pico.registerComponent(FredImpl.class);
205 pico.registerComponent(Wilma.class, WilmaImpl.class);
206 pico.registerComponent(FlintstonesImpl.class);
207
208 pico.instantiateComponents();
209
210 assertTrue("There should have been a FlintstonesImpl in the container", pico.hasComponent(FlintstonesImpl.class));
211 }
212
213 public void testGetComponentTypes() throws PicoRegistrationException, PicoInitializationException {
214 // ASLAK: don't declare as Impl. For IDEA jumps only
215 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
216
217 pico.registerComponent(FredImpl.class);
218 pico.registerComponent(Wilma.class, WilmaImpl.class);
219
220 // You might have thought that starting the container shouldn't be necessary
221 // just to get the types, but it is. The map holding the types->component instances
222 // doesn't receive anything until the components are instantiated.
223 pico.instantiateComponents();
224
225 List types = Arrays.asList(pico.getComponentTypes());
226 assertEquals("There should be 2 types", 2, types.size());
227 assertTrue("There should be a FredImpl type", types.contains(FredImpl.class));
228 assertTrue("There should be a Wilma type", types.contains(Wilma.class));
229 assertTrue("There should not be a WilmaImpl type", !types.contains(WilmaImpl.class));
230 }
231
232 public void testParentContainer() throws PicoRegistrationException, PicoInitializationException {
233
234 final Wilma wilma = new WilmaImpl();
235
236 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.WithParentContainer(new PicoContainer() {
237 public boolean hasComponent(Class componentType) {
238 return componentType == Wilma.class;
239 }
240
241 public Object getComponent(Class componentType) {
242 return componentType == Wilma.class ? wilma : null;
243 }
244
245 public Object[] getComponents() {
246 return new Object[]{wilma};
247 }
248
249 public Class[] getComponentTypes() {
250 return new Class[]{Wilma.class};
251 }
252
253 public void instantiateComponents() throws PicoInitializationException {
254 }
255 });
256
257 pico.registerComponent(FredImpl.class);
258
259 pico.instantiateComponents();
260
261 assertEquals("The parent should return 2 components (one from the parent)", 2, pico.getComponents().length);
262 assertTrue("Wilma should have been passed through the parent container", pico.hasComponent(Wilma.class));
263 assertTrue("There should have been a FredImpl in the container", pico.hasComponent(FredImpl.class));
264
265 }
266
267
268
269 public void testTooManyContructors() throws PicoRegistrationException, PicoInitializationException {
270
271 ClassRegistrationPicoContainer pico = new HierarchicalPicoContainer.Default();
272
273 try {
274 pico.registerComponent(Vector.class);
275 fail("Should fail because there are more than one constructors");
276 } catch (WrongNumberOfConstructorsRegistrationException e) {
277 assertTrue(e.getMessage().indexOf("4") > 0); //expected
278 // expected;
279 }
280
281 }
282
283 public void testRegisterAbstractShouldFail() throws PicoRegistrationException {
284 ClassRegistrationPicoContainer pico = new HierarchicalPicoContainer.Default();
285
286 try {
287 pico.registerComponent(Runnable.class);
288 fail("Shouldn't be allowed to register abstract classes or interfaces.");
289 } catch (NotConcreteRegistrationException e) {
290 assertEquals(Runnable.class, e.getComponentImplementation());
291 assertTrue(e.getMessage().indexOf(Runnable.class.getName()) > 0);
292 }
293 }
294
295
296 public static class A {
297 public A(B b) {
298 }
299 }
300
301 public static class B {
302 public B(C c, D d) {
303 }
304 }
305
306 public static class C {
307 public C(A a, B b) {
308 }
309 }
310
311 public static class D {
312 public D() {
313 }
314 }
315
316 public void testWithComponentFactory() throws PicoRegistrationException, PicoInitializationException {
317 final WilmaImpl wilma = new WilmaImpl();
318 HierarchicalPicoContainer pc = new HierarchicalPicoContainer.WithComponentFactory(new ComponentFactory() {
319 public Object createComponent(Class componentType, Constructor constructor, Object[] args) {
320 return wilma;
321 }
322 });
323 pc.registerComponent(WilmaImpl.class);
324 pc.instantiateComponents();
325 assertEquals(pc.getComponent(WilmaImpl.class), wilma);
326 }
327
328 public static class Barney {
329 public Barney() {
330 throw new RuntimeException("Whoa!");
331 }
332 }
333
334 public void testInvocationTargetException() throws PicoRegistrationException, PicoInitializationException {
335 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
336 pico.registerComponent(Barney.class);
337 try {
338 pico.instantiateComponents();
339 } catch (PicoInvocationTargetInitailizationException e) {
340 assertEquals("Whoa!", e.getCause().getMessage());
341 assertTrue(e.getMessage().indexOf("Whoa!") > 0);
342 }
343 }
344
345 public static class BamBam {
346 public BamBam() {
347 }
348 }
349
350 // TODO uncomment this and make it pass
351 private void tAestCircularDependencyShouldFail() throws PicoRegistrationException, PicoInitializationException {
352 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
353
354 // try {
355 pico.registerComponent(A.class);
356 pico.registerComponent(B.class);
357 pico.registerComponent(C.class);
358 pico.registerComponent(D.class);
359
360 pico.instantiateComponents();
361 fail("Should have gotten a CircularDependencyRegistrationException");
362 // } catch (CircularDependencyRegistrationException e) {
363 // ok
364 // }
365 }
366
367 interface Animal {
368
369 String getFood();
370 }
371
372 public static class Dino implements Animal {
373 String food;
374
375 public Dino(String food) {
376 this.food = food;
377 }
378
379 public String getFood() {
380 return food;
381 }
382 }
383
384 public void testParameterCanBePassedToConstructor() throws Exception {
385 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
386 pico.registerComponent(Animal.class, Dino.class);
387 pico.addParameterToComponent(Dino.class, String.class, "bones");
388 pico.instantiateComponents();
389
390 Animal animal = (Animal) pico.getComponent(Animal.class);
391 assertNotNull("Component not null", animal);
392 assertEquals("bones", animal.getFood());
393 }
394
395 public static class Dino2 extends Dino {
396 public Dino2(int number) {
397 super(String.valueOf(number));
398 }
399 }
400
401 public void testParameterCanBePrimitive() throws Exception {
402 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
403 pico.registerComponent(Animal.class, Dino2.class);
404 pico.addParameterToComponent(Dino2.class, Integer.class, new Integer(22));
405 pico.instantiateComponents();
406
407 Animal animal = (Animal) pico.getComponent(Animal.class);
408 assertNotNull("Component not null", animal);
409 assertEquals("22", animal.getFood());
410 }
411
412 public static class Dino3 extends Dino {
413 public Dino3(String a, String b) {
414 super(a + b);
415 }
416 }
417
418 public void testMultipleParametersCanBePassed() throws Exception {
419 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
420 pico.registerComponent(Animal.class, Dino3.class);
421 pico.addParameterToComponent(Dino3.class, String.class, "a");
422 pico.addParameterToComponent(Dino3.class, String.class, "b");
423 pico.instantiateComponents();
424
425 Animal animal = (Animal) pico.getComponent(Animal.class);
426 assertNotNull("Component not null", animal);
427 assertEquals("ab", animal.getFood());
428
429 }
430
431 public static class Dino4 extends Dino {
432 public Dino4(String a, int n, String b, Wilma wilma) {
433 super(a + n + b + " " + wilma.getClass().getName());
434 }
435 }
436
437 public void testParametersCanBeMixedWithComponentsCanBePassed() throws Exception {
438 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
439 pico.registerComponent(Animal.class, Dino4.class);
440 pico.registerComponent(Wilma.class, WilmaImpl.class);
441 pico.addParameterToComponent(Dino4.class, String.class, "a");
442 pico.addParameterToComponent(Dino4.class, Integer.class, new Integer(3));
443 pico.addParameterToComponent(Dino4.class, String.class, "b");
444 pico.instantiateComponents();
445
446 Animal animal = (Animal) pico.getComponent(Animal.class);
447 assertNotNull("Component not null", animal);
448 assertEquals("a3b picocontainer.testmodel.WilmaImpl", animal.getFood());
449 }
450
451
452 public static final class Donkey implements Animal {
453 private final Wilma wilma;
454 private final String name;
455
456 public Donkey(final Wilma wilma, final String name) {
457 this.wilma = wilma;
458 this.name = name;
459 }
460
461 public String getFood() {
462 return "tin cans";
463 }
464 }
465
466 public static final class Monkey implements Animal {
467 public Monkey() {
468 }
469
470 public String getFood() {
471 return "bananas";
472 }
473 }
474
475 public void testCannotMixLookupTypesWithKeyFirst() throws PicoRegistrationException {
476 //final ClassRegistrationPicoContainer pico = new HierarchicalPicoContainer.Default();
477 //pico.registerComponent(Animal.class, Donkey.class, "donkey");
478 //pico.registerComponent(Wilma.class, WilmaImpl.class);
479 //try {
480 //pico.registerComponent(Animal.class, Monkey.class);
481 //fail("Expected InconsistentLookupTypeRegistrationException");
482 //} catch (InconsistentLookupTypeRegistrationException e) {
483 //}
484 }
485 public void testCannotMixLookupTypesWithTypeFirst() throws PicoRegistrationException {
486 //final PicoContainer pico = new HierarchicalPicoContainer.Default();
487 //pico.registerComponent(Animal.class, Donkey.class);
488 //pico.registerComponent(Wilma.class, WilmaImpl.class);
489 //try {
490 //pico.registerComponent(Animal.class, Monkey.class, "monkey");
491 //fail("Expected InconsistentLookupTypeRegistrationException");
492 //} catch (InconsistentLookupTypeRegistrationException e) {
493 //}
494 }
495
496 public void testKeepingLookupTypesConsistentWorks() throws PicoRegistrationException {
497 //final PicoContainer pico = new HierarchicalPicoContainer.Default();
498 //pico.registerComponent(Animal.class, Donkey.class, "donkey");
499 //pico.registerComponent(Wilma.class, WilmaImpl.class);
500 //pico.registerComponent(Animal.class, Monkey.class, "monkey");
501 }
502
503 public void testCanPassMultipleImplsAsArray() throws PicoRegistrationException, PicoInitializationException {
504 //final PicoContainer pico = new HierarchicalPicoContainer.Default();
505
506 //pico.registerComponent(Animal.class, Donkey.class, "donkey");
507 //pico.registerComponent(Animal.class, Monkey.class, "monkey");
508 //pico.registerComponent(Wilma.class, WilmaImpl.class);
509 //pico.registerComponent(AnimalConsumer.class);
510 //pico.addParameterToComponent(Donkey.class, String.class,"neddy");
511
512 //pico.instantiateComponents();
513 //final Monkey monkey = (Monkey) pico.getComponent(Animal.class, "monkey");
514 //assertNotNull(monkey);
515 //final Donkey donkey = (Donkey) pico.getComponent(Animal.class, "donkey");
516 //assertNotNull(donkey);
517 //assertNotNull(donkey.wilma);
518 //assertEquals("neddy",donkey.name);
519 //final AnimalConsumer animalConsumer = (AnimalConsumer) pico.getComponent(AnimalConsumer.class);
520 //assertSame(monkey,animalConsumer.getAnimal("monkey"));
521 //assertSame(donkey,animalConsumer.getAnimal("donkey"));
522 }
523
524
525 public static interface I {}
526 public static class AA implements I {
527 public AA(I i) {}
528 }
529 public static class BB implements I {
530 public BB(I i) {}
531 }
532
533 public void testExtendAndDependOnSameType() throws PicoRegistrationException {
534
535 HierarchicalPicoContainer pico = new HierarchicalPicoContainer.Default();
536
537 pico.registerComponent(AA.class);
538 pico.registerComponent(BB.class);
539
540 try {
541 pico.instantiateComponents();
542 fail("Should have barfed");
543 } catch (UnsatisfiedDependencyStartupException e) {
544 // Neither can be instantiated without the other.
545 } catch (PicoInitializationException e) {
546 e.printStackTrace(); //To change body of catch statement use Options | File Templates.
547 }
548 }
549 }
This page was automatically generated by Maven