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.defaults;
011    
012    import static org.junit.Assert.assertEquals;
013    import static org.junit.Assert.fail;
014    import static org.picocontainer.tck.MockFactory.mockeryWithCountingNamingScheme;
015    
016    import java.lang.reflect.Constructor;
017    import java.util.Collection;
018    import java.util.Vector;
019    
020    import org.hamcrest.BaseMatcher;
021    import org.hamcrest.Description;
022    import org.hamcrest.Matcher;
023    import org.jmock.Expectations;
024    import org.jmock.Mockery;
025    import org.jmock.integration.junit4.JMock;
026    import org.junit.Test;
027    import org.junit.runner.RunWith;
028    import org.picocontainer.ComponentAdapter;
029    import org.picocontainer.ComponentMonitor;
030    import org.picocontainer.ComponentMonitorStrategy;
031    import org.picocontainer.DefaultPicoContainer;
032    import org.picocontainer.PicoContainer;
033    import org.picocontainer.injectors.ConstructorInjector;
034    import org.picocontainer.monitors.AbstractComponentMonitor;
035    
036    /**
037     * @author Mauro Talevi
038     */
039    @RunWith(JMock.class)
040    public class AbstractComponentMonitorTestCase {
041    
042            private Mockery mockery = mockeryWithCountingNamingScheme();
043            
044        @Test public void testDelegatingMonitorThrowsExpectionWhenConstructionWithNullDelegate(){
045            try {
046                new AbstractComponentMonitor(null);
047                fail("NPE expected");
048            } catch (NullPointerException e) {
049                assertEquals("NPE", "monitor", e.getMessage());
050            }
051        }
052    
053        @Test public void testDelegatingMonitorThrowsExpectionWhenChangingToNullMonitor(){
054            AbstractComponentMonitor dcm = new AbstractComponentMonitor();
055            try {
056                dcm.changeMonitor(null);
057                fail("NPE expected");
058            } catch (NullPointerException e) {
059                assertEquals("NPE", "monitor", e.getMessage());
060            }
061        }
062    
063        @Test public void testDelegatingMonitorCanChangeMonitorInDelegateThatDoesSupportMonitorStrategy() {
064            ComponentMonitor monitor = mockMonitorWithNoExpectedMethods();
065            AbstractComponentMonitor dcm = new AbstractComponentMonitor(mockMonitorThatSupportsStrategy(monitor));
066            dcm.changeMonitor(monitor);
067            assertEquals(monitor, dcm.currentMonitor());
068            dcm.instantiating(null, null, null);
069        }
070    
071        @Test public void testDelegatingMonitorChangesDelegateThatDoesNotSupportMonitorStrategy() {
072            ComponentMonitor delegate = mockMonitorWithNoExpectedMethods();
073            AbstractComponentMonitor dcm = new AbstractComponentMonitor(delegate);
074            ComponentMonitor monitor = mockMonitorWithNoExpectedMethods();
075            assertEquals(delegate, dcm.currentMonitor());
076            dcm.changeMonitor(monitor);
077            assertEquals(monitor, dcm.currentMonitor());
078        }
079    
080        @Test public void testDelegatingMonitorReturnsDelegateThatDoesNotSupportMonitorStrategy() {
081            ComponentMonitor delegate = mockMonitorWithNoExpectedMethods();
082            AbstractComponentMonitor dcm = new AbstractComponentMonitor(delegate);
083            assertEquals(delegate, dcm.currentMonitor());
084        }
085    
086        private ComponentMonitor mockMonitorWithNoExpectedMethods() {
087            return mockery.mock(ComponentMonitor.class);
088        }
089    
090        private ComponentMonitor mockMonitorThatSupportsStrategy(final ComponentMonitor currentMonitor) {
091            final TestMonitorThatSupportsStrategy monitor = mockery.mock(TestMonitorThatSupportsStrategy.class);
092            mockery.checking(new Expectations(){{
093                one(monitor).changeMonitor(with(equal(currentMonitor)));
094                one(monitor).currentMonitor();
095                will(returnValue(currentMonitor));
096                one(monitor).instantiating(with(any(PicoContainer.class)), with(any(ComponentAdapter.class)), with(any(Constructor.class)));
097            }});
098            return monitor;
099        }
100    
101        @Test public void testMonitoringHappensBeforeAndAfterInstantiation() throws NoSuchMethodException {
102            final Vector ourIntendedInjectee0 = new Vector();
103            final String ourIntendedInjectee1 = "hullo";
104            final DefaultPicoContainer parent = new DefaultPicoContainer();
105            final ComponentMonitor monitor = mockery.mock(ComponentMonitor.class);
106            final DefaultPicoContainer child = new DefaultPicoContainer(new AbstractComponentMonitor(monitor), parent);
107            final Constructor needsACoupleOfThings = NeedsACoupleOfThings.class.getConstructors()[0];
108            final Matcher<Long> durationIsGreaterThanOrEqualToZero = new BaseMatcher<Long>() {
109                            public boolean matches(Object item) {
110                    Long duration = (Long)item;
111                    return 0 <= duration;
112                            }
113    
114                            public void describeTo(Description description) {
115                                    description.appendText("The endTime wasn't after the startTime");
116                            }
117            };
118            final Matcher<Object> isANACOTThatWozCreated = new BaseMatcher<Object>() {
119                            public boolean matches(Object item) {
120                    return item instanceof NeedsACoupleOfThings;
121                            }
122    
123                            public void describeTo(Description description) {
124                                    description.appendText("Should have been a NeedsACoupleOfThings");
125                            }
126            };
127            final Matcher<Object[]> collectionAndStringWereInjected = new BaseMatcher<Object[]>() {
128                            public boolean matches(Object item) {
129                                     Object[] args = (Object[]) item;
130                                     return args.length == 2 && args[0] == ourIntendedInjectee0 && args[1] == ourIntendedInjectee1;
131                            }
132                            public void describeTo(Description description) {
133                                    description.appendText("Should have injected our intended vector and string");
134                            }
135            };
136            mockery.checking(new Expectations(){{
137                    one(monitor).instantiating(with(same(child)), with(any(ConstructorInjector.class)), with(equal(needsACoupleOfThings)));
138                    will(returnValue(needsACoupleOfThings));
139                    one(monitor).instantiated(with(same(child)), with(any(ConstructorInjector.class)), with(equal(needsACoupleOfThings)), with(isANACOTThatWozCreated), with(collectionAndStringWereInjected), with(durationIsGreaterThanOrEqualToZero));
140                atLeast(2).of(monitor).noComponentFound(with(any(DefaultPicoContainer.class)), with(any(Object.class)));
141                will(returnValue(null));
142            }});
143            parent.addComponent(ourIntendedInjectee0);
144            parent.addComponent(ourIntendedInjectee1);
145            child.addComponent(NeedsACoupleOfThings.class);
146            child.getComponent(NeedsACoupleOfThings.class);
147        }
148    
149        public static class NeedsACoupleOfThings {
150            public NeedsACoupleOfThings(Collection collection, String string) {
151            }
152        }
153    
154        public static interface TestMonitorThatSupportsStrategy extends ComponentMonitor, ComponentMonitorStrategy {
155        }
156    }