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

Assertions in Switch Expressions lead to compiler error #1845

Open
joshuabrandes opened this issue Dec 13, 2023 · 1 comment
Open

Assertions in Switch Expressions lead to compiler error #1845

joshuabrandes opened this issue Dec 13, 2023 · 1 comment
Labels

Comments

@joshuabrandes
Copy link

Describe the bug

Version: 2.4-M1-groovy-4.0

I have a test case where I need to get content form a map and assert its value. I first tried it with a switch expression and build a example I can share:

class MathTest extends Specification {

    def "test square"() {
        setup: "two numbers"
        var b = 2
        Map<Integer, Integer> map = new HashMap<>()
        map.put(b, Main.square(b))

        expect: "squaring the number"
        switch (b) {
            case 2 -> map.get(b) == 4
            default -> throw new Exception("Not implemented")
        }
    }
}

When I ant to run this test I get the following build output:

Groovyc: While compiling [tests of spock-testing]: Unexpected error during compilation of spec 'MathTest'. Maybe you have used invalid Spock syntax? Anyway, please file a bug report at https://issues.spockframework.org.

java.lang.ClassCastException: class org.codehaus.groovy.ast.stmt.AssertStatement cannot be cast to class org.codehaus.groovy.ast.stmt.BlockStatement (org.codehaus.groovy.ast.stmt.AssertStatement and org.codehaus.groovy.ast.stmt.BlockStatement are in unnamed module of loader org.jetbrains.jps.incremental.groovy.JointCompilationClassLoader @43b8b9ec)
	at org.spockframework.compiler.AstUtil.getStatements(AstUtil.java:88)
	at org.spockframework.compiler.DeepBlockRewriter.defineRecorders(DeepBlockRewriter.java:305)
	at org.spockframework.compiler.DeepBlockRewriter.doVisitClosureExpression(DeepBlockRewriter.java:136)
	at org.spockframework.compiler.AbstractDeepBlockRewriter.visitClosureExpression(AbstractDeepBlockRewriter.java:152)
	at org.codehaus.groovy.ast.expr.ClosureExpression.visit(ClosureExpression.java:110)
	at org.codehaus.groovy.ast.CodeVisitorSupport.visitMethodCallExpression(CodeVisitorSupport.java:184)
	at org.spockframework.compiler.AbstractDeepBlockRewriter.doVisitMethodCallExpression(AbstractDeepBlockRewriter.java:170)
	at org.spockframework.compiler.DeepBlockRewriter.doVisitMethodCallExpression(DeepBlockRewriter.java:148)
	at org.spockframework.compiler.AbstractDeepBlockRewriter.visitMethodCallExpression(AbstractDeepBlockRewriter.java:132)
	at org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:77)
	at org.codehaus.groovy.ast.CodeVisitorSupport.visitReturnStatement(CodeVisitorSupport.java:122)
	at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitReturnStatement(ClassCodeVisitorSupport.java:222)
	at org.codehaus.groovy.ast.stmt.ReturnStatement.visit(ReturnStatement.java:73)
	at org.spockframework.compiler.StatementReplacingVisitorSupport.replace(StatementReplacingVisitorSupport.java:44)
	at org.spockframework.compiler.StatementReplacingVisitorSupport.replaceAll(StatementReplacingVisitorSupport.java:59)
	at org.spockframework.compiler.StatementReplacingVisitorSupport.visitBlockStatement(StatementReplacingVisitorSupport.java:72)
	at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:70)
	at org.spockframework.compiler.StatementReplacingVisitorSupport.replace(StatementReplacingVisitorSupport.java:44)
	at org.spockframework.compiler.StatementReplacingVisitorSupport.visitCaseStatement(StatementReplacingVisitorSupport.java:119)
	at org.codehaus.groovy.ast.stmt.CaseStatement.visit(CaseStatement.java:56)
	at org.spockframework.compiler.StatementReplacingVisitorSupport.replace(StatementReplacingVisitorSupport.java:44)
	at org.spockframework.compiler.StatementReplacingVisitorSupport.replaceAll(StatementReplacingVisitorSupport.java:59)
	at org.spockframework.compiler.StatementReplacingVisitorSupport.visitSwitch(StatementReplacingVisitorSupport.java:112)
	at org.codehaus.groovy.ast.stmt.SwitchStatement.visit(SwitchStatement.java:54)
	at org.spockframework.compiler.StatementReplacingVisitorSupport.replace(StatementReplacingVisitorSupport.java:44)
	at org.spockframework.compiler.StatementReplacingVisitorSupport.replaceAll(StatementReplacingVisitorSupport.java:59)
	at org.spockframework.compiler.StatementReplacingVisitorSupport.visitBlockStatement(StatementReplacingVisitorSupport.java:72)
	at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:70)
	at org.codehaus.groovy.ast.CodeVisitorSupport.visitClosureExpression(CodeVisitorSupport.java:239)
	at org.spockframework.compiler.AbstractDeepBlockRewriter.doVisitClosureExpression(AbstractDeepBlockRewriter.java:174)
	at org.spockframework.compiler.DeepBlockRewriter.doVisitClosureExpression(DeepBlockRewriter.java:135)
	at org.spockframework.compiler.AbstractDeepBlockRewriter.visitClosureExpression(AbstractDeepBlockRewriter.java:152)
	at org.codehaus.groovy.ast.expr.ClosureExpression.visit(ClosureExpression.java:110)
	at org.codehaus.groovy.ast.CodeVisitorSupport.visitMethodCallExpression(CodeVisitorSupport.java:184)
	at org.spockframework.compiler.AbstractDeepBlockRewriter.doVisitMethodCallExpression(AbstractDeepBlockRewriter.java:170)
	at org.spockframework.compiler.DeepBlockRewriter.doVisitMethodCallExpression(DeepBlockRewriter.java:148)
	at org.spockframework.compiler.AbstractDeepBlockRewriter.visitMethodCallExpression(AbstractDeepBlockRewriter.java:132)
	at org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:77)
	at org.codehaus.groovy.ast.CodeVisitorSupport.visitExpressionStatement(CodeVisitorSupport.java:117)
	at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitExpressionStatement(ClassCodeVisitorSupport.java:204)
	at org.spockframework.compiler.AbstractDeepBlockRewriter.doVisitExpressionStatement(AbstractDeepBlockRewriter.java:162)
	at org.spockframework.compiler.DeepBlockRewriter.visitInteractionAwareExpressionStatement(DeepBlockRewriter.java:96)
	at org.spockframework.compiler.DeepBlockRewriter.doVisitExpressionStatement(DeepBlockRewriter.java:78)
	at org.spockframework.compiler.AbstractDeepBlockRewriter.visitExpressionStatement(AbstractDeepBlockRewriter.java:100)
	at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:41)
	at org.spockframework.compiler.StatementReplacingVisitorSupport.replace(StatementReplacingVisitorSupport.java:44)
	at org.spockframework.compiler.AbstractDeepBlockRewriter.visit(AbstractDeepBlockRewriter.java:84)
	at org.spockframework.compiler.DeepBlockRewriter.visit(DeepBlockRewriter.java:56)
	at org.spockframework.compiler.SpecRewriter.visitAnyBlock(SpecRewriter.java:405)
	at org.spockframework.compiler.model.ExpectBlock.accept(ExpectBlock.java:31)
	at org.spockframework.compiler.model.Method.accept(Method.java:70)
	at org.spockframework.compiler.model.Spec.accept(Spec.java:112)
	at org.spockframework.compiler.SpockTransform$Impl.processSpec(SpockTransform.java:76)
	at org.spockframework.compiler.SpockTransform$Impl.visit(SpockTransform.java:63)
	at org.spockframework.compiler.SpockTransform.visit(SpockTransform.java:48)
	at org.codehaus.groovy.transform.ASTTransformationVisitor.lambda$addPhaseOperationsForGlobalTransforms$5(ASTTransformationVisitor.java:377)
	at org.codehaus.groovy.control.CompilationUnit$ISourceUnitOperation.doPhaseOperation(CompilationUnit.java:896)
	at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:692)
	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:666)
	at org.jetbrains.groovy.compiler.rt.GroovyCompilerWrapper.compile(GroovyCompilerWrapper.java:48)
	at org.jetbrains.groovy.compiler.rt.DependentGroovycRunner.runGroovyc(DependentGroovycRunner.java:122)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
	at java.base/java.lang.reflect.Method.invoke(Method.java:578)
	at org.jetbrains.groovy.compiler.rt.GroovycRunner.intMain2(GroovycRunner.java:80)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
	at java.base/java.lang.reflect.Method.invoke(Method.java:578)
	at org.jetbrains.jps.incremental.groovy.InProcessGroovyc.runGroovycInThisProcess(InProcessGroovyc.java:167)
	at org.jetbrains.jps.incremental.groovy.InProcessGroovyc.lambda$runGroovyc$0(InProcessGroovyc.java:77)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1589)

To Reproduce

def "assert test"() {
    expect:
    def b = 3
    switch (b) {
        default -> assert 1 == 1
    }
}

Expected behavior

assertion is executed in the matching case

Actual behavior

compiler error

Java version

java version "21" 2023-09-19 LTS

Buildtool version

Apache Maven 3.8.5

What operating system are you using

Windows

Dependencies

--- maven-dependency-plugin:2.8:tree (default-cli) @ spock-testing ---
[INFO] org.example:spock-testing:jar:1.0-SNAPSHOT
[INFO] +- org.junit.jupiter:junit-jupiter-api:jar:5.8.2:test
[INFO] |  +- org.opentest4j:opentest4j:jar:1.2.0:compile
[INFO] |  +- org.junit.platform:junit-platform-commons:jar:1.8.2:compile
[INFO] |  \- org.apiguardian:apiguardian-api:jar:1.1.2:compile
[INFO] \- org.spockframework:spock-core:jar:2.4-M1-groovy-4.0:compile
[INFO]    +- org.apache.groovy:groovy:jar:4.0.6:compile
[INFO]    +- org.junit.platform:junit-platform-engine:jar:1.9.0:compile
[INFO]    \- org.hamcrest:hamcrest:jar:2.2:compile

Additional context

No response

@leonard84
Copy link
Member

FWIW implicit assertions in if-blocks are ignored, so even if we fix the compile error, I'm not sure that we'd treat the branches of the switch-expression as implicit conditions.

In general I'd consider conditional logic in tests a code smell.
I know that practically might sometimes still make them necessary, but they should be avoided if possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants