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