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