Skip to content

Commit e3b38ed

Browse files
authored
Fix current feature availability in specification context (#2070)
1 parent 833d9e9 commit e3b38ed

File tree

3 files changed

+50
-14
lines changed

3 files changed

+50
-14
lines changed

spock-core/src/main/java/org/spockframework/runtime/PlatformSpecRunner.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,15 +188,18 @@ public void runFeature(SpockExecutionContext context, Runnable feature) {
188188
if (currentFeature.isSkipped()) {
189189
throw new InternalSpockError("Invalid state, feature is executed although it should have been skipped");
190190
}
191-
getSpecificationContext(context).setCurrentFeature(currentFeature);
191+
192+
// at this point the specification context is the one of the shared instance,
193+
// so the current feature cannot be set as features can run in parallel
194+
// so getting the current feature from the specification context would not properly work
195+
192196
getSpecificationContext(context).pushStoreProvider(context.getStoreProvider());
193197

194198
supervisor.beforeFeature(currentFeature);
195199
invoke(context, this, createMethodInfoForDoRunFeature(context, feature));
196200
supervisor.afterFeature(currentFeature);
197201

198202
runCloseContextStoreProvider(context, MethodKind.CLEANUP);
199-
getSpecificationContext(context).setCurrentFeature(null);
200203
getSpecificationContext(context).popStoreProvider();
201204
}
202205

@@ -260,7 +263,6 @@ void runParameterizedFeature(SpockExecutionContext context, ParameterizedFeature
260263
}
261264

262265
void runInitializer(SpockExecutionContext context) {
263-
getSpecificationContext(context).setCurrentFeature(context.getCurrentFeature());
264266
getSpecificationContext(context).setCurrentIteration(context.getCurrentIteration());
265267
runInitializer(context, context.getSpec());
266268
}

spock-core/src/main/java/org/spockframework/runtime/SpecificationContext.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
public class SpecificationContext implements ISpecificationContext {
1717
private volatile SpecInfo currentSpec;
18-
private volatile FeatureInfo currentFeature;
1918
private volatile IterationInfo currentIteration;
2019

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

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

5658
@Nullable
5759
FeatureInfo getCurrentFeatureOrNull() {
58-
return currentFeature;
59-
}
60-
61-
public void setCurrentFeature(@Nullable FeatureInfo currentFeature) {
62-
this.currentFeature = currentFeature;
60+
return currentIteration == null ? null : currentIteration.getFeature();
6361
}
6462

6563
@Override

spock-specs/src/test/groovy/org/spockframework/smoke/Interceptors.groovy

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,104 +157,126 @@ class SubSpec extends SuperSpec {
157157
specInfo.specsBottomToTop*.addSharedInitializerInterceptor {
158158
assertSpecContext(it)
159159
proceed(it, 'shared initializer', "$it.spec.name")
160+
assertSpecContext(it)
160161
}
161162
specInfo.allSharedInitializerMethods*.addInterceptor {
162163
assertSpecMethodContext(it)
163164
proceed(it, 'shared initializer method', "$it.spec.name.$it.method.name()")
165+
assertSpecMethodContext(it)
164166
}
165167
specInfo.addInterceptor {
166168
assertSpecContext(it)
167169
proceed(it, 'specification', "$it.spec.name")
170+
assertSpecContext(it)
168171
}
169172
specInfo.specsBottomToTop*.addSetupSpecInterceptor {
170173
assertSpecContext(it)
171174
proceed(it, 'setup spec', "$it.spec.name")
175+
assertSpecContext(it)
172176
}
173177
specInfo.allSetupSpecMethods*.addInterceptor {
174178
assertSpecMethodContext(it)
175179
proceed(it, 'setup spec method', "$it.spec.name.$it.method.name()")
180+
assertSpecMethodContext(it)
176181
}
177182
allFeatures*.addInterceptor {
178183
assertFeatureContext(it)
179184
proceed(it, 'feature', "$it.spec.name.$it.feature.name")
185+
assertFeatureContext(it)
180186
}
181187
specInfo.specsBottomToTop.each { spec ->
182188
spec.addInitializerInterceptor {
183189
assertIterationContext(it)
184190
proceed(it, 'initializer', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex] / $spec.name")
191+
assertIterationContext(it)
185192
}
186193
}
187194
specInfo.allInitializerMethods*.addInterceptor {
188195
assertIterationMethodContext(it)
189196
proceed(it, 'initializer method', "$it.feature.parent.name.$it.feature.name[#$it.iteration.iterationIndex] / $it.spec.name.$it.method.name()")
197+
assertIterationMethodContext(it)
190198
}
191199
allFeatures.each { feature ->
192200
specInfo.allInitializerMethods.each { mi ->
193201
feature.addScopedMethodInterceptor(mi) {
194202
assertIterationMethodContext(it)
195203
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")
204+
assertIterationMethodContext(it)
196205
}
197206
}
198207
specInfo.allSetupMethods.each { mi ->
199208
feature.addScopedMethodInterceptor(mi) {
200209
assertIterationMethodContext(it)
201210
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")
211+
assertIterationMethodContext(it)
202212
}
203213
}
204214
specInfo.allCleanupMethods.each { mi ->
205215
feature.addScopedMethodInterceptor(mi) {
206216
assertIterationMethodContext(it)
207217
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")
218+
assertIterationMethodContext(it)
208219
}
209220
}
210221
}
211222
allFeatures*.addInitializerInterceptor {
212223
assertIterationContext(it)
213224
proceed(it, 'feature scoped initializer', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex]")
225+
assertIterationContext(it)
214226
}
215227
allFeatures*.addIterationInterceptor {
216228
assertIterationContext(it)
217229
proceed(it, 'iteration', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex]")
230+
assertIterationContext(it)
218231
}
219232
specInfo.specsBottomToTop.each { spec ->
220233
spec.addSetupInterceptor {
221234
assertIterationContext(it)
222235
proceed(it, 'setup', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex] / $spec.name")
236+
assertIterationContext(it)
223237
}
224238
}
225239
allFeatures*.addSetupInterceptor {
226240
assertIterationContext(it)
227241
proceed(it, 'feature scoped setup', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex]")
242+
assertIterationContext(it)
228243
}
229244
specInfo.allSetupMethods*.addInterceptor {
230245
assertIterationMethodContext(it)
231246
proceed(it, 'setup method', "$it.feature.parent.name.$it.feature.name[#$it.iteration.iterationIndex] / $it.spec.name.$it.method.name()")
247+
assertIterationMethodContext(it)
232248
}
233249
allFeatures*.featureMethod*.addInterceptor {
234250
assertIterationMethodContext(it)
235251
proceed(it, 'feature method', "$it.feature.parent.name.$it.feature.name[#$it.iteration.iterationIndex] / $it.spec.name.$it.method.name()")
252+
assertIterationMethodContext(it)
236253
}
237254
specInfo.specsBottomToTop.each { spec ->
238255
spec.addCleanupInterceptor {
239256
assertIterationContext(it)
240257
proceed(it, 'cleanup', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex] / $spec.name")
258+
assertIterationContext(it)
241259
}
242260
}
243261
allFeatures*.addCleanupInterceptor {
244262
assertIterationContext(it)
245263
proceed(it, 'feature scoped cleanup', "$it.spec.name.$it.feature.name[#$it.iteration.iterationIndex]")
264+
assertIterationContext(it)
246265
}
247266
specInfo.allCleanupMethods*.addInterceptor {
248267
assertIterationMethodContext(it)
249268
proceed(it, 'cleanup method', "$it.feature.parent.name.$it.feature.name[#$it.iteration.iterationIndex] / $it.spec.name.$it.method.name()")
269+
assertIterationMethodContext(it)
250270
}
251271
specInfo.specsBottomToTop*.addCleanupSpecInterceptor {
252272
assertSpecContext(it)
253273
proceed(it, 'cleanup spec', "$it.spec.name")
274+
assertSpecContext(it)
254275
}
255276
specInfo.allCleanupSpecMethods*.addInterceptor {
256277
assertSpecMethodContext(it)
257278
proceed(it, 'cleanup spec method', "$it.spec.name.$it.method.name()")
279+
assertSpecMethodContext(it)
258280
}
259281
specInfo.allFixtureMethods*.addInterceptor {
260282
it.with {
@@ -266,6 +288,14 @@ class SubSpec extends SuperSpec {
266288
}
267289
}
268290
proceed(it, 'fixture method', "${it.feature?.with { feature -> "$feature.parent.name.$feature.name[#$it.iteration.iterationIndex] / " } ?: ''}$it.spec.name.$it.method.name()")
291+
it.with {
292+
def specFixture = method.name.endsWith('Spec')
293+
if (specFixture) {
294+
assertSpecMethodContext(it)
295+
} else {
296+
assertIterationMethodContext(it)
297+
}
298+
}
269299
}
270300
}
271301

@@ -282,7 +312,7 @@ class SubSpec extends SuperSpec {
282312
currentFeature
283313
assert false: 'currentFeature should not be set'
284314
} catch (IllegalStateException ise) {
285-
assert ise.message == 'Cannot request current feature in @Shared context'
315+
assert ise.message == 'Cannot request current feature in @Shared context, or feature context'
286316
}
287317
try {
288318
currentIteration
@@ -319,7 +349,6 @@ class SubSpec extends SuperSpec {
319349
assert method
320350
instance.specificationContext.with {
321351
assert currentSpec
322-
assert currentFeature
323352
}
324353
}
325354
}
@@ -333,6 +362,12 @@ class SubSpec extends SuperSpec {
333362
assert !method.reflection
334363
assert !method.name
335364
instance.specificationContext.with {
365+
try {
366+
currentFeature
367+
assert false: 'currentFeature should not be set'
368+
} catch (IllegalStateException ise) {
369+
assert ise.message == 'Cannot request current feature in @Shared context, or feature context'
370+
}
336371
try {
337372
currentIteration
338373
assert false: 'currentIteration should not be set'
@@ -349,6 +384,7 @@ class SubSpec extends SuperSpec {
349384
assert iteration
350385
assert instance != sharedInstance
351386
instance.specificationContext.with {
387+
assert currentFeature
352388
assert currentIteration
353389
}
354390
}

0 commit comments

Comments
 (0)