Skip to content

Commit

Permalink
Use BlockInfo from SpecInfo via an index lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
leonard84 committed Jun 23, 2024
1 parent 6d3c148 commit b819d74
Show file tree
Hide file tree
Showing 30 changed files with 345 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

import org.codehaus.groovy.ast.*;
import org.codehaus.groovy.ast.expr.*;
import org.spockframework.util.Assert;

import static java.util.stream.Collectors.*;
import static org.spockframework.compiler.AstUtil.*;
Expand Down Expand Up @@ -205,6 +206,9 @@ private void addBlockMetadata(Block block, BlockKind kind) {
for (String text : block.getDescriptions())
textExprs.addExpression(new ConstantExpression(text));
blockAnn.setMember(BlockMetadata.TEXTS, textExprs);
int index = blockAnnElems.getExpressions().size();
Assert.that(index == block.getBlockMetaDataIndex(),
() -> kind+" block mismatch of index: " + index + ", block.getBlockMetaDataIndex(): " + block.getBlockMetaDataIndex());

Check warning on line 211 in spock-core/src/main/java/org/spockframework/compiler/SpecAnnotator.java

View check run for this annotation

Codecov / codecov/patch

spock-core/src/main/java/org/spockframework/compiler/SpecAnnotator.java#L211

Added line #L211 was not covered by tests
blockAnnElems.addExpression(new AnnotationConstantExpression(blockAnn));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ private void buildBlocks(Method method) throws InvalidSpecCompileException {
checkIsValidSuccessor(method, BlockParseInfo.METHOD_END,
method.getAst().getLastLineNumber(), method.getAst().getLastColumnNumber());

// set the block metaData index for each block this must be equal to the index of the block in the @BlockMetadata annotation
int i = -1;
for (Block block : method.getBlocks()) {
if(!block.hasBlockMetadata()) continue;
block.setBlockMetaDataIndex(++i);
}
// now that statements have been copied to blocks, the original statement
// list is cleared; statements will be copied back after rewriting is done
stats.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -470,21 +470,13 @@ private IfStatement ifThrowableIsNotNull(Statement statement) {
}

private MethodCallExpression createBlockListenerCall(Block block, BlockParseInfo blockType, MethodNode blockListenerMethod) {
if (block.getBlockMetaDataIndex() < 0) throw new SpockException("Block metadata index not set: " + block);
return createDirectMethodCall(
new ClassExpression(nodeCache.SpockRuntime),
blockListenerMethod,
new ArgumentListExpression(
getSpecificationContext(),
new ConstructorCallExpression(nodeCache.BlockInfo,
new ArgumentListExpression(
new PropertyExpression(
new ClassExpression(nodeCache.BlockKind),
blockType.name()
),
new ListExpression(
block.getDescriptions().stream().map(ConstantExpression::new).collect(Collectors.toList())
)
))
new ConstantExpression(block.getBlockMetaDataIndex(), true)
));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,9 @@ public void accept(ISpecVisitor visitor) throws Exception {
public BlockParseInfo getParseInfo() {
return BlockParseInfo.ANONYMOUS;
}

@Override
public boolean hasBlockMetadata() {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public abstract class Block extends Node<Method, List<Statement>> {
private final List<String> descriptions = new ArrayList<>(3);
private Block prev;
private Block next;
private int blockMetaDataIndex = -1;

public Block(Method parent) {
super(parent, new ArrayList<>());
Expand Down Expand Up @@ -80,5 +81,25 @@ public boolean isFirstInChain() {
return isFirst() || getClass() != prev.getClass();
}

public void setBlockMetaDataIndex(int blockMetaDataIndex) {
this.blockMetaDataIndex = blockMetaDataIndex;
}

public int getBlockMetaDataIndex() {
return blockMetaDataIndex;
}

/**
* Returns whether this block will be written to the {@link org.spockframework.runtime.model.BlockMetadata}.
*/
public boolean hasBlockMetadata() {
return true;
}

public abstract BlockParseInfo getParseInfo();

@Override
public String toString() {
return "Block kind: " + getClass().getSimpleName() + ", descriptions: " + descriptions;

Check warning on line 103 in spock-core/src/main/java/org/spockframework/compiler/model/Block.java

View check run for this annotation

Codecov / codecov/patch

spock-core/src/main/java/org/spockframework/compiler/model/Block.java#L103

Added line #L103 was not covered by tests
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,9 @@ public static Object[] despreadList(Object[] args, Object[] spreads, int[] posit

public static final String CALL_ENTER_BLOCK = "callEnterBlock";

public static void callEnterBlock(SpecificationContext context, BlockInfo blockInfo) {
public static void callEnterBlock(SpecificationContext context, int blockInfoIndex) {
IterationInfo currentIteration = context.getCurrentIteration();
BlockInfo blockInfo = context.getCurrentFeature().getBlocks().get(blockInfoIndex);
context.setCurrentBlock(blockInfo);
notifyBlockListener(currentIteration, blockListener -> blockListener.blockEntered(currentIteration, blockInfo));
}
Expand All @@ -240,8 +241,9 @@ private static void notifyBlockListener(IterationInfo currentIteration, Consumer

public static final String CALL_EXIT_BLOCK = "callExitBlock";

public static void callExitBlock(SpecificationContext context, BlockInfo blockInfo) {
public static void callExitBlock(SpecificationContext context, int blockInfoIndex) {
IterationInfo currentIteration = context.getCurrentIteration();
BlockInfo blockInfo = context.getCurrentFeature().getBlocks().get(blockInfoIndex);
notifyBlockListener(currentIteration, blockListener -> blockListener.blockExited(currentIteration, blockInfo));
context.setCurrentBlock(null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,6 @@ class ASpec extends Specification {
it.kind == block
it.texts == blockTexts
}
assert errorInfo.errorContext.toString() == ''
} else {
assert errorInfo.errorContext.currentBlock == null
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package org.spockframework.smoke.ast

import org.spockframework.EmbeddedSpecification
import org.spockframework.specs.extension.SpockSnapshotter
import spock.lang.Snapshot

class BlocksAst extends EmbeddedSpecification {
@Snapshot(extension = 'groovy')
SpockSnapshotter snapshotter

def "all observable blocks with empty labels"() {
given:
snapshotter.featureBody()

when:
def result = compiler.transpileFeatureBody('''
given: ''
expect: ''
when: ''
then: ''
cleanup: ''
where: ''
combined: ''
filter: ''
''')

then:
snapshotter.assertThat(result.source).matchesSnapshot()
}
def "all observable blocks with labels and blocks"() {
given:
snapshotter.featureBody()

when:
def result = compiler.transpileFeatureBody('''
given: 'given'
and: 'and given'
expect: 'expect'
and: 'and expect'
when: 'when'
and: 'and when'
then: 'then'
and: 'and then'
then: 'then2'
and: 'and then2'
cleanup: 'cleanup'
and: 'and cleanup'
where: 'where'
combined: 'combine'
filter: 'only one execution'
''')

then:
snapshotter.assertThat(result.source).matchesSnapshot()
}

def "all observable blocks with GString labels"() {
given:
snapshotter.featureBody()

when:
def result = compiler.transpileFeatureBody('''
int idx = 0
given: "given ${idx++}"
expect: "expect ${idx++}"
when: "when ${idx++}"
then: "then ${idx++}"
''')

then:
snapshotter.assertThat(result.source).matchesSnapshot()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,8 @@ public class apackage/TestSpec extends spock/lang/Specification implements groov
LDC Lorg/spockframework/runtime/SpecificationContext;.class
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
CHECKCAST org/spockframework/runtime/SpecificationContext
ALOAD 1
LDC 2
AALOAD
LDC Lorg/spockframework/runtime/model/BlockInfo;.class
ALOAD 1
LDC 3
AALOAD
LDC Lorg/spockframework/runtime/model/BlockKind;.class
INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; (itf)
ICONST_0
ANEWARRAY java/lang/Object
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.createList ([Ljava/lang/Object;)Ljava/util/List;
INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.callConstructor (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; (itf)
LDC Lorg/spockframework/runtime/model/BlockInfo;.class
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
CHECKCAST org/spockframework/runtime/model/BlockInfo
INVOKESTATIC org/spockframework/runtime/SpockRuntime.callEnterBlock (Lorg/spockframework/runtime/SpecificationContext;Lorg/spockframework/runtime/model/BlockInfo;)V
INVOKESTATIC org/spockframework/runtime/SpockRuntime.callEnterBlock (Lorg/spockframework/runtime/SpecificationContext;I)V
ACONST_NULL
POP
L0
Expand Down Expand Up @@ -116,47 +101,17 @@ public class apackage/TestSpec extends spock/lang/Specification implements groov
LDC Lorg/spockframework/runtime/SpecificationContext;.class
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
CHECKCAST org/spockframework/runtime/SpecificationContext
ALOAD 1
LDC 4
AALOAD
LDC Lorg/spockframework/runtime/model/BlockInfo;.class
ALOAD 1
LDC 5
AALOAD
LDC Lorg/spockframework/runtime/model/BlockKind;.class
INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; (itf)
ICONST_0
ANEWARRAY java/lang/Object
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.createList ([Ljava/lang/Object;)Ljava/util/List;
INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.callConstructor (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; (itf)
LDC Lorg/spockframework/runtime/model/BlockInfo;.class
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
CHECKCAST org/spockframework/runtime/model/BlockInfo
INVOKESTATIC org/spockframework/runtime/SpockRuntime.callExitBlock (Lorg/spockframework/runtime/SpecificationContext;Lorg/spockframework/runtime/model/BlockInfo;)V
INVOKESTATIC org/spockframework/runtime/SpockRuntime.callExitBlock (Lorg/spockframework/runtime/SpecificationContext;I)V
ACONST_NULL
POP
ALOAD 0
INVOKEVIRTUAL org/spockframework/lang/SpecInternals.getSpecificationContext ()Lorg/spockframework/lang/ISpecificationContext;
LDC Lorg/spockframework/runtime/SpecificationContext;.class
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
CHECKCAST org/spockframework/runtime/SpecificationContext
ALOAD 1
LDC 6
AALOAD
LDC Lorg/spockframework/runtime/model/BlockInfo;.class
ALOAD 1
LDC 7
AALOAD
LDC Lorg/spockframework/runtime/model/BlockKind;.class
INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; (itf)
ICONST_0
ANEWARRAY java/lang/Object
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.createList ([Ljava/lang/Object;)Ljava/util/List;
INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.callConstructor (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; (itf)
LDC Lorg/spockframework/runtime/model/BlockInfo;.class
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
CHECKCAST org/spockframework/runtime/model/BlockInfo
INVOKESTATIC org/spockframework/runtime/SpockRuntime.callEnterBlock (Lorg/spockframework/runtime/SpecificationContext;Lorg/spockframework/runtime/model/BlockInfo;)V
ICONST_1
INVOKESTATIC org/spockframework/runtime/SpockRuntime.callEnterBlock (Lorg/spockframework/runtime/SpecificationContext;I)V
ACONST_NULL
POP
ALOAD 0
Expand Down Expand Up @@ -207,53 +162,23 @@ public class apackage/TestSpec extends spock/lang/Specification implements groov
LDC Lorg/spockframework/runtime/SpecificationContext;.class
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
CHECKCAST org/spockframework/runtime/SpecificationContext
ALOAD 1
LDC 8
AALOAD
LDC Lorg/spockframework/runtime/model/BlockInfo;.class
ALOAD 1
LDC 9
AALOAD
LDC Lorg/spockframework/runtime/model/BlockKind;.class
INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; (itf)
ICONST_0
ANEWARRAY java/lang/Object
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.createList ([Ljava/lang/Object;)Ljava/util/List;
INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.callConstructor (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; (itf)
LDC Lorg/spockframework/runtime/model/BlockInfo;.class
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
CHECKCAST org/spockframework/runtime/model/BlockInfo
INVOKESTATIC org/spockframework/runtime/SpockRuntime.callExitBlock (Lorg/spockframework/runtime/SpecificationContext;Lorg/spockframework/runtime/model/BlockInfo;)V
ICONST_1
INVOKESTATIC org/spockframework/runtime/SpockRuntime.callExitBlock (Lorg/spockframework/runtime/SpecificationContext;I)V
ACONST_NULL
POP
ALOAD 0
INVOKEVIRTUAL org/spockframework/lang/SpecInternals.getSpecificationContext ()Lorg/spockframework/lang/ISpecificationContext;
LDC Lorg/spockframework/runtime/SpecificationContext;.class
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
CHECKCAST org/spockframework/runtime/SpecificationContext
ALOAD 1
LDC 10
AALOAD
LDC Lorg/spockframework/runtime/model/BlockInfo;.class
ALOAD 1
LDC 11
AALOAD
LDC Lorg/spockframework/runtime/model/BlockKind;.class
INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; (itf)
ICONST_0
ANEWARRAY java/lang/Object
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.createList ([Ljava/lang/Object;)Ljava/util/List;
INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.callConstructor (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; (itf)
LDC Lorg/spockframework/runtime/model/BlockInfo;.class
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
CHECKCAST org/spockframework/runtime/model/BlockInfo
INVOKESTATIC org/spockframework/runtime/SpockRuntime.callEnterBlock (Lorg/spockframework/runtime/SpecificationContext;Lorg/spockframework/runtime/model/BlockInfo;)V
ICONST_2
INVOKESTATIC org/spockframework/runtime/SpockRuntime.callEnterBlock (Lorg/spockframework/runtime/SpecificationContext;I)V
ACONST_NULL
POP
L17
LINENUMBER 8 L17
ALOAD 1
LDC 12
LDC 2
AALOAD
ALOAD 0
ACONST_NULL
Expand All @@ -266,23 +191,8 @@ public class apackage/TestSpec extends spock/lang/Specification implements groov
LDC Lorg/spockframework/runtime/SpecificationContext;.class
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
CHECKCAST org/spockframework/runtime/SpecificationContext
ALOAD 1
LDC 13
AALOAD
LDC Lorg/spockframework/runtime/model/BlockInfo;.class
ALOAD 1
LDC 14
AALOAD
LDC Lorg/spockframework/runtime/model/BlockKind;.class
INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; (itf)
ICONST_0
ANEWARRAY java/lang/Object
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.createList ([Ljava/lang/Object;)Ljava/util/List;
INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.callConstructor (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; (itf)
LDC Lorg/spockframework/runtime/model/BlockInfo;.class
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType (Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
CHECKCAST org/spockframework/runtime/model/BlockInfo
INVOKESTATIC org/spockframework/runtime/SpockRuntime.callExitBlock (Lorg/spockframework/runtime/SpecificationContext;Lorg/spockframework/runtime/model/BlockInfo;)V
ICONST_2
INVOKESTATIC org/spockframework/runtime/SpockRuntime.callExitBlock (Lorg/spockframework/runtime/SpecificationContext;I)V
ACONST_NULL
POP
ALOAD 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ public class apackage.ASpec extends spock.lang.Specification {

@org.spockframework.runtime.model.FeatureMetadata(name = 'a feature', ordinal = 0, line = 1, blocks = [@org.spockframework.runtime.model.BlockMetadata(kind = org.spockframework.runtime.model.BlockKind.SETUP, texts = [])], parameterNames = [])
public void $spock_feature_0_0() {
org.spockframework.runtime.SpockRuntime.callEnterBlock(this.getSpecificationContext(), new org.spockframework.runtime.model.BlockInfo(org.spockframework.runtime.model.BlockKind.SETUP, []))
org.spockframework.runtime.SpockRuntime.callEnterBlock(this.getSpecificationContext(), 0)
java.lang.Object nothing = null
org.spockframework.runtime.SpockRuntime.callExitBlock(this.getSpecificationContext(), new org.spockframework.runtime.model.BlockInfo(org.spockframework.runtime.model.BlockKind.SETUP, []))
org.spockframework.runtime.SpockRuntime.callExitBlock(this.getSpecificationContext(), 0)
this.getSpecificationContext().getMockController().leaveScope()
}

Expand Down
Loading

0 comments on commit b819d74

Please sign in to comment.