1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.atlassian.fugue.extras;
17
18 import static com.google.common.collect.Maps.immutableEntry;
19 import static org.hamcrest.Matchers.equalTo;
20 import static org.junit.Assert.assertThat;
21
22 import java.util.Arrays;
23 import java.util.Map;
24 import java.util.function.BiFunction;
25 import java.util.function.Function;
26
27 import javax.annotation.Nullable;
28
29 import org.junit.Test;
30
31 import io.atlassian.fugue.Functions;
32 import io.atlassian.fugue.Option;
33 import com.google.common.collect.ImmutableMap;
34 import com.google.common.collect.Maps;
35
36 public class ImmutableMapsTest {
37
38 @Test public void mapEntry() {
39 BiFunction<String, Integer, Map.Entry<String, Integer>> mapEntryFunction = ImmutableMaps.mapEntry();
40 Map.Entry<String, Integer> entry = mapEntryFunction.apply("abc", 1);
41 assertThat(entry.getKey(), equalTo("abc"));
42 assertThat(entry.getValue(), equalTo(1));
43 }
44
45 @Test public void toMap() {
46 Iterable<Map.Entry<String, Integer>> source = list(immutableEntry("a", 1), immutableEntry("b", 2), immutableEntry("c", 3));
47
48 assertThat(ImmutableMaps.toMap(source), equalTo(ImmutableMap.of("a", 1, "b", 2, "c", 3)));
49 }
50
51 @Test public void toMapContainingNull() {
52 assertThat(ImmutableMaps.toMap(list(immutableEntry("a", 1), null, immutableEntry("c", 3))), equalTo(ImmutableMap.of("a", 1, "c", 3)));
53 }
54
55 @Test public void toMapWithNullKey() {
56 assertThat(ImmutableMaps.toMap(list(immutableEntry("a", 1), Maps.<String, Integer> immutableEntry(null, 2), immutableEntry("c", 3))),
57 equalTo(ImmutableMap.of("a", 1, "c", 3)));
58 }
59
60 @Test public void toMapWithNullValue() {
61 assertThat(ImmutableMaps.toMap(list(immutableEntry("a", 1), Maps.<String, Integer> immutableEntry("b", null), immutableEntry("c", 3))),
62 equalTo(ImmutableMap.of("a", 1, "c", 3)));
63 }
64
65 @Test public void toMapFunction() {
66 assertThat(ImmutableMaps.toMap(list(1, 2, 3), Functions.<Integer> identity(), Object::toString), equalTo(ImmutableMap.of(1, "1", 2, "2", 3, "3")));
67 }
68
69 @Test public void toMapFunctionVariance() {
70 Function<GrandParent, Child> f = input -> new Child(input.num());
71 assertThat(ImmutableMaps.<Parent, Parent, Parent> toMap(list(new Parent(1), new Parent(2), new Parent(3)), f, f),
72 equalTo(ImmutableMap.<Parent, Parent> of(new Child(1), new Child(1), new Child(2), new Child(2), new Child(3), new Child(3))));
73 }
74
75
76 @Test(expected = IllegalArgumentException.class) public void toMapWithDuplicateKey() {
77 ImmutableMaps.toMap(list(immutableEntry("a", 1), immutableEntry("b", 2), immutableEntry("b", 3)));
78 }
79
80 @Test public void transformIterablesToMap() {
81 assertThat(ImmutableMaps.toMap(list(1, 2, 3), new Function<Integer, String>() {
82 @Override public String apply(Integer input) {
83 return "-" + input;
84 }
85 }, new Function<Integer, Integer>() {
86 @Override public Integer apply(Integer input) {
87 return input * -1;
88 }
89 }), equalTo(ImmutableMap.of("-1", -1, "-2", -2, "-3", -3)));
90 }
91
92 @Test public void transformIterablesToMapContainingNull() {
93 assertThat(ImmutableMaps.toMap(list(1, null, 3), new Function<Integer, String>() {
94 @Override public String apply(Integer input) {
95 return "-" + input;
96 }
97 }, new Function<Integer, Integer>() {
98 @Override public Integer apply(Integer input) {
99 return input == null ? 0 : input * -1;
100 }
101 }), equalTo(ImmutableMap.of("-1", -1, "-null", 0, "-3", -3)));
102 }
103
104 @Test public void transformIterablesToMapGeneratingNullKey() {
105 assertThat(ImmutableMaps.toMap(list(1, null, 3), new Function<Integer, String>() {
106 @Override public String apply(Integer input) {
107 return input == null ? null : "-" + input;
108 }
109 }, new Function<Integer, Integer>() {
110 @Override public Integer apply(Integer input) {
111 return input == null ? 0 : input * -1;
112 }
113 }), equalTo(ImmutableMap.of("-1", -1, "-3", -3)));
114 }
115
116 @Test public void transformIterablesToMapGeneratingNullValue() {
117 assertThat(ImmutableMaps.toMap(list(1, null, 3), new Function<Integer, String>() {
118 @Override public String apply(Integer input) {
119 return "-" + input;
120 }
121 }, new Function<Integer, Integer>() {
122 @Override public Integer apply(Integer input) {
123 return input == null ? null : input * -1;
124 }
125 }), equalTo(ImmutableMap.of("-1", -1, "-3", -3)));
126 }
127
128 @Test(expected = IllegalArgumentException.class) public void transformIterablesToMapGeneratingDuplicateKey() {
129 ImmutableMaps.toMap(list(1, 2, 3), new Function<Integer, String>() {
130 @Override public String apply(Integer input) {
131 return String.valueOf(input % 2);
132 }
133 }, new Function<Integer, Integer>() {
134 @Override public Integer apply(Integer input) {
135 return input * -1;
136 }
137 });
138 }
139
140 @Test public void mapBy() {
141 assertThat(ImmutableMaps.mapBy(list(1, 2, 3), new Function<Integer, String>() {
142 @Override public String apply(Integer input) {
143 return "+" + input;
144 }
145 }), equalTo(ImmutableMap.of("+1", 1, "+2", 2, "+3", 3)));
146 }
147
148 @Test public void mapByContravariantKeyFunction() {
149 assertThat(ImmutableMaps.mapBy(list(new Child(1), new Child(2), new Child(3)), new Function<Parent, String>() {
150 @Override public String apply(Parent input) {
151 return "+" + input.num();
152 }
153 }), equalTo(ImmutableMap.of("+1", new Child(1), "+2", new Child(2), "+3", new Child(3))));
154 }
155
156 @Test public void mapByContainingNull() {
157 assertThat(ImmutableMaps.mapBy(list(1, null, 3), new Function<Integer, String>() {
158 @Override public String apply(Integer input) {
159 return "+" + input;
160 }
161 }), equalTo(ImmutableMap.of("+1", 1, "+3", 3)));
162 }
163
164 @Test(expected = IllegalArgumentException.class) public void mapByDuplicateKey() {
165 ImmutableMaps.mapBy(list(1, 2, 3), new Function<Integer, String>() {
166 @Override public String apply(Integer input) {
167 return "+" + (input % 2);
168 }
169 });
170 }
171
172 @Test public void mapTo() {
173 assertThat(ImmutableMaps.mapTo(list(1, 2, 3), new Function<Integer, String>() {
174 @Override public String apply(Integer input) {
175 return "+" + input;
176 }
177 }), equalTo(ImmutableMap.of(1, "+1", 2, "+2", 3, "+3")));
178 }
179
180 @Test public void mapToContainingNull() {
181 assertThat(ImmutableMaps.mapTo(list(1, null, 3), new Function<Integer, String>() {
182 @Override public String apply(Integer input) {
183 return "+" + input;
184 }
185 }), equalTo(ImmutableMap.of(1, "+1", 3, "+3")));
186 }
187
188 @Test(expected = IllegalArgumentException.class) public void mapToContainingDuplicates() {
189 ImmutableMaps.mapTo(list(1, 2, 1), new Function<Integer, String>() {
190 @Override public String apply(Integer input) {
191 return "+" + input;
192 }
193 });
194 }
195
196 @Test public void mapToVariance() {
197 assertThat(ImmutableMaps.<Integer, Parent> mapTo(list(1, 2, 3), new Function<Number, Child>() {
198 @Override public Child apply(Number input) {
199 return new Child((Integer) input);
200 }
201 }), equalTo(ImmutableMap.of(1, new Parent(1), 2, new Parent(2), 3, new Parent(3))));
202 }
203
204 @Test public void transformEntries() {
205 assertThat(
206 ImmutableMaps.transform(ImmutableMap.of("a", 1, "b", 2, "c", 3), new Function<Map.Entry<String, Integer>, Map.Entry<Integer, String>>() {
207 @Override public Map.Entry<Integer, String> apply(@Nullable Map.Entry<String, Integer> input) {
208 return immutableEntry(input.getValue() * 2, input.getKey() + input.getKey());
209 }
210 }), equalTo(ImmutableMap.of(2, "aa", 4, "bb", 6, "cc")));
211 }
212
213 @Test public void transformEntriesContainingNullKey() {
214 Map<String, Integer> source = Maps.newHashMap();
215 source.put("a", 1);
216 source.put(null, 2);
217 source.put("c", 3);
218
219 assertThat(ImmutableMaps.transform(source, new Function<Map.Entry<String, Integer>, Map.Entry<Integer, String>>() {
220 @Override public Map.Entry<Integer, String> apply(@Nullable Map.Entry<String, Integer> input) {
221 return immutableEntry(input.getValue() * 2, input.getKey() + input.getKey());
222 }
223 }), equalTo(ImmutableMap.of(2, "aa", 4, "nullnull", 6, "cc")));
224 }
225
226 @Test public void transformEntriesContainingNullValue() {
227 Map<Integer, String> source = Maps.newHashMap();
228 source.put(1, "a");
229 source.put(2, null);
230 source.put(3, "c");
231
232 assertThat(ImmutableMaps.transform(source, new Function<Map.Entry<Integer, String>, Map.Entry<String, Integer>>() {
233 @Override public Map.Entry<String, Integer> apply(@Nullable Map.Entry<Integer, String> input) {
234 return immutableEntry(input.getValue() + input.getValue(), input.getKey() * 2);
235 }
236 }), equalTo(ImmutableMap.of("aa", 2, "nullnull", 4, "cc", 6)));
237 }
238
239 @Test public void transformEntriesReturningNull() {
240 assertThat(
241 ImmutableMaps.transform(ImmutableMap.of(1, "a", 2, "b", 3, "c"), new Function<Map.Entry<Integer, String>, Map.Entry<String, Integer>>() {
242 @Override public Map.Entry<String, Integer> apply(@Nullable Map.Entry<Integer, String> input) {
243 return input.getKey() % 2 == 0 ? null : immutableEntry(input.getValue() + input.getValue(), input.getKey() * 2);
244 }
245 }), equalTo(ImmutableMap.of("aa", 2, "cc", 6)));
246 }
247
248 @Test public void transformEntriesReturningNullKey() {
249 assertThat(
250 ImmutableMaps.transform(ImmutableMap.of(1, "a", 2, "b", 3, "c"), new Function<Map.Entry<Integer, String>, Map.Entry<String, Integer>>() {
251 @Override public Map.Entry<String, Integer> apply(@Nullable Map.Entry<Integer, String> input) {
252 return immutableEntry(input.getKey() % 2 == 0 ? null : input.getValue() + input.getValue(), input.getKey() * 2);
253 }
254 }), equalTo(ImmutableMap.of("aa", 2, "cc", 6)));
255 }
256
257 @Test public void transformEntriesReturningNullValue() {
258 assertThat(
259 ImmutableMaps.transform(ImmutableMap.of(1, "a", 2, "b", 3, "c"), new Function<Map.Entry<Integer, String>, Map.Entry<String, Integer>>() {
260 @Override public Map.Entry<String, Integer> apply(@Nullable Map.Entry<Integer, String> input) {
261 return immutableEntry(input.getValue() + input.getValue(), input.getKey() % 2 == 0 ? null : input.getKey() * 2);
262 }
263 }), equalTo(ImmutableMap.of("aa", 2, "cc", 6)));
264 }
265
266 @Test(expected = IllegalArgumentException.class) public void transformEntriesReturningDuplicateKey() {
267 ImmutableMaps.transform(ImmutableMap.of("a", 1, "b", 2, "c", 3), new Function<Map.Entry<String, Integer>, Map.Entry<Integer, String>>() {
268 @Override public Map.Entry<Integer, String> apply(@Nullable Map.Entry<String, Integer> input) {
269 return immutableEntry(input.getValue() % 2, input.getKey() + input.getKey());
270 }
271 });
272 }
273
274 @Test public void transformKeysAndValues() {
275 assertThat(ImmutableMaps.transform(ImmutableMap.of("a", 1, "bb", 2, "ccc", 3), new Function<String, Integer>() {
276 @Override public Integer apply(@Nullable String input) {
277 return input == null ? 0 : input.length();
278 }
279 }, new Function<Integer, Boolean>() {
280 @Override public Boolean apply(@Nullable Integer input) {
281 return input != null && input % 2 != 0;
282 }
283 }), equalTo(ImmutableMap.of(1, true, 2, false, 3, true)));
284 }
285
286 @Test public void transformKeysAndValuesContainingNullKey() {
287 Map<String, Integer> source = Maps.newHashMap();
288 source.put("a", 1);
289 source.put(null, 2);
290 source.put("ccc", 3);
291
292 assertThat(ImmutableMaps.transform(source, new Function<String, Integer>() {
293 @Override public Integer apply(@Nullable String input) {
294 return input == null ? 0 : input.length();
295 }
296 }, new Function<Integer, Boolean>() {
297 @Override public Boolean apply(@Nullable Integer input) {
298 return input != null && input % 2 != 0;
299 }
300 }), equalTo(ImmutableMap.of(1, true, 0, false, 3, true)));
301 }
302
303 @Test public void transformKeysAndValuesContainingNullValue() {
304 Map<Integer, String> source = Maps.newHashMap();
305 source.put(1, "a");
306 source.put(2, null);
307 source.put(3, "ccc");
308
309 assertThat(ImmutableMaps.transform(source, new Function<Integer, String>() {
310 @Override public String apply(@Nullable Integer input) {
311 return "(" + input + ")";
312 }
313 }, new Function<String, Integer>() {
314 @Override public Integer apply(@Nullable String input) {
315 return input == null ? 0 : input.length();
316 }
317 }), equalTo(ImmutableMap.of("(1)", 1, "(2)", 0, "(3)", 3)));
318 }
319
320 @Test public void transformKeysAndValuesReturningNullKey() {
321 Map<String, Integer> source = Maps.newHashMap();
322 source.put("a", 1);
323 source.put(null, 2);
324 source.put("ccc", 3);
325
326 assertThat(ImmutableMaps.transform(source, new Function<String, Integer>() {
327 @Override public Integer apply(@Nullable String input) {
328 return input == null ? null : input.length();
329 }
330 }, new Function<Integer, Boolean>() {
331 @Override public Boolean apply(@Nullable Integer input) {
332 return input != null && input % 2 != 0;
333 }
334 }), equalTo(ImmutableMap.of(1, true, 3, true)));
335 }
336
337 @Test public void transformKeysAndValuesReturningNullValue() {
338 Map<Integer, String> source = Maps.newHashMap();
339 source.put(1, "a");
340 source.put(2, null);
341 source.put(3, "ccc");
342
343 assertThat(ImmutableMaps.transform(source, new Function<Integer, String>() {
344 @Override public String apply(@Nullable Integer input) {
345 return "(" + input + ")";
346 }
347 }, new Function<String, Integer>() {
348 @Override public Integer apply(@Nullable String input) {
349 return input == null ? null : input.length();
350 }
351 }), equalTo(ImmutableMap.of("(1)", 1, "(3)", 3)));
352 }
353
354 @Test(expected = IllegalArgumentException.class) public void transformKeysAndValuesReturningDuplicateKey() {
355 ImmutableMaps.transform(ImmutableMap.of(1, "a", 2, "b", 3, "c"), new Function<Integer, Boolean>() {
356 @Override public Boolean apply(@Nullable Integer input) {
357 return input != null && input % 2 != 0;
358 }
359 }, new Function<String, Integer>() {
360 @Override public Integer apply(@Nullable String input) {
361 return input == null ? 0 : input.length();
362 }
363 });
364 }
365
366 @Test public void transformKey() {
367 assertThat(ImmutableMaps.transformKey(ImmutableMap.of("a", 10, "bb", 20, "ccc", 30), new Function<String, Integer>() {
368 @Override public Integer apply(@Nullable String input) {
369 return input == null ? 0 : input.length();
370 }
371 }), equalTo(ImmutableMap.of(1, 10, 2, 20, 3, 30)));
372 }
373
374 @Test public void transformKeyContainingNullKey() {
375 Map<String, Integer> source = Maps.newHashMap();
376 source.put("a", 10);
377 source.put(null, 20);
378 source.put("ccc", 30);
379
380 assertThat(ImmutableMaps.transformKey(source, new Function<String, Integer>() {
381 @Override public Integer apply(@Nullable String input) {
382 return input == null ? 0 : input.length();
383 }
384 }), equalTo(ImmutableMap.of(1, 10, 0, 20, 3, 30)));
385 }
386
387 @Test public void transformKeyContainingNullValue() {
388 Map<Integer, String> source = Maps.newHashMap();
389 source.put(1, "a");
390 source.put(2, null);
391 source.put(3, "ccc");
392
393 assertThat(ImmutableMaps.transformKey(source, new Function<Integer, String>() {
394 @Override public String apply(@Nullable Integer input) {
395 return "(" + input + ")";
396 }
397 }), equalTo(ImmutableMap.of("(1)", "a", "(3)", "ccc")));
398 }
399
400 @Test public void transformKeyReturningNullKey() {
401 Map<String, Integer> source = Maps.newHashMap();
402 source.put("a", 11);
403 source.put(null, 12);
404 source.put("ccc", 13);
405
406 assertThat(ImmutableMaps.transformKey(source, new Function<String, Integer>() {
407 @Override public Integer apply(@Nullable String input) {
408 return input == null ? null : input.length();
409 }
410 }), equalTo(ImmutableMap.of(1, 11, 3, 13)));
411 }
412
413 @Test(expected = IllegalArgumentException.class) public void transformKeyReturningDuplicateKey() {
414 ImmutableMaps.transformKey(ImmutableMap.of(1, "a", 2, "b", 3, "c"), new Function<Integer, Boolean>() {
415 @Override public Boolean apply(@Nullable Integer input) {
416 return input != null && input % 2 != 0;
417 }
418 });
419 }
420
421 @Test public void transformValue() {
422 assertThat(ImmutableMaps.transformValue(ImmutableMap.of("a", 1, "bb", 2, "ccc", 3), new Function<Integer, Boolean>() {
423 @Override public Boolean apply(@Nullable Integer input) {
424 return input != null && input % 2 != 0;
425 }
426 }), equalTo(ImmutableMap.of("a", true, "bb", false, "ccc", true)));
427 }
428
429 @Test public void transformValueContainingNullKey() {
430 Map<String, Integer> source = Maps.newHashMap();
431 source.put("a", 1);
432 source.put(null, 2);
433 source.put("ccc", 3);
434
435 assertThat(ImmutableMaps.transformValue(source, new Function<Integer, Boolean>() {
436 @Override public Boolean apply(@Nullable Integer input) {
437 return input != null && input % 2 != 0;
438 }
439 }), equalTo(ImmutableMap.of("a", true, "ccc", true)));
440 }
441
442 @Test public void transformValueContainingNullValue() {
443 Map<Integer, String> source = Maps.newHashMap();
444 source.put(11, "a");
445 source.put(12, null);
446 source.put(13, "ccc");
447
448 assertThat(ImmutableMaps.transformValue(source, new Function<String, Integer>() {
449 @Override public Integer apply(@Nullable String input) {
450 return input == null ? 0 : input.length();
451 }
452 }), equalTo(ImmutableMap.of(11, 1, 12, 0, 13, 3)));
453 }
454
455 @Test public void transformValueReturningNullValue() {
456 Map<Integer, String> source = Maps.newHashMap();
457 source.put(11, "a");
458 source.put(12, null);
459 source.put(13, "ccc");
460
461 assertThat(ImmutableMaps.transformValue(source, new Function<String, Integer>() {
462 @Override public Integer apply(@Nullable String input) {
463 return input == null ? null : input.length();
464 }
465 }), equalTo(ImmutableMap.of(11, 1, 13, 3)));
466 }
467
468 @Test public void collectEntries() {
469 assertThat(ImmutableMaps.collect(ImmutableMap.of(1, "a", 2, "bb", 3, "ccc"),
470 new Function<Map.Entry<Integer, String>, Option<Map.Entry<String, Integer>>>() {
471 @Override public Option<Map.Entry<String, Integer>> apply(@Nullable Map.Entry<Integer, String> input) {
472 if (input == null || input.getKey() == null || input.getKey() % 2 == 0 || input.getValue() == null) {
473 return Option.none();
474 }
475 return Option.some(immutableEntry(String.valueOf(input.getKey() * 2), input.getValue().length()));
476 }
477 }), equalTo(ImmutableMap.of("2", 1, "6", 3)));
478 }
479
480 @Test public void collectKeysAndValuesWithEitherReturningNone() {
481 assertThat(ImmutableMaps.collect(ImmutableMap.of(1, "a", 2, "bbb", 3, "cc"), new Function<Integer, Option<String>>() {
482 @Override public Option<String> apply(@Nullable Integer input) {
483 return input != null && input % 2 > 0 ? Option.some(String.valueOf(input * 2)) : Option.none(String.class);
484 }
485 }, new Function<String, Option<Integer>>() {
486 @Override public Option<Integer> apply(@Nullable String input) {
487 return input != null && input.length() % 2 > 0 ? Option.some(input.length()) : Option.none(Integer.class);
488 }
489 }), equalTo(ImmutableMap.of("2", 1)));
490 }
491
492 @Test public void collectByKey() {
493 assertThat(ImmutableMaps.collectByKey(ImmutableMap.of(1, "a", 2, "bb", 3, "cccc"), new Function<Integer, Option<String>>() {
494 @Override public Option<String> apply(@Nullable Integer input) {
495 return input != null && input % 2 > 0 ? Option.some(String.valueOf(input * 2)) : Option.none(String.class);
496 }
497 }), equalTo(ImmutableMap.of("2", "a", "6", "cccc")));
498 }
499
500 @Test public void collectByKeyContravariantKeyFunction() {
501 assertThat(ImmutableMaps.collectByKey(ImmutableMap.of(new Child(2), "a", new Child(3), "bb", new Child(6), "cccc"),
502 new Function<Parent, Option<String>>() {
503 @Override public Option<String> apply(@Nullable Parent input) {
504 return input.num() % 2 == 0 ? Option.some(String.valueOf(input.num())) : Option.<String> none();
505 }
506 }), equalTo(ImmutableMap.of("2", "a", "6", "cccc")));
507 }
508
509 @Test public void collectByValue() {
510 assertThat(ImmutableMaps.collectByValue(ImmutableMap.of(1, "a", 2, "bb", 3, "ccccc"), new Function<String, Option<Integer>>() {
511 @Override public Option<Integer> apply(@Nullable String input) {
512 return input != null && input.length() % 2 > 0 ? Option.some(input.length()) : Option.none(Integer.class);
513 }
514 }), equalTo(ImmutableMap.of(1, 1, 3, 5)));
515 }
516
517 @Test public void collectByValueContravariantKeyFunction() {
518 assertThat(
519 ImmutableMaps.collectByValue(ImmutableMap.of(2, new Child(2), 3, new Child(3), 6, new Child(6)), new Function<Parent, Option<String>>() {
520 @Override public Option<String> apply(@Nullable Parent input) {
521 return input.num() % 2 == 0 ? Option.some(String.valueOf(input.num())) : Option.<String> none();
522 }
523 }), equalTo(ImmutableMap.of(2, "2", 6, "6")));
524 }
525
526 static <A> Iterable<A> list(A a) {
527 return Arrays.asList(a);
528 }
529
530 static <A> Iterable<A> list(A a1, A a2) {
531 return Arrays.asList(a1, a2);
532 }
533
534 static <A> Iterable<A> list(A a1, A a2, A a3) {
535 return Arrays.asList(a1, a2, a3);
536 }
537
538 static class GrandParent {
539 int num() {
540 return Integer.MIN_VALUE;
541 }
542
543 @Override public int hashCode() {
544 return num();
545 }
546
547 @Override public boolean equals(Object obj) {
548 return num() == ((GrandParent) obj).num();
549 }
550 }
551
552 static class Parent extends GrandParent {
553 final int num;
554
555 Parent(int num) {
556 this.num = num;
557 }
558
559 Parent() {
560 this.num = -1;
561 }
562
563 int num() {
564 return num;
565 }
566 }
567
568 static class Child extends Parent {
569 Child(int num) {
570 super(num);
571 }
572 }
573 }