1/*
2 * Copyright (C) 2005 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.base;
18
19import com.google.common.annotations.GwtCompatible;
20import com.google.common.collect.ImmutableMap;
21import com.google.common.collect.Maps;
22import com.google.common.testing.EqualsTester;
23
24import junit.framework.TestCase;
25
26import java.io.Serializable;
27import java.util.Map;
28
29/**
30 * Tests for {@link Functions}.
31 *
32 * @author Mike Bostock
33 * @author Vlad Patryshev
34 */
35@GwtCompatible(emulated = true)
36public class FunctionsTest extends TestCase {
37
38  public void testIdentity_same() {
39    Function<String, String> identity = Functions.identity();
40    assertNull(identity.apply(null));
41    assertSame("foo", identity.apply("foo"));
42  }
43
44  public void testIdentity_notSame() {
45    Function<Long, Long> identity = Functions.identity();
46    assertNotSame(new Long(135135L), identity.apply(new Long(135135L)));
47  }
48
49  public void testToStringFunction_apply() {
50    assertEquals("3", Functions.toStringFunction().apply(3));
51    assertEquals("hiya", Functions.toStringFunction().apply("hiya"));
52    assertEquals("I'm a string",
53        Functions.toStringFunction().apply(
54            new Object() {
55              @Override public String toString() {
56                return "I'm a string";
57              }
58            }));
59    try {
60      Functions.toStringFunction().apply(null);
61      fail("expected NullPointerException");
62    } catch (NullPointerException e) {
63      // expected
64    }
65  }
66
67  public void testForMapWithoutDefault() {
68    Map<String, Integer> map = Maps.newHashMap();
69    map.put("One", 1);
70    map.put("Three", 3);
71    map.put("Null", null);
72    Function<String, Integer> function = Functions.forMap(map);
73
74    assertEquals(1, function.apply("One").intValue());
75    assertEquals(3, function.apply("Three").intValue());
76    assertNull(function.apply("Null"));
77
78    try {
79      function.apply("Two");
80      fail();
81    } catch (IllegalArgumentException expected) {
82    }
83
84    new EqualsTester()
85        .addEqualityGroup(function, Functions.forMap(map))
86        .addEqualityGroup(Functions.forMap(map, 42))
87        .testEquals();
88  }
89
90  public void testForMapWithDefault() {
91    Map<String, Integer> map = Maps.newHashMap();
92    map.put("One", 1);
93    map.put("Three", 3);
94    map.put("Null", null);
95    Function<String, Integer> function = Functions.forMap(map, 42);
96
97    assertEquals(1, function.apply("One").intValue());
98    assertEquals(42, function.apply("Two").intValue());
99    assertEquals(3, function.apply("Three").intValue());
100    assertNull(function.apply("Null"));
101
102    new EqualsTester()
103        .addEqualityGroup(function, Functions.forMap(map, 42))
104        .addEqualityGroup(Functions.forMap(map))
105        .addEqualityGroup(Functions.forMap(map, null))
106        .addEqualityGroup(Functions.forMap(map, 43))
107        .testEquals();
108  }
109
110  public void testForMapWithDefault_null() {
111    ImmutableMap<String, Integer> map = ImmutableMap.of("One", 1);
112    Function<String, Integer> function = Functions.forMap(map, null);
113
114    assertEquals((Integer) 1, function.apply("One"));
115    assertNull(function.apply("Two"));
116
117    // check basic sanity of equals and hashCode
118    new EqualsTester()
119        .addEqualityGroup(function)
120        .addEqualityGroup(Functions.forMap(map, 1))
121        .testEquals();
122  }
123
124  public void testForMapWildCardWithDefault() {
125    Map<String, Integer> map = Maps.newHashMap();
126    map.put("One", 1);
127    map.put("Three", 3);
128    Number number = Double.valueOf(42);
129    Function<String, Number> function = Functions.forMap(map, number);
130
131    assertEquals(1, function.apply("One").intValue());
132    assertEquals(number, function.apply("Two"));
133    assertEquals(3L, function.apply("Three").longValue());
134  }
135
136  public void testComposition() {
137    Map<String, Integer> mJapaneseToInteger = Maps.newHashMap();
138    mJapaneseToInteger.put("Ichi", 1);
139    mJapaneseToInteger.put("Ni", 2);
140    mJapaneseToInteger.put("San", 3);
141    Function<String, Integer> japaneseToInteger =
142        Functions.forMap(mJapaneseToInteger);
143
144    Map<Integer, String> mIntegerToSpanish = Maps.newHashMap();
145    mIntegerToSpanish.put(1, "Uno");
146    mIntegerToSpanish.put(3, "Tres");
147    mIntegerToSpanish.put(4, "Cuatro");
148    Function<Integer, String> integerToSpanish =
149        Functions.forMap(mIntegerToSpanish);
150
151    Function<String, String> japaneseToSpanish =
152        Functions.compose(integerToSpanish, japaneseToInteger);
153
154    assertEquals("Uno", japaneseToSpanish.apply("Ichi"));
155    try {
156      japaneseToSpanish.apply("Ni");
157      fail();
158    } catch (IllegalArgumentException e) {
159    }
160    assertEquals("Tres", japaneseToSpanish.apply("San"));
161    try {
162      japaneseToSpanish.apply("Shi");
163      fail();
164    } catch (IllegalArgumentException e) {
165    }
166
167    new EqualsTester()
168        .addEqualityGroup(
169            japaneseToSpanish,
170            Functions.compose(integerToSpanish, japaneseToInteger))
171        .addEqualityGroup(japaneseToInteger)
172        .addEqualityGroup(integerToSpanish)
173        .addEqualityGroup(
174            Functions.compose(japaneseToInteger, integerToSpanish))
175        .testEquals();
176  }
177
178  public void testCompositionWildcard() {
179    Map<String, Integer> mapJapaneseToInteger = Maps.newHashMap();
180    Function<String, Integer> japaneseToInteger =
181        Functions.forMap(mapJapaneseToInteger);
182
183    Function<Object, String> numberToSpanish = Functions.constant("Yo no se");
184
185    Function<String, String> japaneseToSpanish =
186        Functions.compose(numberToSpanish, japaneseToInteger);
187  }
188
189  private static class HashCodeFunction implements Function<Object, Integer> {
190    @Override
191    public Integer apply(Object o) {
192      return (o == null) ? 0 : o.hashCode();
193    }
194  }
195
196  public void testComposeOfFunctionsIsAssociative() {
197    Map<Float, String> m = ImmutableMap.of(
198        4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D");
199    Function<? super Integer, Boolean> h = Functions.constant(Boolean.TRUE);
200    Function<? super String, Integer> g = new HashCodeFunction();
201    Function<Float, String> f = Functions.forMap(m, "F");
202
203    Function<Float, Boolean> c1 = Functions.compose(Functions.compose(h, g), f);
204    Function<Float, Boolean> c2 = Functions.compose(h, Functions.compose(g, f));
205
206    // Might be nice (eventually) to have:
207    //     assertEquals(c1, c2);
208
209    // But for now, settle for this:
210    assertEquals(c1.hashCode(), c2.hashCode());
211
212    assertEquals(c1.apply(1.0f), c2.apply(1.0f));
213    assertEquals(c1.apply(5.0f), c2.apply(5.0f));
214  }
215
216  public void testComposeOfPredicateAndFunctionIsAssociative() {
217    Map<Float, String> m = ImmutableMap.of(
218        4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D");
219    Predicate<? super Integer> h = Predicates.equalTo(42);
220    Function<? super String, Integer> g = new HashCodeFunction();
221    Function<Float, String> f = Functions.forMap(m, "F");
222
223    Predicate<Float> p1 = Predicates.compose(Predicates.compose(h, g), f);
224    Predicate<Float> p2 = Predicates.compose(h, Functions.compose(g, f));
225
226    // Might be nice (eventually) to have:
227    //     assertEquals(p1, p2);
228
229    // But for now, settle for this:
230    assertEquals(p1.hashCode(), p2.hashCode());
231
232    assertEquals(p1.apply(1.0f), p2.apply(1.0f));
233    assertEquals(p1.apply(5.0f), p2.apply(5.0f));
234  }
235
236  public void testForPredicate() {
237    Function<Object, Boolean> alwaysTrue =
238        Functions.forPredicate(Predicates.alwaysTrue());
239    Function<Object, Boolean> alwaysFalse =
240        Functions.forPredicate(Predicates.alwaysFalse());
241
242    assertTrue(alwaysTrue.apply(0));
243    assertFalse(alwaysFalse.apply(0));
244
245    new EqualsTester()
246        .addEqualityGroup(
247            alwaysTrue, Functions.forPredicate(Predicates.alwaysTrue()))
248        .addEqualityGroup(alwaysFalse)
249        .addEqualityGroup(Functions.identity())
250        .testEquals();
251  }
252
253  public void testConstant() {
254    Function<Object, Object> f = Functions.<Object>constant("correct");
255    assertEquals("correct", f.apply(new Object()));
256    assertEquals("correct", f.apply(null));
257
258    Function<Object, String> g = Functions.constant(null);
259    assertEquals(null, g.apply(2));
260    assertEquals(null, g.apply(null));
261
262    new EqualsTester()
263        .addEqualityGroup(f, Functions.constant("correct"))
264        .addEqualityGroup(Functions.constant("incorrect"))
265        .addEqualityGroup(Functions.toStringFunction())
266        .addEqualityGroup(g)
267        .testEquals();
268
269    new EqualsTester()
270        .addEqualityGroup(g, Functions.constant(null))
271        .addEqualityGroup(Functions.constant("incorrect"))
272        .addEqualityGroup(Functions.toStringFunction())
273        .addEqualityGroup(f)
274        .testEquals();
275  }
276
277  private static class CountingSupplier
278      implements Supplier<Integer>, Serializable {
279
280    private static final long serialVersionUID = 0;
281
282    private int value;
283
284    @Override
285    public Integer get() {
286      return ++value;
287    }
288
289    @Override
290    public boolean equals(Object obj) {
291      if (obj instanceof CountingSupplier) {
292        return this.value == ((CountingSupplier) obj).value;
293      }
294      return false;
295    }
296
297    @Override
298    public int hashCode() {
299      return value;
300    }
301  }
302
303  public void testForSupplier() {
304    Supplier<Integer> supplier = new CountingSupplier();
305    Function<Object, Integer> function = Functions.forSupplier(supplier);
306
307    assertEquals(1, (int) function.apply(null));
308    assertEquals(2, (int) function.apply("foo"));
309
310    new EqualsTester()
311        .addEqualityGroup(function, Functions.forSupplier(supplier))
312        .addEqualityGroup(Functions.forSupplier(new CountingSupplier()))
313        .addEqualityGroup(Functions.forSupplier(Suppliers.ofInstance(12)))
314        .addEqualityGroup(Functions.toStringFunction())
315        .testEquals();
316  }
317
318}
319
320