Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding block listener support #111

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ private boolean constructorMayHaveBeenAddedByCompiler(ConstructorNode constructo

public void visitMethod(MethodNode method) {
if (isIgnoredMethod(method)) return;

if (isFixtureMethod(method))
buildFixtureMethod(method);
else if (isFeatureMethod(method))
Expand All @@ -111,7 +111,7 @@ private boolean isFixtureMethod(MethodNode method) {
if (!fmName.equalsIgnoreCase(name)) continue;

// assertion: is (meant to be) a fixture method, so we'll return true in the end

if (method.isStatic())
errorReporter.error(method, "Fixture methods must not be static");
if (!fmName.equals(name))
Expand Down Expand Up @@ -172,7 +172,7 @@ private void buildFeatureMethod(MethodNode method) {
spec.getMethods().add(feature);
}

private void buildHelperMethod(MethodNode method) {
private void buildHelperMethod(MethodNode method) {
Method helper = new HelperMethod(spec, method);
spec.getMethods().add(helper);

Expand All @@ -192,7 +192,7 @@ private void buildBlocks(Method method) throws InvalidSpecCompileException {
else
currBlock = addBlock(method, stat);
}

checkIsValidSuccessor(method, BlockParseInfo.METHOD_END,
method.getAst().getLastLineNumber(), method.getAst().getLastColumnNumber());

Expand All @@ -212,8 +212,13 @@ private Block addBlock(Method method, Statement stat) throws InvalidSpecCompileE
String description = getDescription(stat);
if (description == null)
block.getAst().add(stat);
else
else {
if(block.getName().equalsIgnoreCase("when") || block.getName().equalsIgnoreCase("then")
|| block.getName().equalsIgnoreCase("setup")) {
block.getAst().add(stat);
}
block.getDescriptions().add(description);
}

return block;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.*;

import org.codehaus.groovy.ast.*;
import org.codehaus.groovy.ast.builder.AstBuilder;
import org.codehaus.groovy.ast.expr.*;
import org.codehaus.groovy.ast.stmt.*;
import org.codehaus.groovy.runtime.MetaClassHelper;
Expand All @@ -33,7 +34,7 @@

/**
* A Spec visitor responsible for most of the rewriting of a Spec's AST.
*
*
* @author Peter Niederwieser
*/
// IDEA: mock controller / leaveScope calls should only be inserted when necessary (increases robustness)
Expand Down Expand Up @@ -176,7 +177,7 @@ def sharedFieldGetter() { sharedInstance.sharedField }
class DerivedSpec extends BaseSpec {}

// when DerivedSpec is run:

def sharedInstance = new DerivedSpec()

def spec = new DerivedSpec()
Expand Down Expand Up @@ -312,7 +313,58 @@ public void visitAnyBlock(Block block) {
methodHasCondition |= deep.isConditionFound();
}

private void updateNotify(String method, Block block) {
List<Statement> statements = block.getAst();
if (!statements.isEmpty()) {
int count = 0;
for (Statement stmt : statements) {
if (stmt instanceof ExpressionStatement) {
ExpressionStatement exptrStmt = (ExpressionStatement) stmt;
if (exptrStmt.getExpression() instanceof GStringExpression || (exptrStmt.getExpression() instanceof ConstantExpression && ((ConstantExpression)exptrStmt.getExpression()).getValue() instanceof String)) {
ForStatement forStmt = getNotifyWhenThen(method, exptrStmt.getExpression());
statements.set(count, forStmt);
}
}
count++;
}
}
}

private ForStatement getNotifyWhenThen(String blockType, Expression expr) {
List<ASTNode> nodes = new AstBuilder().buildFromString("for( def listener : getSpecificationContext().getCurrentSpec().getListeners()){ \n" +
"true;\n" +

"}\n");
ForStatement forStatement = (ForStatement) ((BlockStatement) ((BlockStatement) nodes.get(0)).getStatements().get(0)).getStatements().get(0);
BlockStatement forLoopBlock = new BlockStatement();
forLoopBlock.addStatement(
new ExpressionStatement(
new BinaryExpression(
new MethodCallExpression(
new VariableExpression("listener"),
new ConstantExpression("block"),
new ArgumentListExpression(new Expression[]{new ConstantExpression(blockType), expr})
),
new Token( Types.LOGICAL_OR, "||", -1, -1 ),
new ConstantExpression(true)
)
)
);
forStatement.setLoopBlock(forLoopBlock);
return forStatement;
}

public void visitWhenBlock(WhenBlock block) throws Exception {
updateNotify("when", block);
}

public void visitSetupBlock(SetupBlock block) throws Exception {
updateNotify("setup", block);
}

public void visitThenBlock(ThenBlock block) {
updateNotify("then", block);

if (block.isFirstInChain()) thenBlockChainHasExceptionCondition = false;

DeepBlockRewriter deep = new DeepBlockRewriter(this);
Expand Down Expand Up @@ -555,7 +607,7 @@ private Expression createDefaultValueInitializer(DeclarationExpression expr) {
for (Expression elementExpr : tupleExpr.getExpressions()) {
Variable variable = (Variable) elementExpr;
listExpr.addExpression(new ConstantExpression(
ReflectionUtil.getDefaultValue(variable.getOriginType().getTypeClass())));
ReflectionUtil.getDefaultValue(variable.getOriginType().getTypeClass())));
}

return listExpr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,16 @@ public void beforeSpec(SpecInfo spec) {
specFailed = false;

emit(putAll(mapOf(
"package", spec.getPackage(),
"name", spec.getName(),
"start", getCurrentTime()
"package", spec.getPackage(),
"name", spec.getName(),
"start", getCurrentTime()
), renderNarrative(spec.getNarrative()), renderTags(spec.getTags())));
}

public void block(String type, String description) {
// System.out.println(type+description);
}

public void beforeFeature(FeatureInfo feature) {
currentFeature = feature;
featureFailed = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ public void afterSpec(SpecInfo spec) {}
public void error(ErrorInfo error) {}
public void specSkipped(SpecInfo spec) {}
public void featureSkipped(FeatureInfo feature) {}
public void block(String type, String description) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,14 @@ public void beforeSpec(final SpecInfo spec) {
public void run() {
delegate.beforeSpec(spec);
}
});
});
}
public void block(final String type, final String description) {
addEvent(new Runnable() {
public void run() {
delegate.block(type, description);
}
});
}

public void beforeFeature(final FeatureInfo feature) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public interface IRunListener {
*/
void beforeSpec(SpecInfo spec);

/**
* Called when a block is reached.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't be useful to have both beforeBlock and afterBlock?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't have a use case for afterBlock. My current use case for this is to have dinamic reports by resolving the block expression before sending it to the reports listener

*/
void block(String type,String description);

/**
* Called before each feature of a spec.
*/
Expand Down Expand Up @@ -71,7 +76,7 @@ public interface IRunListener {
// IDEA: might be able to remove remaining two methods and
// call before/after instead, since skip flag should be set on
// SpecInfo/FeatureInfo anyway

/**
* Called if a spec is skipped, for example because it is marked
* with @Ignore.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ public void beforeSpec(SpecInfo spec) {
}
}

public void block(String type, String description) {
for (IRunListener listener : spec.getListeners()) {
listener.block(type, description);
}
}

public void beforeFeature(FeatureInfo feature) {
for (IRunListener listener : spec.getListeners()) {
listener.beforeFeature(feature);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ So that bar
then: "baz"
println("out2")


and: "bazbaz"
System.err.println("err2")
}
Expand Down Expand Up @@ -109,7 +110,6 @@ loadLogFile([{

def "write execution log for spec with failing feature"() {
runner.throwFailure = false

when:
runner.runWithImports(
"""
Expand Down