1/*
2 * Copyright (C) 2012 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.common.reflect;
18
19import static com.google.common.base.Preconditions.checkNotNull;
20
21import com.google.common.collect.ImmutableList;
22import com.google.common.testing.EqualsTester;
23import com.google.common.testing.SerializableTester;
24
25import junit.framework.TestCase;
26
27import java.io.Serializable;
28import java.lang.reflect.Method;
29import java.lang.reflect.Proxy;
30import java.util.List;
31
32/**
33 * Tests for {@link AbstractInvocationHandler}.
34 *
35 * @author Ben Yu
36 */
37public class AbstractInvocationHandlerTest extends TestCase {
38
39  private static final ImmutableList<String> LIST1 = ImmutableList.of("one", "two");
40  private static final ImmutableList<String> LIST2 = ImmutableList.of("three");
41
42  public void testDelegate() {
43    assertEquals(LIST1, ImmutableList.copyOf(newDelegatingList(LIST1)));
44    assertEquals(LIST1, ImmutableList.copyOf(newDelegatingListWithEquals(LIST1)));
45  }
46
47  public void testToString() {
48    List<String> proxy = newDelegatingList(LIST1);
49    assertEquals(Proxy.getInvocationHandler(proxy).toString(), proxy.toString());
50  }
51
52  interface A {}
53  interface B{}
54
55  public void testEquals() {
56    class AB implements A, B {}
57    class BA implements B, A {}
58    AB ab = new AB();
59    BA ba = new BA();
60    new EqualsTester()
61        .addEqualityGroup(newDelegatingList(LIST1))
62        // Actually, this violates List#equals contract.
63        // But whatever, no one is going to proxy List (hopefully).
64        .addEqualityGroup(newDelegatingList(LIST1))
65        .addEqualityGroup(newDelegatingList(LIST2))
66        .addEqualityGroup(
67            newProxyWithEqualsForInterfaces(List.class, Runnable.class),
68            newProxyWithEqualsForInterfaces(List.class, Runnable.class))
69        .addEqualityGroup(
70            newProxyWithEqualsForInterfaces(Runnable.class, List.class))
71        .addEqualityGroup(
72            newDelegatingListWithEquals(LIST1),
73            newDelegatingListWithEquals(LIST1),
74            SerializableTester.reserialize(newDelegatingListWithEquals(LIST1)))
75        .addEqualityGroup(
76            newDelegatingListWithEquals(LIST2),
77            newProxyWithSubHandler1(LIST2), // Makes sure type of handler doesn't affect equality
78            newProxyWithSubHandler2(LIST2))
79        .addEqualityGroup(newDelegatingIterableWithEquals(LIST2)) // different interface
80        .testEquals();
81  }
82
83  @SuppressWarnings("unchecked") // proxy of List<String>
84  private static List<String> newDelegatingList(List<String> delegate) {
85    return Reflection.newProxy(List.class, new DelegatingInvocationHandler(delegate));
86  }
87
88  @SuppressWarnings("unchecked") // proxy of List<String>
89  private static List<String> newDelegatingListWithEquals(List<String> delegate) {
90    return Reflection.newProxy(List.class, new DelegatingInvocationHandlerWithEquals(delegate));
91  }
92
93  @SuppressWarnings("unchecked") // proxy of Iterable<String>
94  private static Iterable<String> newDelegatingIterableWithEquals(Iterable<String> delegate) {
95    return Reflection.newProxy(Iterable.class, new DelegatingInvocationHandlerWithEquals(delegate));
96  }
97
98  @SuppressWarnings("unchecked") // proxy of List<String>
99  private static List<String> newProxyWithSubHandler1(List<String> delegate) {
100    return Reflection.newProxy(List.class, new SubHandler1(delegate));
101  }
102
103  @SuppressWarnings("unchecked") // proxy of List<String>
104  private static List<String> newProxyWithSubHandler2(List<String> delegate) {
105    return Reflection.newProxy(List.class, new SubHandler2(delegate));
106  }
107
108  private static Object newProxyWithEqualsForInterfaces(
109      Class<?>... interfaces) {
110    return Proxy.newProxyInstance(AbstractInvocationHandlerTest.class.getClassLoader(),
111        interfaces, new DelegatingInvocationHandlerWithEquals("a string"));
112  }
113
114  private static class DelegatingInvocationHandler extends AbstractInvocationHandler
115      implements Serializable {
116    final Object delegate;
117
118    DelegatingInvocationHandler(Object delegate) {
119      this.delegate = checkNotNull(delegate);
120    }
121
122    @Override protected Object handleInvocation(Object proxy, Method method, Object[] args)
123        throws Throwable {
124      return method.invoke(delegate, args);
125    }
126
127    @Override public String toString() {
128      return "some arbitrary string";
129    }
130  }
131
132  private static class DelegatingInvocationHandlerWithEquals extends DelegatingInvocationHandler {
133
134    DelegatingInvocationHandlerWithEquals(Object delegate) {
135      super(delegate);
136    }
137
138    @Override public boolean equals(Object obj) {
139      if (obj instanceof DelegatingInvocationHandlerWithEquals) {
140        DelegatingInvocationHandlerWithEquals that = (DelegatingInvocationHandlerWithEquals) obj;
141        return delegate.equals(that.delegate);
142      } else {
143        return false;
144      }
145    }
146
147    @Override public int hashCode() {
148      return delegate.hashCode();
149    }
150
151    @Override public String toString() {
152      return "another arbitrary string";
153    }
154  }
155
156  private static class SubHandler1 extends DelegatingInvocationHandlerWithEquals {
157    SubHandler1(Object delegate) {
158      super(delegate);
159    }
160  }
161
162  private static class SubHandler2 extends DelegatingInvocationHandlerWithEquals {
163    SubHandler2(Object delegate) {
164      super(delegate);
165    }
166  }
167}
168