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.junit.jupiter.api.Assertions.*;
20  
21  import org.junit.jupiter.api.*;
22  
23  /**
24   * Tests for {@link AsciiMap}.
25   */
26  class AsciiMap_Test {
27  
28  	//====================================================================================================
29  	// append(char, String) - Basic cases
30  	//====================================================================================================
31  	@Test
32  	void a01_append_basic() {
33  		var map = new AsciiMap();
34  		var result = map.append('a', "value1");
35  		assertSame(map, result); // Should return this
36  		assertEquals("value1", map.get('a'));
37  	}
38  
39  	@Test
40  	void a02_append_multiple() {
41  		var map = new AsciiMap();
42  		map.append('a', "value1");
43  		map.append('b', "value2");
44  		map.append('c', "value3");
45  		assertEquals("value1", map.get('a'));
46  		assertEquals("value2", map.get('b'));
47  		assertEquals("value3", map.get('c'));
48  	}
49  
50  	@Test
51  	void a03_append_overwrite() {
52  		var map = new AsciiMap();
53  		map.append('a', "value1");
54  		map.append('a', "value2");
55  		assertEquals("value2", map.get('a'));
56  	}
57  
58  	@Test
59  	void a04_append_nullValue() {
60  		var map = new AsciiMap();
61  		map.append('a', null);
62  		assertNull(map.get('a'));
63  	}
64  
65  	@Test
66  	void a05_append_emptyString() {
67  		var map = new AsciiMap();
68  		map.append('a', "");
69  		assertEquals("", map.get('a'));
70  	}
71  
72  	//====================================================================================================
73  	// append(char, String) - Boundary cases
74  	//====================================================================================================
75  	@Test
76  	void a06_append_asciiBoundary_min() {
77  		var map = new AsciiMap();
78  		map.append((char)0, "null");
79  		assertEquals("null", map.get((char)0));
80  	}
81  
82  	@Test
83  	void a07_append_asciiBoundary_max() {
84  		var map = new AsciiMap();
85  		map.append((char)127, "del");
86  		assertEquals("del", map.get((char)127));
87  	}
88  
89  	@Test
90  	void a08_append_nonAscii_above127() {
91  		var map = new AsciiMap();
92  		map.append((char)128, "shouldNotBeStored");
93  		// Non-ASCII characters are not stored, so contains should return false
94  		assertFalse(map.contains((char)128));
95  		// get() will throw ArrayIndexOutOfBoundsException for non-ASCII
96  		assertThrows(ArrayIndexOutOfBoundsException.class, () -> {
97  			map.get((char)128);
98  		});
99  	}
100 
101 	@Test
102 	void a09_append_nonAscii_unicode() {
103 		var map = new AsciiMap();
104 		map.append('€', "euro");
105 		// Non-ASCII characters are not stored, so contains should return false
106 		assertFalse(map.contains('€'));
107 		// get() will throw ArrayIndexOutOfBoundsException for non-ASCII
108 		assertThrows(ArrayIndexOutOfBoundsException.class, () -> {
109 			map.get('€');
110 		});
111 	}
112 
113 	@Test
114 	void a10_append_chaining() {
115 		var map = new AsciiMap();
116 		map.append('a', "value1")
117 			.append('b', "value2")
118 			.append('c', "value3");
119 		assertEquals("value1", map.get('a'));
120 		assertEquals("value2", map.get('b'));
121 		assertEquals("value3", map.get('c'));
122 	}
123 
124 	//====================================================================================================
125 	// contains(char) - Basic cases
126 	//====================================================================================================
127 	@Test
128 	void b01_contains_char_present() {
129 		var map = new AsciiMap();
130 		map.append('a', "value1");
131 		assertTrue(map.contains('a'));
132 	}
133 
134 	@Test
135 	void b02_contains_char_notPresent() {
136 		var map = new AsciiMap();
137 		assertFalse(map.contains('a'));
138 	}
139 
140 	@Test
141 	void b03_contains_char_nullValue() {
142 		var map = new AsciiMap();
143 		map.append('a', null);
144 		assertFalse(map.contains('a')); // null values are not considered "contained"
145 	}
146 
147 	@Test
148 	void b04_contains_char_emptyString() {
149 		var map = new AsciiMap();
150 		map.append('a', "");
151 		assertTrue(map.contains('a')); // Empty string is still a value
152 	}
153 
154 	@Test
155 	void b05_contains_char_multiple() {
156 		var map = new AsciiMap();
157 		map.append('a', "value1");
158 		map.append('b', "value2");
159 		map.append('c', "value3");
160 		assertTrue(map.contains('a'));
161 		assertTrue(map.contains('b'));
162 		assertTrue(map.contains('c'));
163 		assertFalse(map.contains('d'));
164 	}
165 
166 	//====================================================================================================
167 	// contains(char) - Boundary cases
168 	//====================================================================================================
169 	@Test
170 	void b06_contains_char_asciiMin() {
171 		var map = new AsciiMap();
172 		map.append((char)0, "null");
173 		assertTrue(map.contains((char)0));
174 	}
175 
176 	@Test
177 	void b07_contains_char_asciiMax() {
178 		var map = new AsciiMap();
179 		map.append((char)127, "del");
180 		assertTrue(map.contains((char)127));
181 	}
182 
183 	@Test
184 	void b08_contains_char_nonAscii_above127() {
185 		var map = new AsciiMap();
186 		assertFalse(map.contains((char)128));
187 	}
188 
189 	@Test
190 	void b09_contains_char_nonAscii_unicode() {
191 		var map = new AsciiMap();
192 		assertFalse(map.contains('€'));
193 	}
194 
195 	@Test
196 	void b10_contains_char_negative() {
197 		var map = new AsciiMap();
198 		// Negative char values are not valid, but let's test the behavior
199 		// In Java, char is unsigned, so this would be a large positive value
200 		assertFalse(map.contains((char)-1));
201 	}
202 
203 	//====================================================================================================
204 	// contains(int) - Basic cases
205 	//====================================================================================================
206 	@Test
207 	void c01_contains_int_present() {
208 		var map = new AsciiMap();
209 		map.append('a', "value1");
210 		assertTrue(map.contains((int)'a'));
211 	}
212 
213 	@Test
214 	void c02_contains_int_notPresent() {
215 		var map = new AsciiMap();
216 		assertFalse(map.contains((int)'a'));
217 	}
218 
219 	@Test
220 	void c03_contains_int_nullValue() {
221 		var map = new AsciiMap();
222 		map.append('a', null);
223 		assertFalse(map.contains((int)'a'));
224 	}
225 
226 	@Test
227 	void c04_contains_int_emptyString() {
228 		var map = new AsciiMap();
229 		map.append('a', "");
230 		assertTrue(map.contains((int)'a'));
231 	}
232 
233 	//====================================================================================================
234 	// contains(int) - Boundary cases
235 	//====================================================================================================
236 	@Test
237 	void c05_contains_int_asciiMin() {
238 		var map = new AsciiMap();
239 		map.append((char)0, "null");
240 		assertTrue(map.contains(0));
241 	}
242 
243 	@Test
244 	void c06_contains_int_asciiMax() {
245 		var map = new AsciiMap();
246 		map.append((char)127, "del");
247 		assertTrue(map.contains(127));
248 	}
249 
250 	@Test
251 	void c07_contains_int_negative() {
252 		var map = new AsciiMap();
253 		assertFalse(map.contains(-1));
254 	}
255 
256 	@Test
257 	void c08_contains_int_above127() {
258 		var map = new AsciiMap();
259 		assertFalse(map.contains(128));
260 	}
261 
262 	@Test
263 	void c09_contains_int_largeValue() {
264 		var map = new AsciiMap();
265 		assertFalse(map.contains(1000));
266 	}
267 
268 	//====================================================================================================
269 	// contains(CharSequence) - Basic cases
270 	//====================================================================================================
271 	@Test
272 	void d01_contains_CharSequence_present() {
273 		var map = new AsciiMap();
274 		map.append('a', "value1");
275 		assertTrue(map.contains("abc"));
276 	}
277 
278 	@Test
279 	void d02_contains_CharSequence_notPresent() {
280 		var map = new AsciiMap();
281 		map.append('a', "value1");
282 		assertFalse(map.contains("xyz"));
283 	}
284 
285 	@Test
286 	void d03_contains_CharSequence_null() {
287 		var map = new AsciiMap();
288 		map.append('a', "value1");
289 		assertFalse(map.contains((CharSequence)null));
290 	}
291 
292 	@Test
293 	void d04_contains_CharSequence_empty() {
294 		var map = new AsciiMap();
295 		map.append('a', "value1");
296 		assertFalse(map.contains(""));
297 	}
298 
299 	@Test
300 	void d05_contains_CharSequence_multipleMatches() {
301 		var map = new AsciiMap();
302 		map.append('a', "value1");
303 		map.append('b', "value2");
304 		assertTrue(map.contains("abc"));
305 	}
306 
307 	@Test
308 	void d06_contains_CharSequence_firstChar() {
309 		var map = new AsciiMap();
310 		map.append('a', "value1");
311 		assertTrue(map.contains("abc"));
312 	}
313 
314 	@Test
315 	void d07_contains_CharSequence_middleChar() {
316 		var map = new AsciiMap();
317 		map.append('b', "value2");
318 		assertTrue(map.contains("abc"));
319 	}
320 
321 	@Test
322 	void d08_contains_CharSequence_lastChar() {
323 		var map = new AsciiMap();
324 		map.append('c', "value3");
325 		assertTrue(map.contains("abc"));
326 	}
327 
328 	@Test
329 	void d09_contains_CharSequence_singleChar() {
330 		var map = new AsciiMap();
331 		map.append('a', "value1");
332 		assertTrue(map.contains("a"));
333 	}
334 
335 	@Test
336 	void d10_contains_CharSequence_StringBuilder() {
337 		var map = new AsciiMap();
338 		map.append('a', "value1");
339 		var sb = new StringBuilder("abc");
340 		assertTrue(map.contains(sb));
341 	}
342 
343 	@Test
344 	void d11_contains_CharSequence_StringBuffer() {
345 		var map = new AsciiMap();
346 		map.append('a', "value1");
347 		var sb = new StringBuffer("abc");
348 		assertTrue(map.contains(sb));
349 	}
350 
351 	//====================================================================================================
352 	// contains(CharSequence) - Edge cases
353 	//====================================================================================================
354 	@Test
355 	void d12_contains_CharSequence_withNonAscii() {
356 		var map = new AsciiMap();
357 		map.append('a', "value1");
358 		// String contains non-ASCII character, but also contains 'a'
359 		assertTrue(map.contains("a€"));
360 	}
361 
362 	@Test
363 	void d13_contains_CharSequence_onlyNonAscii() {
364 		var map = new AsciiMap();
365 		map.append('a', "value1");
366 		assertFalse(map.contains("€"));
367 	}
368 
369 	@Test
370 	void d14_contains_CharSequence_nullValueInMap() {
371 		var map = new AsciiMap();
372 		map.append('a', null);
373 		// null values don't count as "contained"
374 		assertFalse(map.contains("a"));
375 	}
376 
377 	//====================================================================================================
378 	// get(char) - Basic cases
379 	//====================================================================================================
380 	@Test
381 	void e01_get_char_present() {
382 		var map = new AsciiMap();
383 		map.append('a', "value1");
384 		assertEquals("value1", map.get('a'));
385 	}
386 
387 	@Test
388 	void e02_get_char_notPresent() {
389 		var map = new AsciiMap();
390 		assertNull(map.get('a'));
391 	}
392 
393 	@Test
394 	void e03_get_char_nullValue() {
395 		var map = new AsciiMap();
396 		map.append('a', null);
397 		assertNull(map.get('a'));
398 	}
399 
400 	@Test
401 	void e04_get_char_emptyString() {
402 		var map = new AsciiMap();
403 		map.append('a', "");
404 		assertEquals("", map.get('a'));
405 	}
406 
407 	@Test
408 	void e05_get_char_multiple() {
409 		var map = new AsciiMap();
410 		map.append('a', "value1");
411 		map.append('b', "value2");
412 		map.append('c', "value3");
413 		assertEquals("value1", map.get('a'));
414 		assertEquals("value2", map.get('b'));
415 		assertEquals("value3", map.get('c'));
416 	}
417 
418 	//====================================================================================================
419 	// get(char) - Boundary cases
420 	//====================================================================================================
421 	@Test
422 	void e06_get_char_asciiMin() {
423 		var map = new AsciiMap();
424 		map.append((char)0, "null");
425 		assertEquals("null", map.get((char)0));
426 	}
427 
428 	@Test
429 	void e07_get_char_asciiMax() {
430 		var map = new AsciiMap();
431 		map.append((char)127, "del");
432 		assertEquals("del", map.get((char)127));
433 	}
434 
435 	@Test
436 	void e08_get_char_nonAscii_above127() {
437 		var map = new AsciiMap();
438 		// get() doesn't check bounds, so accessing index > 127 will throw ArrayIndexOutOfBoundsException
439 		assertThrows(ArrayIndexOutOfBoundsException.class, () -> {
440 			map.get((char)128);
441 		});
442 	}
443 
444 	@Test
445 	void e09_get_char_unicode() {
446 		var map = new AsciiMap();
447 		// Unicode characters > 127 will cause ArrayIndexOutOfBoundsException
448 		assertThrows(ArrayIndexOutOfBoundsException.class, () -> {
449 			map.get('€');
450 		});
451 	}
452 
453 	//====================================================================================================
454 	// Integration tests
455 	//====================================================================================================
456 	@Test
457 	void f01_integration_fullAsciiRange() {
458 		var map = new AsciiMap();
459 		// Add values for all ASCII characters
460 		for (int i = 0; i <= 127; i++) {
461 			map.append((char)i, "value" + i);
462 		}
463 		// Verify all can be retrieved
464 		for (int i = 0; i <= 127; i++) {
465 			assertEquals("value" + i, map.get((char)i));
466 			assertTrue(map.contains((char)i));
467 			assertTrue(map.contains(i));
468 		}
469 	}
470 
471 	@Test
472 	void f02_integration_containsString() {
473 		var map = new AsciiMap();
474 		map.append('a', "value1");
475 		map.append('b', "value2");
476 		map.append('c', "value3");
477 		assertTrue(map.contains("abc"));
478 		assertTrue(map.contains("xyzabc"));
479 		assertTrue(map.contains("a"));
480 		assertFalse(map.contains("xyz"));
481 		assertFalse(map.contains(""));
482 	}
483 
484 	@Test
485 	void f03_integration_overwriteAndRetrieve() {
486 		var map = new AsciiMap();
487 		map.append('a', "value1");
488 		assertEquals("value1", map.get('a'));
489 		map.append('a', "value2");
490 		assertEquals("value2", map.get('a'));
491 		assertTrue(map.contains('a'));
492 	}
493 
494 	@Test
495 	void f04_integration_mixedOperations() {
496 		var map = new AsciiMap();
497 		map.append('a', "value1")
498 			.append('b', "value2")
499 			.append('c', "value3");
500 		assertTrue(map.contains('a'));
501 		assertTrue(map.contains("abc"));
502 		assertEquals("value1", map.get('a'));
503 		assertTrue(map.contains(98)); // 'b' as int
504 		assertFalse(map.contains('d'));
505 		assertFalse(map.contains("xyz"));
506 	}
507 }
508