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 }