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    package org.picocontainer.behaviors;
009    
010    import static org.junit.Assert.assertEquals;
011    import static org.junit.Assert.assertNotNull;
012    import static org.junit.Assert.assertSame;
013    import static org.junit.Assert.fail;
014    import static org.picocontainer.tck.MockFactory.mockeryWithCountingNamingScheme;
015    
016    import org.jmock.Expectations;
017    import org.jmock.Mockery;
018    import org.jmock.integration.junit4.JMock;
019    import org.junit.Test;
020    import org.junit.runner.RunWith;
021    import org.picocontainer.ComponentAdapter;
022    import org.picocontainer.DefaultPicoContainer;
023    import org.picocontainer.LifecycleStrategy;
024    import org.picocontainer.MutablePicoContainer;
025    import org.picocontainer.PicoContainer;
026    import org.picocontainer.testmodel.SimpleTouchable;
027    import org.picocontainer.testmodel.Touchable;
028    
029    
030    
031    /**
032     * @author Mauro Talevi
033     */
034    @RunWith(JMock.class)
035    public class CachedTestCase {
036    
037            private Mockery mockery = mockeryWithCountingNamingScheme();
038            
039        @Test public void testComponentIsNotStartedWhenCachedAndCanBeStarted() {
040            Cached adapter = new Cached(
041                    mockComponentAdapterSupportingLifecycleStrategy(true, false, false, false, false));
042            PicoContainer pico = new DefaultPicoContainer();
043            adapter.getComponentInstance(pico, ComponentAdapter.NOTHING.class);
044            adapter.start(pico);
045        }
046    
047        @Test public void testComponentCanBeStartedAgainAfterBeingStopped() {
048            Cached adapter = new Cached(
049                    mockComponentAdapterSupportingLifecycleStrategy(true, true, false, false, false));
050            PicoContainer pico = new DefaultPicoContainer();
051            adapter.start(pico);
052            Object instanceAfterFirstStart = adapter.getComponentInstance(pico, ComponentAdapter.NOTHING.class);
053            adapter.stop(pico);
054            adapter.start(pico);
055            Object instanceAfterSecondStart = adapter.getComponentInstance(pico, ComponentAdapter.NOTHING.class);
056            assertSame(instanceAfterFirstStart, instanceAfterSecondStart);
057        }
058    
059        @Test public void testComponentCannotBeStartedIfDisposed() {
060            Cached adapter = new Cached(
061                    mockComponentAdapterSupportingLifecycleStrategy(false, false, true, true, true));
062            PicoContainer pico = new DefaultPicoContainer();
063            adapter.getComponentInstance(pico, ComponentAdapter.NOTHING.class);
064            adapter.dispose(pico);
065            try {
066                adapter.start(pico);
067                fail("IllegalStateException expected");
068            } catch (Exception e) {
069                assertEquals("'interface org.picocontainer.testmodel.Touchable' already disposed", e.getMessage());
070            }
071        }
072    
073        @Test public void testComponentCannotBeDisposedIfNotInstantiated() {
074            Cached adapter = new Cached(
075                    mockComponentAdapterSupportingLifecycleStrategy(false, false, false, true, false));
076            PicoContainer pico = new DefaultPicoContainer();
077            try {
078                adapter.dispose(pico);
079             //   fail("IllegalStateException expected");
080            } catch (Exception e) {
081                assertEquals("'interface org.picocontainer.testmodel.Touchable' not instantiated", e.getMessage());
082            }
083        }
084    
085        @Test public void testComponentCannotBeStartedIfAlreadyStarted() {
086            Cached adapter = new Cached(
087                    mockComponentAdapterSupportingLifecycleStrategy(true, false, false, true, false));
088            PicoContainer pico = new DefaultPicoContainer();
089            adapter.start(pico);
090            try {
091                adapter.start(pico);
092                fail("IllegalStateException expected");
093            } catch (Exception e) {
094                assertEquals("'interface org.picocontainer.testmodel.Touchable' already started", e.getMessage());
095            }
096        }
097    
098        @Test public void testComponentCannotBeStoppedIfDisposed() {
099            Cached adapter = new Cached(
100                    mockComponentAdapterSupportingLifecycleStrategy(false, false, true, true, false));
101            PicoContainer pico = new DefaultPicoContainer();
102            adapter.getComponentInstance(pico, ComponentAdapter.NOTHING.class);        
103            adapter.dispose(pico);
104            try {
105                adapter.stop(pico);
106                fail("IllegalStateException expected");
107            } catch (Exception e) {
108                assertEquals("'interface org.picocontainer.testmodel.Touchable' already disposed", e.getMessage());
109            }
110        }
111    
112        @Test public void testComponentCannotBeStoppedIfNotInstantiated() {
113            Cached adapter = new Cached(
114                    mockComponentAdapterSupportingLifecycleStrategy(false, false, false, true, false));
115            PicoContainer pico = new DefaultPicoContainer();
116            try {
117                adapter.stop(pico);
118                fail("IllegalStateException expected");
119            } catch (Exception e) {
120                assertEquals("'interface org.picocontainer.testmodel.Touchable' not instantiated", e.getMessage());
121            }
122        }
123    
124        @Test public void testComponentCannotBeStoppedIfNotStarted() {
125            Cached adapter = new Cached(
126                    mockComponentAdapterSupportingLifecycleStrategy(true, true, false, true, false));
127            PicoContainer pico = new DefaultPicoContainer();
128            adapter.start(pico);
129            adapter.stop(pico);
130            try {
131            adapter.stop(pico);
132                fail("IllegalStateException expected");
133            } catch (Exception e) {
134                assertEquals("'interface org.picocontainer.testmodel.Touchable' not started", e.getMessage());
135            }
136        }
137    
138        @Test public void testComponentCannotBeDisposedIfAlreadyDisposed() {
139            Cached adapter = new Cached(
140                    mockComponentAdapterSupportingLifecycleStrategy(true, true, true, true, false));
141            PicoContainer pico = new DefaultPicoContainer();
142            adapter.start(pico);
143            adapter.stop(pico);
144            adapter.dispose(pico);
145            try {
146                adapter.dispose(pico);
147                fail("IllegalStateException expected");
148            } catch (Exception e) {
149                assertEquals("'interface org.picocontainer.testmodel.Touchable' already disposed", e.getMessage());
150            }
151        }
152    
153        @Test public void testComponentIsStoppedAndDisposedIfStartedWhenFlushed() {
154            Cached adapter = new Cached(
155                    mockComponentAdapterSupportingLifecycleStrategy(true, true, true, false, false));
156            PicoContainer pico = new DefaultPicoContainer();
157            adapter.start(pico);
158            adapter.flush();
159        }
160    
161        @Test public void testComponentIsNotStoppedAndDisposedWhenFlushedIfNotStarted() {
162            Cached adapter = new Cached(
163                    mockComponentAdapterSupportingLifecycleStrategy(false, false, false, false, false));
164            adapter.flush();
165        }
166    
167        @Test public void testComponentIsNotStoppedAndDisposedWhenFlushedIfDelegateDoesNotSupportLifecycle() {
168            Cached adapter = new Cached(
169                    mockComponentAdapterNotSupportingLifecycleStrategy());
170            adapter.flush();
171        }
172    
173        @Test public void testLifecycleIsIgnoredIfDelegateDoesNotSupportIt() {
174            Cached adapter = new Cached(
175                    mockComponentAdapterNotSupportingLifecycleStrategy());
176            PicoContainer pico = new DefaultPicoContainer();
177            adapter.start(pico);
178            adapter.stop(pico);
179            adapter.dispose(pico);
180        }
181    
182        @Test public void testCanStopAComponentThatWasNeverStartedBecauseItHasNoLifecycle() {
183            MutablePicoContainer pico = new DefaultPicoContainer();
184    
185            pico.addComponent(StringBuffer.class);
186    
187            pico.start();
188    
189            assertNotNull(pico.getComponent(StringBuffer.class));
190    
191            pico.stop();
192            pico.dispose();
193        }
194    
195        private ComponentAdapter mockComponentAdapterNotSupportingLifecycleStrategy() {
196            return mockery.mock(ComponentAdapter.class);
197        }
198    
199        private ComponentAdapter mockComponentAdapterSupportingLifecycleStrategy(
200                final boolean start, final boolean stop, final boolean dispose, final boolean getKey, final boolean instantiate) {
201            final boolean hasLifecycle = start || stop || dispose;
202            final ComponentAdapterSupportingLifecycleStrategy ca = mockery.mock(ComponentAdapterSupportingLifecycleStrategy.class);
203            mockery.checking(new Expectations(){{
204                if (getKey) {
205                    atLeast(1).of(ca).getComponentKey();
206                    will(returnValue(Touchable.class));
207                }
208                if (start) {
209                    atLeast(1).of(ca).start(with(any(Touchable.class)));
210                }
211                if (stop) {
212                    one(ca).stop(with(any(Touchable.class)));
213                }
214                if (dispose) {
215                    one(ca).dispose(with(any(Touchable.class)));
216                }
217                if (hasLifecycle || instantiate) {
218                    one(ca).getComponentInstance(with(any(PicoContainer.class)), with(same(ComponentAdapter.NOTHING.class)));
219                    will(returnValue(new SimpleTouchable()));
220                }
221                one(ca).getComponentImplementation();
222                will(returnValue(SimpleTouchable.class));
223                one(ca).hasLifecycle(with(same(SimpleTouchable.class)));
224                will(returnValue(true));
225            }});
226            return ca;
227        }
228    
229        public static interface ComponentAdapterSupportingLifecycleStrategy extends ComponentAdapter,
230                LifecycleStrategy {
231        }
232    }