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
010package org.picocontainer.behaviors;
011
012
013import org.junit.Test;
014import org.picocontainer.Characteristics;
015import org.picocontainer.ComponentAdapter;
016import org.picocontainer.ComponentFactory;
017import org.picocontainer.DefaultPicoContainer;
018import org.picocontainer.adapters.InstanceAdapter;
019import org.picocontainer.containers.EmptyPicoContainer;
020import org.picocontainer.injectors.AdaptingInjection;
021import org.picocontainer.injectors.ConstructorInjection;
022import org.picocontainer.injectors.ConstructorInjector;
023import org.picocontainer.lifecycle.NullLifecycleStrategy;
024import org.picocontainer.monitors.NullComponentMonitor;
025import org.picocontainer.tck.AbstractComponentFactoryTest;
026
027import static org.junit.Assert.assertEquals;
028import static org.junit.Assert.assertNotNull;
029
030
031public 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}