Skip to content

Commit

Permalink
Fix current feature availability in specification context
Browse files Browse the repository at this point in the history
  • Loading branch information
Vampire committed Jan 6, 2025
1 parent e08b875 commit 26497f0
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -188,15 +188,18 @@ public void runFeature(SpockExecutionContext context, Runnable feature) {
if (currentFeature.isSkipped()) {
throw new InternalSpockError("Invalid state, feature is executed although it should have been skipped");
}
getSpecificationContext(context).setCurrentFeature(currentFeature);

// at this point the specification context is the one of the shared instance,
// so the current feature cannot be set as features can run in parallel
// so getting the current feature from the specification context would not properly work

getSpecificationContext(context).pushStoreProvider(context.getStoreProvider());

supervisor.beforeFeature(currentFeature);
invoke(context, this, createMethodInfoForDoRunFeature(context, feature));
supervisor.afterFeature(currentFeature);

runCloseContextStoreProvider(context, MethodKind.CLEANUP);
getSpecificationContext(context).setCurrentFeature(null);
getSpecificationContext(context).popStoreProvider();
}

Expand Down Expand Up @@ -260,7 +263,6 @@ void runParameterizedFeature(SpockExecutionContext context, ParameterizedFeature
}

void runInitializer(SpockExecutionContext context) {
getSpecificationContext(context).setCurrentFeature(context.getCurrentFeature());
getSpecificationContext(context).setCurrentIteration(context.getCurrentIteration());
runInitializer(context, context.getSpec());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

public class SpecificationContext implements ISpecificationContext {
private volatile SpecInfo currentSpec;
private volatile FeatureInfo currentFeature;
private volatile IterationInfo currentIteration;

private volatile BlockInfo currentBlock;
Expand Down Expand Up @@ -47,19 +46,18 @@ public void setCurrentSpec(SpecInfo currentSpec) {

@Override
public FeatureInfo getCurrentFeature() {
if (currentFeature == null) {
throw new IllegalStateException("Cannot request current feature in @Shared context");
// before an iteration is available we are in the shared context, even in the feature interceptor,
// so the current feature cannot be set as features can run in parallel
// so getting the current feature from the specification context would not properly work
if (currentIteration == null) {
throw new IllegalStateException("Cannot request current feature in @Shared context, or feature context");
}
return currentFeature;
return currentIteration.getFeature();
}

@Nullable
FeatureInfo getCurrentFeatureOrNull() {
return currentFeature;
}

public void setCurrentFeature(@Nullable FeatureInfo currentFeature) {
this.currentFeature = currentFeature;
return currentIteration == null ? null : currentIteration.getFeature();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,104 +157,126 @@ class SubSpec extends SuperSpec {
specInfo.specsBottomToTop*.addSharedInitializerInterceptor {
assertSpecContext(it)
proceed(it, 'shared initializer', "$it.spec.name")
assertSpecContext(it)
}
specInfo.allSharedInitializerMethods*.addInterceptor {
assertSpecMethodContext(it)
proceed(it, 'shared initializer method', "$it.spec.name.$it.method.name()")
assertSpecMethodContext(it)
}
specInfo.addInterceptor {
assertSpecContext(it)
proceed(it, 'specification', "$it.spec.name")
assertSpecContext(it)
}
specInfo.specsBottomToTop*.addSetupSpecInterceptor {
assertSpecContext(it)
proceed(it, 'setup spec', "$it.spec.name")
assertSpecContext(it)
}
specInfo.allSetupSpecMethods*.addInterceptor {
assertSpecMethodContext(it)
proceed(it, 'setup spec method', "$it.spec.name.$it.method.name()")
assertSpecMethodContext(it)
}
allFeatures*.addInterceptor {
assertFeatureContext(it)
proceed(it, 'feature', "$it.spec.name.$it.feature.name")
assertFeatureContext(it)
}
specInfo.specsBottomToTop.each { spec ->
spec.addInitializerInterceptor {
assertIterationContext(it)
proceed(it, 'initializer', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex] / $spec.name")
assertIterationContext(it)
}
}
specInfo.allInitializerMethods*.addInterceptor {
assertIterationMethodContext(it)
proceed(it, 'initializer method', "$it.feature.parent.name.$it.feature.name[#$it.iteration.iterationIndex] / $it.spec.name.$it.method.name()")
assertIterationMethodContext(it)
}
allFeatures.each { feature ->
specInfo.allInitializerMethods.each { mi ->
feature.addScopedMethodInterceptor(mi) {
assertIterationMethodContext(it)
proceed(it, 'feature scoped initializer method', "$it.feature.parent.name.$it.feature.name[#$it.iteration.iterationIndex] / $it.spec.name.$it.method.name() / from $feature.name")
assertIterationMethodContext(it)
}
}
specInfo.allSetupMethods.each { mi ->
feature.addScopedMethodInterceptor(mi) {
assertIterationMethodContext(it)
proceed(it, 'feature scoped setup method', "$it.feature.parent.name.$it.feature.name[#$it.iteration.iterationIndex] / $it.spec.name.$it.method.name() / from $feature.name")
assertIterationMethodContext(it)
}
}
specInfo.allCleanupMethods.each { mi ->
feature.addScopedMethodInterceptor(mi) {
assertIterationMethodContext(it)
proceed(it, 'feature scoped cleanup method', "$it.feature.parent.name.$it.feature.name[#$it.iteration.iterationIndex] / $it.spec.name.$it.method.name() / from $feature.name")
assertIterationMethodContext(it)
}
}
}
allFeatures*.addInitializerInterceptor {
assertIterationContext(it)
proceed(it, 'feature scoped initializer', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex]")
assertIterationContext(it)
}
allFeatures*.addIterationInterceptor {
assertIterationContext(it)
proceed(it, 'iteration', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex]")
assertIterationContext(it)
}
specInfo.specsBottomToTop.each { spec ->
spec.addSetupInterceptor {
assertIterationContext(it)
proceed(it, 'setup', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex] / $spec.name")
assertIterationContext(it)
}
}
allFeatures*.addSetupInterceptor {
assertIterationContext(it)
proceed(it, 'feature scoped setup', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex]")
assertIterationContext(it)
}
specInfo.allSetupMethods*.addInterceptor {
assertIterationMethodContext(it)
proceed(it, 'setup method', "$it.feature.parent.name.$it.feature.name[#$it.iteration.iterationIndex] / $it.spec.name.$it.method.name()")
assertIterationMethodContext(it)
}
allFeatures*.featureMethod*.addInterceptor {
assertIterationMethodContext(it)
proceed(it, 'feature method', "$it.feature.parent.name.$it.feature.name[#$it.iteration.iterationIndex] / $it.spec.name.$it.method.name()")
assertIterationMethodContext(it)
}
specInfo.specsBottomToTop.each { spec ->
spec.addCleanupInterceptor {
assertIterationContext(it)
proceed(it, 'cleanup', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex] / $spec.name")
assertIterationContext(it)
}
}
allFeatures*.addCleanupInterceptor {
assertIterationContext(it)
proceed(it, 'feature scoped cleanup', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex]")
assertIterationContext(it)
}
specInfo.allCleanupMethods*.addInterceptor {
assertIterationMethodContext(it)
proceed(it, 'cleanup method', "$it.feature.parent.name.$it.feature.name[#$it.iteration.iterationIndex] / $it.spec.name.$it.method.name()")
assertIterationMethodContext(it)
}
specInfo.specsBottomToTop*.addCleanupSpecInterceptor {
assertSpecContext(it)
proceed(it, 'cleanup spec', "$it.spec.name")
assertSpecContext(it)
}
specInfo.allCleanupSpecMethods*.addInterceptor {
assertSpecMethodContext(it)
proceed(it, 'cleanup spec method', "$it.spec.name.$it.method.name()")
assertSpecMethodContext(it)
}
specInfo.allFixtureMethods*.addInterceptor {
it.with {
Expand All @@ -266,6 +288,14 @@ class SubSpec extends SuperSpec {
}
}
proceed(it, 'fixture method', "${it.feature?.with { feature -> "$feature.parent.name.$feature.name[#$it.iteration.iterationIndex] / " } ?: ''}$it.spec.name.$it.method.name()")
it.with {
def specFixture = method.name.endsWith('Spec')
if (specFixture) {
assertSpecMethodContext(it)
} else {
assertIterationMethodContext(it)
}
}
}
}

Expand All @@ -282,7 +312,7 @@ class SubSpec extends SuperSpec {
currentFeature
assert false: 'currentFeature should not be set'
} catch (IllegalStateException ise) {
assert ise.message == 'Cannot request current feature in @Shared context'
assert ise.message == 'Cannot request current feature in @Shared context, or feature context'
}
try {
currentIteration
Expand Down Expand Up @@ -319,7 +349,6 @@ class SubSpec extends SuperSpec {
assert method
instance.specificationContext.with {
assert currentSpec
assert currentFeature
}
}
}
Expand All @@ -333,6 +362,12 @@ class SubSpec extends SuperSpec {
assert !method.reflection
assert !method.name
instance.specificationContext.with {
try {
currentFeature
assert false: 'currentFeature should not be set'
} catch (IllegalStateException ise) {
assert ise.message == 'Cannot request current feature in @Shared context, or feature context'
}
try {
currentIteration
assert false: 'currentIteration should not be set'
Expand All @@ -349,6 +384,7 @@ class SubSpec extends SuperSpec {
assert iteration
assert instance != sharedInstance
instance.specificationContext.with {
assert currentFeature
assert currentIteration
}
}
Expand Down

0 comments on commit 26497f0

Please sign in to comment.