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