From 2fff484b7a5e6927913ad75264abf6fd33504f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Kautler?= Date: Mon, 21 Aug 2023 22:43:39 +0200 Subject: [PATCH] Make the AST transformation more robust... (#1704) against missing classes in the compile classpath --- .../compiler/SpecialMethodCall.java | 14 +++++--- .../smoke/CompileTimeErrorReporting.groovy | 34 +++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/spock-core/src/main/java/org/spockframework/compiler/SpecialMethodCall.java b/spock-core/src/main/java/org/spockframework/compiler/SpecialMethodCall.java index fc095b6024..c44de3bc16 100644 --- a/spock-core/src/main/java/org/spockframework/compiler/SpecialMethodCall.java +++ b/spock-core/src/main/java/org/spockframework/compiler/SpecialMethodCall.java @@ -266,11 +266,17 @@ private static boolean checkIsConditionBlock(MethodCallExpression methodCallExpr ClassNode targetType = methodCallExpr.getObjectExpression().getType(); String methodName = methodCallExpr.getMethodAsString(); - List methods = targetType.getMethods(methodName); - for (MethodNode method : methods) { - for (AnnotationNode annotation : method.getAnnotations()) { - if (annotation.getClassNode().getName().equals(ConditionBlock.class.getName())) return true; + try { + // if targetType has any method with a parameter or return type that is not in the + // compile classpath this call will fail with a NoClassDefFoundError + List methods = targetType.getMethods(methodName); + for (MethodNode method : methods) { + for (AnnotationNode annotation : method.getAnnotations()) { + if (annotation.getClassNode().getName().equals(ConditionBlock.class.getName())) return true; + } } + } catch (NoClassDefFoundError e) { + // just assume there is no condition block and return false } return false; diff --git a/spock-specs/src/test/groovy/org/spockframework/smoke/CompileTimeErrorReporting.groovy b/spock-specs/src/test/groovy/org/spockframework/smoke/CompileTimeErrorReporting.groovy index 827d958990..bcb96d985d 100644 --- a/spock-specs/src/test/groovy/org/spockframework/smoke/CompileTimeErrorReporting.groovy +++ b/spock-specs/src/test/groovy/org/spockframework/smoke/CompileTimeErrorReporting.groovy @@ -14,6 +14,8 @@ package org.spockframework.smoke +import org.codehaus.groovy.ast.ClassNode +import org.jetbrains.annotations.Debug import org.spockframework.EmbeddedSpecification import org.spockframework.compiler.InvalidSpecCompileException @@ -80,4 +82,36 @@ println "hi" then: thrown(InvalidSpecCompileException) } + + static class Foo { + Debug getDebug() { return null } + void bar() {} + } + + def "compiling with missing dependencies does not fail"() { + given: + compiler.addClassImport('org.spockframework.smoke.CompileTimeErrorReporting.Foo') + + when: + new ClassNode(Class.forName('org.spockframework.smoke.CompileTimeErrorReporting$Foo')) + .getMethods('bar') + + then: 'make sure it would fail for the right reason, this might change if `Debug` makes it into the runtime classpath' + NoClassDefFoundError ncdfe = thrown() + println(ncdfe.message) + ncdfe.message.contains('org.spockframework.smoke.CompileTimeErrorReporting$Foo') + ncdfe.message.contains('org/jetbrains/annotations/Debug') + + when: + compiler.compileFeatureBody """ +when: +new Foo().bar() + +then: +noExceptionThrown() + """ + + then: + noExceptionThrown() + } }