Skip to content

Commit d362a9d

Browse files
committed
Created IsUnmodifiableCollection class to improve mismatch description
The mismatch description provided by anyOf() is not helpful (it just calls toString() on the item being tested). This is not a fault but just a limitation of what it can do in the general case. By providing a custom IsUnmodifiableCollection Matcher class we can produce a better mismatch description.
1 parent dba4cb2 commit d362a9d

File tree

2 files changed

+58
-4
lines changed

2 files changed

+58
-4
lines changed

hamcrest/src/main/java/org/hamcrest/collection/IsUnmodifiable.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class IsUnmodifiable {
2727
* @return The matcher
2828
*/
2929
public static <E> Matcher<Collection<? extends E>> isUnmodifiableCollection() {
30-
return anyOf(isUnmodifiableJdkCollection(), allOf(not(isModifiableJdkCollection()), isUnmodifiableCustomCollection()));
30+
return new IsUnmodifiableCollection<>();
3131
}
3232

3333
/**
@@ -62,6 +62,47 @@ public static <E> Matcher<Collection<? extends E>> isUnmodifiableCustomCollectio
6262
return new IsUnmodifiableCustomCollection<>();
6363
}
6464

65+
private static class IsUnmodifiableCollection<E> extends TypeSafeDiagnosingMatcher<Collection<? extends E>> {
66+
private final Matcher<Collection<? extends E>> isUnmodifiableJdkCollection;
67+
private final Matcher<Collection<? extends E>> isModifiableJdkCollection;
68+
private final Matcher<Collection<? extends E>> isUnmodifiableCustomCollection;
69+
70+
private IsUnmodifiableCollection() {
71+
this(IsUnmodifiable.isUnmodifiableJdkCollection(), IsUnmodifiable.isModifiableJdkCollection(), IsUnmodifiable.isUnmodifiableCustomCollection());
72+
}
73+
74+
private IsUnmodifiableCollection(Matcher<Collection<? extends E>> isUnmodifiableJdkCollection,
75+
Matcher<Collection<? extends E>> isModifiableJdkCollection,
76+
Matcher<Collection<? extends E>> isUnmodifiableCustomCollection) {
77+
this.isUnmodifiableJdkCollection = isUnmodifiableJdkCollection;
78+
this.isModifiableJdkCollection = isModifiableJdkCollection;
79+
this.isUnmodifiableCustomCollection = isUnmodifiableCustomCollection;
80+
}
81+
82+
@Override
83+
public void describeTo(Description description) {
84+
description.appendText("unmodifiable collection");
85+
}
86+
87+
@Override
88+
protected boolean matchesSafely(Collection<? extends E> collection, Description mismatchDescription) {
89+
if (isUnmodifiableJdkCollection.matches(collection)) {
90+
return true; // It's a known unmodifiable collection, so shortcut the remaining tests
91+
}
92+
if (isModifiableJdkCollection.matches(collection)) {
93+
// If it's a known modifiable collection, then fail
94+
mismatchDescription.appendText(collection.getClass().getName() + " is a known modifiable JDK collection");
95+
return false;
96+
}
97+
if (!isUnmodifiableCustomCollection.matches(collection)) {
98+
// If we are able to modify the collection, then fail
99+
isUnmodifiableCustomCollection.describeMismatch(collection, mismatchDescription);
100+
return false;
101+
}
102+
return true;
103+
}
104+
}
105+
65106
private static class IsUnmodifiableJdkCollection<E> extends TypeSafeDiagnosingMatcher<Collection<? extends E>> {
66107
private static final Set<String> KNOWN_UNMODIFIABLE_COLLECTIONS =
67108
Set.of("java.util.ImmutableCollections",

hamcrest/src/test/java/org/hamcrest/collection/IsUnmodifiableTest.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import static org.hamcrest.collection.IsUnmodifiable.*;
66

77
import org.hamcrest.test.AbstractMatcherTest;
8+
import org.junit.jupiter.api.DisplayName;
89
import org.junit.jupiter.api.Test;
910
import org.junit.jupiter.params.ParameterizedTest;
1011
import org.junit.jupiter.params.provider.Arguments;
@@ -70,23 +71,27 @@ protected Matcher<?> createMatcher() {
7071
return isUnmodifiableCollection();
7172
}
7273

74+
@DisplayName("IsUnmodifiableCollection() matches known unmodifiable JDK collections")
7375
@ParameterizedTest(name = "{1}")
7476
@FieldSource("JDK_KNOWN_UNMODIFIABLE_COLLECTIONS")
7577
public void testIsUnmodifiableMatchesKnownJdkUnmodifiableCollections(Collection<?> collection, String className) {
7678
assertMatches("truly unmodifiable JDK Collection (" + className + ")", isUnmodifiableCollection(), collection);
7779
}
7880

81+
@DisplayName("IsUnmodifiableCollection() mismatches known modifiable JDK collections")
7982
@ParameterizedTest(name = "{1}")
8083
@FieldSource("JDK_KNOWN_MODIFIABLE_COLLECTIONS")
8184
public void testIsUnmodifiableMismatchesKnownJdkModifiableCollections(Collection<?> collection, String className) {
8285
assertMismatchDescription(className + " is a known modifiable JDK collection", isUnmodifiableCollection(), collection);
8386
}
8487

88+
@DisplayName("IsUnmodifiableCollection() matches unmodifiable custom collection")
8589
@Test
8690
public void testIsUnmodifiableMatchesUnmodifiableCustomList() {
8791
assertMatches("truly unmodifiable list", isUnmodifiableCollection(), new CustomUnmodifiableList<>(Arrays.asList(1, 2, 3)));
8892
}
8993

94+
@DisplayName("IsUnmodifiableCollection() mismatches modifiable custom collection")
9095
@ParameterizedTest
9196
@FieldSource("ERROR_CONDITIONS")
9297
public void testIsUnmodifiableMismatchesModifiableCustomList(ModificationErrorCondition errorCondition) {
@@ -104,18 +109,21 @@ public void testIsUnmodifiableMismatchesModifiableCustomList(ModificationErrorCo
104109

105110
// isUnmodifiableJdkCollection() tests
106111

112+
@DisplayName("IsUnmodifiableJdkCollection() matches known unmodifiable JDK collections")
107113
@ParameterizedTest(name = "{1}")
108114
@FieldSource("JDK_KNOWN_UNMODIFIABLE_COLLECTIONS")
109115
public void testIsUnmodifiableJdkCollectionMatchesKnownJdkUnmodifiableCollections(Collection<?> collection, String className) {
110116
assertMatches("truly unmodifiable JDK Collection (" + className + ")", isUnmodifiableJdkCollection(), collection);
111117
}
112118

119+
@DisplayName("IsUnmodifiableJdkCollection() mismatches known modifiable JDK collections")
113120
@ParameterizedTest(name = "{1}")
114121
@FieldSource("JDK_KNOWN_MODIFIABLE_COLLECTIONS")
115122
public void testIsUnmodifiableJdkCollectionMismatchesKnownJdkModifiableCollections(Collection<?> collection, String className) {
116123
assertMismatchDescription(className + " is not a known unmodifiable JDK collection", isUnmodifiableJdkCollection(), collection);
117124
}
118125

126+
@DisplayName("IsUnmodifiableJdkCollection() mismatches unmodifiable custom collection")
119127
@Test
120128
public void testIsUnmodifiableJdkCollectionMismatchesUnmodifiableCustomList() {
121129
CustomUnmodifiableList<Integer> testList = new CustomUnmodifiableList<>(Arrays.asList(1, 2, 3));
@@ -124,30 +132,35 @@ public void testIsUnmodifiableJdkCollectionMismatchesUnmodifiableCustomList() {
124132

125133
// isModifiableJdkCollection() tests
126134

135+
@DisplayName("IsModifiableJdkCollection() mismatches known unmodifiable JDK collections")
127136
@ParameterizedTest(name = "{1}")
128137
@FieldSource("JDK_KNOWN_UNMODIFIABLE_COLLECTIONS")
129138
public void testIsModifiableJdkCollectionMatchesKnownJdkUnmodifiableCollections(Collection<?> collection, String className) {
130139
assertMismatchDescription(className + " is not a known modifiable JDK collection", isModifiableJdkCollection(), collection);
131140
}
132141

142+
@DisplayName("IsModifiableJdkCollection() matches known modifiable JDK collections")
133143
@ParameterizedTest(name = "{1}")
134144
@FieldSource("JDK_KNOWN_MODIFIABLE_COLLECTIONS")
135145
public void testIsModifiableJdkCollectionMatchesKnownJdkModifiableCollections(Collection<?> collection, String className) {
136146
assertMatches("truly unmodifiable JDK Collection (" + className + ")", isModifiableJdkCollection(), collection);
137147
}
138148

149+
@DisplayName("IsModifiableJdkCollection() mismatches modifiable custom collection")
139150
@Test
140-
public void testIsModifiableJdkCollectionMismatchesUnmodifiableCustomList() {
141-
CustomUnmodifiableList<Integer> testList = new CustomUnmodifiableList<>(Arrays.asList(1, 2, 3));
142-
assertMismatchDescription(CustomUnmodifiableList.class.getName() + " is not a known modifiable JDK collection", isModifiableJdkCollection(), testList);
151+
public void testIsModifiableJdkCollectionMismatchesModifiableCustomList() {
152+
CustomModifiableList<Integer> testList = new CustomModifiableList<>(Arrays.asList(1, 2, 3), Set.of());
153+
assertMismatchDescription(CustomModifiableList.class.getName() + " is not a known modifiable JDK collection", isModifiableJdkCollection(), testList);
143154
}
144155

145156
// isUnmodifiableCustomCollection() tests
157+
@DisplayName("IsUnmodifiableCustomCollection() matches unmodifiable custom collection")
146158
@Test
147159
public void testisUnmodifiableCustomCollectionMatchesUnmodifiableCustomList() {
148160
assertMatches("truly unmodifiable list", isUnmodifiableCustomCollection(), new CustomUnmodifiableList<>(Arrays.asList(1, 2, 3)));
149161
}
150162

163+
@DisplayName("IsUnmodifiableCustomCollection() mismatches modifiable custom collection")
151164
@ParameterizedTest
152165
@FieldSource("ERROR_CONDITIONS")
153166
public void testIsUnmodifiableCustomCollectionMismatchesModifiableCustomList(ModificationErrorCondition errorCondition) {

0 commit comments

Comments
 (0)