Skip to content

Commit 1920ff3

Browse files
committed
Fix handling of condition method calls
1 parent af7c30d commit 1920ff3

File tree

25 files changed

+725
-6
lines changed

25 files changed

+725
-6
lines changed

spock-core/src/main/java/org/spockframework/compiler/ConditionRewriter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import static java.util.Collections.singletonList;
4242
import static org.spockframework.compiler.AstUtil.createDirectMethodCall;
4343
import static org.spockframework.compiler.AstUtil.primitiveConstExpression;
44+
import static org.spockframework.compiler.SpecialMethodCall.checkIsConditionMethodCall;
4445

4546
// NOTE: currently some conversions reference old expression objects rather than copying them;
4647
// this can potentially lead to aliasing problems (e.g. for Condition.originalExpression)
@@ -641,8 +642,7 @@ private Statement rewriteCondition(Expression expr, Expression message, boolean
641642
// method conditions with spread operator are not lifted because MOP doesn't support spreading
642643
if (expr instanceof MethodCallExpression && !((MethodCallExpression) expr).isSpreadSafe()) {
643644
MethodCallExpression methodCallExpression = (MethodCallExpression)expr;
644-
String methodName = AstUtil.getMethodName(methodCallExpression);
645-
if ((Identifiers.CONDITION_METHODS.contains(methodName))) {
645+
if (checkIsConditionMethodCall(methodCallExpression)) {
646646
return surroundSpecialTryCatch(expr);
647647
}
648648
return rewriteMethodCondition(methodCallExpression, message, explicit, optOut);

spock-core/src/main/java/org/spockframework/compiler/DeepBlockRewriter.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,17 @@ private boolean handleImplicitCondition(ExpressionStatement stat) {
204204

205205
checkIsValidImplicitCondition(stat, resources.getErrorReporter());
206206

207-
String methodName = AstUtil.getMethodName(stat.getExpression());
208-
boolean isConditionMethodCall = Identifiers.CONDITION_METHODS.contains(methodName);
207+
boolean isConditionMethodCall;
208+
if (stat.getExpression() instanceof MethodCallExpression) {
209+
isConditionMethodCall = SpecialMethodCall.checkIsConditionMethodCall(((MethodCallExpression) stat.getExpression()));
210+
} else {
211+
isConditionMethodCall = false;
212+
}
209213

210214
if (isConditionMethodCall) {
211215
groupConditionFound = currSpecialMethodCall.isGroupConditionBlock();
212-
} else {
216+
}
217+
if (!isConditionMethodCall || currSpecialMethodCall.isConditionMethodCall() || currSpecialMethodCall.isGroupConditionBlock()) {
213218
conditionFound();
214219
}
215220

spock-core/src/main/java/org/spockframework/compiler/SpecialMethodCall.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ public String toString() {
269269
methodName, inferredName, inferredType, methodCallExpr, closureExpr, conditionBlock);
270270
}
271271

272+
static boolean checkIsConditionMethodCall(MethodCallExpression expr) {
273+
if (!AstUtil.isThisOrSuperExpression(expr.getObjectExpression())) return false;
274+
return Identifiers.CONDITION_METHODS.contains(expr.getMethodAsString());
275+
}
276+
272277
private static boolean checkIsBuiltInMethodCall(MethodCallExpression expr) {
273278
if (!AstUtil.isThisOrSuperExpression(expr.getObjectExpression())) return false;
274279
return Identifiers.BUILT_IN_METHODS.contains(expr.getMethodAsString());

spock-specs/src/test/groovy/org/spockframework/smoke/WithBlockFailingConditions.groovy

Lines changed: 144 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414

1515
package org.spockframework.smoke
1616

17+
import org.spockframework.EmbeddedSpecification
1718
import org.spockframework.runtime.*
1819
import spock.lang.*
1920

20-
class WithBlockFailingConditions extends Specification {
21+
class WithBlockFailingConditions extends EmbeddedSpecification {
2122
@FailsWith(ConditionNotSatisfiedError)
2223
def "basic usage"() {
2324
def list = [1, 2]
@@ -155,4 +156,146 @@ class WithBlockFailingConditions extends Specification {
155156
size() == 3
156157
}
157158
}
159+
160+
@FailsWith(ConditionNotSatisfiedError)
161+
def "GDK method that looks like built-in method as implicit condition"() {
162+
expect:
163+
null.with {
164+
false
165+
}
166+
}
167+
168+
@FailsWith(ConditionNotSatisfiedError)
169+
def "GDK method that looks like built-in method as explicit condition"() {
170+
expect:
171+
assert null.with {
172+
false
173+
}
174+
}
175+
176+
def "condition method #conditionMethod within condition method #conditionMethod"() {
177+
when:
178+
runner.runFeatureBody("""
179+
expect:
180+
$conditionMethod(['']) {
181+
$conditionMethod(['']) {
182+
false
183+
}
184+
}
185+
""")
186+
187+
then:
188+
thrown(expectedException)
189+
190+
where:
191+
conditionMethod || expectedException
192+
'with' || ConditionNotSatisfiedError
193+
'verifyAll' || ConditionNotSatisfiedError
194+
'verifyEach' || SpockAssertionError
195+
}
196+
197+
def "condition method #conditionMethod within condition method #conditionMethod with exception"() {
198+
when:
199+
runner.runFeatureBody("""
200+
expect:
201+
$conditionMethod(['']) {
202+
$conditionMethod(['']) {
203+
true
204+
throw new Exception('foo')
205+
}
206+
}
207+
""")
208+
209+
then:
210+
def exception = thrown(expectedException)
211+
exception.message."${expectedException == Exception ? 'equals' : 'contains'}"('foo')
212+
213+
where:
214+
conditionMethod || expectedException
215+
'with' || Exception
216+
'verifyAll' || Exception
217+
'verifyEach' || SpockAssertionError
218+
}
219+
220+
def "condition method #conditionMethod within condition method #conditionMethod with only exception"() {
221+
when:
222+
runner.runFeatureBody("""
223+
expect:
224+
$conditionMethod(['']) {
225+
$conditionMethod(['']) {
226+
throw new Exception('foo')
227+
}
228+
}
229+
""")
230+
231+
then:
232+
def exception = thrown(expectedException)
233+
exception.message."${expectedException == Exception ? 'equals' : 'contains'}"('foo')
234+
235+
where:
236+
conditionMethod || expectedException
237+
'with' || Exception
238+
'verifyAll' || Exception
239+
'verifyEach' || SpockAssertionError
240+
}
241+
242+
def "condition method #conditionMethod"() {
243+
when:
244+
runner.runFeatureBody("""
245+
expect:
246+
$conditionMethod(['']) {
247+
false
248+
}
249+
""")
250+
251+
then:
252+
thrown(expectedException)
253+
254+
where:
255+
conditionMethod || expectedException
256+
'with' || ConditionNotSatisfiedError
257+
'verifyAll' || ConditionNotSatisfiedError
258+
'verifyEach' || SpockAssertionError
259+
}
260+
261+
def "condition method #conditionMethod with exception"() {
262+
when:
263+
runner.runFeatureBody("""
264+
expect:
265+
$conditionMethod(['']) {
266+
true
267+
throw new Exception('foo')
268+
}
269+
""")
270+
271+
then:
272+
def exception = thrown(expectedException)
273+
exception.message."${expectedException == Exception ? 'equals' : 'contains'}"('foo')
274+
275+
where:
276+
conditionMethod || expectedException
277+
'with' || Exception
278+
'verifyAll' || Exception
279+
'verifyEach' || SpockAssertionError
280+
}
281+
282+
def "condition method #conditionMethod with only exception"() {
283+
when:
284+
runner.runFeatureBody("""
285+
expect:
286+
$conditionMethod(['']) {
287+
throw new Exception('foo')
288+
}
289+
""")
290+
291+
then:
292+
def exception = thrown(expectedException)
293+
exception.message."${expectedException == Exception ? 'equals' : 'contains'}"('foo')
294+
295+
where:
296+
conditionMethod || expectedException
297+
'with' || Exception
298+
'verifyAll' || Exception
299+
'verifyEach' || SpockAssertionError
300+
}
158301
}

spock-specs/src/test/groovy/org/spockframework/smoke/ast/AstSpec.groovy

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,4 +387,158 @@ class TestSpec extends Specification {
387387
then:
388388
textSnapshotter.assertThat(result.source).matchesSnapshot()
389389
}
390+
391+
def "GDK method that looks like built-in method as implicit condition"() {
392+
when:
393+
def result = compiler.transpileFeatureBody('''
394+
expect:
395+
null.with {
396+
false
397+
}
398+
''')
399+
400+
then:
401+
snapshotter.assertThat(result.source).matchesSnapshot()
402+
}
403+
404+
def "GDK method that looks like built-in method as explicit condition"() {
405+
when:
406+
def result = compiler.transpileFeatureBody('''
407+
expect:
408+
assert null.with {
409+
false
410+
}
411+
''')
412+
413+
then:
414+
snapshotter.assertThat(result.source).matchesSnapshot()
415+
}
416+
417+
def "condition method #conditionMethod within condition method #conditionMethod"() {
418+
when:
419+
def result = compiler.transpileFeatureBody("""
420+
expect:
421+
$conditionMethod(['']) {
422+
$conditionMethod(['']) {
423+
false
424+
}
425+
}
426+
""")
427+
428+
then:
429+
snapshotter.assertThat(result.source).matchesSnapshot()
430+
431+
where:
432+
conditionMethod << [
433+
'with',
434+
'verifyAll',
435+
'verifyEach'
436+
]
437+
}
438+
439+
def "condition method #conditionMethod within condition method #conditionMethod with exception"() {
440+
when:
441+
def result = compiler.transpileFeatureBody("""
442+
expect:
443+
$conditionMethod(['']) {
444+
$conditionMethod(['']) {
445+
true
446+
throw new Exception('foo')
447+
}
448+
}
449+
""")
450+
451+
then:
452+
snapshotter.assertThat(result.source).matchesSnapshot()
453+
454+
where:
455+
conditionMethod << [
456+
'with',
457+
'verifyAll',
458+
'verifyEach'
459+
]
460+
}
461+
462+
def "condition method #conditionMethod within condition method #conditionMethod with only exception"() {
463+
when:
464+
def result = compiler.transpileFeatureBody("""
465+
expect:
466+
$conditionMethod(['']) {
467+
$conditionMethod(['']) {
468+
throw new Exception('foo')
469+
}
470+
}
471+
""")
472+
473+
then:
474+
snapshotter.assertThat(result.source).matchesSnapshot()
475+
476+
where:
477+
conditionMethod << [
478+
'with',
479+
'verifyAll',
480+
'verifyEach'
481+
]
482+
}
483+
484+
def "condition method #conditionMethod"() {
485+
when:
486+
def result = compiler.transpileFeatureBody("""
487+
expect:
488+
$conditionMethod(['']) {
489+
false
490+
}
491+
""")
492+
493+
then:
494+
snapshotter.assertThat(result.source).matchesSnapshot()
495+
496+
where:
497+
conditionMethod << [
498+
'with',
499+
'verifyAll',
500+
'verifyEach'
501+
]
502+
}
503+
504+
def "condition method #conditionMethod with exception"() {
505+
when:
506+
def result = compiler.transpileFeatureBody("""
507+
expect:
508+
$conditionMethod(['']) {
509+
true
510+
throw new Exception('foo')
511+
}
512+
""")
513+
514+
then:
515+
snapshotter.assertThat(result.source).matchesSnapshot()
516+
517+
where:
518+
conditionMethod << [
519+
'with',
520+
'verifyAll',
521+
'verifyEach'
522+
]
523+
}
524+
525+
def "condition method #conditionMethod with only exception"() {
526+
when:
527+
def result = compiler.transpileFeatureBody("""
528+
expect:
529+
$conditionMethod(['']) {
530+
throw new Exception('foo')
531+
}
532+
""")
533+
534+
then:
535+
snapshotter.assertThat(result.source).matchesSnapshot()
536+
537+
where:
538+
conditionMethod << [
539+
'with',
540+
'verifyAll',
541+
'verifyEach'
542+
]
543+
}
390544
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@org.spockframework.runtime.model.FeatureMetadata(name = 'a feature', ordinal = 0, line = 1, blocks = [@org.spockframework.runtime.model.BlockMetadata(kind = org.spockframework.runtime.model.BlockKind.EXPECT, texts = [])], parameterNames = [])
2+
public void $spock_feature_0_0() {
3+
org.spockframework.runtime.ErrorCollector $spock_errorCollector = org.spockframework.runtime.ErrorRethrower.INSTANCE
4+
org.spockframework.runtime.ValueRecorder $spock_valueRecorder = new org.spockframework.runtime.ValueRecorder()
5+
org.spockframework.runtime.SpockRuntime.callBlockEntered(this, 0)
6+
try {
7+
org.spockframework.runtime.SpockRuntime.verifyMethodCondition($spock_errorCollector, $spock_valueRecorder.reset(), 'null.with {\n false\n}', 2, 8, null, $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(0), null), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(1), 'with'), new java.lang.Object[]{$spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(2), { ->
8+
false
9+
})}, $spock_valueRecorder.realizeNas(5, false), true, 4)
10+
}
11+
catch (java.lang.Throwable $spock_condition_throwable) {
12+
org.spockframework.runtime.SpockRuntime.conditionFailedWithException($spock_errorCollector, $spock_valueRecorder, 'null.with {\n false\n}', 2, 8, null, $spock_condition_throwable)}
13+
finally {
14+
}
15+
org.spockframework.runtime.SpockRuntime.callBlockExited(this, 0)
16+
this.getSpecificationContext().getMockController().leaveScope()
17+
}

0 commit comments

Comments
 (0)