001package org.picocontainer.containers;
002
003import org.junit.Test;
004import static org.junit.Assert.fail;
005import static org.junit.Assert.assertNotNull;
006import static org.junit.Assert.assertTrue;
007import static org.junit.Assert.assertEquals;
008import org.picocontainer.MutablePicoContainer;
009import org.picocontainer.testmodel.SimpleTouchable;
010import org.picocontainer.testmodel.DependsOnTouchable;
011import static org.picocontainer.BindKey.bindKey;
012import org.picocontainer.annotations.Bind;
013import org.picocontainer.injectors.AbstractInjector;
014
015import java.lang.annotation.Retention;
016import java.lang.annotation.RetentionPolicy;
017import java.lang.annotation.Target;
018import java.lang.annotation.ElementType;
019
020public 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<[Immutable]:parent:1<|", child.toString());
182    }
183
184
185
186
187}