1 module MultiMapDemo;
2 
3 import std.stdio;
4 import std.conv;
5 import std.range;
6 
7 import hunt.collection.ArrayList;
8 import hunt.collection.HashMap;
9 import hunt.collection.List;
10 import hunt.collection.Map;
11 import hunt.collection.MultiMap;
12 
13 import hunt.Assert;
14 import hunt.text;
15 import hunt.util.TypeUtils;
16 
17 // alias assertTrue = Assert.assertTrue;
18 // alias assertFalse = Assert.assertFalse;
19 // alias assertThat = Assert.assertThat;
20 // alias assertEquals = Assert.assertEquals;
21 // alias assertNull = Assert.assertNull;
22 
23 class MultiMapDemo {
24 
25     void testBasicOperations() {
26         MultiMap!string outdoorElements = new MultiMap!string();
27         outdoorElements.add("fish", "walleye");
28         outdoorElements.add("fish", "muskellunge");
29         outdoorElements.add("fish", "bass");
30         outdoorElements.add("insect", "ants");
31         outdoorElements.add("insect", "water boatman");
32         outdoorElements.add("insect", "Lord Howe Island stick insect");
33         outdoorElements.add("tree", "oak");
34         outdoorElements.add("tree", "birch");
35 
36         List!(string) fishies = outdoorElements.getValues("fish");
37 
38         writeln("found fishies: ");
39         foreach(string name; fishies) {
40             writeln("\t", name);
41         }
42 
43         assert(fishies.size() == 3);
44     }
45 
46     /**
47 	 * Tests {@link MultiMap#put(Object, Object)}
48 	 */
49 	void testPut() {
50 		MultiMap!(string) mm = new MultiMap!(string)();
51 
52 		string key = "formats";
53 
54 		mm.put(key, "gzip");
55 		assertMapSize(mm, 1);
56 		assertValues(mm, key, "gzip");
57 	}
58 
59 	/**
60 	 * Tests {@link MultiMap#put(Object, Object)}
61 	 */
62 	void testPut_Null_String() {
63 		MultiMap!(string) mm = new MultiMap!(string)();
64 
65 		string key = "formats";
66 		string val = null;
67 
68 		mm.put(key, val);
69 		assertMapSize(mm, 1);
70 		assertNullValues(mm, key);
71 	}
72 
73 	/**
74 	 * Tests {@link MultiMap#put(Object, Object)}
75 	 */
76 	void testPut_Null_List() {
77 		MultiMap!(string) mm = new MultiMap!(string)();
78 
79 		string key = "formats";
80 		List!(string) vals = null;
81 
82 		mm.put(key, vals);
83 		assertMapSize(mm, 1);
84 		assertNullValues(mm, key);
85 	}
86 
87 	/**
88 	 * Tests {@link MultiMap#put(Object, Object)}
89 	 */
90 	void testPut_Replace() {
91 		MultiMap!(string) mm = new MultiMap!(string)();
92 
93 		string key = "formats";
94 		List!(string) ret;
95 
96 		ret = mm.put(key, "gzip");
97 		assertMapSize(mm, 1);
98 		assertValues(mm, key, "gzip");
99 		Assert.assertNull("Should not have replaced anything", ret);
100 		List!(string) orig = mm.get(key);
101 
102 		// Now replace it
103 		ret = mm.put(key, "jar");
104 		assertMapSize(mm, 1);
105 		assertValues(mm, key, "jar");
106 		Assert.assertEquals("Should have replaced original", orig, ret);
107 	}
108 
109 	/**
110 	 * Tests {@link MultiMap#putValues(string, List)}
111 	 */
112 	void testPutValues_List() {
113 		MultiMap!(string) mm = new MultiMap!(string)();
114 
115 		string key = "formats";
116 
117 		List!(string) input = new ArrayList!(string)();
118 		input.add("gzip");
119 		input.add("jar");
120 		input.add("pack200");
121 
122 		mm.putValues(key, input);
123 		assertMapSize(mm, 1);
124 		assertValues(mm, key, "gzip", "jar", "pack200");
125 	}
126 
127 	void testPutValues_StringArray() {
128 		MultiMap!(string) mm = new MultiMap!(string)();
129 
130 		string key = "formats";
131 
132 		string[] input = ["gzip", "jar", "pack200" ];
133 		mm.putValues(key, input);
134 		assertMapSize(mm, 1);
135 		assertValues(mm, key, "gzip", "jar", "pack200");
136 	}
137 
138 	void testPutValues_VarArgs() {
139 		MultiMap!(string) mm = new MultiMap!(string)();
140 
141 		string key = "formats";
142 
143 		mm.putValues(key, "gzip", "jar", "pack200");
144 		assertMapSize(mm, 1);
145 		assertValues(mm, key, "gzip", "jar", "pack200");
146 	}
147 
148 	/**
149 	 * Tests {@link MultiMap#add(string, Object)}
150 	 */
151 	void testAdd() {
152 		MultiMap!(string) mm = new MultiMap!(string)();
153 
154 		string key = "formats";
155 
156 		// Setup the key
157 		mm.put(key, "gzip");
158 		assertMapSize(mm, 1);
159 		assertValues(mm, key, "gzip");
160 
161 		// Add to the key
162 		mm.add(key, "jar");
163 		mm.add(key, "pack200");
164 
165 		assertMapSize(mm, 1);
166 		assertValues(mm, key, "gzip", "jar", "pack200");
167 	}
168 
169 	/**
170 	 * Tests {@link MultiMap#addValues(string, List)}
171 	 */
172 	void testAddValues_List() {
173 		MultiMap!(string) mm = new MultiMap!(string)();
174 
175 		string key = "formats";
176 
177 		// Setup the key
178 		mm.put(key, "gzip");
179 		assertMapSize(mm, 1);
180 		assertValues(mm, key, "gzip");
181 
182 		// Add to the key
183 		List!(string) extras = new ArrayList!(string)();
184 		extras.add("jar");
185 		extras.add("pack200");
186 		extras.add("zip");
187 		mm.addValues(key, extras);
188 
189 		assertMapSize(mm, 1);
190 		assertValues(mm, key, "gzip", "jar", "pack200", "zip");
191 	}
192 
193 	/**
194 	 * Tests {@link MultiMap#addValues(string, List)}
195 	 */
196 	void testAddValues_List_Empty() {
197 		MultiMap!(string) mm = new MultiMap!(string)();
198 
199 		string key = "formats";
200 
201 		// Setup the key
202 		mm.put(key, "gzip");
203 		assertMapSize(mm, 1);
204 		assertValues(mm, key, "gzip");
205 
206 		// Add to the key
207 		List!(string) extras = new ArrayList!(string)();
208 		mm.addValues(key, extras);
209 
210 		assertMapSize(mm, 1);
211 		assertValues(mm, key, "gzip");
212 	}
213 
214 	/**
215 	 * Tests {@link MultiMap#addValues(string, Object[])}
216 	 */
217 	void testAddValues_StringArray() {
218 		MultiMap!(string) mm = new MultiMap!(string)();
219 
220 		string key = "formats";
221 
222 		// Setup the key
223 		mm.put(key, "gzip");
224 		assertMapSize(mm, 1);
225 		assertValues(mm, key, "gzip");
226 
227 		// Add to the key
228 		string[] extras = [ "jar", "pack200", "zip" ];
229 		mm.addValues(key, extras);
230 
231 		assertMapSize(mm, 1);
232 		assertValues(mm, key, "gzip", "jar", "pack200", "zip");
233 	}
234 
235 	/**
236 	 * Tests {@link MultiMap#addValues(string, Object[])}
237 	 */
238 	void testAddValues_StringArray_Empty() {
239 		MultiMap!(string) mm = new MultiMap!(string)();
240 
241 		string key = "formats";
242 
243 		// Setup the key
244 		mm.put(key, "gzip");
245 		assertMapSize(mm, 1);
246 		assertValues(mm, key, "gzip");
247 
248 		// Add to the key
249 		string[] extras = new string[0];
250 		mm.addValues(key, extras);
251 
252 		assertMapSize(mm, 1);
253 		assertValues(mm, key, "gzip");
254 	}
255 
256 	/**
257 	 * Tests {@link MultiMap#removeValue(string, Object)}
258 	 */
259 	void testRemoveValue() {
260 		MultiMap!(string) mm = new MultiMap!(string)();
261 
262 		string key = "formats";
263 
264 		// Setup the key
265 		mm.putValues(key, "gzip", "jar", "pack200");
266 		assertMapSize(mm, 1);
267 		assertValues(mm, key, "gzip", "jar", "pack200");
268 
269 		// Remove a value
270 		mm.removeValue(key, "jar");
271 		assertMapSize(mm, 1);
272 		assertValues(mm, key, "gzip", "pack200");
273 
274 	}
275 
276 	/**
277 	 * Tests {@link MultiMap#removeValue(string, Object)}
278 	 */
279 	void testRemoveValue_InvalidItem() {
280 		MultiMap!(string) mm = new MultiMap!(string)();
281 
282 		string key = "formats";
283 
284 		// Setup the key
285 		mm.putValues(key, "gzip", "jar", "pack200");
286 		assertMapSize(mm, 1);
287 		assertValues(mm, key, "gzip", "jar", "pack200");
288 
289 		// Remove a value that isn't there
290 		mm.removeValue(key, "msi");
291 		assertMapSize(mm, 1);
292 		assertValues(mm, key, "gzip", "jar", "pack200");
293 	}
294 
295 	/**
296 	 * Tests {@link MultiMap#removeValue(string, Object)}
297 	 */
298 	void testRemoveValue_AllItems() {
299 		MultiMap!(string) mm = new MultiMap!(string)();
300 
301 		string key = "formats";
302 
303 		// Setup the key
304 		mm.putValues(key, "gzip", "jar", "pack200");
305 		assertMapSize(mm, 1);
306 		assertValues(mm, key, "gzip", "jar", "pack200");
307 
308 		// Remove a value
309 		mm.removeValue(key, "jar");
310 		assertMapSize(mm, 1);
311 		assertValues(mm, key, "gzip", "pack200");
312 
313 		// Remove another value
314 		mm.removeValue(key, "gzip");
315 		assertMapSize(mm, 1);
316 		assertValues(mm, key, "pack200");
317 
318 		// Remove last value
319 		mm.removeValue(key, "pack200");
320 		assertMapSize(mm, 0); // should be empty now
321 	}
322 
323 	/**
324 	 * Tests {@link MultiMap#removeValue(string, Object)}
325 	 */
326 	void testRemoveValue_FromEmpty() {
327 		MultiMap!(string) mm = new MultiMap!(string)();
328 
329 		string key = "formats";
330 
331 		// Setup the key
332 		mm.putValues(key, new string[0]);
333 		assertMapSize(mm, 1);
334 		assertEmptyValues(mm, key);
335 
336 		// Remove a value that isn't in the underlying values
337 		mm.removeValue(key, "jar");
338 		assertMapSize(mm, 1);
339 		assertEmptyValues(mm, key);
340 	}
341 
342 	/**
343 	 * Tests {@link MultiMap#putAll(java.util.Map)}
344 	 */
345 	void testPutAll_Map() {
346 		MultiMap!(string) mm = new MultiMap!(string)();
347 
348 		assertMapSize(mm, 0); // Shouldn't have anything yet.
349 
350 		Map!(string, string) input = new HashMap!(string, string)();
351 		input.put("food", "apple");
352 		input.put("color", "red");
353 		input.put("amount", "bushel");
354 
355 		mm.putAllValues(input);
356 
357 		assertMapSize(mm, 3);
358 		assertValues(mm, "food", "apple");
359 		assertValues(mm, "color", "red");
360 		assertValues(mm, "amount", "bushel");
361 	}
362 
363 	/**
364 	 * Tests {@link MultiMap#putAll(java.util.Map)}
365 	 */
366 	void testPutAll_MultiMap_Simple() {
367 		MultiMap!(string) mm = new MultiMap!(string)();
368 
369 		assertMapSize(mm, 0); // Shouldn't have anything yet.
370 
371 		MultiMap!(string) input = new MultiMap!(string)();
372 		input.put("food", "apple");
373 		input.put("color", "red");
374 		input.put("amount", "bushel");
375 
376 		mm.putAll(input);
377 
378 		assertMapSize(mm, 3);
379 		assertValues(mm, "food", "apple");
380 		assertValues(mm, "color", "red");
381 		assertValues(mm, "amount", "bushel");
382 	}
383 
384 	/**
385 	 * Tests {@link MultiMap#putAll(java.util.Map)}
386 	 */
387 	void testPutAll_MultiMapComplex() {
388 		MultiMap!(string) mm = new MultiMap!(string)();
389 
390 		assertMapSize(mm, 0); // Shouldn't have anything yet.
391 
392 		MultiMap!(string) input = new MultiMap!(string)();
393 		input.putValues("food", "apple", "cherry", "raspberry");
394 		input.put("color", "red");
395 		input.putValues("amount", "bushel", "pint");
396 
397 		mm.putAll(input);
398 
399 		assertMapSize(mm, 3);
400 		assertValues(mm, "food", "apple", "cherry", "raspberry");
401 		assertValues(mm, "color", "red");
402 		assertValues(mm, "amount", "bushel", "pint");
403 	}
404 
405 	/**
406 	 * Tests {@link MultiMap#toStringArrayMap()}
407 	 */
408 	// void testToStringArrayMap() {
409 	// 	MultiMap!(string) mm = new MultiMap!(string)();
410 	// 	mm.putValues("food", "apple", "cherry", "raspberry");
411 	// 	mm.put("color", "red");
412 	// 	mm.putValues("amount", "bushel", "pint");
413 
414 	// 	assertMapSize(mm, 3);
415 
416 	// 	Map!(string, string[]) sam = mm.toStringArrayMap();
417 	// 	Assert.assertEquals("string Array Map.size", 3, sam.size());
418 
419 	// 	assertArray("toStringArrayMap(food)", sam.get("food"), "apple", "cherry", "raspberry");
420 	// 	assertArray("toStringArrayMap(color)", sam.get("color"), "red");
421 	// 	assertArray("toStringArrayMap(amount)", sam.get("amount"), "bushel", "pint");
422 	// }
423 
424 	/**
425 	 * Tests {@link MultiMap#toString()}
426 	 */
427 	void testToString() {
428 		MultiMap!(string) mm = new MultiMap!(string)();
429 		mm.put("color", "red");
430 
431 		Assert.assertEquals("{color=red}", mm.toString());
432 
433 		mm.putValues("food", "apple", "cherry", "raspberry");
434 
435 		// Assert.assertEquals("{color=red, food=[apple, cherry, raspberry]}", mm.toString());
436         Assert.assertEquals("{food=[apple, cherry, raspberry], color=red}", mm.toString());
437 	}
438 
439 	/**
440 	 * Tests {@link MultiMap#clear()}
441 	 */
442 	void testClear() {
443 		MultiMap!(string) mm = new MultiMap!(string)();
444 		mm.putValues("food", "apple", "cherry", "raspberry");
445 		mm.put("color", "red");
446 		mm.putValues("amount", "bushel", "pint");
447 
448 		assertMapSize(mm, 3);
449 
450 		mm.clear();
451 
452 		assertMapSize(mm, 0);
453 	}
454 
455 	/**
456 	 * Tests {@link MultiMap#containsKey(Object)}
457 	 */
458 	void testContainsKey() {
459 		MultiMap!(string) mm = new MultiMap!(string)();
460 		mm.putValues("food", "apple", "cherry", "raspberry");
461 		mm.put("color", "red");
462 		mm.putValues("amount", "bushel", "pint");
463 
464 		Assert.assertTrue("Contains Key [color]", mm.containsKey("color"));
465 		Assert.assertFalse("Contains Key [nutrition]", mm.containsKey("nutrition"));
466 	}
467 
468 	/**
469 	 * Tests {@link MultiMap#containsSimpleValue(Object)}
470 	 */
471 	void testContainsSimpleValue() {
472 		MultiMap!(string) mm = new MultiMap!(string)();
473 		mm.putValues("food", "apple", "cherry", "raspberry");
474 		mm.put("color", "red");
475 		mm.putValues("amount", "bushel", "pint");
476 
477 		Assert.assertTrue("Contains Value [red]", mm.containsSimpleValue("red"));
478         // TODO: Tasks pending completion -@zxp at 9/20/2018, 4:30:01 PM
479         // 
480 		// Assert.assertFalse("Contains Value [nutrition]", mm.containsValue("nutrition"));
481 	}
482 
483 	/**
484 	 * Tests {@link MultiMap#containsValue(Object)}
485 	 */
486 	void testContainsValue() {
487 		MultiMap!(string) mm = new MultiMap!(string)();
488 		mm.putValues("food", "apple", "cherry", "raspberry");
489 		mm.put("color", "red");
490 		mm.putValues("amount", "bushel", "pint");
491 
492 		List!(string) acr = new ArrayList!(string)();
493 		acr.add("apple");
494 		acr.add("cherry");
495 		acr.add("raspberry");
496 		Assert.assertTrue("Contains Value [apple,cherry,raspberry]", mm.containsValue(acr));
497         // TODO: Tasks pending completion -@zxp at 9/20/2018, 4:31:24 PM
498         // 
499 		// Assert.assertFalse("Contains Value [nutrition]", mm.containsValue("nutrition"));
500 	}
501 
502 	/**
503 	 * Tests {@link MultiMap#containsValue(Object)}
504 	 */
505 	// void testContainsValue_LazyList() {
506 	// 	MultiMap!(string) mm = new MultiMap!(string)();
507 	// 	mm.putValues("food", "apple", "cherry", "raspberry");
508 	// 	mm.put("color", "red");
509 	// 	mm.putValues("amount", "bushel", "pint");
510 
511 	// 	Object list = LazyList.add(null, "bushel");
512 	// 	list = LazyList.add(list, "pint");
513 
514 	// 	Assert.assertTrue("Contains Value [" ~ list ~ "]", mm.containsValue(list));
515 	// }
516 
517 	private void assertArray(T)(string prefix, Object[] actualValues, T[] expectedValues... ) {
518 		Assert.assertEquals(prefix ~ ".size", expectedValues.length, actualValues.length);
519 		int len = cast(int)actualValues.length;
520 		for (int i = 0; i < len; i++) {
521 			Assert.assertEquals(prefix ~ "[" ~ i ~ "]", expectedValues[i], actualValues[i]);
522 		}
523 	}
524 
525 	private void assertValues(T)(MultiMap!(string) mm, string key, T[] expectedValues... ) {
526 		List!(string) values = mm.getValues(key);
527 
528 		string prefix = "MultiMap.getValues(" ~ key ~ ")";
529 
530 		Assert.assertEquals(prefix ~ ".size", expectedValues.length, values.size());
531 		int len = cast(int)expectedValues.length;
532 		for (int i = 0; i < len; i++) {
533             static if(is(T == class)) {
534                 if (expectedValues[i] is null) {
535                     Assert.assertThat(prefix ~ "[" ~ i.to!string() ~ "]", values.get(i), null);
536                 } else {
537                     Assert.assertEquals(prefix ~ "[" ~ i.to!string() ~ "]", expectedValues[i], values.get(i));
538                 }
539             } else {
540                 static assert(false, "unsupported type: " ~ T.stringOf);
541             }
542 		}
543 	}
544 
545 	private void assertValues(MultiMap!(string) mm, string key, string[] expectedValues... ) {
546 		List!(string) values = mm.getValues(key);
547 
548 		string prefix = "MultiMap.getValues(" ~ key ~ ")";
549 
550 		Assert.assertEquals(prefix ~ ".size", expectedValues.length, values.size());
551 		int len = cast(int)expectedValues.length;
552 		for (int i = 0; i < len; i++) {
553             if (expectedValues[i] is null) {
554                 Assert.assertThat(prefix ~ "[" ~ i.to!string() ~ "]", values.get(i), null);
555             } else {
556                 Assert.assertEquals(prefix ~ "[" ~ i.to!string() ~ "]", expectedValues[i], values.get(i));
557             } 
558 		}
559 	}
560 
561 	private void assertNullValues(MultiMap!(string) mm, string key) {
562 		List!(string) values = mm.getValues(key);
563 
564 		string prefix = "MultiMap.getValues(" ~ key ~ ")";
565 
566 		Assert.assertThat(prefix ~ ".size", values, null);
567 	}
568 
569 	private void assertEmptyValues(MultiMap!(string) mm, string key) {
570 		List!(string) values = mm.getValues(key);
571 
572 		string prefix = "MultiMap.getValues(" ~ key ~ ")";
573 
574 		Assert.assertEquals(prefix ~ ".size", 0, LazyList.size(values));
575 	}
576 
577 	private void assertMapSize(MultiMap!(string) mm, int expectedSize) {
578 		Assert.assertEquals("MultiMap.size", expectedSize, mm.size());
579 	}
580 
581 }