From d5d147a48a036dcb9180ea50fd1f9377c653dbbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Kautler?= Date: Wed, 15 Jan 2025 22:15:47 +0100 Subject: [PATCH] Fix using the same previous data table column multiple times in the same cell (#2083) --- .../compiler/WhereBlockRewriter.java | 4 +- .../smoke/ast/DataTablesAstSpec.groovy | 21 ++++++++ ...e_in_a_cell_multiple_times_compiles.groovy | 49 +++++++++++++++++++ 3 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 spock-specs/src/test/resources/snapshots/org/spockframework/smoke/ast/DataTablesAstSpec/using_a_variable_in_a_cell_multiple_times_compiles.groovy diff --git a/spock-core/src/main/java/org/spockframework/compiler/WhereBlockRewriter.java b/spock-core/src/main/java/org/spockframework/compiler/WhereBlockRewriter.java index 0ddad2c2d1..3695811fe8 100644 --- a/spock-core/src/main/java/org/spockframework/compiler/WhereBlockRewriter.java +++ b/spock-core/src/main/java/org/spockframework/compiler/WhereBlockRewriter.java @@ -675,7 +675,7 @@ private void turnIntoSimpleParameterization(List column) throws Inva // otherwise generate the extractors and closure List statements = new ArrayList<>(); - List referencedPreviousVariables = previousVariableAccesses.stream().map(VariableExpression::getName).collect(toList()); + Set referencedPreviousVariables = previousVariableAccesses.stream().map(VariableExpression::getName).collect(toSet()); generatePreviousColumnExtractorStatements(referencedPreviousVariables, row, statements); ReturnStatement providerStatement = new ReturnStatement(providerExpression); providerStatement.setSourcePosition(providerExpression); @@ -702,7 +702,7 @@ private void turnIntoSimpleParameterization(List column) throws Inva rewriteSimpleParameterization(binExpr, varExpr, true); } - private void generatePreviousColumnExtractorStatements(List referencedPreviousVariables, int row, + private void generatePreviousColumnExtractorStatements(Set referencedPreviousVariables, int row, List statements) { for (String referencedPreviousVariable : referencedPreviousVariables) { statements.add(new ExpressionStatement( diff --git a/spock-specs/src/test/groovy/org/spockframework/smoke/ast/DataTablesAstSpec.groovy b/spock-specs/src/test/groovy/org/spockframework/smoke/ast/DataTablesAstSpec.groovy index 92f4dbd45e..9b73808561 100644 --- a/spock-specs/src/test/groovy/org/spockframework/smoke/ast/DataTablesAstSpec.groovy +++ b/spock-specs/src/test/groovy/org/spockframework/smoke/ast/DataTablesAstSpec.groovy @@ -16,6 +16,7 @@ package org.spockframework.smoke.ast import org.spockframework.EmbeddedSpecification import org.spockframework.specs.extension.SpockSnapshotter +import spock.lang.Issue import spock.lang.Snapshot import spock.util.Show @@ -83,4 +84,24 @@ class DataTablesAstSpec extends EmbeddedSpecification { then: snapshotter.assertThat(result.source).matchesSnapshot() } + + @Issue('https://github.com/spockframework/spock/issues/2083') + def 'using a variable in a cell multiple times compiles'() { + given: + snapshotter.featureBody() + + when: + def result = compiler.transpileFeatureBody ''' + expect: + a + b == result + + where: + a | b | result + 1 | 2 | a + b + 3 | 4 | a + a // causes the compile error + ''', EnumSet.of(Show.METHODS) + + then: + snapshotter.assertThat(result.source).matchesSnapshot() + } } diff --git a/spock-specs/src/test/resources/snapshots/org/spockframework/smoke/ast/DataTablesAstSpec/using_a_variable_in_a_cell_multiple_times_compiles.groovy b/spock-specs/src/test/resources/snapshots/org/spockframework/smoke/ast/DataTablesAstSpec/using_a_variable_in_a_cell_multiple_times_compiles.groovy new file mode 100644 index 0000000000..0ba51ee73e --- /dev/null +++ b/spock-specs/src/test/resources/snapshots/org/spockframework/smoke/ast/DataTablesAstSpec/using_a_variable_in_a_cell_multiple_times_compiles.groovy @@ -0,0 +1,49 @@ +package aPackage +import spock.lang.* + +class ASpec extends Specification { + def "aFeature"() { +/*--------- tag::snapshot[] ---------*/ +public void $spock_feature_0_0(java.lang.Object a, java.lang.Object b, java.lang.Object result) { + org.spockframework.runtime.ErrorCollector $spock_errorCollector = org.spockframework.runtime.ErrorRethrower.INSTANCE + org.spockframework.runtime.ValueRecorder $spock_valueRecorder = new org.spockframework.runtime.ValueRecorder() + org.spockframework.runtime.SpockRuntime.callBlockEntered(this, 0) + try { + org.spockframework.runtime.SpockRuntime.verifyCondition($spock_errorCollector, $spock_valueRecorder.reset(), 'a + b == result', 2, 9, null, $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(4), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(2), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(0), a) + $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(1), b)) == $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(3), result))) + } + catch (java.lang.Throwable $spock_condition_throwable) { + org.spockframework.runtime.SpockRuntime.conditionFailedWithException($spock_errorCollector, $spock_valueRecorder, 'a + b == result', 2, 9, null, $spock_condition_throwable)} + finally { + } + org.spockframework.runtime.SpockRuntime.callBlockExited(this, 0) + this.getSpecificationContext().getMockController().leaveScope() +} + +public java.lang.Object $spock_feature_0_0prov0() { + return [1, 3] +} + +public java.lang.Object $spock_feature_0_0prov1(java.util.List $spock_p_a) { + return [2, 4] +} + +public java.lang.Object $spock_feature_0_0prov2(java.util.List $spock_p_a, java.util.List $spock_p_b) { + return [{ -> + java.lang.Object a = $spock_p_a.get(0) + java.lang.Object b = $spock_p_b.get(0) + return a + b + }.call(), { -> + java.lang.Object a = $spock_p_a.get(1) + return a + a + }.call()] +} + +public java.lang.Object $spock_feature_0_0proc(java.lang.Object $spock_p0, java.lang.Object $spock_p1, java.lang.Object $spock_p2) { + java.lang.Object a = (( $spock_p0 ) as java.lang.Object) + java.lang.Object b = (( $spock_p1 ) as java.lang.Object) + java.lang.Object result = (( $spock_p2 ) as java.lang.Object) + return new java.lang.Object[]{ a , b , result } +} +/*--------- end::snapshot[] ---------*/ + } +}