Skip to content

Commit c37f885

Browse files
matchers: optimize containExactly comparison (#1571)
1 parent b837159 commit c37f885

5 files changed

Lines changed: 42 additions & 11 deletions

File tree

webtau-core/src/main/java/org/testingisdocumenting/webtau/Matchers.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,17 +215,29 @@ public static ContainAllMatcher containingAll(Object... expected) {
215215
}
216216

217217
/**
218-
* Contain exact matcher
218+
* Contain exactly matcher
219219
* <pre>
220220
* actual(collection).should(containExact(el1, el2, el3));
221221
* </pre>
222-
* @param expected list of values to check
222+
* @param expected vararg list of values to check
223223
* @return matcher instance
224224
*/
225225
public static ContainExactlyMatcher containExactly(Object... expected) {
226226
return new ContainExactlyMatcher(Arrays.asList(expected));
227227
}
228228

229+
/**
230+
* Contain exactly matcher
231+
* <pre>
232+
* actual(collection).should(containExact(el1, el2, el3));
233+
* </pre>
234+
* @param expected list of values to check
235+
* @return matcher instance
236+
*/
237+
public static ContainExactlyMatcher containExactly(Iterable<Object> expected) {
238+
return new ContainExactlyMatcher(expected);
239+
}
240+
229241
/**
230242
* Greater than matcher
231243
* <pre>

webtau-core/src/main/java/org/testingisdocumenting/webtau/expectation/contain/ContainExactlyMatcher.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,19 @@
2323
import org.testingisdocumenting.webtau.data.render.PrettyPrinter;
2424
import org.testingisdocumenting.webtau.expectation.ExpectedValuesAware;
2525
import org.testingisdocumenting.webtau.expectation.ValueMatcher;
26-
import org.testingisdocumenting.webtau.expectation.equality.CompareToComparator;
27-
import org.testingisdocumenting.webtau.expectation.equality.CompareToResult;
28-
import org.testingisdocumenting.webtau.expectation.equality.ValuePathLazyMessageList;
29-
import org.testingisdocumenting.webtau.expectation.equality.ValuePathMessage;
26+
import org.testingisdocumenting.webtau.expectation.equality.*;
3027
import org.testingisdocumenting.webtau.reporter.TokenizedMessage;
3128

3229
import java.util.*;
3330
import java.util.stream.Collectors;
3431
import java.util.stream.Stream;
32+
import java.util.stream.StreamSupport;
3533

3634
import static org.testingisdocumenting.webtau.WebTauCore.*;
3735
import static org.testingisdocumenting.webtau.expectation.TokenizedReportUtils.*;
3836

3937
public class ContainExactlyMatcher implements ValueMatcher, ExpectedValuesAware, PrettyPrintable {
40-
private final Collection<Object> expectedList;
38+
private final Iterable<Object> expectedList;
4139
private List<ValuePathWithValue<Object>> actualCopy;
4240
private List<ValuePathWithValue<Object>> expectedCopy;
4341

@@ -48,7 +46,7 @@ public class ContainExactlyMatcher implements ValueMatcher, ExpectedValuesAware,
4846

4947
private CompareToComparator comparator;
5048

51-
public ContainExactlyMatcher(Collection<Object> expected) {
49+
public ContainExactlyMatcher(Iterable<Object> expected) {
5250
expectedList = expected;
5351
}
5452

@@ -59,7 +57,7 @@ public ValueConverter valueConverter() {
5957

6058
@Override
6159
public Stream<Object> expectedValues() {
62-
return expectedList.stream();
60+
return StreamSupport.stream(expectedList.spliterator(), false);
6361
}
6462

6563
@Override
@@ -157,6 +155,9 @@ private boolean matches(CompareToComparator comparator, ValuePath actualPath, Ob
157155
actualCopy = ValuePathWithValue.listFromIterable(actualPath, ((Iterable<Object>) actualIterable));
158156
expectedCopy = ValuePathWithValue.listFromIterable(actualPath, expectedList);
159157

158+
CompareToHandler compareToHandlerPrevious = null;
159+
CompareToHandler compareToHandlerToUse = null;
160+
160161
Iterator<ValuePathWithValue<Object>> expectedIt = expectedCopy.iterator();
161162
while (expectedIt.hasNext()) {
162163
ValuePathWithValue<Object> expected = expectedIt.next();
@@ -169,7 +170,20 @@ private boolean matches(CompareToComparator comparator, ValuePath actualPath, Ob
169170
boolean found = false;
170171
while (actualIt.hasNext()) {
171172
ValuePathWithValue<Object> actual = actualIt.next();
172-
CompareToResult compareToResult = comparator.compareUsingEqualOnly(actual.getPath(), actual.getValue(), expected.getValue());
173+
174+
// cache compare to handler to use
175+
if (actual.getValue() != null && expected.getValue() != null) {
176+
if (compareToHandlerPrevious == null) {
177+
compareToHandlerPrevious = CompareToComparator.findCompareToEqualHandler(actual.getValue(), expected.getValue());
178+
}
179+
180+
compareToHandlerToUse = compareToHandlerPrevious;
181+
}
182+
183+
CompareToResult compareToResult = compareToHandlerToUse != null ?
184+
comparator.compareUsingEqualOnly(compareToHandlerToUse, actual.getPath(), actual.getValue(), expected.getValue()):
185+
comparator.compareUsingEqualOnly(actual.getPath(), actual.getValue(), expected.getValue());
186+
173187
if (compareToResult.isEqual()) {
174188
actualIt.remove();
175189
expectedIt.remove();

webtau-core/src/main/java/org/testingisdocumenting/webtau/expectation/equality/ValuePathLazyMessageList.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
* Is NOT thread safe
2828
*/
2929
public class ValuePathLazyMessageList implements Iterable<ValuePathMessage> {
30+
private static final int SIZE_LIMIT = 100;
31+
3032
private List<ValuePathMessage> messages;
3133
private ValuePathMessage singleMessage;
3234
private int size;
@@ -43,7 +45,7 @@ public void add(ValuePathMessage message) {
4345
messages.add(message);
4446
singleMessage = null;
4547
}
46-
} else {
48+
} else if (size < SIZE_LIMIT) {
4749
messages.add(message);
4850
}
4951
}

webtau-core/src/test/groovy/org/testingisdocumenting/webtau/expectation/contain/ContainExactlyMatcherGroovyTest.groovy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ package org.testingisdocumenting.webtau.expectation.contain
1919
import org.junit.Test
2020
import org.testingisdocumenting.webtau.data.Person
2121

22+
import java.util.stream.IntStream
23+
2224
import static org.testingisdocumenting.webtau.WebTauCore.*
2325

2426
class ContainExactlyMatcherGroovyTest {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* Add: speedup [containExactly](matchers/contain-exactly) by pre-caching compare to handler

0 commit comments

Comments
 (0)