Skip to content

Commit bc9fa1f

Browse files
committed
Add some basic tests & refine implementation
1 parent 141ad83 commit bc9fa1f

File tree

4 files changed

+110
-46
lines changed

4 files changed

+110
-46
lines changed

R/extract.R

Lines changed: 31 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -43,40 +43,33 @@ extract_test_lines <- function(exprs, line, error_call = caller_env()) {
4343
check_number_whole(line, min = 1, call = error_call)
4444

4545
srcrefs <- attr(exprs, "srcref")
46-
47-
# Focus on srcrefs before the selected line
48-
keep <- start_line(srcrefs) <= line
49-
exprs <- exprs[keep]
50-
srcrefs <- srcrefs[keep]
51-
52-
# We first capture the prequel, all code outside of tests
5346
is_subtest <- map_lgl(exprs, is_subtest)
54-
if (any(!is_subtest)) {
55-
prequel <- c(
56-
comment_header("prequel"),
57-
map_chr(srcrefs[!is_subtest], as.character),
58-
""
59-
)
60-
} else {
61-
prequel <- NULL
62-
}
6347

64-
# Now we extract the contents of the last test
65-
if (!any(is_subtest)) {
48+
# First we find the test
49+
is_test <- is_subtest &
50+
start_line(srcrefs) <= line &
51+
end_line(srcrefs) >= line
52+
if (!any(is_test)) {
6653
cli::cli_abort("Failed to find test at line {line}.", call = error_call)
6754
}
68-
test_idx <- rev(which(is_subtest))[[1]]
69-
call <- exprs[[test_idx]]
70-
check_test_call(call, error_call = error_call)
71-
55+
call <- exprs[[which(is_test)[[1]]]]
7256
test_contents <- attr(call[[3]], "srcref")[-1] # drop `{`
7357
keep <- start_line(test_contents) <= line
74-
test <- c(
75-
comment_header("test"),
76-
map_chr(test_contents[keep], as.character)
77-
)
58+
test <- srcref_to_character(test_contents[keep])
59+
60+
# We first find the prequel, all non-test code before the test
61+
is_prequel <- !is_subtest & start_line(srcrefs) < line
62+
if (!any(is_prequel)) {
63+
return(test)
64+
}
7865

79-
c(prequel, test)
66+
c(
67+
"# prequel ---------------------------------------------------------------",
68+
srcref_to_character(srcrefs[is_prequel]),
69+
"",
70+
"# test ------------------------------------------------------------------",
71+
test
72+
)
8073
}
8174

8275
# Helpers ---------------------------------------------------------------------
@@ -92,27 +85,20 @@ parse_file <- function(path, error_call = caller_env()) {
9285
parse(path, keep.source = TRUE)
9386
}
9487

95-
check_test_call <- function(expr, error_call = caller_env()) {
96-
if (!is_call(expr, n = 2)) {
97-
cli::cli_abort(
98-
"test call has unexpected number of arguments",
99-
internal = TRUE,
100-
call = error_call
101-
)
102-
}
103-
if (!is_call(expr[[3]], "{")) {
104-
cli::cli_abort(
105-
"test call doesn't use `{`",
106-
internal = TRUE,
107-
call = error_call
108-
)
109-
}
110-
}
88+
parse_text <- function(text) {
89+
text <- sub("^\n", "", text)
90+
indent <- regmatches(text, regexpr("^ *", text))
91+
text <- gsub(paste0("(?m)^", indent), "", text, perl = TRUE)
11192

112-
comment_header <- function(x) {
113-
paste0("# ", x, " ", strrep("-", 80 - nchar(x) - 3))
93+
parse(text = text, keep.source = TRUE)
11494
}
11595

96+
srcref_to_character <- function(x) {
97+
unlist(map(x, as.character))
98+
}
11699
start_line <- function(srcrefs) {
117100
map_int(srcrefs, \(x) x[[1]])
118101
}
102+
end_line <- function(srcrefs) {
103+
map_int(srcrefs, \(x) x[[3]])
104+
}

R/source.R

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ filter_desc <- function(exprs, descs, error_call = caller_env()) {
115115
}
116116

117117
is_subtest <- function(expr) {
118-
is_call(expr, c("test_that", "describe", "it"), n = 2) && is_string(expr[[2]])
118+
is_call(expr, c("test_that", "describe", "it"), n = 2) &&
119+
is_string(expr[[2]]) &&
120+
is_call(expr[[3]], "{")
119121
}
120122

121123
#' @rdname source_file

tests/testthat/_snaps/extract.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# can extract prequel
2+
3+
Code
4+
base::writeLines(extract_test_lines(exprs, 4))
5+
Output
6+
# prequel ---------------------------------------------------------------
7+
x <- 1
8+
y <- 2
9+
10+
# test ------------------------------------------------------------------
11+
expect_true(TRUE)
12+
13+
# preserves code format but not comments
14+
15+
Code
16+
base::writeLines(extract_test_lines(exprs, 3))
17+
Output
18+
# prequel ---------------------------------------------------------------
19+
1 + 1
20+
21+
# test ------------------------------------------------------------------
22+
2 + 2
23+
24+
# can extract selected expectation
25+
26+
Code
27+
base::writeLines(extract_test_lines(exprs, 2))
28+
Output
29+
expect_true(TRUE)
30+

tests/testthat/test-extract.R

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
test_that("can extract prequel", {
2+
# fmt: skip
3+
exprs <- parse_text("
4+
x <- 1
5+
y <- 2
6+
test_that('foo', {
7+
expect_true(TRUE)
8+
})
9+
")
10+
expect_snapshot(base::writeLines(extract_test_lines(exprs, 4)))
11+
})
12+
13+
test_that("preserves code format but not comments", {
14+
# fmt: skip
15+
exprs <- parse_text("
16+
1 + 1 # 2
17+
test_that('foo', {
18+
2 + 2 # 4
19+
})
20+
")
21+
expect_snapshot(base::writeLines(extract_test_lines(exprs, 3)))
22+
})
23+
24+
test_that("can extract selected expectation", {
25+
# fmt: skip
26+
exprs <- parse_text("
27+
test_that('foo', {
28+
expect_true(TRUE)
29+
expect_false(FALSE)
30+
})
31+
")
32+
expect_snapshot(base::writeLines(extract_test_lines(exprs, 2)))
33+
})
34+
35+
test_that("errors if can't find test", {
36+
# fmt: skip
37+
exprs <- parse_text("
38+
# line 1
39+
test_that('foo', {
40+
expect_true(TRUE)
41+
})
42+
# line 5
43+
")
44+
expect_error(extract_test_lines(exprs, 1), "Failed to find test")
45+
expect_error(extract_test_lines(exprs, 5), "Failed to find test")
46+
})

0 commit comments

Comments
 (0)