Skip to content

Commit 0eb3d6c

Browse files
repl: support for test selection using negative index
1 parent f871e17 commit 0eb3d6c

12 files changed

Lines changed: 374 additions & 31 deletions

File tree

webtau-cli-testing/src/test/groovy/scenarios/replTestSelection.groovy

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ scenario('run scenario by index') {
6464
cli.doc.capture('repl-test-scenario-ran-by-idx')
6565
}
6666

67+
scenario('run scenario by negative index') {
68+
repl.clearOutput()
69+
repl << "r -1\n"
70+
repl.output.waitTo contain("validating...")
71+
72+
cli.doc.capture('repl-test-scenario-ran-by-negative-idx')
73+
}
74+
6775
scenario('run scenario by text') {
6876
repl.clearOutput()
6977
repl << "r 'clean'\n"

webtau-docs/znai/REPL/test-runs.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ Selected test file has three scenarios
3636

3737
To run scenario by index
3838

39-
:include-cli-output: cli-tests/repl-test-scenario-ran-by-idx/out.txt {title: "run test scenario by index"}
39+
:include-cli-output: cli-tests/repl-test-scenario-ran-by-idx/out.txt {title: "run test scenario by an index"}
40+
41+
Use negative index to select from the bottom, i.e. -1 will select the last scenario, -2 will select second from the end
42+
43+
:include-cli-output: cli-tests/repl-test-scenario-ran-by-negative-idx/out.txt {title: "run test scenario by a negative index"}
4044

4145
To run scenario by partial name match
4246

webtau-groovy/src/main/groovy/org/testingisdocumenting/webtau/cli/WebTauCliApp.groovy

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ class WebTauCliApp implements TestListener, ReportGenerator {
103103

104104
void startRepl() {
105105
prepareTestsAndRun(WebDriverBehavior.AutoCloseWebDrivers) {
106-
runner.setIsReplMode(true)
107106
def repl = new Repl(runner)
108107
repl.run()
109108
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2021 webtau maintainers
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.testingisdocumenting.webtau.cli.repl
18+
19+
import groovy.transform.PackageScope
20+
21+
@PackageScope
22+
class IndexSelection {
23+
@PackageScope
24+
static int convertNegativeIdxToAbsolute(int size, int idx) {
25+
// 0 1 2 3 4 5 6
26+
// -7 -6 -5 -4 -3 -2 -1
27+
// size = 7
28+
29+
if (idx >= 0) {
30+
return idx
31+
}
32+
33+
return size + idx
34+
}
35+
}

webtau-groovy/src/main/groovy/org/testingisdocumenting/webtau/cli/repl/Repl.groovy

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.testingisdocumenting.webtau.cli.repl
1919

20+
import groovy.transform.PackageScope
2021
import org.apache.groovy.groovysh.Groovysh
2122
import org.codehaus.groovy.tools.shell.IO
2223
import org.codehaus.groovy.tools.shell.util.Preferences
@@ -33,10 +34,15 @@ class Repl {
3334
private final Groovysh groovysh
3435
private final StandaloneTestRunner runner
3536
private final InteractiveTests interactiveTests
36-
private final ReplResultRenderer resultRenderer
37+
38+
@PackageScope
39+
final ReplResultRenderer resultRenderer
3740

3841
Repl(StandaloneTestRunner runner) {
42+
runner.setIsReplMode(true)
43+
3944
this.runner = runner
45+
4046
interactiveTests = new InteractiveTests(runner)
4147
ReplCommands.interactiveTests = interactiveTests
4248

webtau-groovy/src/main/groovy/org/testingisdocumenting/webtau/cli/repl/ReplCommands.groovy

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package org.testingisdocumenting.webtau.cli.repl
1919
import groovy.transform.PackageScope
2020
import org.testingisdocumenting.webtau.cfg.WebTauConfig
2121
import org.testingisdocumenting.webtau.console.ansi.Color
22+
import org.testingisdocumenting.webtau.data.render.PrettyPrintable
2223
import org.testingisdocumenting.webtau.documentation.DocumentationArtifacts
2324
import org.testingisdocumenting.webtau.reporter.stacktrace.StackTraceUtils
2425
import org.testingisdocumenting.webtau.runner.standalone.StandaloneTest
@@ -36,8 +37,11 @@ class ReplCommands {
3637
@PackageScope
3738
static InteractiveTests interactiveTests
3839

39-
private static TestsSelection testsSelection = new TestsSelection()
40-
private static List<StandaloneTest> availableScenarios = []
40+
@PackageScope
41+
static TestsSelection testsSelection = new TestsSelection()
42+
43+
@PackageScope
44+
static List<StandaloneTest> availableScenarios = []
4145

4246
static WebTauConfig getReloadConfig() {
4347
return reloadConfig()
@@ -51,12 +55,12 @@ class ReplCommands {
5155
return WebTauConfig.cfg
5256
}
5357

54-
static boolean getTestSelected() {
58+
static boolean getTestFileSelected() {
5559
return testsSelection.testFilePath != null
5660
}
5761

5862
static void select(Object... selectors) {
59-
if (testSelected) {
63+
if (testFileSelected) {
6064
selectScenariosAndValidate(selectors)
6165
displaySelectedScenarios()
6266
} else {
@@ -65,32 +69,32 @@ class ReplCommands {
6569
return
6670
}
6771

68-
selectTest(selectors[0])
72+
selectTestFile(selectors[0])
6973
}
7074
}
7175

7276
static void s(Object... selectors) {
7377
select(selectors)
7478
}
7579

76-
static void getRun() {
77-
runSelected()
80+
static Object getRun() {
81+
return new ProxyToHandleNegativeIndexAndRunScenarios()
7882
}
7983

80-
static void getR() {
81-
runSelected()
84+
static Object getR() {
85+
return getRun()
8286
}
8387

84-
static void getSelect() {
85-
displaySelectedScenarios()
88+
static Object getSelect() {
89+
return new ProxyToHandleNegativeIndexAndDisplayScenarios()
8690
}
8791

88-
static void getS() {
89-
getSelect()
92+
static Object getS() {
93+
return getSelect()
9094
}
9195

9296
static void run(Object... selectors) {
93-
if (testSelected) {
97+
if (testFileSelected) {
9498
selectScenariosAndValidate(selectors)
9599

96100
if (testsSelection.scenarios) {
@@ -102,7 +106,7 @@ class ReplCommands {
102106
return
103107
}
104108

105-
selectTest(selectors[0])
109+
selectTestFile(selectors[0])
106110

107111
if (testsSelection.testFilePath) {
108112
runSelected()
@@ -177,44 +181,46 @@ class ReplCommands {
177181
}
178182

179183
private static void listTestFilesOrScenarios() {
180-
if (!testSelected) {
184+
if (!testFileSelected) {
181185
displayTestFiles()
182186
} else {
183187
displayScenarios(testsSelection.testFilePath)
184188
}
185189
}
186190

187-
private static void selectTest(Object selector) {
191+
private static void selectTestFile(Object selector) {
188192
if (selector instanceof String) {
189-
selectTestByRegexp(selector)
193+
selectTestFileByRegexp(selector)
190194
return
191195
}
192196

193197
if (selector instanceof Integer) {
194-
selectTestByIndex(selector)
198+
selectTestFileByIndex(selector)
195199
return
196200
}
197201

198-
out(Color.RED, "can't select test using: " + selector)
202+
out(Color.RED, "can't select test file using: " + selector)
199203
testsSelection.testFilePath = ''
200204
testsSelection.scenarios = []
201205
}
202206

203-
private static void selectTestByIndex(Integer idx) {
204-
if (idx < 0 || idx >= interactiveTests.testFilePaths.size()) {
205-
out(Color.RED, 'enter a test index between 0 and ' + interactiveTests.testFilePaths.size())
207+
private static void selectTestFileByIndex(Integer idx) {
208+
def size = interactiveTests.testFilePaths.size()
209+
idx = IndexSelection.convertNegativeIdxToAbsolute(size, idx)
210+
if (idx < 0 || idx >= size) {
211+
out(Color.RED, 'enter a test file index between 0 and ' + (size - 1))
206212
return
207213
}
208214

209215
testsSelection.testFilePath = interactiveTests.testFilePathByIdx(idx)
210216
displayScenarios(testsSelection.testFilePath)
211217
}
212218

213-
private static void selectTestByRegexp(String regexp) {
219+
private static void selectTestFileByRegexp(String regexp) {
214220
def pattern = Pattern.compile(regexp, Pattern.CASE_INSENSITIVE)
215221
def found = interactiveTests.firstTestFilePathByRegexp(pattern)
216222
if (!found) {
217-
out(Color.RED, "didn't find a test matching regexp: " + regexp)
223+
out(Color.RED, "didn't find a test file matching regexp: " + regexp)
218224
return
219225
}
220226

@@ -230,7 +236,7 @@ class ReplCommands {
230236
testsSelection.scenarios = []
231237

232238
withIssues.each {
233-
out(Color.RED, "didn't find a test matching: " + it.input)
239+
out(Color.RED, "didn't find a scenario matching: " + it.input)
234240
}
235241
} else {
236242
testsSelection.scenarios = selector.inputAndResults.scenario
@@ -277,4 +283,31 @@ class ReplCommands {
277283
Color.PURPLE, testsSelection.testFilePath, ' ',
278284
Color.YELLOW, scenario)
279285
}
286+
287+
// <s 1> is treated as method "s" call with parameter <1>
288+
// <s -1> is treated as "getS() - 1" so we need to handle this in a way to make it feel like <s 1>
289+
// <s> still needs to display selected scenarios, so when <s> without minus index is called we need to render
290+
private static class ProxyToHandleNegativeIndexAndDisplayScenarios implements PrettyPrintable {
291+
Object minus(Integer indexToMakeNegative) {
292+
select(indexToMakeNegative * -1)
293+
return null
294+
}
295+
296+
@Override
297+
void prettyPrint() {
298+
displaySelectedScenarios()
299+
}
300+
}
301+
302+
private static class ProxyToHandleNegativeIndexAndRunScenarios implements PrettyPrintable {
303+
Object minus(Integer indexToMakeNegative) {
304+
run(indexToMakeNegative * -1)
305+
return null
306+
}
307+
308+
@Override
309+
void prettyPrint() {
310+
runSelected()
311+
}
312+
}
280313
}

webtau-groovy/src/main/groovy/org/testingisdocumenting/webtau/cli/repl/ReplScenariosSelector.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class ReplScenariosSelector {
5959
}
6060

6161
private SelectInputAndResult selectSingleScenarioByIdx(int idx) {
62+
idx = IndexSelection.convertNegativeIdxToAbsolute(availableScenarios.size(), idx)
6263
def isInRange = idx >= 0 && idx < availableScenarios.size()
6364
def found = isInRange ? availableScenarios[idx] : null
6465

0 commit comments

Comments
 (0)