View Javadoc
1   /**
2    * Copyright (c) 2004-2011 QOS.ch
3    * All rights reserved.
4    *
5    * Permission is hereby granted, free  of charge, to any person obtaining
6    * a  copy  of this  software  and  associated  documentation files  (the
7    * "Software"), to  deal in  the Software without  restriction, including
8    * without limitation  the rights to  use, copy, modify,  merge, publish,
9    * distribute,  sublicense, and/or sell  copies of  the Software,  and to
10   * permit persons to whom the Software  is furnished to do so, subject to
11   * the following conditions:
12   *
13   * The  above  copyright  notice  and  this permission  notice  shall  be
14   * included in all copies or substantial portions of the Software.
15   *
16   * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
17   * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
18   * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
19   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20   * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21   * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
22   * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23   *
24   */
25  package org.slf4j.helpers;
26  
27  import static org.junit.Assert.assertTrue;
28  import static org.junit.Assert.fail;
29  
30  import java.lang.reflect.InvocationHandler;
31  import java.lang.reflect.InvocationTargetException;
32  import java.lang.reflect.Method;
33  import java.lang.reflect.Proxy;
34  import java.util.Arrays;
35  import java.util.HashSet;
36  import java.util.Set;
37  
38  import org.junit.Test;
39  import org.slf4j.Logger;
40  import org.slf4j.event.EventRecordingLogger;
41  
42  /**
43   * @author Chetan Mehrotra
44   * @author Ceki Gülcü
45   */
46  public class SubstitutableLoggerTest {
47  
48      // NOTE: previous implementations of this class performed a hand crafted conversion of 
49      // a method to a string. In this implementation we just invoke method.toString().
50      
51      // WARNING: if you need to add an excluded method to have tests pass, ask yourself whether you
52      // forgot to implement the said method with delegation in SubstituteLogger. You probably did.
53      private static final Set<String> EXCLUDED_METHODS = new HashSet<>(
54              Arrays.asList("getName"));
55  
56      
57      /**
58       * Test that all SubstituteLogger methods invoke the delegate, except for explicitly excluded  methods.
59       */
60      @Test
61      public void delegateIsInvokedTest() throws Exception {
62          SubstituteLogger substituteLogger = new SubstituteLogger("foo", null, false);
63          assertTrue(substituteLogger.delegate() instanceof EventRecordingLogger);
64  
65          Set<String> expectedMethodSignatures = determineMethodSignatures(Logger.class);
66          LoggerInvocationHandler loggerInvocationHandler = new LoggerInvocationHandler();
67          Logger proxyLogger = (Logger) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { Logger.class }, loggerInvocationHandler);
68          substituteLogger.setDelegate(proxyLogger);
69  
70          invokeAllMethodsOf(substituteLogger);
71  
72          // Assert that all methods are delegated
73          expectedMethodSignatures.removeAll(loggerInvocationHandler.getInvokedMethodSignatures());
74          if (!expectedMethodSignatures.isEmpty()) {
75              fail("Following methods are not delegated " + expectedMethodSignatures.toString());
76          }
77      }
78  
79      private void invokeAllMethodsOf(Logger logger) throws InvocationTargetException, IllegalAccessException {
80          for (Method m : Logger.class.getDeclaredMethods()) {
81              if (!EXCLUDED_METHODS.contains(m.getName())) {
82                  m.invoke(logger, new Object[m.getParameterTypes().length]);
83              }
84          }
85      }
86  
87      private static Set<String> determineMethodSignatures(Class<Logger> loggerClass) {
88          Set<String> methodSignatures = new HashSet<>();
89          // Note: Class.getDeclaredMethods() does not include inherited methods
90          for (Method m : loggerClass.getDeclaredMethods()) {
91              if (!EXCLUDED_METHODS.contains(m.getName())) {
92                  methodSignatures.add(m.toString());
93              }
94          }
95          return methodSignatures;
96      }
97  
98      
99      // implements InvocationHandler 
100     private class LoggerInvocationHandler implements InvocationHandler {
101         private final Set<String> invokedMethodSignatures = new HashSet<>();
102 
103         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
104             invokedMethodSignatures.add(method.toString());
105             if (method.getName().startsWith("is")) {
106                 return true;
107             }
108             return null;
109         }
110 
111         public Set<String> getInvokedMethodSignatures() {
112             return invokedMethodSignatures;
113         }
114     }
115 }