001    package org.picocontainer.containers;
002    
003    import org.junit.Test;
004    import static org.junit.Assert.fail;
005    import static org.junit.Assert.assertNotNull;
006    import static org.junit.Assert.assertTrue;
007    import static org.junit.Assert.assertEquals;
008    import org.picocontainer.MutablePicoContainer;
009    import org.picocontainer.testmodel.SimpleTouchable;
010    import org.picocontainer.testmodel.DependsOnTouchable;
011    import static org.picocontainer.BindKey.bindKey;
012    import org.picocontainer.annotations.Bind;
013    import org.picocontainer.injectors.AbstractInjector;
014    
015    import java.lang.annotation.Retention;
016    import java.lang.annotation.RetentionPolicy;
017    import java.lang.annotation.Target;
018    import java.lang.annotation.ElementType;
019    
020    public class TieringPicoContainerTestCase {
021        
022        public static class Couch {
023        }
024    
025        public static class TiredPerson {
026            private Couch couchToSitOn;
027    
028            public TiredPerson(Couch couchToSitOn) {
029                this.couchToSitOn = couchToSitOn;
030            }
031        }
032    
033        @Test
034        public void testThatGrandparentTraversalForComponentsCanBeBlocked() {
035            MutablePicoContainer grandparent = new TieringPicoContainer();
036            MutablePicoContainer parent = grandparent.makeChildContainer();
037            MutablePicoContainer child = parent.makeChildContainer();
038            grandparent.addComponent(Couch.class);
039            child.addComponent(TiredPerson.class);
040    
041            TiredPerson tp = null;
042            try {
043                tp = child.getComponent(TiredPerson.class);
044                fail("should have barfed");
045            } catch (AbstractInjector.UnsatisfiableDependenciesException e) {
046                // expected
047            }
048    
049        }
050    
051        @Test
052        public void testThatParentTraversalIsOkForTiering() {
053            MutablePicoContainer parent = new TieringPicoContainer();
054            MutablePicoContainer child = parent.makeChildContainer();
055            parent.addComponent(Couch.class);
056            child.addComponent(TiredPerson.class);
057    
058            TiredPerson tp = child.getComponent(TiredPerson.class);
059            assertNotNull(tp);
060            assertNotNull(tp.couchToSitOn);
061    
062        }
063    
064        public static class Doctor {
065            private TiredPerson tiredPerson;
066    
067            public Doctor(TiredPerson tiredPerson) {
068                this.tiredPerson = tiredPerson;
069            }
070        }
071    
072        public static class TiredDoctor {
073            private Couch couchToSitOn;
074            private final TiredPerson tiredPerson;
075    
076            public TiredDoctor(Couch couchToSitOn, TiredPerson tiredPerson) {
077                this.couchToSitOn = couchToSitOn;
078                this.tiredPerson = tiredPerson;
079            }
080        }
081    
082        @Test
083        public void testThatParentTraversalIsOnlyBlockedOneTierAtATime() {
084            MutablePicoContainer gp = new TieringPicoContainer();
085            MutablePicoContainer p = gp.makeChildContainer();
086            MutablePicoContainer c = p.makeChildContainer();
087            gp.addComponent(Couch.class);
088            p.addComponent(TiredPerson.class);
089            c.addComponent(Doctor.class);
090            c.addComponent(TiredDoctor.class);
091            Doctor d = c.getComponent(Doctor.class);
092            assertNotNull(d);
093            assertNotNull(d.tiredPerson);
094            assertNotNull(d.tiredPerson.couchToSitOn);
095            try {
096                TiredDoctor td = c.getComponent(TiredDoctor.class);
097                fail("should have barfed");
098            } catch (AbstractInjector.UnsatisfiableDependenciesException e) {
099                // expected
100            }
101    
102        }
103    
104        @Retention(RetentionPolicy.RUNTIME)
105        @Target({ElementType.FIELD, ElementType.PARAMETER})
106        @Bind
107        public static @interface Grouchy {}
108    
109        public static class GrouchyTiredPerson extends TiredPerson {
110            public GrouchyTiredPerson(Couch couchToSitOn) {
111                super(couchToSitOn);
112            }
113        }
114    
115        @Retention(RetentionPolicy.RUNTIME)
116        @Target({ElementType.FIELD, ElementType.PARAMETER})
117        @Bind
118        public static @interface Polite {}
119    
120        public static class PoliteTiredPerson extends TiredPerson {
121            public PoliteTiredPerson(Couch couchToSitOn) {
122                super(couchToSitOn);
123            }
124        }
125    
126        public static class DiscerningDoctor {
127            private final TiredPerson tiredPerson;
128    
129            public DiscerningDoctor(@Polite TiredPerson tiredPerson) {
130                this.tiredPerson = tiredPerson;
131            }
132        }
133    
134        @Test
135        public void testThatGrandparentTraversalForComponentsCanBeBlockedEvenForAnnotatedInjections() {
136            MutablePicoContainer grandparent = new TieringPicoContainer();
137            MutablePicoContainer parent = grandparent.makeChildContainer();
138            MutablePicoContainer child = parent.makeChildContainer();
139            grandparent.addComponent(Couch.class);
140            grandparent.addComponent(bindKey(TiredPerson.class, Polite.class), PoliteTiredPerson.class);
141            grandparent.addComponent(bindKey(TiredPerson.class, Grouchy.class), GrouchyTiredPerson.class);
142            child.addComponent(DiscerningDoctor.class);
143    
144            assertNotNull(grandparent.getComponent(TiredPerson.class, Polite.class));
145            assertNotNull(grandparent.getComponent(TiredPerson.class, Grouchy.class));
146    
147            DiscerningDoctor dd = null;
148            try {
149                dd = child.getComponent(DiscerningDoctor.class);
150                fail("should have barfed");
151            } catch (AbstractInjector.UnsatisfiableDependenciesException e) {
152                // expected
153            }
154    
155        }
156    
157        @Test
158        public void testThatGrandparentTraversalForComponentsCanBeBlockedEvenForAnnotatedInjections2() {
159            MutablePicoContainer grandparent = new TieringPicoContainer();
160            grandparent.addComponent(Couch.class);
161            grandparent.addComponent(bindKey(TiredPerson.class, Polite.class), PoliteTiredPerson.class);
162            grandparent.addComponent(bindKey(TiredPerson.class, Grouchy.class), GrouchyTiredPerson.class);
163            grandparent.addComponent(DiscerningDoctor.class);
164    
165            assertNotNull(grandparent.getComponent(TiredPerson.class, Polite.class));
166            assertNotNull(grandparent.getComponent(TiredPerson.class, Grouchy.class));
167    
168            DiscerningDoctor dd = grandparent.getComponent(DiscerningDoctor.class);
169            assertNotNull(dd.tiredPerson);
170            assertTrue(dd.tiredPerson instanceof PoliteTiredPerson);
171    
172        }
173    
174        @Test public void testRepresentationOfContainerTree() {
175                    TieringPicoContainer parent = new TieringPicoContainer();
176            parent.setName("parent");
177            TieringPicoContainer child = new TieringPicoContainer(parent);
178            child.setName("child");
179                    parent.addComponent("st", SimpleTouchable.class);
180                    child.addComponent("dot", DependsOnTouchable.class);
181            assertEquals("child:1<I<parent:1<|", child.toString());
182        }
183    
184    
185    
186    
187    }