Here is a newbie question. I am writing a custom Hamcrest matcher which compares two maps and displays a list of mismatched keys/values. The code works, but it only works with <Map<String, String>
. I would like to make my code generic and works with any Map
. I have tried replacing String
with Object
only to receive errors such as:
error: incompatible types: Map<String,String> cannot be converted to Map<Object,Object>
I appreciate your help.
Here is my custom matcher:
package net.southeastwind.test;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;
public class MapEquivalent extends TypeSafeDiagnosingMatcher<Map<String, String>> {
private Map<String, String> m_expected;
public MapEquivalent(Map<String, String> expected) {
m_expected = expected;
}
public static MapEquivalent mapEquivalent(Map<String, String> expected) {
return new MapEquivalent(expected);
}
@Override
public void describeTo(Description description) {
description.appendText("Maps are equivalent");
}
@Override
protected boolean matchesSafely(Map<String, String> actual, Description description) {
boolean matched = true;
Set<String> keys = new HashSet<>();
keys.addAll(actual.keySet());
keys.addAll(m_expected.keySet());
for (String key: keys) {
String expectedValue = m_expected.get(key);
String actualValue = actual.get(key);
if (null == expectedValue) {
matched = false;
description
.appendText("\n\t\tOnly in actual: {").appendValue(key)
.appendText(": ").appendValue(actualValue).appendText("}");
} else if (null == actualValue) {
matched = false;
description
.appendText("\n\t\tOnly in expected: {").appendValue(key)
.appendText(": ").appendValue(expectedValue).appendText("}");
} else if (!actualValue.equals(expectedValue)) {
matched = false;
description
.appendText("\n\t\tValues differ: ")
.appendText("actual={").appendValue(key).appendText(": ").appendValue(actualValue).appendText("}")
.appendText(", expected={").appendValue(key).appendText(": ").appendValue(expectedValue).appendText("}");
}
}
return matched;
}
}
Here is a sample test and output:
@Test
public void compareMaps() {
Map<String, String> expected = new HashMap<String, String>() {{
put("alias", "haiv");
put("uid", "501");
put("admin", "no");
}};
Map<String, String> actual = new HashMap<String, String>() {{
put("alias", "haiv");
put("uid", "502");
put("shell", "bash");
}};
assertThat("Error 6a3429f7", actual, is(mapEquivalent(expected)));
// CustomMatchersTest > compareMaps FAILED
// java.lang.AssertionError: Error 6a3429f7
// Expected: Maps are equivalent
// but:
// Values differ: actual={"uid": "502"}, expected={"uid": "501"}
// Only in actual: {"shell": "bash"}
// Only in expected: {"admin": "no"}
}
public class MapEquivalent<K,V> extends TypeSafeDiagnosingMatcher<Map<K, V>> {
private Map<K, V> m_expected;
public MapEquivalent(Map<K, V> expected) {
m_expected = expected;
}
public static MapEquivalent mapEquivalent(Map<K, V> expected) {
return new MapEquivalent(expected);
}
@Override
protected boolean matchesSafely(Map<K, V> actual, Description description)
{ /* you should get the idea now */ }
}
Change it this way:
public class MapEquivalent<T, U> extends TypeSafeDiagnosingMatcher<Map<T, U>> {
private Map<T, U> m_expected;
public MapEquivalent(Map<T, U> expected) {
m_expected = expected;
}
public static <T, U> MapEquivalent<T, U> mapEquivalent(Map<T, U> expected) {
return new MapEquivalent<>(expected);
}
@Override
public void describeTo(Description description) {
description.appendText("Maps are equivalent");
}
@Override
protected boolean matchesSafely(Map<T, U> actual, Description description) {
boolean matched = true;
Set<T> keys = new HashSet<>();
keys.addAll(actual.keySet());
keys.addAll(m_expected.keySet());
for (T key: keys) {
U expectedValue = m_expected.get(key);
U actualValue = actual.get(key);
if (null == expectedValue) {
matched = false;
description
.appendText("\n\t\tOnly in actual: {").appendValue(key)
.appendText(": ").appendValue(actualValue).appendText("}");
} else if (null == actualValue) {
matched = false;
description
.appendText("\n\t\tOnly in expected: {").appendValue(key)
.appendText(": ").appendValue(expectedValue).appendText("}");
} else if (!actualValue.equals(expectedValue)) {
matched = false;
description
.appendText("\n\t\tValues differ: ")
.appendText("actual={").appendValue(key).appendText(": ").appendValue(actualValue).appendText("}")
.appendText(", expected={").appendValue(key).appendText(": ").appendValue(expectedValue).appendText("}");
}
}
return matched;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.