31 import java.lang.ScopedValue.CallableOp;
32 import java.util.NoSuchElementException;
33 import java.util.concurrent.ExecutionException;
34 import java.util.concurrent.Executors;
35 import java.util.concurrent.ThreadFactory;
36 import java.util.function.Supplier;
37 import java.util.stream.Stream;
38
39 import org.junit.jupiter.api.Test;
40 import org.junit.jupiter.params.ParameterizedTest;
41 import org.junit.jupiter.params.provider.MethodSource;
42 import static org.junit.jupiter.api.Assertions.*;
43
44 class ScopedValueAPI {
45
46 private static Stream<ThreadFactory> factories() {
47 return Stream.of(Thread.ofPlatform().factory(), Thread.ofVirtual().factory());
48 }
49
50 /**
51 * Test that runWhere invokes the Runnable's run method.
52 */
53 @ParameterizedTest
54 @MethodSource("factories")
55 void testRunWhere(ThreadFactory factory) throws Exception {
56 test(factory, () -> {
57 class Box { static boolean executed; }
58 ScopedValue<String> name = ScopedValue.newInstance();
59 ScopedValue.runWhere(name, "duke", () -> { Box.executed = true; });
60 assertTrue(Box.executed);
61 });
62 }
63
64 /**
65 * Test runWhere when the run method throws an exception.
66 */
67 @ParameterizedTest
68 @MethodSource("factories")
69 void testRunWhereThrows(ThreadFactory factory) throws Exception {
70 test(factory, () -> {
71 class FooException extends RuntimeException { }
72 ScopedValue<String> name = ScopedValue.newInstance();
73 Runnable op = () -> { throw new FooException(); };
74 assertThrows(FooException.class, () -> ScopedValue.runWhere(name, "duke", op));
75 assertFalse(name.isBound());
76 });
77 }
78
79 /**
80 * Test that callWhere invokes the CallableOp's call method.
81 */
82 @ParameterizedTest
83 @MethodSource("factories")
84 void testCallWhere(ThreadFactory factory) throws Exception {
85 test(factory, () -> {
86 ScopedValue<String> name = ScopedValue.newInstance();
87 String result = ScopedValue.callWhere(name, "duke", name::get);
88 assertEquals("duke", result);
89 });
90 }
91
92 /**
93 * Test callWhere when the call method throws an exception.
94 */
95 @ParameterizedTest
96 @MethodSource("factories")
97 void testCallWhereThrows(ThreadFactory factory) throws Exception {
98 test(factory, () -> {
99 class FooException extends RuntimeException { }
100 ScopedValue<String> name = ScopedValue.newInstance();
101 CallableOp<Void, RuntimeException> op = () -> { throw new FooException(); };
102 assertThrows(FooException.class, () -> ScopedValue.callWhere(name, "duke", op));
103 assertFalse(name.isBound());
104 });
105 }
106
107 /**
108 * Test get method.
109 */
110 @ParameterizedTest
111 @MethodSource("factories")
112 void testGet(ThreadFactory factory) throws Exception {
113 test(factory, () -> {
114 ScopedValue<String> name1 = ScopedValue.newInstance();
115 ScopedValue<String> name2 = ScopedValue.newInstance();
116 assertThrows(NoSuchElementException.class, name1::get);
117 assertThrows(NoSuchElementException.class, name2::get);
118
119 // runWhere
120 ScopedValue.runWhere(name1, "duke", () -> {
121 assertEquals("duke", name1.get());
122 assertThrows(NoSuchElementException.class, name2::get);
123
124 });
125 assertThrows(NoSuchElementException.class, name1::get);
126 assertThrows(NoSuchElementException.class, name2::get);
127
128 // callWhere
129 ScopedValue.callWhere(name1, "duke", () -> {
130 assertEquals("duke", name1.get());
131 assertThrows(NoSuchElementException.class, name2::get);
132 return null;
133 });
134 assertThrows(NoSuchElementException.class, name1::get);
135 assertThrows(NoSuchElementException.class, name2::get);
136 });
137 }
138
139 /**
140 * Test isBound method.
141 */
142 @ParameterizedTest
143 @MethodSource("factories")
144 void testIsBound(ThreadFactory factory) throws Exception {
145 test(factory, () -> {
146 ScopedValue<String> name1 = ScopedValue.newInstance();
147 ScopedValue<String> name2 = ScopedValue.newInstance();
148 assertFalse(name1.isBound());
149 assertFalse(name2.isBound());
150
151 // runWhere
152 ScopedValue.runWhere(name1, "duke", () -> {
153 assertTrue(name1.isBound());
154 assertFalse(name2.isBound());
155 });
156 assertFalse(name1.isBound());
157 assertFalse(name2.isBound());
158
159 // callWhere
160 ScopedValue.callWhere(name1, "duke", () -> {
161 assertTrue(name1.isBound());
162 assertFalse(name2.isBound());
163 return null;
164 });
165 assertFalse(name1.isBound());
166 assertFalse(name2.isBound());
167 });
168 }
169
170 /**
171 * Test orElse method.
172 */
173 @ParameterizedTest
174 @MethodSource("factories")
175 void testOrElse(ThreadFactory factory) throws Exception {
176 test(factory, () -> {
177 ScopedValue<String> name = ScopedValue.newInstance();
178 assertNull(name.orElse(null));
179 assertEquals("default", name.orElse("default"));
180
181 // runWhere
182 ScopedValue.runWhere(name, "duke", () -> {
183 assertEquals("duke", name.orElse(null));
184 assertEquals("duke", name.orElse("default"));
185 });
186
187 // callWhere
188 ScopedValue.callWhere(name, "duke", () -> {
189 assertEquals("duke", name.orElse(null));
190 assertEquals("duke", name.orElse("default"));
191 return null;
192 });
193 });
194 }
195
196 /**
197 * Test orElseThrow method.
198 */
199 @ParameterizedTest
200 @MethodSource("factories")
201 void testOrElseThrow(ThreadFactory factory) throws Exception {
202 test(factory, () -> {
203 class FooException extends RuntimeException { }
204 ScopedValue<String> name = ScopedValue.newInstance();
205 assertThrows(FooException.class, () -> name.orElseThrow(FooException::new));
206
207 // runWhere
208 ScopedValue.runWhere(name, "duke", () -> {
209 assertEquals("duke", name.orElseThrow(FooException::new));
210 });
211
212 // callWhere
213 ScopedValue.callWhere(name, "duke", () -> {
214 assertEquals("duke", name.orElseThrow(FooException::new));
215 return null;
216 });
217 });
218 }
219
220 /**
221 * Test two bindings.
222 */
223 @ParameterizedTest
224 @MethodSource("factories")
225 void testTwoBindings(ThreadFactory factory) throws Exception {
226 test(factory, () -> {
227 ScopedValue<String> name = ScopedValue.newInstance();
228 ScopedValue<Integer> age = ScopedValue.newInstance();
229
230 // Carrier.run
231 ScopedValue.where(name, "duke").where(age, 100).run(() -> {
232 assertTrue(name.isBound());
233 assertTrue(age.isBound());
242 assertTrue(name.isBound());
243 assertTrue(age.isBound());
244 assertEquals("duke", name.get());
245 assertEquals(100, (int) age.get());
246 return null;
247 });
248 assertFalse(name.isBound());
249 assertFalse(age.isBound());
250 });
251 }
252
253 /**
254 * Test rebinding.
255 */
256 @ParameterizedTest
257 @MethodSource("factories")
258 void testRebinding(ThreadFactory factory) throws Exception {
259 test(factory, () -> {
260 ScopedValue<String> name = ScopedValue.newInstance();
261
262 // runWhere
263 ScopedValue.runWhere(name, "duke", () -> {
264 assertTrue(name.isBound());
265 assertEquals("duke", name.get());
266
267 ScopedValue.runWhere(name, "duchess", () -> {
268 assertTrue(name.isBound());
269 assertEquals("duchess", name.get());
270 });
271
272 assertTrue(name.isBound());
273 assertEquals("duke", name.get());
274 });
275 assertFalse(name.isBound());
276
277 // callWhere
278 ScopedValue.callWhere(name, "duke", () -> {
279 assertTrue(name.isBound());
280 assertEquals("duke", name.get());
281
282 ScopedValue.callWhere(name, "duchess", () -> {
283 assertTrue(name.isBound());
284 assertEquals("duchess", name.get());
285 return null;
286 });
287
288 assertTrue(name.isBound());
289 assertEquals("duke", name.get());
290 return null;
291 });
292 assertFalse(name.isBound());
293 });
294 }
295
296 /**
297 * Test rebinding from null vaue to another value.
298 */
299 @ParameterizedTest
300 @MethodSource("factories")
301 void testRebindingFromNull(ThreadFactory factory) throws Exception {
302 test(factory, () -> {
303 ScopedValue<String> name = ScopedValue.newInstance();
304
305 // runWhere
306 ScopedValue.runWhere(name, null, () -> {
307 assertTrue(name.isBound());
308 assertNull(name.get());
309
310 ScopedValue.runWhere(name, "duchess", () -> {
311 assertTrue(name.isBound());
312 assertTrue("duchess".equals(name.get()));
313 });
314
315 assertTrue(name.isBound());
316 assertNull(name.get());
317 });
318 assertFalse(name.isBound());
319
320 // callWhere
321 ScopedValue.callWhere(name, null, () -> {
322 assertTrue(name.isBound());
323 assertNull(name.get());
324
325 ScopedValue.callWhere(name, "duchess", () -> {
326 assertTrue(name.isBound());
327 assertTrue("duchess".equals(name.get()));
328 return null;
329 });
330
331 assertTrue(name.isBound());
332 assertNull(name.get());
333 return null;
334 });
335 assertFalse(name.isBound());
336 });
337 }
338
339 /**
340 * Test rebinding to null value.
341 */
342 @ParameterizedTest
343 @MethodSource("factories")
344 void testRebindingToNull(ThreadFactory factory) throws Exception {
345 test(factory, () -> {
346 ScopedValue<String> name = ScopedValue.newInstance();
347
348 // runWhere
349 ScopedValue.runWhere(name, "duke", () -> {
350 assertTrue(name.isBound());
351 assertEquals("duke", name.get());
352
353 ScopedValue.runWhere(name, null, () -> {
354 assertTrue(name.isBound());
355 assertNull(name.get());
356 });
357
358 assertTrue(name.isBound());
359 assertEquals("duke", name.get());
360 });
361 assertFalse(name.isBound());
362
363 // callWhere
364 ScopedValue.callWhere(name, "duke", () -> {
365 assertTrue(name.isBound());
366 assertEquals("duke", name.get());
367
368 ScopedValue.callWhere(name, null, () -> {
369 assertTrue(name.isBound());
370 assertNull(name.get());
371 return null;
372 });
373
374 assertTrue(name.isBound());
375 assertEquals("duke", name.get());
376 return null;
377 });
378 assertFalse(name.isBound());
379 });
380 }
381
382 /**
383 * Test Carrier.get.
384 */
385 @ParameterizedTest
386 @MethodSource("factories")
387 void testCarrierGet(ThreadFactory factory) throws Exception {
388 test(factory, () -> {
393 var carrier1 = ScopedValue.where(name, "duke");
394 assertEquals("duke", carrier1.get(name));
395 assertThrows(NoSuchElementException.class, () -> carrier1.get(age));
396
397 // two scoped values
398 var carrier2 = carrier1.where(age, 20);
399 assertEquals("duke", carrier2.get(name));
400 assertEquals(20, (int) carrier2.get(age));
401 });
402 }
403
404 /**
405 * Test NullPointerException.
406 */
407 @Test
408 void testNullPointerException() {
409 ScopedValue<String> name = ScopedValue.newInstance();
410
411 assertThrows(NullPointerException.class, () -> ScopedValue.where(null, "duke"));
412
413 assertThrows(NullPointerException.class, () -> ScopedValue.runWhere(null, "duke", () -> { }));
414 assertThrows(NullPointerException.class, () -> ScopedValue.runWhere(name, "duke", null));
415
416 assertThrows(NullPointerException.class, () -> ScopedValue.callWhere(null, "duke", () -> ""));
417 assertThrows(NullPointerException.class, () -> ScopedValue.callWhere(name, "duke", null));
418
419 assertThrows(NullPointerException.class, () -> name.orElseThrow(null));
420
421 var carrier = ScopedValue.where(name, "duke");
422 assertThrows(NullPointerException.class, () -> carrier.where(null, "duke"));
423 assertThrows(NullPointerException.class, () -> carrier.get((ScopedValue<?>)null));
424 assertThrows(NullPointerException.class, () -> carrier.run(null));
425 assertThrows(NullPointerException.class, () -> carrier.call(null));
426 }
427
428 @FunctionalInterface
429 private interface ThrowingRunnable {
430 void run() throws Exception;
431 }
432
433 /**
434 * Run the given task in a thread created with the given thread factory.
435 * @throws Exception if the task throws an exception
436 */
437 private static void test(ThreadFactory factory, ThrowingRunnable task) throws Exception {
|
31 import java.lang.ScopedValue.CallableOp;
32 import java.util.NoSuchElementException;
33 import java.util.concurrent.ExecutionException;
34 import java.util.concurrent.Executors;
35 import java.util.concurrent.ThreadFactory;
36 import java.util.function.Supplier;
37 import java.util.stream.Stream;
38
39 import org.junit.jupiter.api.Test;
40 import org.junit.jupiter.params.ParameterizedTest;
41 import org.junit.jupiter.params.provider.MethodSource;
42 import static org.junit.jupiter.api.Assertions.*;
43
44 class ScopedValueAPI {
45
46 private static Stream<ThreadFactory> factories() {
47 return Stream.of(Thread.ofPlatform().factory(), Thread.ofVirtual().factory());
48 }
49
50 /**
51 * Test that where invokes the Runnable's run method.
52 */
53 @ParameterizedTest
54 @MethodSource("factories")
55 void testRunWhere(ThreadFactory factory) throws Exception {
56 test(factory, () -> {
57 class Box { static boolean executed; }
58 ScopedValue<String> name = ScopedValue.newInstance();
59 ScopedValue.where(name, "duke").run(() -> { Box.executed = true; });
60 assertTrue(Box.executed);
61 });
62 }
63
64 /**
65 * Test where when the run method throws an exception.
66 */
67 @ParameterizedTest
68 @MethodSource("factories")
69 void testRunWhereThrows(ThreadFactory factory) throws Exception {
70 test(factory, () -> {
71 class FooException extends RuntimeException { }
72 ScopedValue<String> name = ScopedValue.newInstance();
73 Runnable op = () -> { throw new FooException(); };
74 assertThrows(FooException.class, () -> ScopedValue.where(name, "duke").run(op));
75 assertFalse(name.isBound());
76 });
77 }
78
79 /**
80 * Test that callWhere invokes the CallableOp's call method.
81 */
82 @ParameterizedTest
83 @MethodSource("factories")
84 void testCallWhere(ThreadFactory factory) throws Exception {
85 test(factory, () -> {
86 ScopedValue<String> name = ScopedValue.newInstance();
87 String result = ScopedValue.where(name, "duke").call(name::get);
88 assertEquals("duke", result);
89 });
90 }
91
92 /**
93 * Test callWhere when the call method throws an exception.
94 */
95 @ParameterizedTest
96 @MethodSource("factories")
97 void testCallWhereThrows(ThreadFactory factory) throws Exception {
98 test(factory, () -> {
99 class FooException extends RuntimeException { }
100 ScopedValue<String> name = ScopedValue.newInstance();
101 CallableOp<Void, RuntimeException> op = () -> { throw new FooException(); };
102 assertThrows(FooException.class, () -> ScopedValue.where(name, "duke").call(op));
103 assertFalse(name.isBound());
104 });
105 }
106
107 /**
108 * Test get method.
109 */
110 @ParameterizedTest
111 @MethodSource("factories")
112 void testGet(ThreadFactory factory) throws Exception {
113 test(factory, () -> {
114 ScopedValue<String> name1 = ScopedValue.newInstance();
115 ScopedValue<String> name2 = ScopedValue.newInstance();
116 assertThrows(NoSuchElementException.class, name1::get);
117 assertThrows(NoSuchElementException.class, name2::get);
118
119 // where
120 ScopedValue.where(name1, "duke").run(() -> {
121 assertEquals("duke", name1.get());
122 assertThrows(NoSuchElementException.class, name2::get);
123
124 });
125 assertThrows(NoSuchElementException.class, name1::get);
126 assertThrows(NoSuchElementException.class, name2::get);
127
128 // callWhere
129 ScopedValue.where(name1, "duke").call(() -> {
130 assertEquals("duke", name1.get());
131 assertThrows(NoSuchElementException.class, name2::get);
132 return null;
133 });
134 assertThrows(NoSuchElementException.class, name1::get);
135 assertThrows(NoSuchElementException.class, name2::get);
136 });
137 }
138
139 /**
140 * Test isBound method.
141 */
142 @ParameterizedTest
143 @MethodSource("factories")
144 void testIsBound(ThreadFactory factory) throws Exception {
145 test(factory, () -> {
146 ScopedValue<String> name1 = ScopedValue.newInstance();
147 ScopedValue<String> name2 = ScopedValue.newInstance();
148 assertFalse(name1.isBound());
149 assertFalse(name2.isBound());
150
151 // where
152 ScopedValue.where(name1, "duke").run(() -> {
153 assertTrue(name1.isBound());
154 assertFalse(name2.isBound());
155 });
156 assertFalse(name1.isBound());
157 assertFalse(name2.isBound());
158
159 // callWhere
160 ScopedValue.where(name1, "duke").call(() -> {
161 assertTrue(name1.isBound());
162 assertFalse(name2.isBound());
163 return null;
164 });
165 assertFalse(name1.isBound());
166 assertFalse(name2.isBound());
167 });
168 }
169
170 /**
171 * Test orElse method.
172 */
173 @ParameterizedTest
174 @MethodSource("factories")
175 void testOrElse(ThreadFactory factory) throws Exception {
176 test(factory, () -> {
177 ScopedValue<String> name = ScopedValue.newInstance();
178 assertNull(name.orElse(null));
179 assertEquals("default", name.orElse("default"));
180
181 // where
182 ScopedValue.where(name, "duke").run(() -> {
183 assertEquals("duke", name.orElse(null));
184 assertEquals("duke", name.orElse("default"));
185 });
186
187 // callWhere
188 ScopedValue.where(name, "duke").call(() -> {
189 assertEquals("duke", name.orElse(null));
190 assertEquals("duke", name.orElse("default"));
191 return null;
192 });
193 });
194 }
195
196 /**
197 * Test orElseThrow method.
198 */
199 @ParameterizedTest
200 @MethodSource("factories")
201 void testOrElseThrow(ThreadFactory factory) throws Exception {
202 test(factory, () -> {
203 class FooException extends RuntimeException { }
204 ScopedValue<String> name = ScopedValue.newInstance();
205 assertThrows(FooException.class, () -> name.orElseThrow(FooException::new));
206
207 // where
208 ScopedValue.where(name, "duke").run(() -> {
209 assertEquals("duke", name.orElseThrow(FooException::new));
210 });
211
212 // callWhere
213 ScopedValue.where(name, "duke").call(() -> {
214 assertEquals("duke", name.orElseThrow(FooException::new));
215 return null;
216 });
217 });
218 }
219
220 /**
221 * Test two bindings.
222 */
223 @ParameterizedTest
224 @MethodSource("factories")
225 void testTwoBindings(ThreadFactory factory) throws Exception {
226 test(factory, () -> {
227 ScopedValue<String> name = ScopedValue.newInstance();
228 ScopedValue<Integer> age = ScopedValue.newInstance();
229
230 // Carrier.run
231 ScopedValue.where(name, "duke").where(age, 100).run(() -> {
232 assertTrue(name.isBound());
233 assertTrue(age.isBound());
242 assertTrue(name.isBound());
243 assertTrue(age.isBound());
244 assertEquals("duke", name.get());
245 assertEquals(100, (int) age.get());
246 return null;
247 });
248 assertFalse(name.isBound());
249 assertFalse(age.isBound());
250 });
251 }
252
253 /**
254 * Test rebinding.
255 */
256 @ParameterizedTest
257 @MethodSource("factories")
258 void testRebinding(ThreadFactory factory) throws Exception {
259 test(factory, () -> {
260 ScopedValue<String> name = ScopedValue.newInstance();
261
262 // where
263 ScopedValue.where(name, "duke").run(() -> {
264 assertTrue(name.isBound());
265 assertEquals("duke", name.get());
266
267 ScopedValue.where(name, "duchess").run(() -> {
268 assertTrue(name.isBound());
269 assertEquals("duchess", name.get());
270 });
271
272 assertTrue(name.isBound());
273 assertEquals("duke", name.get());
274 });
275 assertFalse(name.isBound());
276
277 // callWhere
278 ScopedValue.where(name, "duke").call(() -> {
279 assertTrue(name.isBound());
280 assertEquals("duke", name.get());
281
282 ScopedValue.where(name, "duchess").call(() -> {
283 assertTrue(name.isBound());
284 assertEquals("duchess", name.get());
285 return null;
286 });
287
288 assertTrue(name.isBound());
289 assertEquals("duke", name.get());
290 return null;
291 });
292 assertFalse(name.isBound());
293 });
294 }
295
296 /**
297 * Test rebinding from null vaue to another value.
298 */
299 @ParameterizedTest
300 @MethodSource("factories")
301 void testRebindingFromNull(ThreadFactory factory) throws Exception {
302 test(factory, () -> {
303 ScopedValue<String> name = ScopedValue.newInstance();
304
305 // where
306 ScopedValue.where(name, null).run(() -> {
307 assertTrue(name.isBound());
308 assertNull(name.get());
309
310 ScopedValue.where(name, "duchess").run(() -> {
311 assertTrue(name.isBound());
312 assertTrue("duchess".equals(name.get()));
313 });
314
315 assertTrue(name.isBound());
316 assertNull(name.get());
317 });
318 assertFalse(name.isBound());
319
320 // callWhere
321 ScopedValue.where(name, null).call(() -> {
322 assertTrue(name.isBound());
323 assertNull(name.get());
324
325 ScopedValue.where(name, "duchess").call(() -> {
326 assertTrue(name.isBound());
327 assertTrue("duchess".equals(name.get()));
328 return null;
329 });
330
331 assertTrue(name.isBound());
332 assertNull(name.get());
333 return null;
334 });
335 assertFalse(name.isBound());
336 });
337 }
338
339 /**
340 * Test rebinding to null value.
341 */
342 @ParameterizedTest
343 @MethodSource("factories")
344 void testRebindingToNull(ThreadFactory factory) throws Exception {
345 test(factory, () -> {
346 ScopedValue<String> name = ScopedValue.newInstance();
347
348 // where
349 ScopedValue.where(name, "duke").run(() -> {
350 assertTrue(name.isBound());
351 assertEquals("duke", name.get());
352
353 ScopedValue.where(name, null).run(() -> {
354 assertTrue(name.isBound());
355 assertNull(name.get());
356 });
357
358 assertTrue(name.isBound());
359 assertEquals("duke", name.get());
360 });
361 assertFalse(name.isBound());
362
363 // callWhere
364 ScopedValue.where(name, "duke").call(() -> {
365 assertTrue(name.isBound());
366 assertEquals("duke", name.get());
367
368 ScopedValue.where(name, null).call(() -> {
369 assertTrue(name.isBound());
370 assertNull(name.get());
371 return null;
372 });
373
374 assertTrue(name.isBound());
375 assertEquals("duke", name.get());
376 return null;
377 });
378 assertFalse(name.isBound());
379 });
380 }
381
382 /**
383 * Test Carrier.get.
384 */
385 @ParameterizedTest
386 @MethodSource("factories")
387 void testCarrierGet(ThreadFactory factory) throws Exception {
388 test(factory, () -> {
393 var carrier1 = ScopedValue.where(name, "duke");
394 assertEquals("duke", carrier1.get(name));
395 assertThrows(NoSuchElementException.class, () -> carrier1.get(age));
396
397 // two scoped values
398 var carrier2 = carrier1.where(age, 20);
399 assertEquals("duke", carrier2.get(name));
400 assertEquals(20, (int) carrier2.get(age));
401 });
402 }
403
404 /**
405 * Test NullPointerException.
406 */
407 @Test
408 void testNullPointerException() {
409 ScopedValue<String> name = ScopedValue.newInstance();
410
411 assertThrows(NullPointerException.class, () -> ScopedValue.where(null, "duke"));
412
413 assertThrows(NullPointerException.class, () -> ScopedValue.where(null, "duke").run(() -> { }));
414 assertThrows(NullPointerException.class, () -> ScopedValue.where(name, "duke").run(null));
415
416 assertThrows(NullPointerException.class, () -> ScopedValue.where(null, "duke").call(() -> ""));
417 assertThrows(NullPointerException.class, () -> ScopedValue.where(name, "duke").call(null));
418
419 assertThrows(NullPointerException.class, () -> name.orElseThrow(null));
420
421 var carrier = ScopedValue.where(name, "duke");
422 assertThrows(NullPointerException.class, () -> carrier.where(null, "duke"));
423 assertThrows(NullPointerException.class, () -> carrier.get((ScopedValue<?>)null));
424 assertThrows(NullPointerException.class, () -> carrier.run(null));
425 assertThrows(NullPointerException.class, () -> carrier.call(null));
426 }
427
428 @FunctionalInterface
429 private interface ThrowingRunnable {
430 void run() throws Exception;
431 }
432
433 /**
434 * Run the given task in a thread created with the given thread factory.
435 * @throws Exception if the task throws an exception
436 */
437 private static void test(ThreadFactory factory, ThrowingRunnable task) throws Exception {
|