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     *****************************************************************************/
009    
010    package org.picocontainer.behaviors;
011    
012    
013    import org.junit.Test;
014    import org.picocontainer.Characteristics;
015    import org.picocontainer.ComponentAdapter;
016    import org.picocontainer.ComponentFactory;
017    import org.picocontainer.DefaultPicoContainer;
018    import org.picocontainer.adapters.InstanceAdapter;
019    import org.picocontainer.containers.EmptyPicoContainer;
020    import org.picocontainer.injectors.AdaptingInjection;
021    import org.picocontainer.injectors.ConstructorInjection;
022    import org.picocontainer.injectors.ConstructorInjector;
023    import org.picocontainer.lifecycle.NullLifecycleStrategy;
024    import org.picocontainer.monitors.NullComponentMonitor;
025    import org.picocontainer.tck.AbstractComponentFactoryTest;
026    
027    import static org.junit.Assert.assertEquals;
028    import static org.junit.Assert.assertNotNull;
029    
030    
031    public class ImplementationHidingTestCase extends AbstractComponentFactoryTest{
032    
033        @Test public void testAddComponentUsesImplementationHidingBehavior() {
034            DefaultPicoContainer pico =
035                new DefaultPicoContainer(new ImplementationHiding().wrap(new ConstructorInjection()), new NullLifecycleStrategy(), new EmptyPicoContainer());
036            pico.addComponent("foo", String.class);
037            ComponentAdapter<?> foo = pico.getComponentAdapter("foo");
038            assertEquals(HiddenImplementation.class, foo.getClass());
039            assertEquals(ConstructorInjector.class, ((AbstractBehavior) foo).getDelegate().getClass());
040        }
041    
042        @Test public void testAddComponentUsesImplementationHidingBehaviorWithRedundantHideImplProperty() {
043            DefaultPicoContainer pico =
044                new DefaultPicoContainer(new ImplementationHiding().wrap(new ConstructorInjection()), new NullLifecycleStrategy(), new EmptyPicoContainer());
045            pico.change(Characteristics.HIDE_IMPL).addComponent("foo", String.class);
046            ComponentAdapter<?> foo = pico.getComponentAdapter("foo");
047            assertEquals(HiddenImplementation.class, foo.getClass());
048            assertEquals(ConstructorInjector.class, ((AbstractBehavior) foo).getDelegate().getClass());
049        }
050    
051        @Test public void testAddComponentNoesNotUseImplementationHidingBehaviorWhenNoCachePropertyIsSpecified() {
052            DefaultPicoContainer pico =
053                new DefaultPicoContainer(new ImplementationHiding().wrap(new ConstructorInjection()), new NullLifecycleStrategy(), new EmptyPicoContainer());
054            pico.change(Characteristics.NO_HIDE_IMPL).addComponent("foo", String.class);
055            ComponentAdapter<?> foo = pico.getComponentAdapter("foo");
056            assertEquals(ConstructorInjector.class, foo.getClass());
057        }
058    
059        @Test public void testAddAdapterUsesImplementationHidingBehavior() {
060            DefaultPicoContainer pico =
061                new DefaultPicoContainer(new ImplementationHiding().wrap(new ConstructorInjection()));
062            pico.addAdapter(new InstanceAdapter("foo", "bar", new NullLifecycleStrategy(), new NullComponentMonitor()));
063            ComponentAdapter<?> foo = pico.getComponentAdapter("foo");
064            assertEquals(HiddenImplementation.class, foo.getClass());
065            assertEquals(InstanceAdapter.class, ((AbstractBehavior) foo).getDelegate().getClass());
066        }
067    
068        @Test public void testAddAdapterUsesImplementationHidingBehaviorWithRedundantHideImplProperty() {
069            DefaultPicoContainer pico =
070                new DefaultPicoContainer(new ImplementationHiding().wrap(new ConstructorInjection()));
071            pico.change(Characteristics.HIDE_IMPL).addAdapter(new InstanceAdapter("foo", "bar", new NullLifecycleStrategy(), new NullComponentMonitor()));
072            ComponentAdapter<?> foo = pico.getComponentAdapter("foo");
073            assertEquals(HiddenImplementation.class, foo.getClass());
074            assertEquals(InstanceAdapter.class, ((AbstractBehavior) foo).getDelegate().getClass());
075        }
076    
077        @Test public void testAddAdapterNoesNotUseImplementationHidingBehaviorWhenNoCachePropertyIsSpecified() {
078            DefaultPicoContainer pico =
079                new DefaultPicoContainer(new ImplementationHiding().wrap(new ConstructorInjection()));
080            pico.change(Characteristics.NO_HIDE_IMPL).addAdapter(new InstanceAdapter("foo", "bar", new NullLifecycleStrategy(), new NullComponentMonitor()));
081            ComponentAdapter<?> foo = pico.getComponentAdapter("foo");
082            assertEquals(InstanceAdapter.class, foo.getClass());
083        }
084    
085    
086        private final ComponentFactory implementationHidingComponentFactory =
087            new ImplementationHiding().wrap(new AdaptingInjection());
088    
089        protected ComponentFactory createComponentFactory() {
090            return implementationHidingComponentFactory;
091        }
092    
093    
094        public static interface NeedsStringBuilder {
095            void foo();
096        }
097        public static class NeedsStringBuilderImpl implements NeedsStringBuilder {
098            StringBuilder sb;
099    
100            public NeedsStringBuilderImpl(StringBuilder sb) {
101                this.sb = sb;
102                sb.append("<init>");
103            }
104            public void foo() {
105                sb.append("foo()");
106            }
107        }
108        public static class NeedsNeedsStringBuilder {
109    
110            NeedsStringBuilder nsb;
111    
112            public NeedsNeedsStringBuilder(NeedsStringBuilder nsb) {
113                this.nsb = nsb;
114            }
115            public void foo() {
116                nsb.foo();
117            }
118        }
119    
120        @Test public void testLazyInstantiationSideEffectWhenForceOfDelayedInstantiationOfDependantClass() {
121            DefaultPicoContainer pico =
122                new DefaultPicoContainer(new ImplementationHiding().wrap(new Caching().wrap(new ConstructorInjection())));
123            pico.addComponent(StringBuilder.class);
124            pico.addComponent(NeedsStringBuilder.class, NeedsStringBuilderImpl.class);
125            pico.addComponent(NeedsNeedsStringBuilder.class);
126            NeedsNeedsStringBuilder nnsb = pico.getComponent(NeedsNeedsStringBuilder.class);
127            assertNotNull(nnsb);
128            StringBuilder sb = pico.getComponent(StringBuilder.class);
129            assertEquals("", sb.toString()); // not instantiated yet
130            nnsb.foo();
131            assertEquals("<init>foo()", sb.toString()); // instantiated
132        }
133    
134        @Test public void shouldInstantiateForEveryGetComponentCall() {
135            DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
136            parent.addComponent(StringBuilder.class);
137            DefaultPicoContainer pico =
138                new DefaultPicoContainer(new ImplementationHiding(), parent);
139            pico.addComponent(NeedsStringBuilder.class, NeedsStringBuilderImpl.class);
140            NeedsStringBuilder nsb = pico.getComponent(NeedsStringBuilder.class);
141            nsb.foo();
142            nsb = pico.getComponent(NeedsStringBuilder.class);
143            nsb.foo();
144            StringBuilder sb = pico.getComponent(StringBuilder.class);
145            assertEquals("<init>foo()<init>foo()", sb.toString());
146        }
147    
148        @Test public void shouldInstantiateForEveryMethodCall() {
149            cachingTestBody("<init>foo()foo()", new ImplementationHiding());
150        }
151    
152        private void cachingTestBody(String expectation, ComponentFactory compFactory) {
153            DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
154            parent.addComponent(StringBuilder.class);
155            DefaultPicoContainer pico =
156                new DefaultPicoContainer(compFactory, parent);
157            pico.addComponent(NeedsStringBuilder.class, NeedsStringBuilderImpl.class);
158            NeedsStringBuilder nsb = pico.getComponent(NeedsStringBuilder.class);
159            assertNotNull(nsb);
160            nsb.foo();
161            nsb.foo();
162            StringBuilder sb = pico.getComponent(StringBuilder.class);
163            assertEquals(expectation, sb.toString());
164        }
165    
166    }