1/*
2 * Copyright (C) 2011 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 static org.truth0.Truth.ASSERT;
20
21import com.google.common.annotations.GwtCompatible;
22import com.google.common.annotations.GwtIncompatible;
23import com.google.common.collect.FluentIterable;
24import com.google.common.collect.ImmutableList;
25import com.google.common.testing.NullPointerTester;
26import com.google.common.testing.SerializableTester;
27
28import junit.framework.TestCase;
29
30import java.util.Collections;
31import java.util.List;
32import java.util.Set;
33
34/**
35 * Unit test for {@link Optional}.
36 *
37 * @author Kurt Alfred Kluever
38 */
39@GwtCompatible(emulated = true)
40public final class OptionalTest extends TestCase {
41  public void testAbsent() {
42    Optional<String> optionalName = Optional.absent();
43    assertFalse(optionalName.isPresent());
44  }
45
46  public void testOf() {
47    assertEquals("training", Optional.of("training").get());
48  }
49
50  public void testOf_null() {
51    try {
52      Optional.of(null);
53      fail();
54    } catch (NullPointerException expected) {
55    }
56  }
57
58  public void testFromNullable() {
59    Optional<String> optionalName = Optional.fromNullable("bob");
60    assertEquals("bob", optionalName.get());
61  }
62
63  public void testFromNullable_null() {
64    // not promised by spec, but easier to test
65    assertSame(Optional.absent(), Optional.fromNullable(null));
66  }
67
68  public void testIsPresent_no() {
69    assertFalse(Optional.absent().isPresent());
70  }
71
72  public void testIsPresent_yes() {
73    assertTrue(Optional.of("training").isPresent());
74  }
75
76  public void testGet_absent() {
77    Optional<String> optional = Optional.absent();
78    try {
79      optional.get();
80      fail();
81    } catch (IllegalStateException expected) {
82    }
83  }
84
85  public void testGet_present() {
86    assertEquals("training", Optional.of("training").get());
87  }
88
89  public void testOr_T_present() {
90    assertEquals("a", Optional.of("a").or("default"));
91  }
92
93  public void testOr_T_absent() {
94    assertEquals("default", Optional.absent().or("default"));
95  }
96
97  public void testOr_supplier_present() {
98    assertEquals("a", Optional.of("a").or(Suppliers.ofInstance("fallback")));
99  }
100
101  public void testOr_supplier_absent() {
102    assertEquals("fallback", Optional.absent().or(Suppliers.ofInstance("fallback")));
103  }
104
105  public void testOr_nullSupplier_absent() {
106    Supplier<Object> nullSupplier = Suppliers.ofInstance(null);
107    Optional<Object> absentOptional = Optional.absent();
108    try {
109      absentOptional.or(nullSupplier);
110      fail();
111    } catch (NullPointerException expected) {
112    }
113  }
114
115  public void testOr_nullSupplier_present() {
116    Supplier<String> nullSupplier = Suppliers.ofInstance(null);
117    assertEquals("a", Optional.of("a").or(nullSupplier));
118  }
119
120  public void testOr_Optional_present() {
121    assertEquals(Optional.of("a"), Optional.of("a").or(Optional.of("fallback")));
122  }
123
124  public void testOr_Optional_absent() {
125    assertEquals(Optional.of("fallback"), Optional.absent().or(Optional.of("fallback")));
126  }
127
128  public void testOrNull_present() {
129    assertEquals("a", Optional.of("a").orNull());
130  }
131
132  public void testOrNull_absent() {
133    assertNull(Optional.absent().orNull());
134  }
135
136  public void testAsSet_present() {
137    Set<String> expected = Collections.singleton("a");
138    assertEquals(expected, Optional.of("a").asSet());
139  }
140
141  public void testAsSet_absent() {
142    assertTrue("Returned set should be empty", Optional.absent().asSet().isEmpty());
143  }
144
145  public void testAsSet_presentIsImmutable() {
146    Set<String> presentAsSet = Optional.of("a").asSet();
147    try {
148      presentAsSet.add("b");
149      fail();
150    } catch (UnsupportedOperationException expected) {
151    }
152  }
153
154  public void testAsSet_absentIsImmutable() {
155    Set<Object> absentAsSet = Optional.absent().asSet();
156    try {
157      absentAsSet.add("foo");
158      fail();
159    } catch (UnsupportedOperationException expected) {
160    }
161  }
162
163  public void testTransform_absent() {
164    assertEquals(Optional.absent(), Optional.absent().transform(Functions.identity()));
165    assertEquals(Optional.absent(), Optional.absent().transform(Functions.toStringFunction()));
166  }
167
168  public void testTransform_presentIdentity() {
169    assertEquals(Optional.of("a"), Optional.of("a").transform(Functions.identity()));
170  }
171
172  public void testTransform_presentToString() {
173    assertEquals(Optional.of("42"), Optional.of(42).transform(Functions.toStringFunction()));
174  }
175
176  public void testTransform_present_functionReturnsNull() {
177    try {
178      Optional.of("a").transform(
179          new Function<String, String>() {
180            @Override public String apply(String input) {
181              return null;
182            }
183          });
184      fail("Should throw if Function returns null.");
185    } catch (NullPointerException expected) {
186    }
187  }
188
189  public void testTransform_abssent_functionReturnsNull() {
190    assertEquals(Optional.absent(),
191        Optional.absent().transform(
192          new Function<Object, Object>() {
193            @Override public Object apply(Object input) {
194              return null;
195            }
196          }));
197  }
198
199  // TODO(kevinb): use EqualsTester
200
201  public void testEqualsAndHashCode_absent() {
202    assertEquals(Optional.<String>absent(), Optional.<Integer>absent());
203    assertEquals(Optional.absent().hashCode(), Optional.absent().hashCode());
204  }
205
206  public void testEqualsAndHashCode_present() {
207    assertEquals(Optional.of("training"), Optional.of("training"));
208    assertFalse(Optional.of("a").equals(Optional.of("b")));
209    assertFalse(Optional.of("a").equals(Optional.absent()));
210    assertEquals(Optional.of("training").hashCode(), Optional.of("training").hashCode());
211  }
212
213  public void testToString_absent() {
214    assertEquals("Optional.absent()", Optional.absent().toString());
215  }
216
217  public void testToString_present() {
218    assertEquals("Optional.of(training)", Optional.of("training").toString());
219  }
220
221  public void testPresentInstances_allPresent() {
222    List<Optional<String>> optionals =
223        ImmutableList.of(Optional.of("a"), Optional.of("b"), Optional.of("c"));
224    ASSERT.that(Optional.presentInstances(optionals)).iteratesOverSequence("a", "b", "c");
225  }
226
227  public void testPresentInstances_allAbsent() {
228    List<Optional<Object>> optionals =
229        ImmutableList.of(Optional.absent(), Optional.absent());
230    ASSERT.that(Optional.presentInstances(optionals)).isEmpty();
231  }
232
233  public void testPresentInstances_somePresent() {
234    List<Optional<String>> optionals =
235        ImmutableList.of(Optional.of("a"), Optional.<String>absent(), Optional.of("c"));
236    ASSERT.that(Optional.presentInstances(optionals)).iteratesOverSequence("a", "c");
237  }
238
239  public void testPresentInstances_callingIteratorTwice() {
240    List<Optional<String>> optionals =
241        ImmutableList.of(Optional.of("a"), Optional.<String>absent(), Optional.of("c"));
242    Iterable<String> onlyPresent = Optional.presentInstances(optionals);
243    ASSERT.that(onlyPresent).iteratesOverSequence("a", "c");
244    ASSERT.that(onlyPresent).iteratesOverSequence("a", "c");
245  }
246
247  public void testPresentInstances_wildcards() {
248    List<Optional<? extends Number>> optionals =
249        ImmutableList.<Optional<? extends Number>>of(Optional.<Double>absent(), Optional.of(2));
250    Iterable<Number> onlyPresent = Optional.presentInstances(optionals);
251    ASSERT.that(onlyPresent).iteratesOverSequence(2);
252  }
253
254  private static Optional<Integer> getSomeOptionalInt() {
255    return Optional.of(1);
256  }
257
258  private static FluentIterable<? extends Number> getSomeNumbers() {
259    return FluentIterable.from(ImmutableList.<Number>of());
260  }
261
262  /*
263   * The following tests demonstrate the shortcomings of or() and test that the casting workaround
264   * mentioned in the method Javadoc does in fact compile.
265   */
266
267  @SuppressWarnings("unused") // compilation test
268  public void testSampleCodeError1() {
269    Optional<Integer> optionalInt = getSomeOptionalInt();
270    // Number value = optionalInt.or(0.5); // error
271  }
272
273  @SuppressWarnings("unused") // compilation test
274  public void testSampleCodeError2() {
275    FluentIterable<? extends Number> numbers = getSomeNumbers();
276    Optional<? extends Number> first = numbers.first();
277    // Number value = first.or(0.5); // error
278  }
279
280  @SuppressWarnings("unused") // compilation test
281  public void testSampleCodeFine1() {
282    Optional<Number> optionalInt = Optional.of((Number) 1);
283    Number value = optionalInt.or(0.5); // fine
284  }
285
286  @SuppressWarnings("unused") // compilation test
287  public void testSampleCodeFine2() {
288    FluentIterable<? extends Number> numbers = getSomeNumbers();
289
290    // Sadly, the following is what users will have to do in some circumstances.
291
292    @SuppressWarnings("unchecked") // safe covariant cast
293    Optional<Number> first = (Optional) numbers.first();
294    Number value = first.or(0.5); // fine
295  }
296
297  @GwtIncompatible("SerializableTester")
298  public void testSerialization() {
299    SerializableTester.reserializeAndAssert(Optional.absent());
300    SerializableTester.reserializeAndAssert(Optional.of("foo"));
301  }
302
303  @GwtIncompatible("NullPointerTester")
304  public void testNullPointers() {
305    NullPointerTester npTester = new NullPointerTester();
306    npTester.testAllPublicConstructors(Optional.class);
307    npTester.testAllPublicStaticMethods(Optional.class);
308    npTester.testAllPublicInstanceMethods(Optional.absent());
309    npTester.testAllPublicInstanceMethods(Optional.of("training"));
310  }
311}
312