Skip to content

AST transformation messes up setter/getter in dot-property notation #1158

@kriegaex

Description

@kriegaex

I found this on StackOverflow. Here is my slightly modifed version of the sample code:

package de.scrum_master.stackoverflow.q61599143

import spock.lang.Specification

class PropertyAccessTest extends Specification {
  def 'test setter on interface'() {
    given:
    def foo = Mock(Foo)
    when:
    foo.prop = 'val'
    then:
    1 * foo.setProp(_)
  }

  def 'test getter on interface'() {
    given:
    def foo = Mock(Foo)
    when:
    foo.prop
    then:
    1 * foo.getProp()
  }

  def 'test setter on abstract'() {
    given:
    def foo = Mock(FooBase)
    when:
    foo.prop = 'val'
    //foo.setProp('val')
    then:
    1 * foo.setProp(_)
    //1 * foo.setProperty('prop', 'val')
  }

  def 'test getter on abstract'() {
    given:
    def foo = Mock(FooBase)
    when:
    foo.prop
    //foo.getProp()
    then:
    1 * foo.getProp()
    //1 * foo.getProperty('prop')
  }

  def 'test setter on concrete'() {
    given:
    def foo = Mock(FooImpl)
    when:
    foo.prop = 'val'
    //foo.setProp('val')
    then:
    1 * foo.setProp(_)
    //1 * foo.setProperty('prop', 'val')
  }

  def 'test getter on concrete'() {
    given:
    def foo = Mock(FooImpl)
    when:
    foo.prop
    //foo.getProp()
    then:
    1 * foo.getProp()
    //1 * foo.getProperty('prop')
  }

  static interface Foo {
    String getProp()
    void setProp(String val)
  }

  static abstract class FooBase implements Foo {
    abstract String getProp();
    abstract void setProp(String val);
  }

  static class FooImpl extends FooBase {
    private String prop
    String getProp() {
      println('Foo.getProp')
      return prop
    }

    void setProp(String val) {
      println('Foo.setProp')
      this.prop = val
    }

    static void main(String[] args) {
      def fooImpl = new FooImpl()
      fooImpl.prop = "test1"
      println fooImpl.prop
      fooImpl.setProp("test2")
      println fooImpl.prop
    }
  }
}

Running this test in Spock 1.3-groovy-2.5 yields 4 failed tests:

Too few invocations for:

1 * foo.setProp(_)   (0 invocations)

Unmatched invocations (ordered by similarity):

1 * foo.setProperty('prop', 'val')
methodName == "setProp"
|          |
|          false
|          4 differences (63% similarity)
|          setProp(erty)
|          setProp(----)
setProperty

<too many arguments>
	at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:98)
	at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:77)
	at de.scrum_master.stackoverflow.q61599143.PropertyAccessTest.test setter on abstract(PropertyAccessTest.groovy:28)


Too few invocations for:

1 * foo.getProp()   (0 invocations)

Unmatched invocations (ordered by similarity):

1 * foo.getProperty('prop')
methodName == "getProp"
|          |
|          false
|          4 differences (63% similarity)
|          getProp(erty)
|          getProp(----)
getProperty

<no args expected>
	at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:98)
	at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:77)
	at de.scrum_master.stackoverflow.q61599143.PropertyAccessTest.test getter on abstract(PropertyAccessTest.groovy:39)


Too few invocations for:

1 * foo.setProp(_)   (0 invocations)

Unmatched invocations (ordered by similarity):

1 * foo.setProperty('prop', 'val')
methodName == "setProp"
|          |
|          false
|          4 differences (63% similarity)
|          setProp(erty)
|          setProp(----)
setProperty

<too many arguments>
	at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:98)
	at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:77)
	at de.scrum_master.stackoverflow.q61599143.PropertyAccessTest.test setter on concrete(PropertyAccessTest.groovy:50)


Too few invocations for:

1 * foo.getProp()   (0 invocations)

Unmatched invocations (ordered by similarity):

1 * foo.getProperty('prop')
methodName == "getProp"
|          |
|          false
|          4 differences (63% similarity)
|          getProp(erty)
|          getProp(----)
getProperty

<no args expected>
	at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:98)
	at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:77)
	at de.scrum_master.stackoverflow.q61599143.PropertyAccessTest.test getter on concrete(PropertyAccessTest.groovy:61)

Running the exact same test on Spock 2.0-M2-groovy-3.0 yields only 2 failed tests:

Too few invocations for:

1 * foo.setProp(_)   (0 invocations)

Unmatched invocations (ordered by similarity):

1 * foo.setProperty('prop', 'val')
methodName == "setProp"
|          |
|          false
|          4 differences (63% similarity)
|          setProp(erty)
|          setProp(----)
setProperty

<too many arguments>
	at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:98)
	at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:77)
	at de.scrum_master.stackoverflow.q61599143.PropertyAccessTest.test setter on abstract(PropertyAccessTest.groovy:33)


Too few invocations for:

1 * foo.setProp(_)   (0 invocations)

Unmatched invocations (ordered by similarity):

1 * foo.setProperty('prop', 'val')
methodName == "setProp"
|          |
|          false
|          4 differences (63% similarity)
|          setProp(erty)
|          setProp(----)
setProperty

<too many arguments>
	at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:98)
	at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:77)
	at de.scrum_master.stackoverflow.q61599143.PropertyAccessTest.test setter on concrete(PropertyAccessTest.groovy:60)

Running the main method on both platforms shows that it is not a Groovy problem but probably related to a Spock AST transformation glitch:

Foo.setProp
Foo.getProp
test1
Foo.setProp
Foo.getProp
test2

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions