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