joke / spock-mockable

Mock the un-mockable
Apache License 2.0
28 stars 2 forks source link

Compilation error when mocking Groovy class #350

Open rosincc opened 1 year ago

rosincc commented 1 year ago
import spock.lang.Specification

class T extends Specification {
    def t() {
        given:
        def a = Spy(A)
    }
}

class A {}

The execution reports the following error:

Groovyc: While compiling [tests of spock-mockable-static]: BUG! exception in phase 'canonicalization' in source unit '/Users/xxx/workspace/spock-mockable-static/src/test/groovy/T.groovy' ClassNode#getTypeClass for A called before the type class is set
    at org.codehaus.groovy.ast.ClassNode.getTypeClass(ClassNode.java:1465)
    at org.codehaus.groovy.ast.ClassNode.getTypeClass(ClassNode.java:1459)
    at java.util.Optional.map(Optional.java:215)
    at io.github.joke.spockmockable.ast.visitors.MockVisitor$Visitor.extractClass(MockVisitor.java:88)
    at java.util.Optional.flatMap(Optional.java:241)
    at io.github.joke.spockmockable.ast.visitors.MockVisitor$Visitor.visitClassExpression(MockVisitor.java:59)
    at org.codehaus.groovy.ast.expr.ClassExpression.visit(ClassExpression.java:36)
    at org.codehaus.groovy.ast.GroovyCodeVisitor.lambda$visitListOfExpressions$0(GroovyCodeVisitor.java:209)
    at java.util.ArrayList.forEach(ArrayList.java:1259)
    at org.codehaus.groovy.ast.GroovyCodeVisitor.visitListOfExpressions(GroovyCodeVisitor.java:209)
    at org.codehaus.groovy.ast.CodeVisitorSupport.visitTupleExpression(CodeVisitorSupport.java:249)
    at org.codehaus.groovy.ast.CodeVisitorSupport.visitArgumentlistExpression(CodeVisitorSupport.java:367)
    at org.codehaus.groovy.ast.expr.ArgumentListExpression.visit(ArgumentListExpression.java:75)
    at io.github.joke.spockmockable.ast.visitors.MockVisitor$Visitor.visitMethodCallExpression(MockVisitor.java:51)
    at io.github.joke.spockmockable.ast.visitors.MockVisitor.visit(MockVisitor.java:37)
    at io.github.joke.spockmockable.ast.visitors.SpecificationVisitor$Visitor.visitMethodCallExpression(SpecificationVisitor.java:37)
    at org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:77)
    at org.codehaus.groovy.ast.CodeVisitorSupport.visitBinaryExpression(CodeVisitorSupport.java:202)
    at org.codehaus.groovy.ast.CodeVisitorSupport.visitDeclarationExpression(CodeVisitorSupport.java:335)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitDeclarationExpression(ClassCodeVisitorSupport.java:154)
    at org.codehaus.groovy.ast.expr.DeclarationExpression.visit(DeclarationExpression.java:89)
    at org.codehaus.groovy.ast.CodeVisitorSupport.visitExpressionStatement(CodeVisitorSupport.java:117)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitExpressionStatement(ClassCodeVisitorSupport.java:204)
    at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:41)
    at org.codehaus.groovy.ast.CodeVisitorSupport.visitBlockStatement(CodeVisitorSupport.java:86)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitBlockStatement(ClassCodeVisitorSupport.java:168)
    at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:70)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClassCodeContainer(ClassCodeVisitorSupport.java:142)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitConstructorOrMethod(ClassCodeVisitorSupport.java:115)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitMethod(ClassCodeVisitorSupport.java:110)
    at org.codehaus.groovy.ast.ClassNode.visitMethods(ClassNode.java:1131)
    at org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:1124)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClass(ClassCodeVisitorSupport.java:52)
    at io.github.joke.spockmockable.ast.visitors.SpecificationVisitor.visit(SpecificationVisitor.java:24)
    at io.github.joke.spockmockable.ast.SpecificationProcessor.process(SpecificationProcessor.java:14)
    at io.github.joke.spockmockable.ast.SourceUnitProcessor.lambda$process$1(SourceUnitProcessor.java:22)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
    at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
    at java.util.LinkedList$LLSpliterator.forEachRemaining(LinkedList.java:1235)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:485)
    at io.github.joke.spockmockable.ast.SourceUnitProcessor.process(SourceUnitProcessor.java:22)
    at io.github.joke.spockmockable.ast.Processor.analyze(Processor.java:21)
    at io.github.joke.spockmockable.ast.MockableASTTransformation.visit(MockableASTTransformation.java:34)
    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:120)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.jetbrains.groovy.compiler.rt.GroovycRunner.intMain2(GroovycRunner.java:80)
    at org.jetbrains.groovy.compiler.rt.GroovycRunner.intMain(GroovycRunner.java:40)
    at org.jetbrains.groovy.compiler.rt.GroovycRunner.main(GroovycRunner.java:19)
joke commented 1 year ago

Hi @hellsof

could you provide a more detailed example? I can reproduce the error but I'm entirely sure about what you are actually trying to do in the first place. If I create a groovy class in the compile scope (main) everything works fine.

Are you really trying to spy a class with is placed alongside your test classes?

rosincc commented 1 year ago

There is no specific application scenario for the time being. When writing a demo program, this exception is reported, but no relevant records are found, and this problem is accidentally discovered when it is about to give up.

joke commented 1 year ago

@hellsof It has something to do with the compile time groovy transformation for this extension. I'll take a closer look today.

Regards Joke

ClaudioConsolmagno commented 1 year ago

Coming across this issue as well when using thrown with my custom Exception class in Groovy. Here's a short test case example:

    class FooException extends RuntimeException {}

    def exceptionThrower() { throw new FooException() }

    def "Test"() {
        when:
            exceptionThrower()
        then:
            thrown(FooException)
    }

This fails compilation (error below). If you swap thrown(FooException) by thrown(RuntimeException) compilation and test pass.

Caused by: BUG! exception in phase 'canonicalization' in source unit 'xxxxx/Test.groovy' ClassNode#getTypeClass for xxxxx.Test$FooException called before the type class is set
    at io.github.joke.spockmockable.ast.visitors.MockVisitor$Visitor.extractClass(MockVisitor.java:88)
    at io.github.joke.spockmockable.ast.visitors.MockVisitor$Visitor.visitClassExpression(MockVisitor.java:59)
    at io.github.joke.spockmockable.ast.visitors.MockVisitor$Visitor.visitMethodCallExpression(MockVisitor.java:51)
    at io.github.joke.spockmockable.ast.visitors.MockVisitor.visit(MockVisitor.java:37)
    at io.github.joke.spockmockable.ast.visitors.SpecificationVisitor$Visitor.visitMethodCallExpression(SpecificationVisitor.java:37)
    at io.github.joke.spockmockable.ast.visitors.SpecificationVisitor.visit(SpecificationVisitor.java:24)
    at io.github.joke.spockmockable.ast.SpecificationProcessor.process(SpecificationProcessor.java:14)
    at io.github.joke.spockmockable.ast.SourceUnitProcessor.lambda$process$1(SourceUnitProcessor.java:22)
    at io.github.joke.spockmockable.ast.SourceUnitProcessor.process(SourceUnitProcessor.java:22)
    at io.github.joke.spockmockable.ast.Processor.analyze(Processor.java:21)
    at io.github.joke.spockmockable.ast.MockableASTTransformation.visit(MockableASTTransformation.java:34)
    at org.gradle.api.internal.tasks.compile.ApiGroovyCompiler.execute(ApiGroovyCompiler.java:271)
    at org.gradle.api.internal.tasks.compile.ApiGroovyCompiler.execute(ApiGroovyCompiler.java:64)
    at org.gradle.api.internal.tasks.compile.GroovyCompilerFactory$DaemonSideCompiler.execute(GroovyCompilerFactory.java:97)
    at org.gradle.api.internal.tasks.compile.GroovyCompilerFactory$DaemonSideCompiler.execute(GroovyCompilerFactory.java:76)
    at org.gradle.api.internal.tasks.compile.daemon.AbstractDaemonCompiler$CompilerWorkAction.execute(AbstractDaemonCompiler.java:135)
    at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
    at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:49)
    at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:43)
    at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
    at org.gradle.workers.internal.AbstractClassLoaderWorker.executeInClassLoader(AbstractClassLoaderWorker.java:43)
    at org.gradle.workers.internal.IsolatedClassloaderWorker.run(IsolatedClassloaderWorker.java:49)
    at org.gradle.workers.internal.IsolatedClassloaderWorker.run(IsolatedClassloaderWorker.java:30)
    at org.gradle.workers.internal.WorkerDaemonServer.run(WorkerDaemonServer.java:87)
    at org.gradle.workers.internal.WorkerDaemonServer.run(WorkerDaemonServer.java:56)
    at org.gradle.process.internal.worker.request.WorkerAction$1.call(WorkerAction.java:138)
    at org.gradle.process.internal.worker.child.WorkerLogEventListener.withWorkerLoggingProtocol(WorkerLogEventListener.java:41)
    at org.gradle.process.internal.worker.request.WorkerAction.run(WorkerAction.java:135)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:49)