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     * Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant   *
009     *****************************************************************************/
010    
011    package org.picocontainer.alternatives;
012    
013    import org.jmock.Mock;
014    import org.jmock.MockObjectTestCase;
015    import org.picocontainer.ComponentAdapter;
016    import org.picocontainer.Disposable;
017    import org.picocontainer.MutablePicoContainer;
018    import org.picocontainer.PicoContainer;
019    import org.picocontainer.PicoVerificationException;
020    import org.picocontainer.PicoVisitor;
021    import org.picocontainer.defaults.DefaultPicoContainer;
022    import org.picocontainer.defaults.VerifyingVisitor;
023    
024    import java.util.Collection;
025    import java.util.HashMap;
026    import java.util.Iterator;
027    import java.util.List;
028    import java.util.Map;
029    import java.util.Vector;
030    
031    /**
032     * @author Paul Hammant
033     * @version $Revision: 2382 $
034     */
035    public class ImmutablePicoContainerTestCase extends MockObjectTestCase {
036    
037        public void testImmutingofNullBarfs() {
038            try {
039                new ImmutablePicoContainer(null);
040                fail("Should have barfed");
041            } catch (NullPointerException e) {
042                //expected
043            }
044        }
045    
046        public void testDelegationOfGettingComponentInstance() {
047            DefaultPicoContainer mpc = new DefaultPicoContainer();
048            mpc.registerComponentImplementation(Map.class, HashMap.class);
049            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
050            Map map = (Map) ipc.getComponentInstance(Map.class);
051            assertNotNull(map);
052        }
053    
054        public void testDelegationOfGettingComponentInstanceOfType() {
055            DefaultPicoContainer mpc = new DefaultPicoContainer();
056            mpc.registerComponentImplementation(Map.class, HashMap.class);
057            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
058            Map map = (Map) ipc.getComponentInstanceOfType(Map.class);
059            assertNotNull(map);
060        }
061    
062        public void testDelegationOfGettingComponentInstancesOfType() {
063            DefaultPicoContainer mpc = new DefaultPicoContainer();
064            mpc.registerComponentImplementation(Map.class, HashMap.class);
065            mpc.registerComponentImplementation(Collection.class, Vector.class);
066            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
067            List list = ipc.getComponentInstancesOfType(Map.class);
068            assertNotNull(list);
069            assertEquals(1,list.size());
070        }
071    
072        public void testDelegationOfGetComponentInstances() {
073            DefaultPicoContainer mpc = new DefaultPicoContainer();
074            mpc.registerComponentImplementation(Map.class, HashMap.class);
075            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
076            List comps = ipc.getComponentInstances();
077            assertNotNull(comps);
078            assertEquals(1, comps.size());
079        }
080    
081        public void testDelegationOfGetComponentAdapter() {
082            DefaultPicoContainer mpc = new DefaultPicoContainer();
083            mpc.registerComponentImplementation(Map.class, HashMap.class);
084            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
085            ComponentAdapter ca = ipc.getComponentAdapter(Map.class);
086            assertNotNull(ca);
087    
088        }
089    
090        public void testDelegationOfGetComponentAdapterOfType() {
091            DefaultPicoContainer mpc = new DefaultPicoContainer();
092            mpc.registerComponentImplementation(Map.class, HashMap.class);
093            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
094            ComponentAdapter ca = ipc.getComponentAdapterOfType(Map.class);
095            assertNotNull(ca);
096        }
097    
098        public void testDelegationOfGetComponentAdapters() {
099            DefaultPicoContainer mpc = new DefaultPicoContainer();
100            mpc.registerComponentImplementation(Map.class, HashMap.class);
101            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
102            Collection comps = ipc.getComponentAdapters();
103            assertNotNull(comps);
104            assertEquals(1, comps.size());
105        }
106    
107        public void testDelegationOfGetComponentAdaptersOfType() {
108            DefaultPicoContainer mpc = new DefaultPicoContainer();
109            mpc.registerComponentImplementation(Map.class, HashMap.class);
110            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
111            List comps = ipc.getComponentAdaptersOfType(Map.class);
112            assertNotNull(comps);
113            assertEquals(1, comps.size());
114        }
115    
116        public static class UnsatisfiableIterator implements Iterator {
117    
118            public UnsatisfiableIterator(Map map) {
119            }
120    
121            public void remove() {
122            }
123    
124            public boolean hasNext() {
125                return false;
126            }
127    
128            public Object next() {
129                return null;
130            }
131        }
132    
133        public void testDelegationOfVerify() {
134            DefaultPicoContainer mpc = new DefaultPicoContainer();
135            mpc.registerComponentImplementation(Iterator.class, UnsatisfiableIterator.class);
136            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
137            try {
138                new VerifyingVisitor().traverse(ipc);
139                fail("PicoVerificationException expected");
140            } catch (PicoVerificationException e) {
141                // expected
142            }
143            try {
144                ipc.verify();
145                fail("PicoVerificationException expected");
146            } catch (PicoVerificationException e) {
147                // expected
148            }
149        }
150    
151        public void testGetParentForMutable() {
152            DefaultPicoContainer par = new DefaultPicoContainer();
153            DefaultPicoContainer mpc = new DefaultPicoContainer(par);
154            mpc.registerComponentImplementation(Map.class, HashMap.class);
155            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
156            PicoContainer parent = ipc.getParent();
157            assertNotNull(parent);
158            assertNotSame(par, parent);
159            PicoContainer parent2 = ipc.getParent();
160            assertNotNull(parent2);
161            assertEquals(parent, parent2);
162        }
163    
164        public void testGetParentForNonMutable() {
165            DefaultPicoContainer par = new DefaultPicoContainer();
166            ImmutablePicoContainer par2 = new ImmutablePicoContainer(par);
167            DefaultPicoContainer mpc = new DefaultPicoContainer(par2);
168            mpc.registerComponentImplementation(Map.class, HashMap.class);
169            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
170            PicoContainer parent = ipc.getParent();
171            assertNotNull(parent);
172            assertNotSame(par, parent);
173            PicoContainer parent2 = ipc.getParent();
174            assertNotNull(parent2);
175            assertEquals(parent, parent2);
176        }
177    
178        public void testStartBarfs() {
179            DefaultPicoContainer mpc = new DefaultPicoContainer();
180            mpc.registerComponentImplementation(Map.class, HashMap.class);
181            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
182            try {
183                ipc.start();
184                fail("should have barfed");
185            } catch (UnsupportedOperationException e) {
186                // expected
187            }
188        }
189    
190        public void testStopBarfs() {
191            DefaultPicoContainer mpc = new DefaultPicoContainer();
192            mpc.registerComponentImplementation(Map.class, HashMap.class);
193            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
194            try {
195                ipc.stop();
196                fail("stop have barfed");
197            } catch (UnsupportedOperationException e) {
198                // expected
199            }
200        }
201    
202        public void testDisposeBarfs() {
203            DefaultPicoContainer mpc = new DefaultPicoContainer();
204            mpc.registerComponentImplementation(Map.class, HashMap.class);
205            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
206            try {
207                ipc.dispose();
208                fail("should have barfed");
209            } catch (UnsupportedOperationException e) {
210                // expected
211            }
212        }
213    
214        public static class MyDisposable implements Disposable {
215            public boolean disposed;
216    
217            public void dispose() {
218                disposed = true;
219            }
220        }
221    
222        public void testLifecycleGuardIsEasyToCircumventSoItMightAsWellBeDeleted() {
223            DefaultPicoContainer mpc = new DefaultPicoContainer();
224            mpc.registerComponentImplementation(MyDisposable.class);
225            ImmutablePicoContainer ipc = new ImmutablePicoContainer(mpc);
226            List componentInstances = ipc.getComponentInstances();
227            for (Iterator iterator = componentInstances.iterator(); iterator.hasNext();) {
228                Object o = iterator.next();
229                if(o instanceof Disposable) {
230                    ((Disposable) o).dispose();
231                }
232            }
233            MyDisposable disposable = (MyDisposable ) ipc.getComponentInstance(MyDisposable.class);
234            assertTrue(disposable.disposed);
235        }
236    
237        public void testFacetiouslyThatLifeCycleGuardPreventsCyclingOfChildContainersAsComponentsAreNotTheOnlyThingsThatAreLifecycleable() {
238            DefaultPicoContainer parent = new DefaultPicoContainer();
239            MutablePicoContainer child = parent.makeChildContainer();
240            parent.registerComponentImplementation("foo", MyDisposable.class);
241            child.registerComponentImplementation("bar", MyDisposable.class);
242            ImmutablePicoContainer ipc = new ImmutablePicoContainer(parent);
243            try {
244                ipc.dispose();
245                fail("Should have barfed");
246            } catch (UnsupportedOperationException e) {
247                // expected
248            }
249    
250            MyDisposable parentDisposable = (MyDisposable) parent.getComponentInstance("foo");
251            assertFalse(parentDisposable.disposed);
252    
253            MyDisposable childDisposable = (MyDisposable) child.getComponentInstance("bar");
254            assertFalse(childDisposable.disposed);
255    
256            // If this were on parent, it would cascade to child.
257            ((Disposable) ipc.getComponentInstances().get(0)).dispose();
258    
259            // I can live with this below....
260            assertTrue(parentDisposable.disposed);
261    
262            // However, I'd be in favor of changing
263            //   interface PicoContainer extends Startable, Disposable {}
264            // to
265            //   interface PicoContainer {}
266            // AND
267            //   interface MutablePicoContainer extends PicoContainer {}
268            // to
269            //   interface MutablePicoContainer extends PicoContainer implements Startable, Disposable {}
270            // That despite breaking (marginally) backwards compatability.
271            // - Paul
272        }
273    
274        public void testVisitingOfImmutableContainerWorks() {
275            DefaultPicoContainer pico = new DefaultPicoContainer();
276            Object foo = new Object();
277            ComponentAdapter componentAdapter = pico.registerComponentInstance(foo);
278    
279            Mock fooVisitor = new Mock(PicoVisitor.class);
280            fooVisitor.expects(once()).method("visitContainer").with(eq(pico));
281            fooVisitor.expects(once()).method("visitComponentAdapter").with(eq(componentAdapter));
282    
283            ImmutablePicoContainer ipc = new ImmutablePicoContainer(pico);
284    
285            ipc.accept((PicoVisitor) fooVisitor.proxy());
286    
287    
288        }
289    }