Skip to content

Commit 8da8df0

Browse files
committed
Fix Boxed Boolean is getter methods are not properly mocked in Groovy <= 3
Added tests to verify that boolean is getter work according to Groovy rules. Fixes #2131
1 parent c035dd4 commit 8da8df0

File tree

4 files changed

+180
-2
lines changed

4 files changed

+180
-2
lines changed

docs/release_notes.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ spockPull:2112[]
111111
* Fix several bugs in cross-multiplication implementation spockPull:2123[]
112112
* Fix filter blocks with shared fields and derived data variables spockPull:2088[]
113113
* Fix combined labels with comments being ignored spockPull:2121[]
114+
* Fix Boxed Boolean is getter methods are not properly mocked in Groovy <= 3 spockIssue:2131[]
114115

115116
Thanks to all the contributors to this release: Andreas Turban, Björn Kautler, Christoph Loy, Marcin Zajączkowski, Pavlo Shevchenko
116117

spock-core/src/main/java/org/spockframework/runtime/GroovyRuntimeUtil.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,10 @@ public static String getterMethodToPropertyName(String methodName, List<Class<?>
137137
if (methodName.startsWith(GET))
138138
return getPropertyName(methodName, 3);
139139

140-
if (methodName.startsWith(IS)
141-
&& returnType == boolean.class) // Boolean.class is not allowed
140+
if (methodName.startsWith(IS) && (
141+
returnType == boolean.class // Boolean.class is not allowed for Groovy >= 4
142+
|| (MAJOR_VERSION <= 3 && returnType == Boolean.class) // In Groovy <= 3 a isGetter can also be a boxed Boolean.
143+
))
142144
return getPropertyName(methodName, 2);
143145

144146
return null;

spock-specs/src/test/groovy/org/spockframework/runtime/GroovyRuntimeUtilSpec.groovy

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package org.spockframework.runtime
1616

1717
import org.codehaus.groovy.runtime.typehandling.GroovyCastException
18+
import spock.lang.Requires
1819
import spock.lang.Specification
1920

2021
import static org.spockframework.runtime.GroovyRuntimeUtil.propertyToBooleanGetterMethodName
@@ -48,6 +49,28 @@ class GroovyRuntimeUtilSpec extends Specification {
4849
"setFoo" | void | null
4950
}
5051

52+
@Requires({ GroovyRuntimeUtil.MAJOR_VERSION <= 3 })
53+
def "getterMethodToPropertyName Groovy <= 3"() {
54+
expect:
55+
GroovyRuntimeUtil.getterMethodToPropertyName(methodName, [], returnType) == propertyName
56+
57+
where:
58+
methodName | returnType | propertyName
59+
"isEmpty" | Boolean | "empty"
60+
"isEmpty" | boolean | "isEmpty"
61+
}
62+
63+
@Requires({ GroovyRuntimeUtil.MAJOR_VERSION >= 4 })
64+
def "getterMethodToPropertyName Groovy >= 4"() {
65+
expect:
66+
GroovyRuntimeUtil.getterMethodToPropertyName(methodName, [], returnType) == propertyName
67+
68+
where:
69+
methodName | returnType | propertyName
70+
"isEmpty" | Boolean | null //In Groovy >= 4 not a property anymore, see https://issues.apache.org/jira/browse/GROOVY-9382
71+
"isEmpty" | boolean | "empty"
72+
}
73+
5174
def "propertyToGetterMethodName"() {
5275
expect:
5376
propertyToGetterMethodName("prop") == "getProp"

spock-specs/src/test/groovy/org/spockframework/smoke/mock/GroovyMocksForInterfaces.groovy

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
package org.spockframework.smoke.mock
1717

1818
import org.spockframework.mock.CannotCreateMockException
19+
import org.spockframework.runtime.GroovyRuntimeUtil
1920
import org.spockframework.runtime.model.parallel.Resources
21+
import spock.lang.Issue
22+
import spock.lang.Requires
2023
import spock.lang.ResourceLock
2124
import spock.lang.Specification
2225

@@ -126,11 +129,160 @@ class GroovyMocksForInterfaces extends Specification {
126129
ex.message == "Cannot create mock for interface java.lang.Runnable. Global mocking is only possible for classes, but not for interfaces."
127130
}
128131

132+
@Issue("https://github.com/spockframework/spock/issues/2131")
133+
def "Boolean is getters shall be mockable"() {
134+
expect:
135+
m.booleanValue
136+
m.isBooleanValue()
137+
138+
where:
139+
m << [
140+
Stub(BooleanGetters) {
141+
booleanValue >> true
142+
},
143+
Stub(BooleanGetters) {
144+
isBooleanValue() >> true
145+
}
146+
]
147+
}
148+
149+
/**
150+
* Verify that a boxed Boolean is getter does not have a property representation in Groovy >= 4.
151+
*/
152+
@Requires({ GroovyRuntimeUtil.MAJOR_VERSION >= 4 })
153+
def "Boolean boxed is getters Groovy >=4 semantic check"() {
154+
given:
155+
def m = createBooleanGetterInterfaceObjPlain()
156+
157+
expect:
158+
m.isBooleanValueBoxed()
159+
160+
when:
161+
m.booleanValueBoxed
162+
then:
163+
thrown(MissingPropertyException)
164+
//The property for a boxed Boolean does not exist in Groovy >=4
165+
}
166+
167+
/**
168+
* Verify that a boxed Boolean is getter does have a property representation in Groovy <= 3.
169+
*/
170+
@Requires({ GroovyRuntimeUtil.MAJOR_VERSION <= 3 })
171+
def "Boolean boxed is getters Groovy <= 3 semantic check"() {
172+
given:
173+
def m = createBooleanGetterInterfaceObjPlain()
174+
175+
expect:
176+
m.booleanValueBoxed
177+
m.isBooleanValueBoxed()
178+
}
179+
180+
@Issue("https://github.com/spockframework/spock/issues/2131")
181+
@Requires({ GroovyRuntimeUtil.MAJOR_VERSION >= 4 })
182+
def "Boolean boxed is getters is not mockable Groovy >= 4"() {
183+
given:
184+
def m = Stub(BooleanGetters) {
185+
isBooleanValueBoxed() >> true
186+
}
187+
188+
expect:
189+
m.isBooleanValueBoxed()
190+
191+
when:
192+
m.booleanValueBoxed
193+
then:
194+
thrown(MissingPropertyException)
195+
//According to Groovy >=4 rules the property for a boxed Boolean is getter does not exist.
196+
}
197+
198+
@Issue("https://github.com/spockframework/spock/issues/2131")
199+
@Requires({ GroovyRuntimeUtil.MAJOR_VERSION <= 3 })
200+
def "Boolean boxed is getters shall be mockable Groovy <= 3"() {
201+
expect:
202+
//Groovy <= 3 does not throw an MissingProperty exception
203+
m.booleanValueBoxed
204+
m.isBooleanValueBoxed()
205+
206+
where:
207+
m << [
208+
Stub(BooleanGetters) {
209+
booleanValueBoxed >> true
210+
},
211+
Stub(BooleanGetters) {
212+
isBooleanValueBoxed() >> true
213+
}
214+
]
215+
}
216+
217+
@Issue("https://github.com/spockframework/spock/issues/2131")
218+
def "Boolean get getters shall be mockable"() {
219+
expect:
220+
m.isBooleanValue
221+
m.getIsBooleanValue()
222+
223+
where:
224+
m << [
225+
Stub(BooleanGetters) {
226+
isBooleanValue >> true
227+
},
228+
Stub(BooleanGetters) {
229+
getIsBooleanValue() >> true
230+
}
231+
]
232+
}
233+
234+
@Issue("https://github.com/spockframework/spock/issues/2131")
235+
def "Boolean boxed get getters shall be mockable"() {
236+
expect:
237+
m.isBooleanValueBoxed
238+
m.getIsBooleanValueBoxed()
239+
240+
where:
241+
m << [
242+
Stub(BooleanGetters) {
243+
isBooleanValueBoxed >> true
244+
},
245+
Stub(BooleanGetters) {
246+
getIsBooleanValueBoxed() >> true
247+
}
248+
]
249+
}
250+
129251
interface Person {
130252
String getName()
131253

132254
void setName(String name)
133255

134256
void sing(String song)
135257
}
258+
259+
interface BooleanGetters {
260+
boolean isBooleanValue()
261+
262+
Boolean isBooleanValueBoxed()
263+
264+
boolean getIsBooleanValue()
265+
266+
Boolean getIsBooleanValueBoxed()
267+
}
268+
269+
private BooleanGetters createBooleanGetterInterfaceObjPlain() {
270+
new BooleanGetters() {
271+
boolean isBooleanValue() {
272+
true
273+
}
274+
275+
Boolean isBooleanValueBoxed() {
276+
true
277+
}
278+
279+
boolean getIsBooleanValue() {
280+
true
281+
}
282+
283+
Boolean getIsBooleanValueBoxed() {
284+
true
285+
}
286+
}
287+
}
136288
}

0 commit comments

Comments
 (0)