From e5287335552d8fbebaf5241ea8466b0455df2df1 Mon Sep 17 00:00:00 2001 From: Tobias Brennecke Date: Mon, 29 Jan 2018 13:25:12 +0100 Subject: [PATCH] Fix #817 Allow specifying global extension order --- .../runtime/GlobalExtensionRegistry.java | 23 +++++++++++++++---- .../runtime/IExtensionRegistry.java | 4 ++-- .../GlobalExtensionRegistrySpec.groovy | 21 +++++++++++++++++ 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/spock-core/src/main/java/org/spockframework/runtime/GlobalExtensionRegistry.java b/spock-core/src/main/java/org/spockframework/runtime/GlobalExtensionRegistry.java index 05bdffe255..3fabcddc60 100644 --- a/spock-core/src/main/java/org/spockframework/runtime/GlobalExtensionRegistry.java +++ b/spock-core/src/main/java/org/spockframework/runtime/GlobalExtensionRegistry.java @@ -27,17 +27,32 @@ * Maintains a registry of global Spock extensions and their configuration objects, * which can be used to configure other extensions. * + *

If an extension is specified in two or more {@code IGlobalExtension} files on the classpath, it will only + * be processed for the first time it is discovered. + * This allows processing other extensions (e.g. Spring) before custom ones by listing the order of extensions + * explicitly in the file. + * + *

+ * For instance this will load and run {@code SpringExtension} before {@code MyExtension}: + *

{@code
+ * org.spockframework.spring.SpringExtension
+ * com.example.MyExtension}
+ *

+ * + * * @author Peter Niederwieser */ public class GlobalExtensionRegistry implements IExtensionRegistry, IConfigurationRegistry { - private final List> globalExtensionClasses; + private final Set> globalExtensionClasses; private final Map, Object> configurationsByType = new HashMap<>(); private final Map configurationsByName = new HashMap<>(); - private final List globalExtensions = new ArrayList<>(); + private final Set globalExtensions = new LinkedHashSet<>(); GlobalExtensionRegistry(List> globalExtensionClasses, List initialConfigurations) { - this.globalExtensionClasses = globalExtensionClasses; + // Only add an extension the first time it is encountered, i.e + // turns [A, A, B, A,] into [A,B] + this.globalExtensionClasses = new LinkedHashSet<>(globalExtensionClasses); initializeConfigurations(initialConfigurations); } @@ -72,7 +87,7 @@ public Object getConfigurationByName(String name) { } @Override - public List getGlobalExtensions() { + public Set getGlobalExtensions() { return globalExtensions; } diff --git a/spock-core/src/main/java/org/spockframework/runtime/IExtensionRegistry.java b/spock-core/src/main/java/org/spockframework/runtime/IExtensionRegistry.java index 61b632b896..bee39f8cc6 100644 --- a/spock-core/src/main/java/org/spockframework/runtime/IExtensionRegistry.java +++ b/spock-core/src/main/java/org/spockframework/runtime/IExtensionRegistry.java @@ -16,8 +16,8 @@ import org.spockframework.runtime.extension.IGlobalExtension; -import java.util.List; +import java.util.Set; public interface IExtensionRegistry { - List getGlobalExtensions(); + Set getGlobalExtensions(); } diff --git a/spock-specs/src/test/groovy/org/spockframework/runtime/GlobalExtensionRegistrySpec.groovy b/spock-specs/src/test/groovy/org/spockframework/runtime/GlobalExtensionRegistrySpec.groovy index 58b55f5dc0..3f98a2f51e 100644 --- a/spock-specs/src/test/groovy/org/spockframework/runtime/GlobalExtensionRegistrySpec.groovy +++ b/spock-specs/src/test/groovy/org/spockframework/runtime/GlobalExtensionRegistrySpec.groovy @@ -161,6 +161,27 @@ class GlobalExtensionRegistrySpec extends Specification { e.message.contains("unknown configuration class") } + // See https://github.com/spockframework/spock/issues/817 + def "Extensions discovered later in the classpath are ignored if already processed earlier"() { + when: + def registry = new GlobalExtensionRegistry(extensionClasses, []) + registry.initializeGlobalExtensions() + + then: + registry.globalExtensions*.class == expectedExtensionClasses + + where: + // Ignore subsequent additions, even if they appear later in the list + extensionClasses || expectedExtensionClasses + [MyExtension, MyExtension] || [MyExtension] + [SpringExtension, MyExtension, SpringExtension] || [SpringExtension, MyExtension] + [SpringExtension, SpringExtension, MyExtension, SpringExtension] || [SpringExtension, MyExtension] + } + + static class SpringExtension extends AbstractGlobalExtension { + + } + static class MyExtension extends AbstractGlobalExtension { static instantiated = false