1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau.junit.bct;
18
19 import static org.junit.jupiter.api.Assertions.*;
20
21 import java.util.*;
22 import java.util.function.*;
23
24 import org.apache.juneau.*;
25 import org.junit.jupiter.api.*;
26
27
28
29
30
31
32
33 class Listifier_Test extends TestBase {
34
35
36
37
38
39 @Nested
40 class A_functionalInterfaceCompliance extends TestBase {
41
42 @SuppressWarnings("cast")
43 @Test
44 void a01_functionalInterfaceContract() {
45
46 Listifier<String> listifier = (converter, obj) -> Arrays.asList(obj, obj.toUpperCase());
47
48 assertNotNull(listifier);
49 assertTrue(listifier instanceof BiFunction);
50 assertTrue(listifier instanceof Listifier);
51 }
52
53 @Test
54 void a02_lambdaExpressionCompatibility() {
55
56 Listifier<String> lambda = (converter, str) -> Arrays.asList(str.toLowerCase(), str.toUpperCase());
57
58 var converter = BasicBeanConverter.DEFAULT;
59 var result = lambda.apply(converter, "Test");
60
61 assertEquals(2, result.size());
62 assertEquals("test", result.get(0));
63 assertEquals("TEST", result.get(1));
64 }
65
66 @Test
67 void a03_methodReferenceCompatibility() {
68
69 Listifier<String> methodRef = ListifierMethods::splitToChars;
70
71 var converter = BasicBeanConverter.DEFAULT;
72 var result = methodRef.apply(converter, "abc");
73
74 assertEquals(3, result.size());
75 assertEquals("a", result.get(0));
76 assertEquals("b", result.get(1));
77 assertEquals("c", result.get(2));
78 }
79
80 @Test
81 void a04_biFunctionInheritance() {
82
83 Listifier<String> listifier = (converter, str) -> Arrays.asList((Object[])str.split(""));
84
85
86 var converter = BasicBeanConverter.DEFAULT;
87 var result = listifier.apply(converter, "xy");
88 assertEquals(2, result.size());
89 }
90 }
91
92
93
94
95
96 @Nested
97 class B_lambdaComposition extends TestBase {
98
99 @Test
100 void b01_andThenComposition() {
101 Listifier<String> base = (converter, str) -> Arrays.asList(str.toLowerCase());
102 Function<List<Object>, List<Object>> mapper = list -> {
103 List<Object> result = new ArrayList<>(list);
104 result.add("ADDED");
105 return result;
106 };
107
108 BiFunction<BeanConverter, String, List<Object>> composed = base.andThen(mapper);
109
110 var converter = BasicBeanConverter.DEFAULT;
111 var result = composed.apply(converter, "TEST");
112
113 assertEquals(2, result.size());
114 assertEquals("test", result.get(0));
115 assertEquals("ADDED", result.get(1));
116 }
117
118 @Test
119 void b02_functionalComposition() {
120
121 Listifier<String> splitter = (converter, str) -> Arrays.asList((Object[])str.split(","));
122 Listifier<String> trimmer = (converter, str) -> Arrays.asList((Object[])str.trim().split("\\s+"));
123
124 var converter = BasicBeanConverter.DEFAULT;
125
126 var splitResult = splitter.apply(converter, "a,b,c");
127 assertEquals(3, splitResult.size());
128
129 var trimResult = trimmer.apply(converter, " hello world ");
130 assertEquals(2, trimResult.size());
131 assertEquals("hello", trimResult.get(0));
132 assertEquals("world", trimResult.get(1));
133 }
134 }
135
136
137
138
139
140 @Nested
141 class C_edgeCases extends TestBase {
142
143 @Test
144 void c01_nullInputHandling() {
145 Listifier<String> nullSafe = (converter, str) -> {
146 if (str == null) return Arrays.asList("NULL_INPUT");
147 return Arrays.asList(str);
148 };
149
150 var converter = BasicBeanConverter.DEFAULT;
151 var result = nullSafe.apply(converter, null);
152
153 assertEquals(1, result.size());
154 assertEquals("NULL_INPUT", result.get(0));
155 }
156
157 @Test
158 void c02_emptyResultHandling() {
159 Listifier<String> emptyReturner = (converter, str) -> new ArrayList<>();
160
161 var converter = BasicBeanConverter.DEFAULT;
162 var result = emptyReturner.apply(converter, "anything");
163
164 assertNotNull(result);
165 assertEquals(0, result.size());
166 }
167
168 @Test
169 void c03_exceptionHandling() {
170 Listifier<String> throwing = (converter, str) -> {
171 if ("ERROR".equals(str)) {
172 throw new RuntimeException("Intentional test exception");
173 }
174 return Arrays.asList(str);
175 };
176
177 var converter = BasicBeanConverter.DEFAULT;
178
179
180 var normalResult = throwing.apply(converter, "normal");
181 assertEquals(1, normalResult.size());
182 assertEquals("normal", normalResult.get(0));
183
184
185 assertThrows(RuntimeException.class, () -> throwing.apply(converter, "ERROR"));
186 }
187
188 @Test
189 void c04_largeListHandling() {
190 Listifier<Integer> largeListGenerator = (converter, count) -> {
191 List<Object> result = new ArrayList<>();
192 for (int i = 0; i < count; i++) {
193 result.add("item_" + i);
194 }
195 return result;
196 };
197
198 var converter = BasicBeanConverter.DEFAULT;
199 var result = largeListGenerator.apply(converter, 1000);
200
201 assertEquals(1000, result.size());
202 assertEquals("item_0", result.get(0));
203 assertEquals("item_999", result.get(999));
204 }
205 }
206
207
208
209
210
211 @Nested
212 class D_integration extends TestBase {
213
214 @Test
215 void d01_converterIntegration() {
216
217 var customConverter = BasicBeanConverter.builder()
218 .defaultSettings()
219 .addListifier(TestObject.class, (converter, obj) ->
220 Arrays.asList(obj.name, obj.value, "LISTIFIED"))
221 .build();
222
223 var test = new TestObject("test", 42);
224 var result = customConverter.listify(test);
225
226 assertEquals(3, result.size());
227 assertEquals("test", result.get(0));
228 assertEquals(42, result.get(1));
229 assertEquals("LISTIFIED", result.get(2));
230 }
231
232 @Test
233 void d02_multipleListifierRegistration() {
234 var customConverter = BasicBeanConverter.builder()
235 .defaultSettings()
236 .addListifier(String.class, (converter, str) -> Arrays.asList(str.toLowerCase()))
237 .addListifier(Integer.class, (converter, num) -> Arrays.asList(num, num * 2))
238 .build();
239
240
241 var stringResult = customConverter.listify("TEST");
242 assertEquals(1, stringResult.size());
243 assertEquals("test", stringResult.get(0));
244
245
246 var intResult = customConverter.listify(5);
247 assertEquals(2, intResult.size());
248 assertEquals(5, intResult.get(0));
249 assertEquals(10, intResult.get(1));
250 }
251
252 @Test
253 void d03_converterPassthrough() {
254
255 Listifier<String> converterUser = (converter, str) -> {
256
257 String stringified = converter.stringify(Arrays.asList("nested", "call"));
258 return Arrays.asList(str, stringified);
259 };
260
261 var converter = BasicBeanConverter.DEFAULT;
262 var result = converterUser.apply(converter, "test");
263
264 assertEquals(2, result.size());
265 assertEquals("test", result.get(0));
266 assertTrue(result.get(1).toString().contains("nested"));
267 }
268 }
269
270
271
272
273
274 @Nested
275 class E_performance extends TestBase {
276
277 @Test
278 void e01_performanceWithLargeLists() {
279 Listifier<Integer> rangeGenerator = (converter, count) -> {
280 List<Object> result = new ArrayList<>();
281 for (int i = 0; i < count; i++) {
282 result.add(i);
283 }
284 return result;
285 };
286
287 var converter = BasicBeanConverter.DEFAULT;
288
289 var start = System.currentTimeMillis();
290 var result = rangeGenerator.apply(converter, 10000);
291 var end = System.currentTimeMillis();
292
293 assertEquals(10000, result.size());
294 assertTrue(end - start < 1000, "Should complete within 1 second");
295 }
296
297 @Test
298 void e02_memoryEfficiency() {
299 Listifier<String> memoryTest = (converter, str) -> {
300
301 List<Object> result = new ArrayList<>();
302 for (int i = 0; i < 1000; i++) {
303 result.add(str + "_" + i);
304 }
305 return result;
306 };
307
308 var converter = BasicBeanConverter.DEFAULT;
309 var result = memoryTest.apply(converter, "test");
310
311 assertEquals(1000, result.size());
312 assertEquals("test_0", result.get(0));
313 assertEquals("test_999", result.get(999));
314 }
315 }
316
317
318
319
320
321 static class ListifierMethods {
322 static List<Object> splitToChars(BeanConverter converter, String str) {
323 return Arrays.asList((Object[])str.split(""));
324 }
325 }
326
327 static class TestObject {
328 final String name;
329 final int value;
330
331 TestObject(String name, int value) {
332 this.name = name;
333 this.value = value;
334 }
335 }
336 }