Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add array support to collection conditions #1734

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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