Skip to content

Commit 5feb20c

Browse files
authored
Merge pull request #5 from jakubsob/4-indentation
✨ Allow setting feature file indentation
2 parents 463ddff + d5f4d85 commit 5feb20c

File tree

16 files changed

+203
-15
lines changed

16 files changed

+203
-15
lines changed

.github/workflows/R-CMD-check.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
33
on:
44
push:
5-
branches: [main, master]
5+
branches: [main, master, dev]
66
pull_request:
7-
branches: [main, master]
7+
branches: [main, master, dev]
88

99
name: R-CMD-check
1010

.github/workflows/test-coverage.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
33
on:
44
push:
5-
branches: [main, master]
5+
branches: [main, master, dev]
66
pull_request:
7-
branches: [main, master]
7+
branches: [main, master, dev]
88

99
name: test-coverage
1010

DESCRIPTION

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: cucumber
22
Type: Package
33
Title: Behavior-Driven Development for R
4-
Version: 1.1.0
4+
Version: 1.1.1
55
Authors@R: person("Jakub", "Sobolewski", email = "[email protected]", role = c("aut", "cre"))
66
Description: Write executable specifications in a natural language that describes how your code should behave.
77
Write specifications in feature files using 'Gherkin' language and execute them using functions implemented in R.
@@ -24,6 +24,7 @@ Suggests:
2424
Config/testthat/edition: 3
2525
Imports:
2626
checkmate,
27+
cli,
2728
dplyr,
2829
fs,
2930
glue,

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ importFrom(checkmate,assert_string)
1616
importFrom(checkmate,assert_subset)
1717
importFrom(checkmate,test_character)
1818
importFrom(checkmate,test_subset)
19+
importFrom(cli,cli_abort)
1920
importFrom(dplyr,bind_cols)
2021
importFrom(fs,dir_ls)
2122
importFrom(glue,glue)

NEWS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# cucumber 1.1.1
2+
3+
- ✨ Added option to set the indent of feature files. Useful when you use a different indent than the default 2 whitespaces. All user-facing options are documented in `?cucumber::opts`. (#5)
4+
- ✨ Added validation of feature files to check if they have a consistent indentation. (#5)
5+
16
# cucumber 1.1.0
27

38
- ✨ Added scenario `before` and `after` hooks.

R/options.R

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#' {cucumber} Options
2+
#'
3+
#' Internally used, package-specific options.
4+
#' They allow overriding the default behavior of the package.
5+
#'
6+
#' @details
7+
#'
8+
#' The following options are available:
9+
#'
10+
#' - `cucumber.indent`
11+
#'
12+
#' Regular expression for the indent of the feature files.
13+
#'
14+
#' default: `^\\s{2}`
15+
#'
16+
#' - `cucumber.interactive`
17+
#'
18+
#' Logical value indicating whether to ask which feature files to run.
19+
#'
20+
#' default: `FALSE`
21+
#'
22+
#' See [base::options()] and [base::getOption()] on how to work with options.
23+
#'
24+
#' @md
25+
#' @name opts
26+
NULL

R/test.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ test <- function(
5656
} # nocov end
5757
feature_files |>
5858
map(readLines) |>
59+
map(validate_feature) |>
5960
map(normalize_feature) |>
6061
walk(run, steps = steps, parameters = get_parameters())
6162
}

R/tokenize.R

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
INDENT <- "^\\s{2}"
21
NODE_REGEX <- paste0(
32
"^(?!\\s+)(",
43
paste0(
@@ -32,7 +31,7 @@ remove_trailing_colon <- function(x) {
3231

3332
#' @importFrom stringr str_remove_all
3433
remove_indent <- function(x) {
35-
str_remove_all(x, INDENT)
34+
str_remove_all(x, getOption("cucumber.indent", default = "^\\s{2}"))
3635
}
3736

3837
#' @importFrom stringr str_detect

R/validate.R

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#' Validate lines read from a feature file
2+
#' @keywords internal
3+
validate_feature <- function(lines) {
4+
# Remove comments and empty lines for validation
5+
clean_lines <- remove_comments(remove_empty_lines(lines))
6+
clean_lines |>
7+
validate_indentation()
8+
invisible(lines)
9+
}
10+
11+
#' @keywords internal
12+
#' @importFrom stringr str_detect
13+
#' @importFrom cli cli_abort
14+
validate_indentation <- function(lines) {
15+
indent <- getOption("cucumber.indent", default = "^\\s{2}")
16+
test_lines <- lines[!str_detect(lines, "^Feature")] |>
17+
remove_empty_lines()
18+
if (any(!str_detect(test_lines, indent))) {
19+
cli_abort(c(
20+
"All lines must be indented with {indent}",
21+
"i" = "Check the {.code getOption('cucumber.indent')} option if it is set to your feature file indent."
22+
))
23+
}
24+
invisible(lines)
25+
}

man/opts.Rd

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/validate_feature.Rd

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/_snaps/examples.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,16 +177,16 @@
177177
--------------------------------------------------------------------------------
178178
Failure ('test-cucumber.R:1:1'): Scenario: Adding integer and float
179179
context$result (`actual`) not equal to `expected` (`expected`).
180-
`actual`: 2
181-
`expected`: 5
180+
`actual`: 2.1
181+
`expected`: 5.0
182182
Backtrace:
183183
x
184184
1. \-global `<step>`(expected = 5L, context = `<env>`)
185185
2. \-testthat::expect_equal(context$result, expected) at ./steps/addition.R:7:3
186186
Failure ('test-cucumber.R:1:1'): Scenario: Adding float and float
187187
context$result (`actual`) not equal to `expected` (`expected`).
188-
`actual`: 2
189-
`expected`: 5
188+
`actual`: 2.2
189+
`expected`: 5.0
190190
Backtrace:
191191
x
192192
1. \-global `<step>`(expected = 5L, context = `<env>`)
@@ -207,16 +207,16 @@
207207
-- Failed tests ----------------------------------------------------------------
208208
Failure ('test-cucumber.R:1:1'): Scenario: Adding integer and float
209209
context$result (`actual`) not equal to `expected` (`expected`).
210-
`actual`: 2
211-
`expected`: 5
210+
`actual`: 2.1
211+
`expected`: 5.0
212212
Backtrace:
213213
x
214214
1. \-global `<step>`(expected = 5L, context = `<env>`)
215215
2. \-testthat::expect_equal(context$result, expected) at ./steps/addition.R:7:3
216216
Failure ('test-cucumber.R:1:1'): Scenario: Adding float and float
217217
context$result (`actual`) not equal to `expected` (`expected`).
218-
`actual`: 2
219-
`expected`: 5
218+
`actual`: 2.2
219+
`expected`: 5.0
220220
Backtrace:
221221
x
222222
1. \-global `<step>`(expected = 5L, context = `<env>`)

tests/testthat/_snaps/validate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# validate_feature: should validate indent
2+
3+
All lines must be indented with ^\s{4}
4+
i Check the `getOption('cucumber.indent')` option if it is set to your feature file indent.
5+

tests/testthat/test-examples.R

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ describe("test", {
3636
})
3737

3838
it("should run with shinytest2", {
39+
# nolint start
40+
# Produces on r-devel:
41+
# Superclass process has cloneable=FALSE, but subclass r_process has cloneable=TRUE. A subclass cannot be cloneable when its superclass is not cloneable, so cloning will be disabled for r_process.
42+
# nolint end
43+
skip_if(R.version$status == "Under development (unstable)")
3944
test_example("examples/shinytest2")
4045
})
4146

tests/testthat/test-tokenize.R

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,4 +454,53 @@ describe("parse", {
454454
)
455455
)
456456
})
457+
458+
it("should parse feature files with 4 spaces indent", {
459+
# Arrange
460+
lines <- c(
461+
"Feature: Guess the word",
462+
" Scenario: Maker starts a game",
463+
" When the Maker starts a game",
464+
" Then the Maker waits for a Breaker to join"
465+
)
466+
indent <- "^\\s{4}"
467+
468+
# Act
469+
withr::with_options(list(cucumber.indent = indent), {
470+
result <- tokenize(lines)
471+
})
472+
473+
# Assert
474+
expect_equal(
475+
result,
476+
list(
477+
list(
478+
type = "Feature",
479+
value = "Guess the word",
480+
children = list(
481+
list(
482+
type = "Scenario",
483+
value = "Maker starts a game",
484+
children = list(
485+
list(
486+
type = "When",
487+
value = "the Maker starts a game",
488+
children = NULL,
489+
data = NULL
490+
),
491+
list(
492+
type = "Then",
493+
value = "the Maker waits for a Breaker to join",
494+
children = NULL,
495+
data = NULL
496+
)
497+
),
498+
data = NULL
499+
)
500+
),
501+
data = NULL
502+
)
503+
)
504+
)
505+
})
457506
})

tests/testthat/test-validate.R

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
describe("validate_feature", {
2+
it("shouldn't produce error feature with valid indentation", {
3+
withr::with_options(list(cucumber.indent = "^\\s{2}"), {
4+
expect_no_error(
5+
validate_feature(
6+
c(
7+
"Feature: foo",
8+
" Scenario: bar",
9+
" Given foo",
10+
" When foo",
11+
" Then foo"
12+
)
13+
)
14+
)
15+
})
16+
})
17+
18+
it("should validate indent", {
19+
withr::with_options(list(cucumber.indent = "^\\s{4}"), {
20+
expect_snapshot_error(
21+
validate_feature(
22+
c(
23+
"Feature: foo",
24+
" Scenario: bar",
25+
" Given foo",
26+
" When foo",
27+
" Then foo"
28+
)
29+
)
30+
)
31+
})
32+
})
33+
})

0 commit comments

Comments
 (0)