Skip to content

Commit

Permalink
Add array support to collection conditions (#1734)
Browse files Browse the repository at this point in the history
  • Loading branch information
leonard84 authored Aug 4, 2023
1 parent c47a54e commit 8af7477
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 4 deletions.
2 changes: 1 addition & 1 deletion docs/utilities.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ include::{sourcedir}/utilities/CollectionConditions.groovy[tag=strict-matcher]
include::{sourcedir}/utilities/CollectionConditions.groovy[tag=strict-matcher-result]
----

NOTE: Both operands must be `Iterable` for this to work.
NOTE: Both operands must either be `Iterable` or an array for this to work.
Otherwise, it will be treated like the standard groovy https://groovy-lang.org/operators.html#_find_operator[find operator] or https://groovy-lang.org/operators.html#_match_operator[match operators].

[[file-stystem-fixture]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.spockframework.runtime;

import static java.util.stream.Collectors.toList;
import static org.spockframework.util.ReflectionUtil.isArray;

import org.spockframework.runtime.model.*;
import org.spockframework.util.*;
Expand Down Expand Up @@ -241,7 +242,8 @@ void verify(ErrorCollector errorCollector, @Nullable List<Object> values, @Nulla
int idxActual = values.indexOf(left);
int idxExpected = values.indexOf(right);

if (left instanceof Iterable && right instanceof Iterable) {

if (isIterableOrArray(left) && isIterableOrArray(right)) {
if (SpockRuntime.MATCH_COLLECTIONS_AS_SET.equals(method)) {
Set<?> actual = GroovyRuntimeUtil.coerce(left, LinkedHashSet.class);
Set<?> expected = GroovyRuntimeUtil.coerce(right, LinkedHashSet.class);
Expand All @@ -253,11 +255,13 @@ void verify(ErrorCollector errorCollector, @Nullable List<Object> values, @Nulla
values.set(idxExpected, expected);

} else {
Matcher<?> matcher = StreamSupport.stream(((Iterable<?>)right).spliterator(), false)
Object localLeft = convertArrayToCollectionIfNecessary(left);
Object localRight = convertArrayToCollectionIfNecessary(right);
Matcher<?> matcher = StreamSupport.stream(((Iterable<?>)localRight).spliterator(), false)
.map(CoreMatchers::equalTo)
.collect(Collectors.collectingAndThen(toList(), IsIterableContainingInAnyOrder::containsInAnyOrder));

if (HamcrestFacade.matches(matcher, left)) {
if (HamcrestFacade.matches(matcher, localLeft)) {
return;
}
description = HamcrestFacade.getFailureDescription(matcher, left, message);
Expand Down Expand Up @@ -303,4 +307,14 @@ static CollectionCondition parse(Object target, String method, Object[] args, bo
return null;
}
}
private static boolean isIterableOrArray(Object o) {
return o instanceof Iterable || isArray(o);
}

private static Object convertArrayToCollectionIfNecessary(Object o) {
if (isArray(o)) {
return GroovyRuntimeUtil.coerce(o, List.class);
}
return o;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ public static boolean isAnnotationPresent(AnnotatedElement element, String class

return false;
}
public static boolean isArray(Object obj) {
return (obj != null && obj.getClass().isArray());
}

public static boolean isAnnotationPresentRecursive(Class<?> cls, Class<? extends Annotation> annotationClass) {
return cls.isAnnotationPresent(annotationClass) ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,38 @@ class ConditionEvaluation extends EmbeddedSpecification {
}
def "collection conditions work with various types"() {
when:
runner.runFeatureBody("""
given:
def a = [1,1,2,2,3,3] as ${aType}
def b = [1,2,3] as ${bType}
expect:
a =~ b
""")
then:
noExceptionThrown()
where:
[aType, bType] << ['int[]', 'Integer[]', 'List', 'Set', 'Queue', 'Deque'].with { [it, it] }.combinations()
}
def "strict collection conditions work with various types"() {
when:
runner.runFeatureBody("""
given:
def a = [1,1,2,2,3,3] as ${aType}
def b = [1,2,3,3,2,1] as ${bType}
expect:
a ==~ b
""")
then:
noExceptionThrown()
where:
[aType, bType] << ['int[]', 'Integer[]', 'List', 'Queue', 'Deque'].with { [it, it] }.combinations()
}
/*
def "MapEntryExpression"() {
// tested as part of testMapExpression
Expand Down

0 comments on commit 8af7477

Please sign in to comment.