1   /* Copyright (c) 2005 Per S Hustad. All rights reserved.
2    *
3    * Redistribution and use in source and binary forms, with or without 
4    * modification, are permitted provided that the following conditions are met:
5    *
6    *  o Redistributions of source code must retain the above copyright notice, 
7    *    this list of conditions and the following disclaimer. 
8    *    
9    *  o Redistributions in binary form must reproduce the above copyright notice, 
10   *    this list of conditions and the following disclaimer in the documentation 
11   *    and/or other materials provided with the distribution. 
12   *    
13   *  o Neither the name of surrogate.sourceforge.net nor the names of 
14   *    its contributors may be used to endorse or promote products derived 
15   *    from this software without specific prior written permission. 
16   *    
17   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
18   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
19   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
20   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
21   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
22   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
23   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
24   * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
25   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
26   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
27   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28   */
29  package net.sf.surrogate.core;
30  
31  import junit.framework.TestCase;
32  
33  /***
34   * Tests the SurrogateManager.
35   * <p>
36   * Note that this testCase will be woven by the test framwork so that it can
37   * test that its own classes are "mocked" ! Keep this in mind when trying to
38   * understand the code
39   * 
40   * @author Per S Hustad
41   */
42  public class SurrogateManagerTestCase extends TestCase {
43  
44      public SurrogateManagerTestCase(String name) {
45          super(name);
46      }
47  
48      /***
49       * test the getMockObjectForInterface
50       */
51      public void testGetMockObject_ForInterface() throws Exception {
52          SurrogateManager mm = SurrogateManager.getInstance();
53          mm.reset();
54          InterfaceToMockImp mI = new InterfaceToMockImp();
55          mm.addMock(mI);
56          Object mRet = mm.getMockObject(InterfaceToMock.class);
57          assertEquals(mI, mRet);
58          mm.reset();
59          mRet = mm.getMockObject(InterfaceToMock.class);
60          assertNull(mRet);
61      }
62  
63      /***
64       * test the getMockObjectForInterface
65       */
66      public void testGetMockObject_ForClass() throws Exception {
67          SurrogateManager mm = SurrogateManager.getInstance();
68          mm.reset();
69          MockClassToMock mock = new MockClassToMock();
70          mm.addMock(mock);
71          Object mRet = mm.getMockObject(ClassToMock.class);
72          assertEquals(mock, mRet);
73          mm.reset();
74          mRet = mm.getMockObject(ClassToMock.class);
75          assertNull(mRet);
76      }
77  
78      /***
79       * Test basic AspectJ pointcut pcGetInterfaceOrClass interaction. In the
80       * AspectJ file, we have defined a pointcut intercepting the calls to
81       * "getInterfaceToMock"
82       */
83      public void testPcGetInterfaceOrClass() {
84          SurrogateManager mm = SurrogateManager.getInstance();
85          mm.reset();
86          mm.addMock(new MockInterfaceToMock());
87          InterfaceToMock it = (InterfaceToMock) new TestClass01().getInterfaceToMock();
88          assertEquals("MOCK", it.getSomething("test"));
89      }
90  
91      /***
92       * This method is to test the difference between "call" and "execution"
93       * pointcuts when the returned class is casted to another type. This method
94       * MUST NOT be adviced
95       * 
96       * @return an ExtendedClassToMock
97       */
98      private ClassToMock getExtendedClassToMock_call() {
99          return new ExtendedClassToMock();
100 
101     }
102 
103     /***
104      * This method is to test the difference between "call" and "execution"
105      * pointcuts when the returned class is casted to another type. This method
106      * MUST be adviced
107      * 
108      * @return an ExtendedClassToMock
109      */
110     private ClassToMock getExtendedClassToMock_execution() {
111         return new ExtendedClassToMock(); // AOP pointcut here !
112     }
113 
114     /***
115      * Test that if we register both a Mock Method and a mock object
116      * corresponding to a poinctut, the MockMethod takes precedence
117      * 
118      * @throws Exception
119      *             if unexpected failure
120      */
121     public void testSetMockMethodAndObject() throws Exception {
122         SurrogateManager mm = SurrogateManager.getInstance();
123         mm.reset();
124         // first register a mock object
125         MockInterfaceToMock mockInterfaceToMock = new MockInterfaceToMock();
126         mm.addMock(mockInterfaceToMock);
127         TestClass01 sub = new TestClass01();
128         assertEquals("MOCK", sub.getInterfaceToMock().getSomething("hello"));
129         // Then register a mockmethod and tell that method
130         // to return a different mock class
131         MockMethod mocktestCall01 = mm.addMockMethod(new MockMethod(TestClass01.class, "getInterfaceToMock"));
132         mocktestCall01.setExpectedCalls(1);
133         mocktestCall01.addReturnValue(new InterfaceToMock() {
134             public String getSomething(String s) {
135                 return "Setup by mockmethod";
136             }
137         });
138         assertEquals("Setup by mockmethod", sub.getInterfaceToMock().getSomething("hello"));
139         mocktestCall01.verify();
140         // Then, remove the mock method and verify that the class is returned
141         Object removedMethod = mm.removeMockMethod(mocktestCall01);
142         assertEquals(mocktestCall01, removedMethod);
143         assertEquals("MOCK", sub.getInterfaceToMock().getSomething("hello"));
144         // Then remove the class and verify that "real" is returned
145         Object removedMock = mm.removeMock(mockInterfaceToMock);
146         assertEquals(mockInterfaceToMock, removedMock);
147         assertEquals("REAL", sub.getInterfaceToMock().getSomething("hello"));
148 
149     }
150 
151     /***
152      * Verifies that the SurrogateManager returns mocks corresponding to the
153      * <b>signature </b> of the declared method in execution and call pointcuts.
154      * I.e. when casting the class to another class, we might get a
155      * ClassCastException
156      * 
157      * @throws Exception
158      */
159     public void testClassCastException() throws Exception {
160         SurrogateManager mm = SurrogateManager.getInstance();
161         mm.reset();
162         MockClassToMock mockClassToMock = new MockClassToMock();
163         MockExtendedClassToMock mockExtendedClassToMock = new MockExtendedClassToMock();
164 
165         // Verify that we get no ClassCastException - no mocks
166         ExtendedClassToMock extendedClassToMock = (ExtendedClassToMock) getExtendedClassToMock_call(); // AOP
167                                                                                                        // advice
168                                                                                                        // here
169                                                                                                        // !
170         assertEquals("ExtendedClassToMock", extendedClassToMock.status);
171         mm.addMock(mockClassToMock);
172 
173         // Check that casting of classes in a "call" pointcut is invariant. In
174         // this
175         // case, since the funtion actually returns a ExtendedClassToMock but
176         // declares that
177         // it returns a ClassToMock, the returned object will be MockClassToMock
178         // but since we cast it to ExtendedClassToMock - we expect a
179         // ClassCastException
180         try {
181             extendedClassToMock = (ExtendedClassToMock) getExtendedClassToMock_call(); // AOP
182                                                                                        // advice
183                                                                                        // here
184                                                                                        // !
185             fail("Expected ClassCastException");
186         } catch (ClassCastException cce) {
187         }
188 
189         ClassToMock classToMock = getExtendedClassToMock_call(); // AOP advice
190                                                                  // here !
191         assertEquals("MockClassToMock", classToMock.status);
192 
193         //   Check that casting of classes in a "execution" pointcut is invariant
194         //   As in the case above, the method declares that it returns a
195         // ClassToMock
196         try {
197             extendedClassToMock = (ExtendedClassToMock) getExtendedClassToMock_execution(); // AOP
198                                                                                             // in
199                                                                                             // method
200                                                                                             // executing
201             fail("Expected ClassCastException");
202         } catch (ClassCastException cce) {
203         }
204 
205         classToMock = getExtendedClassToMock_execution(); // AOP in method
206                                                           // executing
207         assertEquals("MockClassToMock", classToMock.status);
208 
209     }
210 
211     private static interface InterfaceToMock {
212 
213         public String getSomething(String s);
214     }
215 
216     private static class MockInterfaceToMock implements InterfaceToMock {
217 
218         public String getSomething(String s) {
219             return "MOCK";
220         }
221     }
222 
223     private static class InterfaceToMockImp implements InterfaceToMock {
224 
225         public String getSomething(String s) {
226             return "REAL";
227         }
228     }
229 
230     private static class ClassToMock {
231 
232         public String status;
233 
234         public ClassToMock() {
235             status = "ClassToMock";
236         }
237 
238         public String getSomething(String s) {
239             return s;
240         }
241     }
242 
243     private static class ExtendedClassToMock extends ClassToMock {
244 
245         public String status;
246 
247         public ExtendedClassToMock() {
248             status = "ExtendedClassToMock";
249         }
250 
251         public String getSomething(String s) {
252             return s;
253         }
254 
255         public void fooExtend() {
256             ;
257         }
258     }
259 
260     private static class MockClassToMock extends ClassToMock {
261 
262         public String getSomething(String s) {
263             return super.getSomething(s);
264         }
265 
266         public MockClassToMock() {
267             status = "MockClassToMock";
268         }
269 
270         public String getStatus() {
271             return status;
272         }
273     }
274 
275     private static class MockExtendedClassToMock extends ExtendedClassToMock {
276 
277         public String getSomething(String s) {
278             return super.getSomething(s);
279         }
280 
281         public MockExtendedClassToMock() {
282             status = "MockExtendedClassToMock";
283         }
284 
285         public String getStatus() {
286             return status;
287         }
288     }
289 
290     private static class TestClass01 {
291 
292         //should be adviced in aspect
293         public String testCall01(String a, String b) {
294             return "OK";
295         }
296 
297         //should be adviced
298         public boolean isSomething() {
299             return true;
300         }
301 
302         // should be adviced
303         public boolean isSomething(String arg1) {
304             return true;
305         }
306 
307         // should be adviced
308         public InterfaceToMock getInterfaceToMock() {
309             return new InterfaceToMockImp();
310         }
311 
312     }
313 
314 }