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

SpockConfig can include/exclude by regex pattern string. #24

Open
wants to merge 1 commit into
base: groovy-1.8
Choose a base branch
from
Open
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
19 changes: 19 additions & 0 deletions docs/new_and_noteworthy.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
New and Noteworthy
==================

1.0
~~~

Patterns in SpockConfig
-----------------------

``SpockConfig.groovy`` now supports regex patterns of simple names of annotations,
spec classes, or features. This is useful in Grails, where the project classes
are not available to the config loader. Here is an example using both classes and patterns:

import some.pkg.Fast
import some.pkg.IntegrationSpec

runner {
include Fast, 'Good', 'Browser.*Spec'
exclude some.pkg.Slow, IntegrationSpec
}


0.7
~~~

Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@

import java.lang.annotation.Annotation;
import java.util.List;
import java.util.regex.Pattern;

import org.spockframework.runtime.extension.AbstractGlobalExtension;
import org.spockframework.runtime.model.*;
@@ -43,15 +44,17 @@ private void handleSpecIncludes(SpecInfo spec, IncludeExcludeCriteria criteria)
if (criteria.isEmpty()) return;

if (!hasAnyAnnotation(spec, criteria.annotations)
&& !hasAnyBaseClass(spec, criteria.baseClasses))
&& !hasAnyBaseClass(spec, criteria.baseClasses)
&& !matchesAnyPattern(spec, criteria.patterns))
spec.setExcluded(true);
}

private void handleSpecExcludes(SpecInfo spec, IncludeExcludeCriteria criteria) {
if (criteria.isEmpty()) return;

if (hasAnyAnnotation(spec, criteria.annotations)
|| hasAnyBaseClass(spec, criteria.baseClasses))
|| hasAnyBaseClass(spec, criteria.baseClasses)
|| matchesAnyPattern(spec, criteria.patterns))
spec.setExcluded(true);
}

@@ -60,15 +63,17 @@ private void handleFeatureIncludes(SpecInfo spec, IncludeExcludeCriteria criteri
if (criteria.isEmpty()) return;

for (FeatureInfo feature : spec.getAllFeatures())
if (hasAnyAnnotation(feature.getFeatureMethod(), criteria.annotations))
if (hasAnyAnnotation(feature.getFeatureMethod(), criteria.annotations)
|| matchesAnyPattern(feature.getFeatureMethod(), criteria.patterns))
feature.setExcluded(false);
}

private void handleFeatureExcludes(SpecInfo spec, IncludeExcludeCriteria criteria) {
if (criteria.isEmpty()) return;

for (FeatureInfo feature : spec.getAllFeatures())
if (hasAnyAnnotation(feature.getFeatureMethod(), criteria.annotations))
if (hasAnyAnnotation(feature.getFeatureMethod(), criteria.annotations)
|| matchesAnyPattern(feature.getFeatureMethod(), criteria.patterns))
feature.setExcluded(true);
}

@@ -99,5 +104,24 @@ private boolean hasAnyBaseClass(SpecInfo spec, List<Class<?>> baseClasses) {

return false;
}

private boolean matchesAnyPattern(NodeInfo<?, ?> node, List<Pattern> patterns) {
if (matchesAnyPattern(node.getName(), patterns))
return true;

for (Annotation ann : node.getAnnotations())
if (matchesAnyPattern(ann.annotationType().getSimpleName(), patterns))
return true;

return false;
}

private boolean matchesAnyPattern(String s, List<Pattern> patterns) {
for (Pattern p : patterns)
if (p.matcher(s).matches())
return true;

return false;
}
}

29 changes: 21 additions & 8 deletions spock-core/src/main/java/spock/config/IncludeExcludeCriteria.java
Original file line number Diff line number Diff line change
@@ -17,29 +17,42 @@
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
* Configuration indicating which specs and methods should be
* included/excluded from a spec run. Specs can be included/excluded
* based on their annotations and their (base) classes. Methods
* can be included/excluded based on their annotations.
* can be included/excluded based on their annotations and names.
* Criteria can be annotations, spec classes, base classes,
* and regex pattern strings. Patterns are matched against the
* simple names of annotations, spec (but not base) classes,
* and methods.
*
* @author Peter Niederwieser
*/
public class IncludeExcludeCriteria {
@SuppressWarnings("unchecked")
public IncludeExcludeCriteria(Class<?>... criteria) {
for (Class<?> criterium : criteria)
if (criterium.isAnnotation())
annotations.add((Class<? extends Annotation>)criterium);
else
baseClasses.add(criterium);
public IncludeExcludeCriteria(Object... criteria) {
for (Object criterium : criteria)
if (criterium instanceof Class) {
Class<?> classCriterium = (Class<?>) criterium;
if (classCriterium.isAnnotation())
annotations.add((Class<? extends Annotation>)classCriterium);
else
baseClasses.add(classCriterium);
} else if (criterium instanceof String) {
patterns.add(Pattern.compile((String) criterium));
} else {
throw new ConfigurationException("unsupported criterium, must be pattern string or class: %s", criterium.toString());
}
}

public List<Class<? extends Annotation>> annotations = new ArrayList<Class<? extends Annotation>>();
public List<Class<?>> baseClasses = new ArrayList<Class<?>>();
public List<Pattern> patterns = new ArrayList<Pattern>();

public boolean isEmpty() {
return annotations.isEmpty() && baseClasses.isEmpty();
return annotations.isEmpty() && baseClasses.isEmpty() && patterns.isEmpty();
}
}
Original file line number Diff line number Diff line change
@@ -23,11 +23,8 @@
* import some.pkg.IntegrationSpec
*
* runner {
* include Fast // could be either an annotation or a (base) class
* exclude {
* annotation some.pkg.Slow
* baseClass IntegrationSpec
* }
* include Fast, 'Good' // annotations, (base) classes, or regex patterns
* exclude some.pkg.Slow, IntegrationSpec
* filterStackTrace true // this is the default
* }
* </pre>
Original file line number Diff line number Diff line change
@@ -39,10 +39,10 @@ def feature3() {
""")
}

def "include methods based on annotations"() {
def "include methods based on annotations or patterns"() {
runner.configurationScript = {
runner {
include(*annotationTypes)
include(*criteria)
}
}

@@ -55,14 +55,24 @@ def feature3() {
result.ignoreCount == 0

where:
annotationTypes << [[Slow], [Fast], [Slow, Fast]]
runCount << [1, 1, 2 ]
criteria || runCount
[Slow] || 1
[Fast] || 1
[Slow, Fast] || 2

['Slow'] || 1
['Fast'] || 1
['Slow', 'Fast'] || 2

['feature1'] || 1
['feature[12]'] || 2
['feature.'] || 3
}

def "exclude methods based on annotations"() {
def "exclude methods based on annotations or patterns"() {
runner.configurationScript = {
runner {
exclude(*annotationTypes)
exclude(*criteria)
}
}

@@ -75,8 +85,18 @@ def feature3() {
result.ignoreCount == 0

where:
annotationTypes << [[Slow], [Fast], [Slow, Fast]]
runCount << [2, 2, 1 ]
criteria || runCount
[Slow] || 2
[Fast] || 2
[Slow, Fast] || 1

['Slow'] || 2
['Fast'] || 2
['Slow', 'Fast'] || 1

['feature1'] || 2
['feature[12]'] || 1
['feature.'] || 0
}

def "include and exclude features based on annotations"() {
@@ -100,9 +120,34 @@ def feature3() {
annTypes2 << [[Slow], [Fast], [Slow, Fast], [Slow], [Fast], [Slow, Fast], [Slow], [Fast], [Slow, Fast]]
runCount << [0, 1, 0, 1, 0, 0, 1, 1, 0 ]
}
}

def "include and exclude features based on patterns"() {
runner.configurationScript = {
runner {
include(*includes)
exclude(*excludes)
}
}

when:
def result = runner.runClass(spec)

then:
result.runCount == runCount
result.failureCount == 0
result.ignoreCount == (runCount == 0 ? 1 : 0) // cannot prevent JUnit from running excluded specs, so they get ignored

where:
includes | excludes || runCount
['Slow'] | ['Slow'] || 0
['Slow'] | ['Fast'] || 1
['Slow'] | ['Slow', 'Fast'] || 0
['Fast'] | ['Slow'] || 1
['Fast'] | ['Fast'] || 0
['Fast'] | ['Slow', 'Fast'] || 0
['Slow', 'Fast'] | ['Slow'] || 1
['Slow', 'Fast'] | ['Fast'] || 1
['Slow', 'Fast'] | ['Slow', 'Fast'] || 0
}
}

Original file line number Diff line number Diff line change
@@ -45,10 +45,10 @@ class Spec3 extends Specification {
""")
}

def "include specs based on annotations"() {
def "include specs based on annotations or patterns"() {
runner.configurationScript = {
runner {
include(*annotationTypes)
include(*criteria)
}
}

@@ -61,14 +61,24 @@ class Spec3 extends Specification {
result.ignoreCount == 3 - runCount // cannot prevent JUnit from running excluded specs, so they get ignored

where:
annotationTypes << [[Slow], [Fast], [Slow, Fast]]
runCount << [1, 1, 2 ]
criteria || runCount
[Slow] || 1
[Fast] || 1
[Slow, Fast] || 2

['Slow'] || 1
['Fast'] || 1
['Slow', 'Fast'] || 2

['Spec1'] || 1
['Spec[12]'] || 2
['Spec.'] || 3
}

def "exclude specs based on annotations"() {
def "exclude specs based on annotations or patterns"() {
runner.configurationScript = {
runner {
exclude(*annotationTypes)
exclude(*criteria)
}
}

@@ -81,8 +91,18 @@ class Spec3 extends Specification {
result.ignoreCount == 3 - runCount // cannot prevent JUnit from running excluded specs, so they get ignored

where:
annotationTypes << [[Slow], [Fast], [Slow, Fast]]
runCount << [2, 2, 1 ]
criteria || runCount
[Slow] || 2
[Fast] || 2
[Slow, Fast] || 1

['Slow'] || 2
['Fast'] || 2
['Slow', 'Fast'] || 1

['Spec1'] || 2
['Spec[12]'] || 1
['Spec.'] || 0
}

def "include and exclude specs based on annotations"() {
@@ -106,4 +126,33 @@ class Spec3 extends Specification {
annTypes2 << [[Slow], [Fast], [Slow, Fast], [Slow], [Fast], [Slow, Fast], [Slow], [Fast], [Slow, Fast]]
runCount << [0, 1, 0, 1, 0, 0, 1, 1, 0 ]
}

def "include and exclude specs based on patterns"() {
runner.configurationScript = {
runner {
include(*includes)
exclude(*excludes)
}
}

when:
def result = runner.runClasses(specs)

then:
result.runCount == runCount
result.failureCount == 0
result.ignoreCount == 3 - runCount // cannot prevent JUnit from running excluded specs, so they get ignored

where:
includes | excludes || runCount
['Slow'] | ['Slow'] || 0
['Slow'] | ['Fast'] || 1
['Slow'] | ['Slow', 'Fast'] || 0
['Fast'] | ['Slow'] || 1
['Fast'] | ['Fast'] || 0
['Fast'] | ['Slow', 'Fast'] || 0
['Slow', 'Fast'] | ['Slow'] || 1
['Slow', 'Fast'] | ['Fast'] || 1
['Slow', 'Fast'] | ['Slow', 'Fast'] || 0
}
}