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 *****************************************************************************/
010package org.picocontainer;
011
012import org.picocontainer.behaviors.Cached;
013
014import java.util.Map;
015
016import com.thoughtworks.xstream.XStream;
017import org.junit.Before;
018import org.junit.Test;
019import org.picocontainer.behaviors.Caching;
020import org.picocontainer.behaviors.ImplementationHiding;
021import org.picocontainer.behaviors.Locking;
022import org.picocontainer.behaviors.PropertyApplying;
023import org.picocontainer.behaviors.Synchronizing;
024import org.picocontainer.containers.EmptyPicoContainer;
025import org.picocontainer.injectors.AdaptingInjection;
026import org.picocontainer.injectors.AnnotatedFieldInjection;
027import org.picocontainer.injectors.AnnotatedMethodInjection;
028import org.picocontainer.injectors.CompositeInjection;
029import org.picocontainer.injectors.ConstructorInjection;
030import org.picocontainer.injectors.NamedFieldInjection;
031import org.picocontainer.injectors.NamedMethodInjection;
032import org.picocontainer.injectors.SetterInjection;
033import org.picocontainer.injectors.TypedFieldInjection;
034import org.picocontainer.lifecycle.JavaEE5LifecycleStrategy;
035import org.picocontainer.lifecycle.NullLifecycleStrategy;
036import org.picocontainer.lifecycle.ReflectionLifecycleStrategy;
037import org.picocontainer.lifecycle.StartableLifecycleStrategy;
038import org.picocontainer.monitors.ConsoleComponentMonitor;
039import org.picocontainer.monitors.NullComponentMonitor;
040
041import java.util.HashMap;
042import java.util.Properties;
043
044import static junit.framework.Assert.assertTrue;
045import static org.junit.Assert.assertEquals;
046import static org.junit.Assert.assertNotNull;
047import static org.junit.Assert.fail;
048import static org.picocontainer.behaviors.Behaviors.caching;
049import static org.picocontainer.behaviors.Behaviors.implementationHiding;
050import static org.picocontainer.behaviors.Behaviors.synchronizing;
051import static org.picocontainer.injectors.Injectors.SDI;
052
053@SuppressWarnings("serial")
054public 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}