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