Skip to content

Commit 875e10c

Browse files
committed
add LazyValueTest
1 parent f6a698d commit 875e10c

File tree

1 file changed

+231
-0
lines changed

1 file changed

+231
-0
lines changed
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
package org.framefork.typedIds.common;
2+
3+
import org.junit.jupiter.api.Assertions;
4+
import org.junit.jupiter.api.Nested;
5+
import org.junit.jupiter.api.Test;
6+
7+
import static org.assertj.core.api.Assertions.assertThat;
8+
9+
import java.util.concurrent.CountDownLatch;
10+
import java.util.concurrent.ExecutorService;
11+
import java.util.concurrent.Executors;
12+
import java.util.concurrent.Future;
13+
import java.util.concurrent.TimeUnit;
14+
import java.util.concurrent.atomic.AtomicInteger;
15+
16+
final class LazyValueTest
17+
{
18+
19+
@Nested
20+
final class BasicFunctionality
21+
{
22+
23+
@Test
24+
public void shouldInitializeValueOnFirstAccess()
25+
{
26+
var callCount = new AtomicInteger(0);
27+
LazyValue<String> lazyValue = new LazyValue<>(() -> {
28+
callCount.incrementAndGet();
29+
return "test-value";
30+
});
31+
32+
Assertions.assertEquals(0, callCount.get());
33+
34+
String result = lazyValue.get();
35+
36+
Assertions.assertEquals("test-value", result);
37+
Assertions.assertEquals(1, callCount.get());
38+
}
39+
40+
@Test
41+
public void shouldReturnSameInstanceOnMultipleCalls()
42+
{
43+
var callCount = new AtomicInteger(0);
44+
LazyValue<String> lazyValue = new LazyValue<>(() -> {
45+
callCount.incrementAndGet();
46+
return "test-value";
47+
});
48+
49+
Assertions.assertEquals(0, callCount.get());
50+
51+
String first = lazyValue.get();
52+
String second = lazyValue.get();
53+
String third = lazyValue.get();
54+
55+
Assertions.assertSame(first, second);
56+
Assertions.assertSame(second, third);
57+
Assertions.assertEquals(1, callCount.get());
58+
}
59+
60+
}
61+
62+
@Nested
63+
final class SetMethod
64+
{
65+
66+
@Test
67+
public void shouldOverrideValueWhenSet()
68+
{
69+
var callCount = new AtomicInteger(0);
70+
LazyValue<String> lazyValue = new LazyValue<>(() -> {
71+
callCount.incrementAndGet();
72+
return "initial-value";
73+
});
74+
75+
lazyValue.set("override-value");
76+
String result = lazyValue.get();
77+
78+
Assertions.assertEquals("override-value", result);
79+
Assertions.assertEquals(0, callCount.get());
80+
}
81+
82+
@Test
83+
public void shouldOverrideInitializedValue()
84+
{
85+
LazyValue<String> lazyValue = new LazyValue<>(() -> "initial-value");
86+
87+
String initialResult = lazyValue.get();
88+
lazyValue.set("override-value");
89+
String overriddenResult = lazyValue.get();
90+
91+
Assertions.assertEquals("initial-value", initialResult);
92+
Assertions.assertEquals("override-value", overriddenResult);
93+
}
94+
95+
}
96+
97+
@Nested
98+
final class NullHandling
99+
{
100+
101+
@Test
102+
@SuppressWarnings("NullAway")
103+
public void shouldThrowWhenSupplierIsNull()
104+
{
105+
Assertions.assertThrows(
106+
NullPointerException.class,
107+
() -> new LazyValue<>(null),
108+
"initialValueSupplier must not be null"
109+
);
110+
}
111+
112+
@Test
113+
public void shouldThrowWhenSupplierReturnsNull()
114+
{
115+
LazyValue<String> lazyValue = new LazyValue<>(() -> null);
116+
117+
NullPointerException exception = Assertions.assertThrows(
118+
NullPointerException.class,
119+
lazyValue::get
120+
);
121+
122+
assertThat(exception).hasMessage("initialValueSupplier must not return null");
123+
}
124+
125+
@Test
126+
@SuppressWarnings("NullAway")
127+
public void shouldThrowWhenSetWithNull()
128+
{
129+
LazyValue<String> lazyValue = new LazyValue<>(() -> "test");
130+
131+
Assertions.assertThrows(
132+
NullPointerException.class,
133+
() -> lazyValue.set(null),
134+
"newValue must not be null"
135+
);
136+
}
137+
138+
}
139+
140+
@Nested
141+
final class ThreadSafety
142+
{
143+
144+
@Test
145+
public void shouldHandleConcurrentSetAndGet() throws InterruptedException
146+
{
147+
LazyValue<String> lazyValue = new LazyValue<>(() -> "initial");
148+
var startLatch = new CountDownLatch(1);
149+
var finishLatch = new CountDownLatch(20);
150+
151+
ExecutorService executor = Executors.newFixedThreadPool(20);
152+
153+
for (int i = 0; i < 10; i++) {
154+
int index = i;
155+
@SuppressWarnings("unused")
156+
Future<?> future1 = executor.submit(() -> {
157+
try {
158+
startLatch.await();
159+
lazyValue.set("set-" + index);
160+
} catch (InterruptedException e) {
161+
Thread.currentThread().interrupt();
162+
} finally {
163+
finishLatch.countDown();
164+
}
165+
});
166+
}
167+
168+
for (int i = 0; i < 10; i++) {
169+
@SuppressWarnings("unused")
170+
Future<?> future2 = executor.submit(() -> {
171+
try {
172+
startLatch.await();
173+
String result = lazyValue.get();
174+
Assertions.assertNotNull(result);
175+
} catch (InterruptedException e) {
176+
Thread.currentThread().interrupt();
177+
} finally {
178+
finishLatch.countDown();
179+
}
180+
});
181+
}
182+
183+
startLatch.countDown();
184+
Assertions.assertTrue(finishLatch.await(5, TimeUnit.SECONDS));
185+
186+
executor.shutdown();
187+
Assertions.assertTrue(executor.awaitTermination(1, TimeUnit.SECONDS));
188+
189+
String finalValue = lazyValue.get();
190+
Assertions.assertNotNull(finalValue);
191+
}
192+
193+
}
194+
195+
@Nested
196+
final class ExceptionHandling
197+
{
198+
199+
@Test
200+
public void shouldPropagateSupplierException()
201+
{
202+
LazyValue<String> lazyValue = new LazyValue<>(() -> {
203+
throw new RuntimeException("Test exception");
204+
});
205+
206+
RuntimeException exception = Assertions.assertThrows(
207+
RuntimeException.class,
208+
lazyValue::get
209+
);
210+
211+
assertThat(exception).hasMessage("Test exception");
212+
}
213+
214+
@Test
215+
public void shouldRethrowExceptionOnSubsequentCalls()
216+
{
217+
var callCount = new AtomicInteger(0);
218+
LazyValue<String> lazyValue = new LazyValue<>(() -> {
219+
callCount.incrementAndGet();
220+
throw new RuntimeException("Test exception");
221+
});
222+
223+
Assertions.assertThrows(RuntimeException.class, lazyValue::get);
224+
Assertions.assertThrows(RuntimeException.class, lazyValue::get);
225+
226+
Assertions.assertEquals(2, callCount.get());
227+
}
228+
229+
}
230+
231+
}

0 commit comments

Comments
 (0)