1   //----------------------------------------------------------------------
2   // 
3   // PerfectJPattern: "Design patterns are good but components are better!" 
4   // TestDelegator.java Copyright (c) 2009 Giovanni Azua Garcia
5   // bravegag@hotmail.com
6   //  
7   // This program is free software; you can redistribute it and/or
8   // modify it under the terms of the GNU General Public License
9   // as published by the Free Software Foundation; either version 3
10  // of the License, or (at your option) any later version.
11  //
12  // This program is distributed in the hope that it will be useful,
13  // but WITHOUT ANY WARRANTY; without even the implied warranty of
14  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  // GNU General Public License for more details.
16  //
17  // You should have received a copy of the GNU General Public License
18  // along with this program; if not, see <http://www.gnu.org/licenses/>.
19  //
20  //----------------------------------------------------------------------
21  package org.perfectjpattern.core.extras.delegate;
22  
23  import java.lang.reflect.*;
24  
25  import junit.framework.*;
26  
27  import org.perfectjpattern.core.api.extras.delegate.*;
28  import org.slf4j.*;
29  
30  /**
31   * Test Suite for {@link Delegator} implementation.
32   * <br/><br/>
33   * <b>Notes</b>: Base source code implemented by Steve Lewis and Wilhelm 
34   * Fitzpatrick and adapted to fit PerfectJPattern componentization 
35   * criteria and code conventions.
36   * 
37   * @see IDelegate
38   * @see IDelegator
39   * @see Delegator
40   * @see DynamicDelegator
41   *
42   * @author <a href="mailto:smlewis@lordjoe.com">Steve Lewis</a>
43   * @author <a href="mailto:wilhelmf@agileinformatics.com">Wilhelm 
44   * Fitzpatrick</a>
45   * @author <a href="mailto:bravegag@hotmail.com">Giovanni Azua</a>
46   * @version $Revision: 2.0 $ $Date: Jun 24, 2007 11:16:36 AM $
47   */
48  @SuppressWarnings("unchecked")
49  public 
50  class TestDelegator 
51  extends TestCase 
52  {
53      //------------------------------------------------------------------------
54      // public
55      //------------------------------------------------------------------------
56      public void 
57      testIsSuitableMethod() 
58      {
59          int myNoArguments = 1;
60          Method[] myPossibilities = AbstractDelegator.findMethod(IStringDisplay.
61              class, "doDisplay", myNoArguments);
62  
63          Class myReturnClass = void.class;
64          Class[] myArguments = new Class[] {String.class };
65          
66          AbstractDelegator<IStringDisplay> myDelegate = new Delegator<
67              IStringDisplay>(IStringDisplay.class);
68          
69          assertTrue("AbstractDelegator.searchCandidateMethods() did not " +
70              "produce the expeted result.", myDelegate.isSuitableMethod(
71                  myPossibilities[0], myReturnClass, myArguments));
72      }
73      
74      //------------------------------------------------------------------------
75      public void 
76      testSearchCandidateMethods() 
77      {
78          int myNumberOfArguments = 1;
79          Method[] myPossibilities =             
80              AbstractDelegator.findMethod(
81                  IBadStringDisplay.class, "doDisplay", myNumberOfArguments);
82          
83          assertEquals("AbstractDelegator.searchCandidateMethods() did not " +
84                  "return the expected number of matches.", 1, 
85                      myPossibilities.length);
86  
87          assertEquals("AbstractDelegator.searchCandidateMethods() did not " +
88              "find the right match.", "doDisplay", 
89                  myPossibilities[0].getName());
90      }    
91  
92      //------------------------------------------------------------------------
93      public void 
94      testDelegateBuild() 
95      {
96          try 
97          {
98              // Target interface must have a single method
99              new Delegator<IBadStringDisplay>(IBadStringDisplay.class);
100             fail("Delegator multiple method interface was not rejected.");
101         } 
102         catch (IllegalArgumentException anException)
103         {
104             // ok
105         }
106 
107         try 
108         {
109             // Target interface must have at least one method
110             new Delegator<IBadStringDisplay2>(IBadStringDisplay2.class);
111             fail("Delegator interface with no methods was not rejected.");
112         } 
113         catch (IllegalArgumentException anException) 
114         {
115             // ok
116         }
117     }
118 
119     //------------------------------------------------------------------------
120     /**
121      * Test calls to <code>Delegator</code>
122      */
123     public void 
124     testDelegator() 
125     throws Exception 
126     {
127         IDelegator<IStringDisplay> myDelegate = 
128             new Delegator<IStringDisplay>(IStringDisplay.class);
129         
130         Class1 myObject1 = new Class1();
131         Class2 myObject2 = new Class2();
132         
133         IStringDisplay[] myItems = new IStringDisplay[3];
134         myItems[0] = myDelegate.build(myObject1, "show");
135         myItems[1] = myDelegate.build(myObject2, "display");
136         myItems[2] = myDelegate.build(Class3.class,
137             "staticDisplay");
138 
139         for (int i = 0; i < myItems.length; i++) 
140         {
141             IStringDisplay myItem = myItems[i];
142             myItem.doDisplay("test");
143         }
144         
145         final int myIterationsCount = 10000;
146         timingTest(myItems, myObject1, myObject2, myIterationsCount);        
147     }
148     
149     //------------------------------------------------------------------------
150     /**
151      * Test calls to <code>Delegator</code>
152      */
153     public void 
154     testDynamicDelegator() 
155     throws Exception 
156     {
157         IDelegator<IDelegate> myDelegator = new DynamicDelegator(Void.TYPE, 
158             String.class);
159         
160         Class1 myObject1 = new Class1();
161         Class2 myObject2 = new Class2();
162         
163         IDelegate[] myDelegates = new IDelegate[3];
164         myDelegates[0] = myDelegator.build(myObject1, "show");
165         myDelegates[1] = myDelegator.build(myObject2, "display");
166         
167         Class3.reset();
168         myDelegates[2] = myDelegator.build(Class3.class, "staticDisplay");
169 
170         for (int i = 0; i < myDelegates.length; i++) 
171         {
172             IDelegate myDelegate = myDelegates[i];
173             myDelegate.invoke("test");
174         }        
175         
176         assertEquals("Wrong calls count", 1, myObject1.getCount());            
177         assertEquals("Wrong calls count", 1, myObject2.getCount());            
178         assertEquals("Wrong calls count", 1, Class3.getCount());            
179     }
180 
181     //------------------------------------------------------------------------
182     /**
183      * Test of timing - note set iteration large i.e. 1000000 for reasonable 
184      * results
185      */
186     public void 
187     timingTest(IStringDisplay[] anItems, Class1 anObject1, Class2 anObject2,
188         int anIterations) 
189     {
190         // Warm up hotspot
191         for (int i = 0; i < 100; i++) 
192         {
193             for (int j = 0; j < anItems.length; j++) 
194             {
195                 IStringDisplay myItem = anItems[j];
196                 myItem.doDisplay("test");
197             }
198 
199             anObject1.show("test");
200             anObject2.display("test");
201             Class3.staticDisplay("test");
202         }
203 
204         long myStart = System.currentTimeMillis();
205 
206         for (int i = 0; i < anIterations; i++) 
207         {
208             for (int j = 0; j < anItems.length; j++) 
209             {
210                 IStringDisplay myItem = anItems[j];
211                 myItem.doDisplay("test");
212             }
213         }
214 
215         long myEnd = System.currentTimeMillis();
216         double myDelegateTime = (myEnd - myStart) / 1000.;
217         double myPerIteration = (1000. * 1000. * myDelegateTime) / anIterations;
218 
219         myStart = System.currentTimeMillis();
220 
221         for (int myJ = 0; myJ < anIterations; myJ++) 
222         {
223             anObject1.show("test");
224             anObject2.display("test");
225             Class3.staticDisplay("test");
226         }
227 
228         myEnd = System.currentTimeMillis();
229 
230         double myDirectTime = (myEnd - myStart) / 1000.;
231         double myPerCallIteration = (1000. * 1000. * myDirectTime) / 
232             anIterations;
233 
234         theLogger.debug("Ran '" + anIterations + "' iterations ");
235         theLogger.debug("Delegator Test took '" + myDelegateTime + "' secs");
236         theLogger.debug("per iteration '" + myPerIteration + " microsecs");
237         theLogger.debug("Direct Calls took '" + myDirectTime + " secs");
238         theLogger.debug("per iteration '" + myPerCallIteration + "' microsecs");
239     }
240 
241     //------------------------------------------------------------------------
242     // inner classes
243     //------------------------------------------------------------------------
244     private static 
245     interface 
246     IStringDisplay 
247     {
248         //--------------------------------------------------------------------
249         public void 
250         doDisplay(String aValue);
251     }
252 
253     //------------------------------------------------------------------------
254     private static 
255     interface IBadStringDisplay 
256     {
257         //--------------------------------------------------------------------
258         public void 
259         doDisplay(String aValue);
260 
261         //--------------------------------------------------------------------
262         public void 
263         doDisplay2(String aValue);
264     }
265 
266     //------------------------------------------------------------------------
267     private static 
268     interface IBadStringDisplay2 
269     {
270         // empty
271     }
272     
273     //------------------------------------------------------------------------
274     private static 
275     class Class1 
276     {
277         //--------------------------------------------------------------------
278         public void 
279         show(String aValue) 
280         {
281             theCount++; 
282         }
283 
284         //--------------------------------------------------------------------
285         public int 
286         getCount()
287         {
288             return theCount;
289         }
290 
291         //--------------------------------------------------------------------
292         // members
293         //--------------------------------------------------------------------
294         private int theCount;
295     }
296 
297     //------------------------------------------------------------------------
298     private static 
299     class Class2 
300     {
301         //--------------------------------------------------------------------
302         public void 
303         display(String aValue) 
304         {
305             theCount++;
306         }
307 
308         //--------------------------------------------------------------------
309         public int 
310         getCount()
311         {
312             return theCount;
313         }
314 
315         //--------------------------------------------------------------------
316         // members
317         //--------------------------------------------------------------------
318         private int theCount;
319     }
320 
321     //------------------------------------------------------------------------
322     // CHECKSTYLE:OFF
323     private final static     
324     class Class3 
325     // CHECKSTYLE:ON
326     {
327         //--------------------------------------------------------------------
328         public static void 
329         staticDisplay(String aValue) 
330         {
331             theCount++;
332         }
333 
334         //--------------------------------------------------------------------
335         public static int 
336         getCount()
337         {
338             return theCount;
339         }
340         
341         //--------------------------------------------------------------------
342         public static void
343         reset()
344         {
345             theCount = 0;
346         }
347         
348         //--------------------------------------------------------------------
349         // members
350         //--------------------------------------------------------------------
351         private static int theCount;
352     }  
353     
354     //------------------------------------------------------------------------
355     // members
356     //------------------------------------------------------------------------
357     /**
358      * Provides logging services for this class.
359      */
360     private final Logger theLogger = LoggerFactory.getLogger(this.getClass());
361 }