View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.commons.lang;
18  
19  import static org.apache.juneau.commons.utils.CollectionUtils.*;
20  import static org.junit.jupiter.api.Assertions.*;
21  
22  import java.lang.reflect.Type;
23  
24  import org.apache.juneau.*;
25  import org.junit.jupiter.api.*;
26  
27  class Value_Test extends TestBase {
28  
29  	//-----------------------------------------------------------------------------------------------------------------
30  	// Value defined on parent class.
31  	//-----------------------------------------------------------------------------------------------------------------
32  
33  	public static class A extends Value<A1>{}
34  	public static class A1 {}
35  
36  	@Test void a01_testSubclass() {
37  		assertEquals(A1.class, Value.getParameterType(A.class));
38  	}
39  
40  	//-----------------------------------------------------------------------------------------------------------------
41  	// getAndSet(T)
42  	//-----------------------------------------------------------------------------------------------------------------
43  
44  	@Test
45  	void b01_getAndSet_withExistingValue() {
46  		var v = Value.of("old");
47  		var old = v.getAndSet("new");
48  		assertEquals("old", old, "Should return old value");
49  		assertEquals("new", v.get(), "Should have new value");
50  	}
51  
52  	@Test
53  	void b02_getAndSet_withNullValue() {
54  		var v = Value.of(null);
55  		var old = v.getAndSet("new");
56  		assertNull(old, "Should return null");
57  		assertEquals("new", v.get(), "Should have new value");
58  	}
59  
60  	@Test
61  	void b03_getAndSet_toNull() {
62  		var v = Value.of("old");
63  		var old = v.getAndSet(null);
64  		assertEquals("old", old, "Should return old value");
65  		assertNull(v.get(), "Should have null value");
66  	}
67  
68  	@Test
69  	void b04_getAndSet_multiple() {
70  		var v = Value.of(1);
71  		assertEquals(1, v.getAndSet(2), "First getAndSet");
72  		assertEquals(2, v.getAndSet(3), "Second getAndSet");
73  		assertEquals(3, v.getAndSet(4), "Third getAndSet");
74  		assertEquals(4, v.get(), "Final value");
75  	}
76  
77  	@Test
78  	void b05_getAndSet_withEmptyValue() {
79  		var v = Value.empty();
80  		var old = v.getAndSet("new");
81  		assertNull(old, "Should return null");
82  		assertEquals("new", v.get(), "Should have new value");
83  	}
84  
85  	@Test
86  	void b06_getAndSet_chainability() {
87  		var v = Value.of("old");
88  		v.getAndSet("new");
89  		assertEquals("new", v.get(), "Value should be set after getAndSet");
90  	}
91  
92  	@Test
93  	void b07_getAndSet_withListener() {
94  		var v = Value.of("old");
95  		var sb = new StringBuilder();
96  		v.listener((val) -> sb.append(val));
97  
98  		var old = v.getAndSet("new");
99  
100 		assertEquals("old", old, "Should return old value");
101 		assertEquals("new", v.get(), "Should have new value");
102 		assertEquals("new", sb.toString(), "Listener should be called with new value");
103 	}
104 
105 	//-----------------------------------------------------------------------------------------------------------------
106 	// is(T)
107 	//-----------------------------------------------------------------------------------------------------------------
108 
109 	@Test
110 	void c01_is_equalStrings() {
111 		var v = Value.of("hello");
112 		assertTrue(v.is("hello"), "Should be equal to same string");
113 		assertFalse(v.is("world"), "Should not be equal to different string");
114 	}
115 
116 	@Test
117 	void c02_is_withNull() {
118 		var v = Value.empty();
119 		assertTrue(v.is(null), "Empty value should equal null");
120 		assertFalse(v.is("test"), "Empty value should not equal non-null");
121 
122 		v.set("test");
123 		assertFalse(v.is(null), "Non-null value should not equal null");
124 	}
125 
126 	@Test
127 	void c03_is_equalIntegers() {
128 		var v = Value.of(42);
129 		assertTrue(v.is(42), "Should be equal to same integer");
130 		assertFalse(v.is(43), "Should not be equal to different integer");
131 	}
132 
133 	@Test
134 	void c04_is_equalBooleans() {
135 		var v = Value.of(true);
136 		assertTrue(v.is(true), "Should be equal to true");
137 		assertFalse(v.is(false), "Should not be equal to false");
138 	}
139 
140 	@Test
141 	void c05_is_equalArrays() {
142 		var v = Value.of(ints(1, 2, 3));
143 		assertTrue(v.is(ints(1, 2, 3)), "Should be equal to same array content");
144 		assertFalse(v.is(ints(1, 2, 4)), "Should not be equal to different array content");
145 		assertFalse(v.is(ints(1, 2)), "Should not be equal to shorter array");
146 	}
147 
148 	@Test
149 	void c06_is_equalLists() {
150 		var v = Value.of(l("a", "b", "c"));
151 		assertTrue(v.is(l("a", "b", "c")), "Should be equal to same list content");
152 		assertFalse(v.is(l("a", "b", "d")), "Should not be equal to different list content");
153 	}
154 
155 	@Test
156 	void c07_is_emptyVsEmpty() {
157 		var v1 = Value.empty();
158 		var v2 = Value.empty();
159 		assertTrue(v1.is(v2.get()), "Two empty values should be equal");
160 	}
161 
162 	@Test
163 	void c08_is_differentTypes() {
164 		Value<Object> v = Value.of("42");
165 		assertFalse(v.is(42), "String '42' should not equal Integer 42");
166 	}
167 
168 	@Test
169 	void c09_is_sameObject() {
170 		var s = "test";
171 		var v = Value.of(s);
172 		assertTrue(v.is(s), "Should be equal to same object reference");
173 	}
174 
175 	@Test
176 	void c10_is_equalCustomObjects() {
177 		// Using A1 class defined at the top
178 		var obj1 = new A1();
179 		var obj2 = new A1();
180 
181 		var v = Value.of(obj1);
182 		assertTrue(v.is(obj1), "Should be equal to same object");
183 		// Note: A1 doesn't override equals(), so different instances won't be equal
184 		assertFalse(v.is(obj2), "Should not be equal to different instance without equals override");
185 	}
186 
187 	@Test
188 	void c11_is_afterSet() {
189 		var v = Value.of("initial");
190 		assertTrue(v.is("initial"));
191 
192 		v.set("updated");
193 		assertFalse(v.is("initial"), "Should not equal old value after set");
194 		assertTrue(v.is("updated"), "Should equal new value after set");
195 	}
196 
197 	//-----------------------------------------------------------------------------------------------------------------
198 	// filter(Predicate)
199 	//-----------------------------------------------------------------------------------------------------------------
200 
201 	@Test
202 	void d01_filter_passing() {
203 		var v = Value.of("hello");
204 		var filtered = v.filter(s -> s.length() > 3);
205 		assertTrue(filtered.isPresent());
206 		assertEquals("hello", filtered.get());
207 	}
208 
209 	@Test
210 	void d02_filter_failing() {
211 		var v = Value.of("hello");
212 		var filtered = v.filter(s -> s.length() > 10);
213 		assertFalse(filtered.isPresent());
214 	}
215 
216 	@Test
217 	void d03_filter_empty() {
218 		Value<String> v = Value.empty();
219 		var filtered = v.filter(s -> s.length() > 3);
220 		assertFalse(filtered.isPresent());
221 	}
222 
223 	@Test
224 	void d04_filter_chain() {
225 		var v = Value.of(100);
226 		var filtered = v.filter(x -> x > 50).filter(x -> x < 150);
227 		assertTrue(filtered.isPresent());
228 		assertEquals(100, filtered.get());
229 	}
230 
231 	@Test
232 	void d05_filter_chainFails() {
233 		var v = Value.of(100);
234 		var filtered = v.filter(x -> x > 50).filter(x -> x < 80);
235 		assertFalse(filtered.isPresent());
236 	}
237 
238 	//-----------------------------------------------------------------------------------------------------------------
239 	// flatMap(Function)
240 	//-----------------------------------------------------------------------------------------------------------------
241 
242 	@Test
243 	void e01_flatMap_basic() {
244 		var v = Value.of("hello");
245 		var mapped = v.flatMap(s -> Value.of(s.length()));
246 		assertTrue(mapped.isPresent());
247 		assertEquals(5, mapped.get());
248 	}
249 
250 	@Test
251 	void e02_flatMap_toEmpty() {
252 		var v = Value.of("hello");
253 		var mapped = v.flatMap(s -> Value.empty());
254 		assertFalse(mapped.isPresent());
255 	}
256 
257 	@Test
258 	void e03_flatMap_fromEmpty() {
259 		Value<String> v = Value.empty();
260 		var mapped = v.flatMap(s -> Value.of(s.length()));
261 		assertFalse(mapped.isPresent());
262 	}
263 
264 	@Test
265 	void e04_flatMap_chain() {
266 		var v = Value.of("hello");
267 		var mapped = v.flatMap(s -> Value.of(s.length()))
268 			.flatMap(n -> Value.of(n * 2));
269 		assertTrue(mapped.isPresent());
270 		assertEquals(10, mapped.get());
271 	}
272 
273 	@Test
274 	void e05_flatMap_withFilter() {
275 		var v = Value.of("hello");
276 		var result = v.filter(s -> s.length() > 3)
277 			.flatMap(s -> Value.of(s.toUpperCase()));
278 		assertTrue(result.isPresent());
279 		assertEquals("HELLO", result.get());
280 	}
281 
282 	//-----------------------------------------------------------------------------------------------------------------
283 	// equals(Object)
284 	//-----------------------------------------------------------------------------------------------------------------
285 
286 	@Test
287 	void f01_equals_sameValue() {
288 		var v1 = Value.of("hello");
289 		var v2 = Value.of("hello");
290 		assertEquals(v1, v2);
291 	}
292 
293 	@Test
294 	void f02_equals_differentValue() {
295 		var v1 = Value.of("hello");
296 		var v2 = Value.of("world");
297 		assertNotEquals(v1, v2);
298 	}
299 
300 	@Test
301 	void f03_equals_bothEmpty() {
302 		var v1 = Value.empty();
303 		var v2 = Value.empty();
304 		assertEquals(v1, v2);
305 	}
306 
307 	@Test
308 	void f04_equals_oneEmpty() {
309 		var v1 = Value.of("hello");
310 		var v2 = Value.empty();
311 		assertNotEquals(v1, v2);
312 	}
313 
314 	@Test
315 	void f05_equals_sameReference() {
316 		var v = Value.of("hello");
317 		assertEquals(v, v);
318 	}
319 
320 	@Test
321 	void f06_equals_null() {
322 		var v = Value.of("hello");
323 		assertNotEquals(null, v);
324 	}
325 
326 	@Test
327 	void f07_equals_differentType() {
328 		var v = Value.of("hello");
329 		assertNotEquals("hello", v);
330 	}
331 
332 	@Test
333 	void f08_equals_integers() {
334 		var v1 = Value.of(42);
335 		var v2 = Value.of(42);
336 		var v3 = Value.of(43);
337 		assertEquals(v1, v2);
338 		assertNotEquals(v1, v3);
339 	}
340 
341 	//-----------------------------------------------------------------------------------------------------------------
342 	// hashCode()
343 	//-----------------------------------------------------------------------------------------------------------------
344 
345 	@Test
346 	void g01_hashCode_consistent() {
347 		var v = Value.of("hello");
348 		assertEquals(v.hashCode(), v.hashCode());
349 	}
350 
351 	@Test
352 	void g02_hashCode_equalValues() {
353 		var v1 = Value.of("hello");
354 		var v2 = Value.of("hello");
355 		assertEquals(v1.hashCode(), v2.hashCode());
356 	}
357 
358 	@Test
359 	void g03_hashCode_empty() {
360 		var v = Value.empty();
361 		assertEquals(0, v.hashCode());
362 	}
363 
364 	@Test
365 	void g04_hashCode_afterSet() {
366 		var v = Value.of("hello");
367 		var hash1 = v.hashCode();
368 		v.set("world");
369 		var hash2 = v.hashCode();
370 		assertNotEquals(hash1, hash2);
371 	}
372 
373 	@Test
374 	void g05_hashCode_nullValue() {
375 		var v = Value.of(null);
376 		assertEquals(0, v.hashCode());
377 	}
378 
379 	@Test
380 	void g06_hashCode_useInHashMap() {
381 		var map = new java.util.HashMap<Value<String>, String>();
382 		var key1 = Value.of("key");
383 		var key2 = Value.of("key");
384 		map.put(key1, "value");
385 		assertEquals("value", map.get(key2), "HashMap should work with Value's hashCode and equals");
386 	}
387 
388 	//-----------------------------------------------------------------------------------------------------------------
389 	// isType(Type)
390 	//-----------------------------------------------------------------------------------------------------------------
391 
392 	@Test
393 	void h01_isType_parameterizedType() {
394 		java.lang.reflect.Type type = new java.lang.reflect.ParameterizedType() {
395 			@Override
396 			public Type[] getActualTypeArguments() {
397 				return new Type[]{String.class};
398 			}
399 			@Override
400 			public Type getRawType() {
401 				return Value.class;
402 			}
403 			@Override
404 			public Type getOwnerType() {
405 				return null;
406 			}
407 		};
408 		assertTrue(Value.isType(type), "ParameterizedType with Value.class as raw type should return true");
409 	}
410 
411 	@Test
412 	void h02_isType_parameterizedType_differentRawType() {
413 		java.lang.reflect.Type type = new java.lang.reflect.ParameterizedType() {
414 			@Override
415 			public Type[] getActualTypeArguments() {
416 				return new Type[]{String.class};
417 			}
418 			@Override
419 			public Type getRawType() {
420 				return String.class; // Not Value.class
421 			}
422 			@Override
423 			public Type getOwnerType() {
424 				return null;
425 			}
426 		};
427 		assertFalse(Value.isType(type), "ParameterizedType with different raw type should return false");
428 	}
429 
430 	@Test
431 	void h03_isType_valueClass() {
432 		assertTrue(Value.isType(Value.class), "Value.class should return true");
433 	}
434 
435 	@Test
436 	void h04_isType_valueSubclass() {
437 		assertTrue(Value.isType(IntegerValue.class), "IntegerValue (subclass of Value) should return true");
438 		assertTrue(Value.isType(StringValue.class), "StringValue (subclass of Value) should return true");
439 	}
440 
441 	@Test
442 	void h05_isType_nonValueClass() {
443 		assertFalse(Value.isType(String.class), "String.class should return false");
444 		assertFalse(Value.isType(Integer.class), "Integer.class should return false");
445 	}
446 
447 	@Test
448 	void h06_isType_null() {
449 		// null should be handled gracefully
450 		assertFalse(Value.isType(null), "null type should return false");
451 	}
452 
453 	//-----------------------------------------------------------------------------------------------------------------
454 	// unwrap(Type)
455 	//-----------------------------------------------------------------------------------------------------------------
456 
457 	@Test
458 	void i01_unwrap_parameterizedValueType() throws Exception {
459 		java.lang.reflect.Type valueType = new java.lang.reflect.ParameterizedType() {
460 			@Override
461 			public Type[] getActualTypeArguments() {
462 				return new Type[]{String.class};
463 			}
464 			@Override
465 			public Type getRawType() {
466 				return Value.class;
467 			}
468 			@Override
469 			public Type getOwnerType() {
470 				return null;
471 			}
472 		};
473 		Type unwrapped = Value.unwrap(valueType);
474 		assertEquals(String.class, unwrapped, "Should unwrap Value<String> to String");
475 	}
476 
477 	@Test
478 	void i02_unwrap_valueSubclass() {
479 		Type unwrapped = Value.unwrap(IntegerValue.class);
480 		assertEquals(Integer.class, unwrapped, "Should unwrap IntegerValue to Integer");
481 	}
482 
483 	@Test
484 	void i03_unwrap_nonValueType() {
485 		Type unwrapped = Value.unwrap(String.class);
486 		assertEquals(String.class, unwrapped, "Non-Value type should be returned as-is");
487 	}
488 
489 	@Test
490 	void i04_unwrap_valueClass() {
491 		// Value.class itself (without parameter) cannot be unwrapped because it has no type parameter
492 		// getParameterType throws IllegalArgumentException when the class is not a subclass
493 		assertThrows(IllegalArgumentException.class, () -> {
494 			Value.unwrap(Value.class);
495 		}, "Value.class without parameter should throw IllegalArgumentException");
496 	}
497 
498 	//-----------------------------------------------------------------------------------------------------------------
499 	// toString()
500 	//-----------------------------------------------------------------------------------------------------------------
501 
502 	@Test
503 	void j01_toString_withValue() {
504 		var v = Value.of("hello");
505 		assertEquals("Value(hello)", v.toString());
506 	}
507 
508 	@Test
509 	void j02_toString_withNull() {
510 		var v = Value.empty();
511 		assertEquals("Value(null)", v.toString());
512 	}
513 
514 	@Test
515 	void j03_toString_withInteger() {
516 		var v = Value.of(42);
517 		assertEquals("Value(42)", v.toString());
518 	}
519 
520 	@Test
521 	void j04_toString_afterSet() {
522 		var v = Value.of("initial");
523 		assertEquals("Value(initial)", v.toString());
524 		v.set("updated");
525 		assertEquals("Value(updated)", v.toString());
526 	}
527 
528 	@Test
529 	void j05_toString_withCustomObject() {
530 		var obj = new A1();
531 		var v = Value.of(obj);
532 		String result = v.toString();
533 		assertTrue(result.startsWith("Value("), "Should start with 'Value('");
534 		assertTrue(result.endsWith(")"), "Should end with ')'");
535 	}
536 
537 	//-----------------------------------------------------------------------------------------------------------------
538 	// Value() - default constructor
539 	//-----------------------------------------------------------------------------------------------------------------
540 
541 	@Test
542 	void k01_defaultConstructor_createsEmpty() {
543 		var v = new Value<String>();
544 		assertNull(v.get(), "Default constructor should create empty Value");
545 		assertTrue(v.isEmpty(), "Default constructor should create empty Value");
546 		assertFalse(v.isPresent(), "Default constructor should create empty Value");
547 	}
548 
549 	@Test
550 	void k02_defaultConstructor_canSetValue() {
551 		var v = new Value<String>();
552 		v.set("test");
553 		assertEquals("test", v.get(), "Should be able to set value after default constructor");
554 	}
555 
556 	@Test
557 	void k03_defaultConstructor_equalsEmpty() {
558 		var v1 = new Value<String>();
559 		var v2 = Value.empty();
560 		assertEquals(v1, v2, "Default constructor should equal Value.empty()");
561 	}
562 }
563