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

NPE when variable is initialized using a method with the same name in features calling "thrown()" #1266

Closed
rieske opened this issue Jan 26, 2021 · 1 comment · Fixed by #1314

Comments

@rieske
Copy link
Contributor

rieske commented Jan 26, 2021

Issue description

A variable initialized using a method with the same name, as in def foo = foo() throws a NullPointerException when used in a feature method that calls thrown() in then: block.

How to reproduce

class SomeSpec extends spock.lang.Specification {
    def "foo test"() { // fails
        when:
        def foo = foo() // fails here
        println(foo)
        throw new IllegalStateException()

        then:
        thrown IllegalStateException
    }

    def "bar test"() { // passes
        when:
        def bar = foo()
        println(bar)
        throw new IllegalStateException()

        then:
        thrown IllegalStateException
    }

    String foo() {
        return "foo"
    }
}

foo test fails when running this test class (only tried with Gradle):

Expected exception of type 'java.lang.IllegalStateException', but got 'java.lang.NullPointerException'
	at org.spockframework.lang.SpecInternals.checkExceptionThrown(SpecInternals.java:81)
	at org.spockframework.lang.SpecInternals.thrownImpl(SpecInternals.java:68)
	at SomeSpec.foo test(SomeSpec.groovy:9)
Caused by: java.lang.NullPointerException: Cannot invoke method call() on null object
	at SomeSpec.foo test(SomeSpec.groovy:4)

Additional Environment information

Java/JDK

java -version

openjdk version "11.0.8" 2020-07-14
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.8+10)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.8+10, mixed mode)

Build-tool dependencies used

Gradle 6.8.1

Fails with: testImplementation("org.spockframework:spock-core:2.0-M4-groovy-2.5") and testImplementation("org.spockframework:spock-core:2.0-M4-groovy-3.0")

Works with: testImplementation("org.spockframework:spock-core:1.3-groovy-2.5")

@leonard84
Copy link
Member

Hm, this might be a bit tricky to fix.

This happens because Spock transforms the when block above thrown into

        java.lang.Object foo 
        this.getSpecificationContext().setThrownException(null)
        try {
            foo = foo.call()
            this.println(foo)
            throw new java.lang.IllegalStateException()
        } 
        catch (java.lang.Throwable $spock_ex) {
            this.getSpecificationContext().setThrownException($spock_ex)
        } 

as you can see declaration and assignment are now split.

It is basically the same as

class Other {

   void bar() {
        def foo = null
        foo = foo() // fails here
   }


    String foo() {
        return "foo"
    }
}

I'm pretty sure that is some groovy heuristic that turns this.foo() into foo.call() when foo is declared as a local variable, but this needs further investigation. Probably the VariableScopeVisitor again.

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

Successfully merging a pull request may close this issue.

2 participants