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     * Original code by                                                          *
009     *****************************************************************************/
010    package org.picocontainer;
011    
012    import org.picocontainer.behaviors.Cached;
013    
014    import java.util.Map;
015    
016    import com.thoughtworks.xstream.XStream;
017    import org.junit.Before;
018    import org.junit.Test;
019    import org.picocontainer.behaviors.Caching;
020    import org.picocontainer.behaviors.ImplementationHiding;
021    import org.picocontainer.behaviors.Locking;
022    import org.picocontainer.behaviors.PropertyApplying;
023    import org.picocontainer.behaviors.Synchronizing;
024    import org.picocontainer.containers.EmptyPicoContainer;
025    import org.picocontainer.injectors.AdaptingInjection;
026    import org.picocontainer.injectors.AnnotatedFieldInjection;
027    import org.picocontainer.injectors.AnnotatedMethodInjection;
028    import org.picocontainer.injectors.CompositeInjection;
029    import org.picocontainer.injectors.ConstructorInjection;
030    import org.picocontainer.injectors.NamedFieldInjection;
031    import org.picocontainer.injectors.NamedMethodInjection;
032    import org.picocontainer.injectors.SetterInjection;
033    import org.picocontainer.injectors.TypedFieldInjection;
034    import org.picocontainer.lifecycle.JavaEE5LifecycleStrategy;
035    import org.picocontainer.lifecycle.NullLifecycleStrategy;
036    import org.picocontainer.lifecycle.ReflectionLifecycleStrategy;
037    import org.picocontainer.lifecycle.StartableLifecycleStrategy;
038    import org.picocontainer.monitors.ConsoleComponentMonitor;
039    import org.picocontainer.monitors.NullComponentMonitor;
040    
041    import java.util.HashMap;
042    import java.util.Properties;
043    
044    import static junit.framework.Assert.assertTrue;
045    import static org.junit.Assert.assertEquals;
046    import static org.junit.Assert.assertNotNull;
047    import static org.junit.Assert.fail;
048    import static org.picocontainer.behaviors.Behaviors.caching;
049    import static org.picocontainer.behaviors.Behaviors.implementationHiding;
050    import static org.picocontainer.behaviors.Behaviors.synchronizing;
051    import static org.picocontainer.injectors.Injectors.SDI;
052    
053    @SuppressWarnings("serial")
054    public class PicoBuilderTestCase {
055    
056        private XStream xs;
057        private EmptyPicoContainer parent = new EmptyPicoContainer();
058        private NullLifecycleStrategy lifecycle = new NullLifecycleStrategy();
059        private NullComponentMonitor ncm = new NullComponentMonitor();
060        private AdaptingInjection ai = new AdaptingInjection();
061    
062        @Before
063        public void setUp() throws Exception {
064            xs = new XStream();
065            xs.setMode(XStream.XPATH_ABSOLUTE_REFERENCES);
066        }
067    
068        @Test public void testDefaultHasNullComponentManagerAndNullLifecycleAndAdaptingInjection() {
069            Object actual = new PicoBuilder().build();
070            Object expected = new DefaultPicoContainer(ai, lifecycle, parent);
071            assertEquals(toXml(expected), toXml(actual));
072        }
073    
074        @Test public void testWithStartableLifecycle() {
075            Object actual = new PicoBuilder().withLifecycle().build();
076            Object expected = new DefaultPicoContainer(ai, new StartableLifecycleStrategy(ncm), parent, ncm);
077            assertEquals(toXml(expected), toXml(actual));
078        }
079    
080        public static class FooLifecycleStrategy extends NullLifecycleStrategy{
081        }
082    
083        @Test public void testWithCustomLifecycle() {
084            Object actual = new PicoBuilder().withLifecycle(FooLifecycleStrategy.class).build();
085            Object expected = new DefaultPicoContainer(ai, new FooLifecycleStrategy(), parent);
086            assertEquals(toXml(expected), toXml(actual));
087        }
088    
089        @Test public void testWithCustomLifecycle2() {
090            Object actual = new PicoBuilder().withLifecycle(new FooLifecycleStrategy()).build();
091            Object expected = new DefaultPicoContainer(ai, new FooLifecycleStrategy(), parent);
092            assertEquals(toXml(expected), toXml(actual));
093        }
094    
095        @Test public void testWithJEE5Lifecycle() {
096    
097            Object actual = new PicoBuilder().withJavaEE5Lifecycle().build();
098            Object expected = new DefaultPicoContainer(ai, new JavaEE5LifecycleStrategy(ncm), parent, ncm);
099            assertEquals(toXml(expected), toXml(actual));
100        }
101    
102        @Test public void testWithLifecycleInstance() {
103    
104            Object actual = new PicoBuilder().withLifecycle(new FooLifecycleStrategy()).build();
105            Object expected = new DefaultPicoContainer(ai, new FooLifecycleStrategy(), parent);
106            assertEquals(toXml(expected), toXml(actual));
107        }
108    
109        @Test public void testThatLastOfInstanceOrClassLifecycleIsDominant() {
110            Object actual = new PicoBuilder().withLifecycle(new FooLifecycleStrategy()).withLifecycle().build();
111            Object expected = new DefaultPicoContainer(ai, new StartableLifecycleStrategy(ncm), parent, ncm);
112            assertEquals(toXml(expected), toXml(actual));
113            actual = new PicoBuilder().withLifecycle().withLifecycle(new FooLifecycleStrategy()).build();
114            expected = new DefaultPicoContainer(ai,
115                    new FooLifecycleStrategy(), parent);
116            assertEquals(toXml(expected), toXml(actual));
117        }
118    
119    
120        @Test public void testWithReflectionLifecycle() {
121            Object actual = new PicoBuilder().withReflectionLifecycle().build();
122            Object expected = new DefaultPicoContainer(ai, new ReflectionLifecycleStrategy(ncm), parent, ncm);
123            assertEquals(toXml(expected), toXml(actual));
124        }
125    
126    
127        @Test public void testWithConsoleMonitor() {
128            Object actual = new PicoBuilder().withConsoleMonitor().build();
129            Object expected = new DefaultPicoContainer(ai, lifecycle, parent, new ConsoleComponentMonitor());
130            assertEquals(toXml(expected), toXml(actual));
131        }
132    
133        @Test public void testWithConsoleMonitorAndLifecycleUseTheSameUltimateMonitor() {
134            Object actual = new PicoBuilder().withLifecycle().withConsoleMonitor().build();
135            ConsoleComponentMonitor cm = new ConsoleComponentMonitor();
136            Object expected = new DefaultPicoContainer(ai, new StartableLifecycleStrategy(cm), parent, cm);
137            assertEquals(toXml(expected), toXml(actual));
138        }
139    
140    
141        @Test public void testWithCustomMonitorByClass() {
142            Object actual = new PicoBuilder().withMonitor(ConsoleComponentMonitor.class).build();
143            ConsoleComponentMonitor cm = new ConsoleComponentMonitor();
144            Object expected = new DefaultPicoContainer(ai, lifecycle, parent, cm);
145            assertEquals(toXml(expected), toXml(actual));
146        }
147    
148        @SuppressWarnings({ "unchecked" })
149        @Test public void testWithBogusCustomMonitorByClass() {
150            // We do unchecked assignment so we test what its really doing, and smart IDE's don't complain
151            try {
152                Class aClass = HashMap.class;
153                new PicoBuilder().withMonitor(aClass).build();
154                fail("should have barfed");
155            } catch (ClassCastException e) {
156                // expected
157            }
158        }
159    
160        @Test public void testWithImplementationHiding() {
161            Object actual = new PicoBuilder().withHiddenImplementations().build();
162            Object expected = new DefaultPicoContainer(new ImplementationHiding().wrap(ai), lifecycle, parent, ncm);
163            assertEquals(toXml(expected), toXml(actual));
164        }
165    
166        @Test public void testWithImplementationHidingInstance() {
167            Object actual = new PicoBuilder().withComponentFactory(new ImplementationHiding()).build();
168            Object expected = new DefaultPicoContainer(new ImplementationHiding().wrap(ai), lifecycle, parent, ncm);
169            assertEquals(toXml(expected), toXml(actual));
170        }
171    
172        @Test public void testWithInjectionFactoryChain() {
173            Object actual = new PicoBuilder(SDI()).withBehaviors(caching(), synchronizing(), implementationHiding()).build();
174            Object expected = new DefaultPicoContainer(new Caching().wrap(new Synchronizing()
175                    .wrap(new ImplementationHiding().wrap(new SetterInjection()))), lifecycle, parent, ncm);
176            assertEquals(toXml(expected), toXml(actual));
177        }
178    
179        public static class CustomParentcontainer extends EmptyPicoContainer {}
180    
181        @Test public void testCustomParentContainer() {
182            Object actual = new PicoBuilder(new CustomParentcontainer()).build();
183            Object expected = new DefaultPicoContainer(ai, lifecycle, new CustomParentcontainer(), ncm);
184            assertEquals(toXml(expected), toXml(actual));
185        }
186    
187        @Test public void testBogusParentContainerBehavesAsIfNotSet() {
188            Object actual = new PicoBuilder((PicoContainer)null).build();
189            Object expected = new DefaultPicoContainer(ai, lifecycle, parent, ncm);
190            assertEquals(toXml(expected), toXml(actual));
191        }
192    
193        @Test public void testParentAndChildContainersMutallyVisible() {
194            MutablePicoContainer parent = new PicoBuilder().build();
195            MutablePicoContainer actual = new PicoBuilder(parent).addChildToParent().build();
196    
197            MutablePicoContainer parentExpected = new PicoBuilder().build();
198            MutablePicoContainer expected = new DefaultPicoContainer(ai, lifecycle, parentExpected, ncm);
199            parentExpected.addChildContainer(expected); 
200    
201            assertEquals(toXml(expected), toXml(actual));
202            boolean b = parent.removeChildContainer(actual);
203            assertTrue(b);
204        }
205    
206        @Test
207        public void testParentAndChildContainersVetoedWhenParentNotMutable() {
208            try {
209                new PicoBuilder(parent).addChildToParent().build();
210                fail("should have barfed");
211            } catch (PicoCompositionException e) {
212                assertTrue(e.getMessage().contains("parent must be a MutablePicoContainer"));
213            }
214        }
215    
216        @Test public void testWithSetterInjection() {
217            Object actual = new PicoBuilder().withSetterInjection().build();
218            Object expected = new DefaultPicoContainer(new SetterInjection(), lifecycle, parent, ncm);
219            assertEquals(toXml(expected), toXml(actual));
220        }
221    
222        @Test public void testWithConstructorAndSetterInjectionMakesHiddenCompositeInjection() {
223            Object actual = new PicoBuilder().withConstructorInjection().withSetterInjection().build();
224            Object expected = new DefaultPicoContainer(
225                    new CompositeInjection(new ConstructorInjection(), new SetterInjection()), lifecycle, parent, ncm);
226            assertEquals(toXml(expected), toXml(actual));
227        }
228    
229        @Test public void testWithAnnotatedMethodDI() {
230            Object actual = new PicoBuilder().withAnnotatedMethodInjection().build();
231            Object expected = new DefaultPicoContainer(new AnnotatedMethodInjection(), lifecycle, parent, ncm);
232            assertEquals(toXml(expected), toXml(actual));
233        }
234    
235        @Test public void testWithAnnotatedFieldDI() {
236            Object actual = new PicoBuilder().withAnnotatedFieldInjection().build();
237            Object expected = new DefaultPicoContainer(new AnnotatedFieldInjection(), lifecycle, parent, ncm);
238            assertEquals(toXml(expected), toXml(actual));
239        }
240    
241        @Test public void testWithTypedFieldDI() {
242            Object actual = new PicoBuilder().withTypedFieldInjection().build();
243            Object expected = new DefaultPicoContainer(new TypedFieldInjection(), lifecycle, parent, ncm);
244            assertEquals(toXml(expected), toXml(actual));
245        }
246    
247        @Test public void testWithCtorDI() {
248            Object actual = new PicoBuilder().withConstructorInjection().build();
249            Object expected = new DefaultPicoContainer(new ConstructorInjection(), lifecycle, parent, ncm);
250            assertEquals(toXml(expected), toXml(actual));
251        }
252    
253        @Test public void testWithNamedMethodInjection() {
254            Object actual = new PicoBuilder().withNamedMethodInjection().build();
255            Object expected = new DefaultPicoContainer(new NamedMethodInjection(), lifecycle, parent, ncm);
256            assertEquals(toXml(expected), toXml(actual));
257        }
258    
259        @Test public void testWithNamedFieldInjection() {
260            Object actual = new PicoBuilder().withNamedFieldInjection().build();
261            Object expected = new DefaultPicoContainer(new NamedFieldInjection(), lifecycle, parent, ncm);
262            assertEquals(toXml(expected), toXml(actual));
263        }
264    
265        @Test public void testWithImplementationHidingAndSetterDI() {
266            Object actual = new PicoBuilder().withHiddenImplementations().withSetterInjection().build();
267            Object expected = new DefaultPicoContainer(new ImplementationHiding().wrap(new SetterInjection()),
268                    lifecycle, parent, ncm);
269            assertEquals(toXml(expected), toXml(actual));
270        }
271    
272        @Test public void testWithCachingImplementationHidingAndSetterDI() {
273            Object actual = new PicoBuilder().withCaching().withHiddenImplementations().withSetterInjection().build();
274            Object expected = new DefaultPicoContainer(new Caching().wrap(new ImplementationHiding().wrap(new SetterInjection())),
275                    lifecycle, parent, ncm);
276            assertEquals(toXml(expected), toXml(actual));
277        }
278    
279        @Test public void testWithSynchronizing() {
280            Object actual = new PicoBuilder().withSynchronizing().build();
281            Object expected = new DefaultPicoContainer(new Synchronizing().wrap(ai), lifecycle, parent, ncm);
282            assertEquals(toXml(expected), toXml(actual));
283        }
284    
285        @Test public void testWithLocking() {
286            Object actual = new PicoBuilder().withLocking().build();
287            Object expected = new DefaultPicoContainer(new Locking().wrap(ai), lifecycle, parent, ncm);
288            assertEquals(toXml(expected), toXml(actual));
289        }
290    
291        @Test public void testWithPropertyApplier() {
292            Object actual = new PicoBuilder().withPropertyApplier().build();
293            Object expected = new DefaultPicoContainer(new PropertyApplying().wrap(ai), lifecycle, parent, ncm);
294            assertEquals(toXml(expected), toXml(actual));
295        }
296    
297        //TODO - fix up to refer to SomeContainerDependency
298        @Test public void testWithCustomComponentFactory() {
299            Object actual = new PicoBuilder().withCustomContainerComponent(new SomeContainerDependency()).withComponentFactory(CustomComponentFactory.class).build();
300            Object expected = new DefaultPicoContainer(new CustomComponentFactory(new SomeContainerDependency()),
301                    lifecycle, parent, ncm);
302            assertEquals(toXml(expected), toXml(actual));
303        }
304    
305        public static class SomeContainerDependency {
306        }
307        public static class CustomComponentFactory implements ComponentFactory {
308    
309            @SuppressWarnings({ "UnusedDeclaration" })
310            public CustomComponentFactory(SomeContainerDependency someDependency) {
311            }
312    
313            public ComponentAdapter createComponentAdapter(ComponentMonitor componentMonitor,
314                                                           LifecycleStrategy lifecycleStrategy,
315                                                           Properties componentProperties,
316                                                           Object componentKey,
317                                                           Class componentImplementation,
318                                                           Parameter... parameters) throws PicoCompositionException {
319                return null;
320            }
321    
322            public void verify(PicoContainer container) {
323            }
324    
325            public void accept(PicoVisitor visitor) {
326                visitor.visitComponentFactory(this);
327            }
328        }
329    
330    
331        @Test public void testWithCustomPicoContainer() {
332            Object actual = new PicoBuilder().implementedBy(TestPicoContainer.class).build();
333            Object expected = new TestPicoContainer(ai, ncm, lifecycle, parent);
334            assertEquals(toXml(expected), toXml(actual));
335        }
336        
337        @Test
338        public void testMultipleUsesAreSupported() {
339            PicoBuilder picoBuilder = new PicoBuilder().withCaching().withLifecycle();
340            MutablePicoContainer pico = picoBuilder.build();
341            
342            pico.addComponent(Map.class, HashMap.class);
343            assertNotNull(pico.getComponentAdapter(Map.class).findAdapterOfType(Cached.class));
344            
345            pico = picoBuilder.build();
346            pico.addComponent(Map.class, HashMap.class);
347            assertNotNull(pico.getComponentAdapter(Map.class).findAdapterOfType(Cached.class));
348            
349            
350        }
351    
352    
353        public static class TestPicoContainer extends DefaultPicoContainer {
354            public TestPicoContainer(ComponentFactory componentFactory, ComponentMonitor monitor, LifecycleStrategy lifecycleStrategy, PicoContainer parent) {
355                super(componentFactory, lifecycleStrategy, parent, monitor);
356            }
357        }
358    
359        private String toXml(Object expected) {
360            return xs.toXML(expected);
361        }
362    
363    
364    }