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    package org.picocontainer.lifecycle;
009    
010    import org.picocontainer.ComponentMonitor;
011    import org.picocontainer.Disposable;
012    import org.picocontainer.Startable;
013    import org.picocontainer.lifecycle.ReflectionLifecycleStrategy;
014    
015    import org.jmock.Mock;
016    import org.jmock.MockObjectTestCase;
017    import org.jmock.core.Constraint;
018    
019    import java.io.Serializable;
020    import java.lang.reflect.Method;
021    
022    /**
023     * @author Paul Hammant
024     * @author Mauro Talevi
025     * @author Jörg Schaible
026     */
027    public class ReflectionLifecycleStrategyTestCase extends MockObjectTestCase {
028    
029        private ReflectionLifecycleStrategy strategy;
030        private Mock componentMonitorMock;
031        
032        public void setUp(){
033            componentMonitorMock = mock(ComponentMonitor.class);
034            strategy = new ReflectionLifecycleStrategy((ComponentMonitor)componentMonitorMock.proxy());
035        }
036    
037        public void testStartable(){
038            Object startable = mockComponent(true, false);
039            strategy.start(startable);
040            strategy.stop(startable);
041            strategy.dispose(startable);
042        }
043    
044        public void testDisposable(){
045            Object disposable = mockComponent(false, true);
046            strategy.start(disposable);
047            strategy.stop(disposable);
048            strategy.dispose(disposable);
049        }
050    
051        public void testNotStartableNorDisposable(){
052            Object serializable = mock(Serializable.class);
053            assertFalse(strategy.hasLifecycle(serializable.getClass()));
054            strategy.start(serializable);
055            strategy.stop(serializable);
056            strategy.dispose(serializable);
057        }
058        
059        public void testMonitorChanges() {
060            Mock componentMonitorMock2 = mock(ComponentMonitor.class);
061            Mock mock = mock(Disposable.class);
062            Object disposable = mock.proxy();
063            mock.expects(once()).method("dispose");
064            componentMonitorMock.expects(once()).method("invoking").with(NULL, NULL, method("dispose"), same(mock.proxy()));
065            componentMonitorMock.expects(once()).method("invoked").with(new Constraint[] {NULL, NULL, method("dispose"), same(mock.proxy()), ANYTHING});
066            strategy.dispose(disposable);
067            strategy.changeMonitor((ComponentMonitor)componentMonitorMock2.proxy());
068            mock.expects(once()).method("dispose");
069            componentMonitorMock2.expects(once()).method("invoking").with(NULL, NULL, method("dispose"), same(mock.proxy()));
070            componentMonitorMock2.expects(once()).method("invoked").with(new Constraint[] {NULL, NULL, method("dispose"), same(mock.proxy()), ANYTHING});
071            strategy.dispose(disposable);
072        }
073        
074        static interface MyLifecylce {
075            void start();
076            void stop();
077            void dispose();
078        }
079        
080        public void testWithDifferentTypes() {
081            Mock anotherStartableMock = mock(MyLifecylce.class);
082            anotherStartableMock.expects(once()).method("start");
083            anotherStartableMock.expects(once()).method("stop");
084            anotherStartableMock.expects(once()).method("dispose");
085            componentMonitorMock.expects(once()).method("invoking").with(NULL, NULL, method("start"), same(anotherStartableMock.proxy()));
086            componentMonitorMock.expects(once()).method("invoked").with(new Constraint[] {NULL, NULL, method("start"), same(anotherStartableMock.proxy()), ANYTHING});
087            componentMonitorMock.expects(once()).method("invoking").with(NULL, NULL, method("stop"), same(anotherStartableMock.proxy()));
088            componentMonitorMock.expects(once()).method("invoked").with(new Constraint[] {NULL, NULL, method("stop"), same(anotherStartableMock.proxy()), ANYTHING});
089            componentMonitorMock.expects(once()).method("invoking").with(NULL, NULL, method("dispose"), same(anotherStartableMock.proxy()));
090            componentMonitorMock.expects(once()).method("invoked").with(new Constraint[] {NULL, NULL, method("dispose"), same(anotherStartableMock.proxy()), ANYTHING});
091    
092            Object startable = mockComponent(true, false);
093            strategy.start(startable);
094            strategy.stop(startable);
095            strategy.dispose(startable);
096            startable = anotherStartableMock.proxy();
097            strategy.start(startable);
098            strategy.stop(startable);
099            strategy.dispose(startable);
100        }
101        
102        private Object mockComponent(boolean startable, boolean disposable) {
103            Mock mock = mock(Serializable.class);
104            if ( startable ) {
105                mock = mock(Startable.class);
106                mock.expects(atLeastOnce()).method("start");
107                mock.expects(atLeastOnce()).method("stop");
108                componentMonitorMock.expects(once()).method("invoking").with(NULL, NULL, method("start"), same(mock.proxy()));
109                componentMonitorMock.expects(once()).method("invoked").with(new Constraint[] {NULL, NULL, method("start"), same(mock.proxy()), ANYTHING});
110                componentMonitorMock.expects(once()).method("invoking").with(NULL, NULL, method("stop"), same(mock.proxy()));
111                componentMonitorMock.expects(once()).method("invoked").with(new Constraint[] {NULL, NULL, method("stop"), same(mock.proxy()), ANYTHING});
112            }
113            if ( disposable ) {
114                mock = mock(Disposable.class);
115                mock.expects(atLeastOnce()).method("dispose");
116                componentMonitorMock.expects(once()).method("invoking").with(NULL, NULL, method("dispose"), same(mock.proxy()));
117                componentMonitorMock.expects(once()).method("invoked").with(new Constraint[] {NULL, NULL, method("dispose"), same(mock.proxy()), ANYTHING});
118            }
119            return mock.proxy();
120        }
121        
122        MethodNameIsEqual method(String name) {
123            return new MethodNameIsEqual(name);
124        }
125        
126        static class MethodNameIsEqual implements Constraint {
127    
128            private final String name;
129    
130            public MethodNameIsEqual(String name) {
131                this.name = name;
132            }
133            
134            public boolean eval(Object o) {
135                return o instanceof Method && ((Method)o).getName().equals(name);
136            }
137    
138            public StringBuffer describeTo(StringBuffer buffer) {
139                buffer.append("a method with name <");
140                buffer.append(name);
141                return buffer.append('>');
142            }
143            
144        }
145    }