Skip to content

Commit c660e41

Browse files
committed
Implement Review Comments
1 parent 4d60a7f commit c660e41

File tree

10 files changed

+87
-12
lines changed

10 files changed

+87
-12
lines changed

spock-core/src/main/java/org/spockframework/compiler/SpecRewriter.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -399,16 +399,20 @@ private void handleWhereBlock(Method method) {
399399
public void visitMethodAgain(Method method) {
400400
this.block = null;
401401

402-
if (!movedStatsBackToMethod)
402+
if (!movedStatsBackToMethod) {
403403
for (Block b : method.getBlocks()) {
404-
// this will only have the blocks if there was no 'cleanup' block in the method
404+
// This will only run if there was no 'cleanup' block in the method.
405+
// Otherwise, the blocks have already been copied to try block by visitCleanupBlock.
406+
// We need to run as late as possible, so we'll have to do the handling here and in visitCleanupBlock.
405407
addBlockListeners(b);
406408
method.getStatements().addAll(b.getAst());
407409
}
410+
}
408411

409412
// for global required interactions
410-
if (method instanceof FeatureMethod)
413+
if (method instanceof FeatureMethod) {
411414
method.getStatements().add(createMockControllerCall(nodeCache.MockController_LeaveScope));
415+
}
412416

413417
if (methodHasCondition) {
414418
defineValueRecorder(method.getStatements(), "");
@@ -423,16 +427,18 @@ private void addBlockListeners(Block block) {
423427
BlockParseInfo blockType = block.getParseInfo();
424428
if (blockType == BlockParseInfo.WHERE
425429
|| blockType == BlockParseInfo.METHOD_END
430+
|| blockType == BlockParseInfo.COMBINED
426431
|| blockType == BlockParseInfo.ANONYMOUS) return;
427432

428433
// SpockRuntime.enterBlock(getSpecificationContext(), new BlockInfo(blockKind, [blockTexts]))
429434
MethodCallExpression enterBlockCall = createBlockListenerCall(block, blockType, nodeCache.SpockRuntime_CallEnterBlock);
430435
// SpockRuntime.exitedBlock(getSpecificationContext(), new BlockInfo(blockKind, [blockTexts]))
431436
MethodCallExpression exitBlockCall = createBlockListenerCall(block, blockType, nodeCache.SpockRuntime_CallExitBlock);
432437

433-
// As the cleanup block finalizes the specification, it would override any previous block in ErrorInfo,
434-
// so we only call enterBlock if there is no error yet.
435438
if (blockType == BlockParseInfo.CLEANUP) {
439+
// In case of a cleanup block we need store a reference of the previously `currentBlock` in case that an exception occurred
440+
// and restore it at the end of the cleanup block, so that the correct `BlockInfo` is available for the `IErrorContext`.
441+
// The restoration happens in the `finally` statement created by `createCleanupTryCatch`.
436442
VariableExpression failedBlock = new VariableExpression(SpockNames.FAILED_BLOCK, nodeCache.BlockInfo);
437443
block.getAst().addAll(0, asList(
438444
ifThrowableIsNotNull(storeFailedBlock(failedBlock)),
@@ -451,7 +457,6 @@ private void addBlockListeners(Block block) {
451457
}
452458

453459
private @NotNull Statement restoreFailedBlock(VariableExpression failedBlock) {
454-
455460
return new ExpressionStatement(createDirectMethodCall(new CastExpression(nodeCache.SpecificationContext, getSpecificationContext()), nodeCache.SpecificationContext_SetBlockCurrentBlock, new ArgumentListExpression(failedBlock)));
456461
}
457462

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package org.spockframework.runtime;
22

33
import org.spockframework.runtime.model.*;
4+
import org.spockframework.util.Nullable;
45

56
class ErrorContext implements IErrorContext {
67
private final SpecInfo spec;
78
private final FeatureInfo feature;
89
private final IterationInfo iteration;
910
private final BlockInfo block;
1011

11-
private ErrorContext(SpecInfo spec, FeatureInfo feature, IterationInfo iteration, BlockInfo block) {
12+
private ErrorContext(@Nullable SpecInfo spec, @Nullable FeatureInfo feature, @Nullable IterationInfo iteration, @Nullable BlockInfo block) {
1213
this.spec = spec;
1314
this.feature = feature;
1415
this.iteration = iteration;
@@ -43,4 +44,13 @@ public IterationInfo getCurrentIteration() {
4344
public BlockInfo getCurrentBlock() {
4445
return block;
4546
}
47+
48+
@Override
49+
public String toString() {
50+
return "ErrorContext{Spec: " + (spec == null ? "null" : spec.getDisplayName()) +
51+
", Feature: " + (feature == null ? "null" : feature.getDisplayName()) +
52+
", Iteration: " + (iteration == null ? "null" : iteration.getDisplayName()) +
53+
", Block: " + (block == null ? "null" : (block.getKind() + " " + block.getTexts()))
54+
+ "}";
55+
}
4656
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
* Listens to a spec run. Currently, only extensions can register listeners.
2222
* They do so by invoking <tt>SpecInfo.addListener()<tt>. See
2323
* {@link StepwiseExtension} for an example of how to use a listener.
24+
* <p>
2425
*
26+
* @see org.spockframework.runtime.extension.IBlockListener
2527
* @author Peter Niederwieser
2628
*/
2729
public interface IRunListener {

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,7 @@ private FeatureInfo createFeature(Method method, FeatureMetadata featureMetadata
169169
}
170170

171171
for (BlockMetadata blockMetadata : featureMetadata.blocks()) {
172-
BlockInfo block = new BlockInfo();
173-
block.setKind(blockMetadata.kind());
174-
block.setTexts(asList(blockMetadata.texts()));
175-
feature.addBlock(block);
172+
feature.addBlock(new BlockInfo(blockMetadata.kind(), asList(blockMetadata.texts())));
176173
}
177174

178175
return feature;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,43 @@
11
package org.spockframework.runtime.extension;
22

33
import org.spockframework.runtime.model.BlockInfo;
4+
import org.spockframework.runtime.model.ErrorInfo;
45
import org.spockframework.runtime.model.IterationInfo;
6+
import org.spockframework.util.Beta;
57

8+
/**
9+
* Listens to block events during the execution of a feature.
10+
* <p>
11+
* Usually used in conjunction with {@link org.spockframework.runtime.IRunListener}.
12+
* Currently, only extensions can register listeners.
13+
* They do so by invoking {@link org.spockframework.runtime.model.FeatureInfo#addBlockListener(IBlockListener)}.
14+
* It is preferred to use a single instance of this.
15+
* <p>
16+
* It is discouraged to perform long-running operations in the listener methods,
17+
* as they are called during the execution of the specification.
18+
* It is discouraged to perform any side effects affecting the tests.
19+
* <p>
20+
* When an exception is thrown in a block, the {@code blockExited} will not be called for that block.
21+
* If a cleanup block is present the cleanup block listener methods will still be called.
22+
*
23+
* @see org.spockframework.runtime.IRunListener
24+
* @author Leonard Brünings
25+
* @since 2.4
26+
*/
27+
@Beta
628
public interface IBlockListener {
29+
30+
/**
31+
* Called when a block is entered.
32+
*/
733
default void blockEntered(IterationInfo iterationInfo, BlockInfo blockInfo) {}
34+
35+
/**
36+
* Called when a block is exited.
37+
* <p>
38+
* This method is not called if an exception is thrown in the block.
39+
* The block that was active will be available in the {@link org.spockframework.runtime.model.IErrorContext}
40+
* and can be observed via {@link org.spockframework.runtime.IRunListener#error(ErrorInfo)}.
41+
*/
842
default void blockExited(IterationInfo iterationInfo, BlockInfo blockInfo) {}
943
}

spock-core/src/main/java/org/spockframework/runtime/model/BlockInfo.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.spockframework.runtime.model;
1818

19+
import org.spockframework.util.Nullable;
20+
1921
import java.util.List;
2022

2123
/**
@@ -35,6 +37,7 @@ public BlockInfo(BlockKind kind, List<String> texts) {
3537
this.texts = texts;
3638
}
3739

40+
@Nullable
3841
public BlockKind getKind() {
3942
return kind;
4043
}
@@ -43,6 +46,7 @@ public void setKind(BlockKind kind) {
4346
this.kind = kind;
4447
}
4548

49+
@Nullable
4650
public List<String> getTexts() {
4751
return texts;
4852
}

spock-core/src/main/java/org/spockframework/runtime/model/ErrorInfo.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,13 @@ public Throwable getException() {
3636
public IErrorContext getErrorContext() {
3737
return errorContext;
3838
}
39+
40+
@Override
41+
public String toString() {
42+
return "ErrorInfo{" +
43+
"method=" + method +
44+
", errorContext=" + errorContext +
45+
", error=" + error +
46+
'}';
47+
}
3948
}

spock-core/src/main/java/org/spockframework/runtime/model/FeatureInfo.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ public List<IMethodInterceptor> getInitializerInterceptors() {
168168
}
169169

170170
/**
171-
* Adds a initializer interceptor for this feature.
171+
* Adds an initializer interceptor for this feature.
172172
* <p>
173173
* The feature-scoped interceptors will execute before the spec interceptors.
174174
*
@@ -224,10 +224,18 @@ public void addIterationInterceptor(IMethodInterceptor interceptor) {
224224
iterationInterceptors.add(interceptor);
225225
}
226226

227+
/**
228+
* @since 2.4
229+
*/
230+
@Beta
227231
public List<IBlockListener> getBlockListeners() {
228232
return blockListeners;
229233
}
230234

235+
/**
236+
* @since 2.4
237+
*/
238+
@Beta
231239
public void addBlockListener(IBlockListener blockListener) {
232240
blockListeners.add(blockListener);
233241
}

spock-core/src/main/java/org/spockframework/runtime/model/IErrorContext.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
import org.spockframework.util.Nullable;
44

5+
/**
6+
* Provides context information for an error that occurred during the execution of a specification.
7+
* <p>
8+
* Depending on the context in which the error occurred, some of the methods may return {@code null}.
9+
*/
510
public interface IErrorContext {
611
@Nullable
712
SpecInfo getCurrentSpec();

spock-specs/src/test/groovy/org/spockframework/runtime/RunListenerSpec.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ class ASpec extends Specification {
234234
it.kind == block
235235
it.texts == blockTexts
236236
}
237+
assert errorInfo.errorContext.toString() == ''
237238
} else {
238239
assert errorInfo.errorContext.currentBlock == null
239240
}

0 commit comments

Comments
 (0)