Resolve collisions in composite collections
Before this commit, creating a CompositeMap from two maps with the same key has strange results, such as entrySet returning duplicate entries with the same key. After this commit, we give precedence to the first map by filtering out all entries in the second map that are also mapped by the first map. See gh-32245
This commit is contained in:
@@ -23,6 +23,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -218,4 +219,85 @@ class CompositeMapTests {
|
||||
Set<Map.Entry<String, String>> entries = composite.entrySet();
|
||||
assertThat(entries).containsExactly(entry("foo", "bar"), entry("baz", "qux"));
|
||||
}
|
||||
|
||||
@Nested
|
||||
class CollisionTests {
|
||||
|
||||
@Test
|
||||
void size() {
|
||||
Map<String, String> first = Map.of("foo", "bar", "baz", "qux");
|
||||
Map<String, String> second = Map.of("baz", "quux", "corge", "grault");
|
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second);
|
||||
|
||||
assertThat(composite).hasSize(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsValue() {
|
||||
Map<String, String> first = Map.of("foo", "bar", "baz", "qux");
|
||||
Map<String, String> second = Map.of("baz", "quux", "corge", "grault");
|
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second);
|
||||
|
||||
assertThat(composite.containsValue("bar")).isTrue();
|
||||
assertThat(composite.containsValue("qux")).isTrue();
|
||||
assertThat(composite.containsValue("quux")).isFalse();
|
||||
assertThat(composite.containsValue("grault")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void get() {
|
||||
Map<String, String> first = Map.of("foo", "bar", "baz", "qux");
|
||||
Map<String, String> second = Map.of("baz", "quux", "corge", "grault");
|
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second);
|
||||
|
||||
assertThat(composite.get("foo")).isEqualTo("bar");
|
||||
assertThat(composite.get("baz")).isEqualTo("qux");
|
||||
assertThat(composite.get("corge")).isEqualTo("grault");
|
||||
}
|
||||
|
||||
@Test
|
||||
void remove() {
|
||||
Map<String, String> first = new HashMap<>(Map.of("foo", "bar", "baz", "qux"));
|
||||
Map<String, String> second = new HashMap<>(Map.of("baz", "quux", "corge", "grault"));
|
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second);
|
||||
|
||||
assertThat(composite.remove("baz")).isEqualTo("qux");
|
||||
assertThat(composite.containsKey("baz")).isFalse();
|
||||
assertThat(first).containsExactly(entry("foo", "bar"));
|
||||
assertThat(second).containsExactly(entry("corge", "grault"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void keySet() {
|
||||
Map<String, String> first = Map.of("foo", "bar", "baz", "qux");
|
||||
Map<String, String> second = Map.of("baz", "quux", "corge", "grault");
|
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second);
|
||||
|
||||
Set<String> keySet = composite.keySet();
|
||||
assertThat(keySet).containsExactlyInAnyOrder("foo", "baz", "corge");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void values() {
|
||||
Map<String, String> first = Map.of("foo", "bar", "baz", "qux");
|
||||
Map<String, String> second = Map.of("baz", "quux", "corge", "grault");
|
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second);
|
||||
|
||||
Collection<String> values = composite.values();
|
||||
assertThat(values).containsExactlyInAnyOrder("bar", "qux", "grault");
|
||||
}
|
||||
|
||||
@Test
|
||||
void entrySet() {
|
||||
Map<String, String> first = Map.of("foo", "bar", "baz", "qux");
|
||||
Map<String, String> second = Map.of("baz", "quux", "corge", "grault");
|
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second);
|
||||
|
||||
Set<Map.Entry<String, String>> entries = composite.entrySet();
|
||||
assertThat(entries).containsExactlyInAnyOrder(entry("foo", "bar"), entry("baz", "qux"), entry("corge", "grault"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
class FilteredCollectionTests {
|
||||
|
||||
@Test
|
||||
void size() {
|
||||
List<String> list = List.of("foo", "bar", "baz");
|
||||
FilteredCollection<String> filtered = new FilteredCollection<>(list, s -> !s.equals("bar"));
|
||||
|
||||
assertThat(filtered).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void iterator() {
|
||||
List<String> list = List.of("foo", "bar", "baz");
|
||||
FilteredCollection<String> filtered = new FilteredCollection<>(list, s -> !s.equals("bar"));
|
||||
|
||||
assertThat(filtered.iterator()).toIterable().containsExactly("foo", "baz");
|
||||
}
|
||||
|
||||
@Test
|
||||
void add() {
|
||||
List<String> list = new ArrayList<>(List.of("foo"));
|
||||
FilteredCollection<String> filtered = new FilteredCollection<>(list, s -> !s.equals("bar"));
|
||||
boolean added = filtered.add("bar");
|
||||
assertThat(added).isFalse();
|
||||
assertThat(filtered).containsExactly("foo");
|
||||
assertThat(list).containsExactly("foo", "bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void remove() {
|
||||
List<String> list = new ArrayList<>(List.of("foo", "bar"));
|
||||
FilteredCollection<String> filtered = new FilteredCollection<>(list, s -> !s.equals("bar"));
|
||||
assertThat(list).contains("bar");
|
||||
assertThat(filtered).doesNotContain("bar");
|
||||
boolean removed = filtered.remove("bar");
|
||||
assertThat(removed).isFalse();
|
||||
assertThat(filtered).doesNotContain("bar");
|
||||
assertThat(list).doesNotContain("bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void contains() {
|
||||
List<String> list = List.of("foo", "bar", "baz");
|
||||
FilteredCollection<String> filtered = new FilteredCollection<>(list, s -> !s.equals("bar"));
|
||||
boolean contained = filtered.contains("bar");
|
||||
assertThat(contained).isFalse();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
final class FilteredIteratorTests {
|
||||
|
||||
@Test
|
||||
void filter() {
|
||||
List<String> list = List.of("foo", "bar", "baz");
|
||||
FilteredIterator<String> filtered = new FilteredIterator<>(list.iterator(), s -> !s.equals("bar"));
|
||||
|
||||
assertThat(filtered).toIterable().containsExactly("foo", "baz");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
class FilteredMapTests {
|
||||
|
||||
@Test
|
||||
void size() {
|
||||
Map<String, String> map = Map.of("foo", "bar", "baz", "qux", "quux", "corge");
|
||||
FilteredMap<String, String> filtered = new FilteredMap<>(map, s -> !s.equals("baz"));
|
||||
|
||||
assertThat(filtered).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void entrySet() {
|
||||
Map<String, String> map = Map.of("foo", "bar", "baz", "qux", "quux", "corge");
|
||||
FilteredMap<String, String> filtered = new FilteredMap<>(map, s -> !s.equals("baz"));
|
||||
|
||||
assertThat(filtered.entrySet()).containsExactlyInAnyOrder(entry("foo", "bar"), entry("quux", "corge"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsKey() {
|
||||
Map<String, String> map = Map.of("foo", "bar", "baz", "qux", "quux", "corge");
|
||||
FilteredMap<String, String> filtered = new FilteredMap<>(map, s -> !s.equals("baz"));
|
||||
|
||||
boolean contained = filtered.containsKey("baz");
|
||||
assertThat(contained).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void get() {
|
||||
Map<String, String> map = Map.of("foo", "bar", "baz", "qux", "quux", "corge");
|
||||
FilteredMap<String, String> filtered = new FilteredMap<>(map, s -> !s.equals("baz"));
|
||||
|
||||
String value = filtered.get("baz");
|
||||
assertThat(value).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void put() {
|
||||
Map<String, String> map = new HashMap<>(Map.of("foo", "bar", "quux", "corge"));
|
||||
FilteredMap<String, String> filtered = new FilteredMap<>(map, s -> !s.equals("baz"));
|
||||
|
||||
String value = filtered.put("baz", "qux");
|
||||
assertThat(value).isNull();
|
||||
assertThat(filtered.containsKey("baz")).isFalse();
|
||||
assertThat(map.get("baz")).isEqualTo("qux");
|
||||
|
||||
// overwrite
|
||||
value = filtered.put("baz", "QUX");
|
||||
assertThat(value).isNull();
|
||||
assertThat(filtered.containsKey("baz")).isFalse();
|
||||
assertThat(map.get("baz")).isEqualTo("QUX");
|
||||
}
|
||||
|
||||
@Test
|
||||
void remove() {
|
||||
Map<String, String> map = new HashMap<>(Map.of("foo", "bar", "baz", "qux", "quux", "corge"));
|
||||
FilteredMap<String, String> filtered = new FilteredMap<>(map, s -> !s.equals("baz"));
|
||||
|
||||
String value = filtered.remove("baz");
|
||||
assertThat(value).isNull();
|
||||
assertThat(filtered.containsKey("baz")).isFalse();
|
||||
assertThat(map.containsKey("baz")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void keySet() {
|
||||
Map<String, String> map = Map.of("foo", "bar", "baz", "qux", "quux", "corge");
|
||||
FilteredMap<String, String> filtered = new FilteredMap<>(map, s -> !s.equals("baz"));
|
||||
|
||||
Set<String> keySet = filtered.keySet();
|
||||
assertThat(keySet).containsExactlyInAnyOrder("foo", "quux");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
class FilteredSetTests {
|
||||
|
||||
@Test
|
||||
void testEquals() {
|
||||
Set<String> set = Set.of("foo", "bar", "baz");
|
||||
FilteredSet<String> filtered = new FilteredSet<>(set, s -> !s.equals("bar"));
|
||||
|
||||
Set<String> expected = Set.of("foo", "baz");
|
||||
|
||||
assertThat(filtered.equals(expected)).isTrue();
|
||||
assertThat(filtered.equals(set)).isFalse();
|
||||
assertThat(filtered.equals(Collections.emptySet())).isFalse();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user