20 * or visit www.oracle.com if you need additional information or have any |
20 * or visit www.oracle.com if you need additional information or have any |
21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 |
23 |
24 /* @test |
24 /* @test |
25 * @bug 8195649 |
|
26 * @summary Basic functional test of Optional |
25 * @summary Basic functional test of Optional |
27 * @author Mike Duigou |
26 * @author Mike Duigou |
28 * @build ObscureException |
|
29 * @run testng Basic |
27 * @run testng Basic |
30 */ |
28 */ |
31 |
29 |
32 import java.util.List; |
30 import java.lang.AssertionError; |
|
31 import java.lang.NullPointerException; |
|
32 import java.lang.Throwable; |
33 import java.util.NoSuchElementException; |
33 import java.util.NoSuchElementException; |
34 import java.util.Optional; |
34 import java.util.Optional; |
35 import java.util.concurrent.atomic.AtomicBoolean; |
35 import java.util.concurrent.atomic.AtomicBoolean; |
36 import java.util.stream.Stream; |
36 import java.util.stream.Stream; |
37 |
37 |
38 import static java.util.stream.Collectors.toList; |
|
39 |
|
40 import static org.testng.Assert.*; |
38 import static org.testng.Assert.*; |
41 import org.testng.annotations.Test; |
39 import org.testng.annotations.Test; |
42 |
40 |
|
41 |
43 public class Basic { |
42 public class Basic { |
44 |
43 |
45 /** |
44 @Test(groups = "unit") |
46 * Checks a block of assertions over an empty Optional. |
45 public void testEmpty() { |
47 */ |
46 Optional<Boolean> empty = Optional.empty(); |
48 void checkEmpty(Optional<String> empty) { |
47 Optional<String> presentEmptyString = Optional.of(""); |
|
48 Optional<Boolean> present = Optional.of(Boolean.TRUE); |
|
49 |
|
50 // empty |
|
51 assertTrue(empty.equals(empty)); |
49 assertTrue(empty.equals(Optional.empty())); |
52 assertTrue(empty.equals(Optional.empty())); |
50 assertTrue(Optional.empty().equals(empty)); |
53 assertTrue(!empty.equals(present)); |
51 assertFalse(empty.equals(Optional.of("unexpected"))); |
54 assertTrue(0 == empty.hashCode()); |
52 assertFalse(Optional.of("unexpected").equals(empty)); |
55 assertTrue(!empty.toString().isEmpty()); |
53 assertFalse(empty.equals("unexpected")); |
56 assertTrue(!empty.toString().equals(presentEmptyString.toString())); |
54 |
57 assertTrue(!empty.isPresent()); |
55 assertFalse(empty.isPresent()); |
58 |
56 assertEquals(empty.hashCode(), 0); |
59 empty.ifPresent(v -> fail()); |
57 assertEquals(empty.orElse("x"), "x"); |
60 |
58 assertEquals(empty.orElseGet(() -> "y"), "y"); |
61 AtomicBoolean emptyCheck = new AtomicBoolean(); |
59 |
62 empty.ifPresentOrElse(v -> fail(), () -> emptyCheck.set(true)); |
60 assertThrows(NoSuchElementException.class, () -> empty.get()); |
63 assertTrue(emptyCheck.get()); |
61 assertThrows(NoSuchElementException.class, () -> empty.orElseThrow()); |
64 |
62 assertThrows(ObscureException.class, () -> empty.orElseThrow(ObscureException::new)); |
65 try { |
63 |
66 empty.ifPresentOrElse(v -> fail(), () -> { throw new ObscureException(); }); |
64 var b = new AtomicBoolean(); |
67 fail(); |
65 empty.ifPresent(s -> b.set(true)); |
68 } catch (ObscureException expected) { |
66 assertFalse(b.get()); |
69 } catch (AssertionError e) { |
67 |
70 throw e; |
68 var b1 = new AtomicBoolean(false); |
71 } catch (Throwable t) { |
69 var b2 = new AtomicBoolean(false); |
72 fail(); |
70 empty.ifPresentOrElse(s -> b1.set(true), () -> b2.set(true)); |
73 } |
71 assertFalse(b1.get()); |
74 |
72 assertTrue(b2.get()); |
75 assertSame(null, empty.orElse(null)); |
73 |
76 RuntimeException orElse = new RuntimeException() { }; |
74 assertEquals(empty.toString(), "Optional.empty"); |
77 assertSame(Boolean.FALSE, empty.orElse(Boolean.FALSE)); |
75 } |
78 assertSame(null, empty.orElseGet(() -> null)); |
76 |
79 assertSame(Boolean.FALSE, empty.orElseGet(() -> Boolean.FALSE)); |
77 /** |
80 } |
78 * Checks a block of assertions over an Optional that is expected to |
81 |
79 * have a particular value present. |
82 @Test(groups = "unit") |
80 */ |
83 public void testIfPresentAndOrElseAndNull() { |
81 void checkPresent(Optional<String> opt, String expected) { |
84 Optional<Boolean> empty = Optional.empty(); |
82 assertFalse(opt.equals(Optional.empty())); |
85 Optional<Boolean> present = Optional.of(Boolean.TRUE); |
83 assertFalse(Optional.empty().equals(opt)); |
86 |
84 assertTrue(opt.equals(Optional.of(expected))); |
87 // No NPE |
85 assertTrue(Optional.of(expected).equals(opt)); |
88 present.ifPresentOrElse(v -> {}, null); |
86 assertFalse(opt.equals(Optional.of("unexpected"))); |
89 empty.ifPresent(null); |
87 assertFalse(Optional.of("unexpected").equals(opt)); |
90 empty.ifPresentOrElse(null, () -> {}); |
88 assertFalse(opt.equals("unexpected")); |
91 |
89 |
92 // NPE |
90 assertTrue(opt.isPresent()); |
93 try { |
91 assertEquals(opt.hashCode(), expected.hashCode()); |
94 present.ifPresent(null); |
92 assertEquals(opt.orElse("unexpected"), expected); |
95 fail(); |
93 assertEquals(opt.orElseGet(() -> "unexpected"), expected); |
96 } catch (NullPointerException ex) {} |
94 |
97 try { |
95 assertEquals(opt.get(), expected); |
98 present.ifPresentOrElse(null, () -> {}); |
96 assertEquals(opt.orElseThrow(), expected); |
99 fail(); |
97 assertEquals(opt.orElseThrow(ObscureException::new), expected); |
100 } catch (NullPointerException ex) {} |
98 |
101 try { |
99 var b = new AtomicBoolean(false); |
102 empty.ifPresentOrElse(v -> {}, null); |
100 opt.ifPresent(s -> b.set(true)); |
103 fail(); |
101 assertTrue(b.get()); |
104 } catch (NullPointerException ex) {} |
102 |
105 } |
103 var b1 = new AtomicBoolean(false); |
106 |
104 var b2 = new AtomicBoolean(false); |
107 @Test(expectedExceptions=NoSuchElementException.class) |
105 opt.ifPresentOrElse(s -> b1.set(true), () -> b2.set(true)); |
108 public void testEmptyGet() { |
106 assertTrue(b1.get()); |
109 Optional<Boolean> empty = Optional.empty(); |
107 assertFalse(b2.get()); |
110 |
108 |
111 Boolean got = empty.get(); |
109 assertEquals(opt.toString(), "Optional[" + expected + "]"); |
112 } |
110 } |
113 |
111 |
114 @Test(expectedExceptions=NullPointerException.class) |
112 @Test(groups = "unit") |
115 public void testEmptyOrElseGetNull() { |
113 public void testEmpty() { |
116 Optional<Boolean> empty = Optional.empty(); |
114 checkEmpty(Optional.empty()); |
117 |
115 } |
118 Boolean got = empty.orElseGet(null); |
116 |
119 } |
117 @Test(groups = "unit") |
120 |
118 public void testOfNull() { |
121 @Test(expectedExceptions=NullPointerException.class) |
119 assertThrows(NullPointerException.class, () -> Optional.of(null)); |
122 public void testEmptyOrElseThrowNull() throws Throwable { |
120 } |
123 Optional<Boolean> empty = Optional.empty(); |
121 |
124 |
122 @Test(groups = "unit") |
125 Boolean got = empty.orElseThrow(null); |
123 public void testOfPresent() { |
126 } |
124 checkPresent(Optional.of("xyzzy"), "xyzzy"); |
127 |
125 } |
128 @Test(expectedExceptions=ObscureException.class) |
126 |
129 public void testEmptyOrElseThrow() throws Exception { |
127 @Test(groups = "unit") |
130 Optional<Boolean> empty = Optional.empty(); |
128 public void testOfNullableNull() { |
131 |
129 checkEmpty(Optional.ofNullable(null)); |
132 Boolean got = empty.orElseThrow(ObscureException::new); |
130 } |
133 } |
131 |
134 |
132 @Test(groups = "unit") |
135 @Test(expectedExceptions=NoSuchElementException.class) |
133 public void testOfNullablePresent() { |
136 public void testEmptyOrElseThrowNoArg() throws Exception { |
134 checkPresent(Optional.of("xyzzy"), "xyzzy"); |
137 Optional<Boolean> empty = Optional.empty(); |
135 } |
138 |
136 |
139 Boolean got = empty.orElseThrow(); |
137 @Test(groups = "unit") |
140 } |
138 public void testFilterEmpty() { |
141 |
139 checkEmpty(Optional.<String>empty().filter(s -> { fail(); return true; })); |
142 @Test(groups = "unit") |
140 } |
143 public void testPresent() { |
141 |
144 Optional<Boolean> empty = Optional.empty(); |
142 @Test(groups = "unit") |
145 Optional<String> presentEmptyString = Optional.of(""); |
143 public void testFilterFalse() { |
146 Optional<Boolean> present = Optional.of(Boolean.TRUE); |
144 checkEmpty(Optional.of("xyzzy").filter(s -> s.equals("plugh"))); |
147 |
145 } |
148 // present |
146 |
149 assertTrue(present.equals(present)); |
147 @Test(groups = "unit") |
150 assertTrue(present.equals(Optional.of(Boolean.TRUE))); |
148 public void testFilterTrue() { |
151 assertTrue(!present.equals(empty)); |
149 checkPresent(Optional.of("xyzzy").filter(s -> s.equals("xyzzy")), "xyzzy"); |
152 assertTrue(Boolean.TRUE.hashCode() == present.hashCode()); |
150 } |
153 assertTrue(!present.toString().isEmpty()); |
151 |
154 assertTrue(!present.toString().equals(presentEmptyString.toString())); |
152 @Test(groups = "unit") |
155 assertTrue(-1 != present.toString().indexOf(Boolean.TRUE.toString())); |
153 public void testMapEmpty() { |
156 assertSame(Boolean.TRUE, present.get()); |
154 checkEmpty(Optional.empty().map(s -> { fail(); return ""; })); |
157 assertSame(Boolean.TRUE, present.orElseThrow()); |
155 } |
158 |
156 |
159 AtomicBoolean presentCheck = new AtomicBoolean(); |
157 @Test(groups = "unit") |
160 present.ifPresent(v -> presentCheck.set(true)); |
158 public void testMapPresent() { |
161 assertTrue(presentCheck.get()); |
159 checkPresent(Optional.of("xyzzy").map(s -> s.replace("xyzzy", "plugh")), "plugh"); |
162 presentCheck.set(false); |
160 } |
163 present.ifPresentOrElse(v -> presentCheck.set(true), () -> fail()); |
161 |
164 assertTrue(presentCheck.get()); |
162 @Test(groups = "unit") |
165 |
163 public void testFlatMapEmpty() { |
166 try { |
164 checkEmpty(Optional.empty().flatMap(s -> { fail(); return Optional.of(""); })); |
167 present.ifPresent(v -> { throw new ObscureException(); }); |
165 } |
168 fail(); |
166 |
169 } catch (ObscureException expected) { |
167 @Test(groups = "unit") |
170 } catch (AssertionError e) { |
168 public void testFlatMapPresentReturnEmpty() { |
171 throw e; |
169 checkEmpty(Optional.of("xyzzy") |
172 } catch (Throwable t) { |
170 .flatMap(s -> { assertEquals(s, "xyzzy"); return Optional.empty(); })); |
173 fail(); |
171 } |
174 } |
172 |
175 try { |
173 @Test(groups = "unit") |
176 present.ifPresentOrElse(v -> { throw new ObscureException(); }, () -> fail()); |
174 public void testFlatMapPresentReturnPresent() { |
177 fail(); |
175 checkPresent(Optional.of("xyzzy") |
178 } catch (ObscureException expected) { |
176 .flatMap(s -> { assertEquals(s, "xyzzy"); return Optional.of("plugh"); }), |
179 } catch (AssertionError e) { |
177 "plugh"); |
180 throw e; |
178 } |
181 } catch (Throwable t) { |
179 |
182 fail(); |
180 @Test(groups = "unit") |
183 } |
181 public void testOrEmptyEmpty() { |
184 |
182 checkEmpty(Optional.<String>empty().or(() -> Optional.empty())); |
185 assertSame(Boolean.TRUE, present.orElse(null)); |
183 } |
186 assertSame(Boolean.TRUE, present.orElse(Boolean.FALSE)); |
184 |
187 assertSame(Boolean.TRUE, present.orElseGet(null)); |
185 @Test(groups = "unit") |
188 assertSame(Boolean.TRUE, present.orElseGet(() -> null)); |
186 public void testOrEmptyPresent() { |
189 assertSame(Boolean.TRUE, present.orElseGet(() -> Boolean.FALSE)); |
187 checkPresent(Optional.<String>empty().or(() -> Optional.of("plugh")), "plugh"); |
190 assertSame(Boolean.TRUE, present.<RuntimeException>orElseThrow(null)); |
188 } |
191 assertSame(Boolean.TRUE, present.<RuntimeException>orElseThrow(ObscureException::new)); |
189 |
192 } |
190 @Test(groups = "unit") |
193 |
191 public void testOrPresentDontCare() { |
194 @Test(groups = "unit") |
192 checkPresent(Optional.of("xyzzy").or(() -> { fail(); return Optional.of("plugh"); }), "xyzzy"); |
195 public void testOfNullable() { |
193 } |
196 Optional<String> instance = Optional.ofNullable(null); |
194 |
197 assertFalse(instance.isPresent()); |
195 @Test(groups = "unit") |
198 |
196 public void testStreamEmpty() { |
199 instance = Optional.ofNullable("Duke"); |
197 assertEquals(Optional.empty().stream().collect(toList()), List.of()); |
200 assertTrue(instance.isPresent()); |
198 } |
201 assertEquals(instance.get(), "Duke"); |
199 |
202 assertEquals(instance.orElseThrow(), "Duke"); |
200 @Test(groups = "unit") |
203 } |
201 public void testStreamPresent() { |
204 |
202 assertEquals(Optional.of("xyzzy").stream().collect(toList()), List.of("xyzzy")); |
205 @Test(groups = "unit") |
|
206 public void testFilter() { |
|
207 // Null mapper function |
|
208 Optional<String> empty = Optional.empty(); |
|
209 Optional<String> duke = Optional.of("Duke"); |
|
210 |
|
211 try { |
|
212 Optional<String> result = empty.filter(null); |
|
213 fail("Should throw NPE on null mapping function"); |
|
214 } catch (NullPointerException npe) { |
|
215 // expected |
|
216 } |
|
217 |
|
218 Optional<String> result = empty.filter(String::isEmpty); |
|
219 assertFalse(result.isPresent()); |
|
220 |
|
221 result = duke.filter(String::isEmpty); |
|
222 assertFalse(result.isPresent()); |
|
223 result = duke.filter(s -> s.startsWith("D")); |
|
224 assertTrue(result.isPresent()); |
|
225 assertEquals(result.get(), "Duke"); |
|
226 assertEquals(result.orElseThrow(), "Duke"); |
|
227 |
|
228 Optional<String> emptyString = Optional.of(""); |
|
229 result = emptyString.filter(String::isEmpty); |
|
230 assertTrue(result.isPresent()); |
|
231 assertEquals(result.get(), ""); |
|
232 assertEquals(result.orElseThrow(), ""); |
|
233 } |
|
234 |
|
235 @Test(groups = "unit") |
|
236 public void testMap() { |
|
237 Optional<String> empty = Optional.empty(); |
|
238 Optional<String> duke = Optional.of("Duke"); |
|
239 |
|
240 // Null mapper function |
|
241 try { |
|
242 Optional<Boolean> b = empty.map(null); |
|
243 fail("Should throw NPE on null mapping function"); |
|
244 } catch (NullPointerException npe) { |
|
245 // expected |
|
246 } |
|
247 |
|
248 // Map an empty value |
|
249 Optional<Boolean> b = empty.map(String::isEmpty); |
|
250 assertFalse(b.isPresent()); |
|
251 |
|
252 // Map into null |
|
253 b = empty.map(n -> null); |
|
254 assertFalse(b.isPresent()); |
|
255 b = duke.map(s -> null); |
|
256 assertFalse(b.isPresent()); |
|
257 |
|
258 // Map to value |
|
259 Optional<Integer> l = duke.map(String::length); |
|
260 assertEquals(l.get().intValue(), 4); |
|
261 } |
|
262 |
|
263 @Test(groups = "unit") |
|
264 public void testFlatMap() { |
|
265 Optional<String> empty = Optional.empty(); |
|
266 Optional<String> duke = Optional.of("Duke"); |
|
267 |
|
268 // Null mapper function |
|
269 try { |
|
270 Optional<Boolean> b = empty.flatMap(null); |
|
271 fail("Should throw NPE on null mapping function"); |
|
272 } catch (NullPointerException npe) { |
|
273 // expected |
|
274 } |
|
275 |
|
276 // Map into null |
|
277 try { |
|
278 Optional<Boolean> b = duke.flatMap(s -> null); |
|
279 fail("Should throw NPE when mapper return null"); |
|
280 } catch (NullPointerException npe) { |
|
281 // expected |
|
282 } |
|
283 |
|
284 // Empty won't invoke mapper function |
|
285 try { |
|
286 Optional<Boolean> b = empty.flatMap(s -> null); |
|
287 assertFalse(b.isPresent()); |
|
288 } catch (NullPointerException npe) { |
|
289 fail("Mapper function should not be invoked"); |
|
290 } |
|
291 |
|
292 // Map an empty value |
|
293 Optional<Integer> l = empty.flatMap(s -> Optional.of(s.length())); |
|
294 assertFalse(l.isPresent()); |
|
295 |
|
296 // Map to value |
|
297 Optional<Integer> fixture = Optional.of(Integer.MAX_VALUE); |
|
298 l = duke.flatMap(s -> Optional.of(s.length())); |
|
299 assertTrue(l.isPresent()); |
|
300 assertEquals(l.get().intValue(), 4); |
|
301 assertEquals(l.orElseThrow().intValue(), 4); |
|
302 |
|
303 // Verify same instance |
|
304 l = duke.flatMap(s -> fixture); |
|
305 assertSame(l, fixture); |
|
306 } |
|
307 |
|
308 @Test(groups = "unit") |
|
309 public void testOr() { |
|
310 Optional<String> empty = Optional.empty(); |
|
311 Optional<String> duke = Optional.of("Duke"); |
|
312 |
|
313 // Null supplier |
|
314 try { |
|
315 Optional<String> b = empty.or(null); |
|
316 fail("Should throw NPE on null supplier"); |
|
317 } catch (NullPointerException npe) { |
|
318 // expected |
|
319 } |
|
320 |
|
321 // Supply null |
|
322 try { |
|
323 Optional<String> b = empty.or(() -> null); |
|
324 fail("Should throw NPE when supplier returns null"); |
|
325 } catch (NullPointerException npe) { |
|
326 // expected |
|
327 } |
|
328 |
|
329 // Non-empty won't invoke supplier |
|
330 try { |
|
331 Optional<String> b = duke.or(() -> null); |
|
332 assertTrue(b.isPresent()); |
|
333 } catch (NullPointerException npe) { |
|
334 fail("Supplier should not be invoked"); |
|
335 } |
|
336 |
|
337 // Supply for empty |
|
338 Optional<String> suppliedDuke = empty.or(() -> duke); |
|
339 assertTrue(suppliedDuke.isPresent()); |
|
340 assertSame(suppliedDuke, duke); |
|
341 |
|
342 // Supply for non-empty |
|
343 Optional<String> actualDuke = duke.or(() -> Optional.of("Other Duke")); |
|
344 assertTrue(actualDuke.isPresent()); |
|
345 assertSame(actualDuke, duke); |
|
346 } |
|
347 |
|
348 @Test(groups = "unit") |
|
349 public void testStream() { |
|
350 { |
|
351 Stream<String> s = Optional.<String>empty().stream(); |
|
352 assertFalse(s.isParallel()); |
|
353 |
|
354 Object[] es = s.toArray(); |
|
355 assertEquals(es.length, 0); |
|
356 } |
|
357 |
|
358 { |
|
359 Stream<String> s = Optional.of("Duke").stream(); |
|
360 assertFalse(s.isParallel()); |
|
361 |
|
362 String[] es = s.toArray(String[]::new); |
|
363 assertEquals(es.length, 1); |
|
364 assertEquals(es[0], "Duke"); |
|
365 } |
|
366 } |
|
367 |
|
368 private static class ObscureException extends RuntimeException { |
|
369 |
203 } |
370 } |
204 } |
371 } |