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.annotations.GwtIncompatible;
21import com.google.common.collect.ImmutableMap;
22import com.google.common.collect.Maps;
23import com.google.common.testing.EqualsTester;
24import com.google.common.testing.NullPointerTester;
25import com.google.common.testing.SerializableTester;
26
27import junit.framework.TestCase;
28
29import java.io.Serializable;
30import java.util.Map;
31
32/**
33 * Tests for {@link Functions}.
34 *
35 * @author Mike Bostock
36 * @author Vlad Patryshev
37 */
38@GwtCompatible(emulated = true)
39public class FunctionsTest extends TestCase {
40
41  public void testIdentity_same() {
42    Function<String, String> identity = Functions.identity();
43    assertNull(identity.apply(null));
44    assertSame("foo", identity.apply("foo"));
45  }
46
47  public void testIdentity_notSame() {
48    Function<Long, Long> identity = Functions.identity();
49    assertNotSame(new Long(135135L), identity.apply(new Long(135135L)));
50  }
51
52  @GwtIncompatible("SerializableTester")
53  public void testIdentitySerializable() {
54    checkCanReserializeSingleton(Functions.identity());
55  }
56
57  public void testToStringFunction_apply() {
58    assertEquals("3", Functions.toStringFunction().apply(3));
59    assertEquals("hiya", Functions.toStringFunction().apply("hiya"));
60    assertEquals("I'm a string",
61        Functions.toStringFunction().apply(
62            new Object() {
63              @Override public String toString() {
64                return "I'm a string";
65              }
66            }));
67    try {
68      Functions.toStringFunction().apply(null);
69      fail("expected NullPointerException");
70    } catch (NullPointerException e) {
71      // expected
72    }
73  }
74
75  @GwtIncompatible("SerializableTester")
76  public void testToStringFunctionSerializable() {
77    checkCanReserializeSingleton(Functions.toStringFunction());
78  }
79
80  @GwtIncompatible("NullPointerTester")
81  public void testNullPointerExceptions() throws Exception {
82    NullPointerTester tester = new NullPointerTester();
83    tester.testAllPublicStaticMethods(Functions.class);
84  }
85
86  public void testForMapWithoutDefault() {
87    Map<String, Integer> map = Maps.newHashMap();
88    map.put("One", 1);
89    map.put("Three", 3);
90    map.put("Null", null);
91    Function<String, Integer> function = Functions.forMap(map);
92
93    assertEquals(1, function.apply("One").intValue());
94    assertEquals(3, function.apply("Three").intValue());
95    assertNull(function.apply("Null"));
96
97    try {
98      function.apply("Two");
99      fail();
100    } catch (IllegalArgumentException expected) {
101    }
102
103    new EqualsTester()
104        .addEqualityGroup(function, Functions.forMap(map))
105        .addEqualityGroup(Functions.forMap(map, 42))
106        .testEquals();
107  }
108
109  @GwtIncompatible("SerializableTester")
110  public void testForMapWithoutDefaultSerializable() {
111    checkCanReserialize(Functions.forMap(ImmutableMap.of(1, 2)));
112  }
113
114  public void testForMapWithDefault() {
115    Map<String, Integer> map = Maps.newHashMap();
116    map.put("One", 1);
117    map.put("Three", 3);
118    map.put("Null", null);
119    Function<String, Integer> function = Functions.forMap(map, 42);
120
121    assertEquals(1, function.apply("One").intValue());
122    assertEquals(42, function.apply("Two").intValue());
123    assertEquals(3, function.apply("Three").intValue());
124    assertNull(function.apply("Null"));
125
126    new EqualsTester()
127        .addEqualityGroup(function, Functions.forMap(map, 42))
128        .addEqualityGroup(Functions.forMap(map))
129        .addEqualityGroup(Functions.forMap(map, null))
130        .addEqualityGroup(Functions.forMap(map, 43))
131        .testEquals();
132  }
133
134  @GwtIncompatible("SerializableTester")
135  public void testForMapWithDefault_includeSerializable() {
136    Map<String, Integer> map = Maps.newHashMap();
137    map.put("One", 1);
138    map.put("Three", 3);
139    Function<String, Integer> function = Functions.forMap(map, 42);
140
141    assertEquals(1, function.apply("One").intValue());
142    assertEquals(42, function.apply("Two").intValue());
143    assertEquals(3, function.apply("Three").intValue());
144
145    new EqualsTester()
146        .addEqualityGroup(
147            function,
148            Functions.forMap(map, 42),
149            SerializableTester.reserialize(function))
150        .addEqualityGroup(Functions.forMap(map))
151        .addEqualityGroup(Functions.forMap(map, null))
152        .addEqualityGroup(Functions.forMap(map, 43))
153        .testEquals();
154  }
155
156  @GwtIncompatible("SerializableTester")
157  public void testForMapWithDefaultSerializable() {
158    checkCanReserialize(Functions.forMap(ImmutableMap.of(1, 2), 3));
159  }
160
161  public void testForMapWithDefault_null() {
162    ImmutableMap<String, Integer> map = ImmutableMap.of("One", 1);
163    Function<String, Integer> function = Functions.forMap(map, null);
164
165    assertEquals((Integer) 1, function.apply("One"));
166    assertNull(function.apply("Two"));
167
168    // check basic sanity of equals and hashCode
169    new EqualsTester()
170        .addEqualityGroup(function)
171        .addEqualityGroup(Functions.forMap(map, 1))
172        .testEquals();
173  }
174
175  @GwtIncompatible("SerializableTester")
176  public void testForMapWithDefault_null_compareWithSerializable() {
177    ImmutableMap<String, Integer> map = ImmutableMap.of("One", 1);
178    Function<String, Integer> function = Functions.forMap(map, null);
179
180    assertEquals((Integer) 1, function.apply("One"));
181    assertNull(function.apply("Two"));
182
183    // check basic sanity of equals and hashCode
184    new EqualsTester()
185        .addEqualityGroup(function, SerializableTester.reserialize(function))
186        .addEqualityGroup(Functions.forMap(map, 1))
187        .testEquals();
188  }
189
190  public void testForMapWildCardWithDefault() {
191    Map<String, Integer> map = Maps.newHashMap();
192    map.put("One", 1);
193    map.put("Three", 3);
194    Number number = Double.valueOf(42);
195    Function<String, Number> function = Functions.forMap(map, number);
196
197    assertEquals(1, function.apply("One").intValue());
198    assertEquals(number, function.apply("Two"));
199    assertEquals(3L, function.apply("Three").longValue());
200  }
201
202  public void testComposition() {
203    Map<String, Integer> mJapaneseToInteger = Maps.newHashMap();
204    mJapaneseToInteger.put("Ichi", 1);
205    mJapaneseToInteger.put("Ni", 2);
206    mJapaneseToInteger.put("San", 3);
207    Function<String, Integer> japaneseToInteger =
208        Functions.forMap(mJapaneseToInteger);
209
210    Map<Integer, String> mIntegerToSpanish = Maps.newHashMap();
211    mIntegerToSpanish.put(1, "Uno");
212    mIntegerToSpanish.put(3, "Tres");
213    mIntegerToSpanish.put(4, "Cuatro");
214    Function<Integer, String> integerToSpanish =
215        Functions.forMap(mIntegerToSpanish);
216
217    Function<String, String> japaneseToSpanish =
218        Functions.compose(integerToSpanish, japaneseToInteger);
219
220    assertEquals("Uno", japaneseToSpanish.apply("Ichi"));
221    try {
222      japaneseToSpanish.apply("Ni");
223      fail();
224    } catch (IllegalArgumentException e) {
225    }
226    assertEquals("Tres", japaneseToSpanish.apply("San"));
227    try {
228      japaneseToSpanish.apply("Shi");
229      fail();
230    } catch (IllegalArgumentException e) {
231    }
232
233    new EqualsTester()
234        .addEqualityGroup(
235            japaneseToSpanish,
236            Functions.compose(integerToSpanish, japaneseToInteger))
237        .addEqualityGroup(japaneseToInteger)
238        .addEqualityGroup(integerToSpanish)
239        .addEqualityGroup(
240            Functions.compose(japaneseToInteger, integerToSpanish))
241        .testEquals();
242  }
243
244  @GwtIncompatible("SerializableTester")
245  public void testComposition_includeReserializabled() {
246    Map<String, Integer> mJapaneseToInteger = Maps.newHashMap();
247    mJapaneseToInteger.put("Ichi", 1);
248    mJapaneseToInteger.put("Ni", 2);
249    mJapaneseToInteger.put("San", 3);
250    Function<String, Integer> japaneseToInteger =
251        Functions.forMap(mJapaneseToInteger);
252
253    Map<Integer, String> mIntegerToSpanish = Maps.newHashMap();
254    mIntegerToSpanish.put(1, "Uno");
255    mIntegerToSpanish.put(3, "Tres");
256    mIntegerToSpanish.put(4, "Cuatro");
257    Function<Integer, String> integerToSpanish =
258        Functions.forMap(mIntegerToSpanish);
259
260    Function<String, String> japaneseToSpanish =
261        Functions.compose(integerToSpanish, japaneseToInteger);
262
263    new EqualsTester()
264        .addEqualityGroup(
265            japaneseToSpanish,
266            Functions.compose(integerToSpanish, japaneseToInteger),
267            SerializableTester.reserialize(japaneseToSpanish))
268        .addEqualityGroup(japaneseToInteger)
269        .addEqualityGroup(integerToSpanish)
270        .addEqualityGroup(
271            Functions.compose(japaneseToInteger, integerToSpanish))
272        .testEquals();
273  }
274
275  public void testCompositionWildcard() {
276    Map<String, Integer> mapJapaneseToInteger = Maps.newHashMap();
277    Function<String, Integer> japaneseToInteger =
278        Functions.forMap(mapJapaneseToInteger);
279
280    Function<Object, String> numberToSpanish = Functions.constant("Yo no se");
281
282    Function<String, String> japaneseToSpanish =
283        Functions.compose(numberToSpanish, japaneseToInteger);
284  }
285
286  private static class HashCodeFunction implements Function<Object, Integer> {
287    @Override
288    public Integer apply(Object o) {
289      return (o == null) ? 0 : o.hashCode();
290    }
291  }
292
293  public void testComposeOfFunctionsIsAssociative() {
294    Map<Float, String> m = ImmutableMap.of(
295        4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D");
296    Function<? super Integer, Boolean> h = Functions.constant(Boolean.TRUE);
297    Function<? super String, Integer> g = new HashCodeFunction();
298    Function<Float, String> f = Functions.forMap(m, "F");
299
300    Function<Float, Boolean> c1 = Functions.compose(Functions.compose(h, g), f);
301    Function<Float, Boolean> c2 = Functions.compose(h, Functions.compose(g, f));
302
303    // Might be nice (eventually) to have:
304    //     assertEquals(c1, c2);
305
306    // But for now, settle for this:
307    assertEquals(c1.hashCode(), c2.hashCode());
308
309    assertEquals(c1.apply(1.0f), c2.apply(1.0f));
310    assertEquals(c1.apply(5.0f), c2.apply(5.0f));
311  }
312
313  public void testComposeOfPredicateAndFunctionIsAssociative() {
314    Map<Float, String> m = ImmutableMap.of(
315        4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D");
316    Predicate<? super Integer> h = Predicates.equalTo(42);
317    Function<? super String, Integer> g = new HashCodeFunction();
318    Function<Float, String> f = Functions.forMap(m, "F");
319
320    Predicate<Float> p1 = Predicates.compose(Predicates.compose(h, g), f);
321    Predicate<Float> p2 = Predicates.compose(h, Functions.compose(g, f));
322
323    // Might be nice (eventually) to have:
324    //     assertEquals(p1, p2);
325
326    // But for now, settle for this:
327    assertEquals(p1.hashCode(), p2.hashCode());
328
329    assertEquals(p1.apply(1.0f), p2.apply(1.0f));
330    assertEquals(p1.apply(5.0f), p2.apply(5.0f));
331  }
332
333  public void testForPredicate() {
334    Function<Object, Boolean> alwaysTrue =
335        Functions.forPredicate(Predicates.alwaysTrue());
336    Function<Object, Boolean> alwaysFalse =
337        Functions.forPredicate(Predicates.alwaysFalse());
338
339    assertTrue(alwaysTrue.apply(0));
340    assertFalse(alwaysFalse.apply(0));
341
342    new EqualsTester()
343        .addEqualityGroup(
344            alwaysTrue, Functions.forPredicate(Predicates.alwaysTrue()))
345        .addEqualityGroup(alwaysFalse)
346        .addEqualityGroup(Functions.identity())
347        .testEquals();
348  }
349
350  @GwtIncompatible("SerializableTester")
351  public void testForPredicateSerializable() {
352    checkCanReserialize(Functions.forPredicate(Predicates.equalTo(5)));
353  }
354
355  public void testConstant() {
356    Function<Object, Object> f = Functions.<Object>constant("correct");
357    assertEquals("correct", f.apply(new Object()));
358    assertEquals("correct", f.apply(null));
359
360    Function<Object, String> g = Functions.constant(null);
361    assertEquals(null, g.apply(2));
362    assertEquals(null, g.apply(null));
363
364    new EqualsTester()
365        .addEqualityGroup(f, Functions.constant("correct"))
366        .addEqualityGroup(Functions.constant("incorrect"))
367        .addEqualityGroup(Functions.toStringFunction())
368        .addEqualityGroup(g)
369        .testEquals();
370
371    new EqualsTester()
372        .addEqualityGroup(g, Functions.constant(null))
373        .addEqualityGroup(Functions.constant("incorrect"))
374        .addEqualityGroup(Functions.toStringFunction())
375        .addEqualityGroup(f)
376        .testEquals();
377  }
378
379  @GwtIncompatible("SerializableTester")
380  public void testConstantSerializable() {
381    checkCanReserialize(Functions.constant(5));
382  }
383
384  private static class CountingSupplier
385      implements Supplier<Integer>, Serializable {
386
387    private static final long serialVersionUID = 0;
388
389    private int value;
390
391    @Override
392    public Integer get() {
393      return ++value;
394    }
395
396    @Override
397    public boolean equals(Object obj) {
398      if (obj instanceof CountingSupplier) {
399        return this.value == ((CountingSupplier) obj).value;
400      }
401      return false;
402    }
403
404    @Override
405    public int hashCode() {
406      return value;
407    }
408  }
409
410  public void testForSupplier() {
411    Supplier<Integer> supplier = new CountingSupplier();
412    Function<Object, Integer> function = Functions.forSupplier(supplier);
413
414    assertEquals(1, (int) function.apply(null));
415    assertEquals(2, (int) function.apply("foo"));
416
417    new EqualsTester()
418        .addEqualityGroup(function, Functions.forSupplier(supplier))
419        .addEqualityGroup(Functions.forSupplier(new CountingSupplier()))
420        .addEqualityGroup(Functions.forSupplier(Suppliers.ofInstance(12)))
421        .addEqualityGroup(Functions.toStringFunction())
422        .testEquals();
423  }
424
425  @GwtIncompatible("SerializableTester")
426  public void testForSupplierSerializable() {
427    checkCanReserialize(Functions.forSupplier(new CountingSupplier()));
428  }
429
430  @GwtIncompatible("SerializableTester")
431  private <Y> void checkCanReserialize(Function<? super Integer, Y> f) {
432    Function<? super Integer, Y> g = SerializableTester.reserializeAndAssert(f);
433    for (int i = 1; i < 5; i++) {
434      // convoluted way to check that the same result happens from each
435      Y expected = null;
436      try {
437        expected = f.apply(i);
438      } catch (IllegalArgumentException e) {
439        try {
440          g.apply(i);
441          fail();
442        } catch (IllegalArgumentException ok) {
443          continue;
444        }
445      }
446      assertEquals(expected, g.apply(i));
447    }
448  }
449
450  @GwtIncompatible("SerializableTester")
451  private <Y> void checkCanReserializeSingleton(Function<? super String, Y> f) {
452    Function<? super String, Y> g = SerializableTester.reserializeAndAssert(f);
453    assertSame(f, g);
454    for (Integer i = 1; i < 5; i++) {
455      assertEquals(f.apply(i.toString()), g.apply(i.toString()));
456    }
457  }
458
459}
460