Skip to content

Commit a478401

Browse files
authored
Run a single test (#1840)
Fixes #1776
1 parent 4b57565 commit a478401

File tree

7 files changed

+175
-15
lines changed

7 files changed

+175
-15
lines changed

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# testthat (development version)
22

3+
* `test_file()` gains a `desc` argument which allows you to run a single
4+
test from a file (#1776).
5+
36
* `expect_setequal()` correctly displays results when only one of actual and
47
expected is missing values (#1835).
58

R/source.R

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@
55
#' @param path Path to files.
66
#' @param pattern Regular expression used to filter files.
77
#' @param env Environment in which to evaluate code.
8+
#' @param desc If not-`NULL`, will run only test with this `desc`ription.
89
#' @param chdir Change working directory to `dirname(path)`?
910
#' @param wrap Automatically wrap all code within [test_that()]? This ensures
1011
#' that all expectations are reported, even if outside a test block.
1112
#' @export
1213
#' @keywords internal
13-
source_file <- function(path, env = test_env(), chdir = TRUE,
14-
wrap = TRUE) {
14+
source_file <- function(path,
15+
env = test_env(),
16+
chdir = TRUE,
17+
desc = NULL,
18+
wrap = TRUE,
19+
error_call = caller_env()) {
1520
stopifnot(file.exists(path))
1621
stopifnot(is.environment(env))
1722

@@ -23,6 +28,7 @@ source_file <- function(path, env = test_env(), chdir = TRUE,
2328
con <- textConnection(lines, encoding = "UTF-8")
2429
on.exit(try(close(con), silent = TRUE), add = TRUE)
2530
exprs <- parse(con, n = -1, srcfile = srcfile, encoding = "UTF-8")
31+
exprs <- filter_desc(exprs, desc, error_call = error_call)
2632

2733
n <- length(exprs)
2834
if (n == 0L) return(invisible())
@@ -46,13 +52,52 @@ source_file <- function(path, env = test_env(), chdir = TRUE,
4652
error = function(err) {
4753
abort(
4854
paste0("In path: ", encodeString(path, quote = '"')),
49-
parent = err
55+
parent = err,
56+
call = error_call
5057
)
5158
}
5259
)
5360
}
5461
}
5562

63+
filter_desc <- function(exprs, desc = NULL, error_call = caller_env()) {
64+
if (is.null(desc)) {
65+
return(exprs)
66+
}
67+
68+
found <- FALSE
69+
include <- rep(FALSE, length(exprs))
70+
71+
for (i in seq_along(exprs)) {
72+
expr <- exprs[[i]]
73+
74+
if (!is_call(expr, "test_that", n = 2)) {
75+
if (!found) {
76+
include[[i]] <- TRUE
77+
}
78+
} else {
79+
if (!is_string(expr[[2]]))
80+
next
81+
82+
test_desc <- as.character(expr[[2]])
83+
if (test_desc != desc)
84+
next
85+
86+
if (found) {
87+
abort("Found multiple tests with specified description", call = error_call)
88+
}
89+
include[[i]] <- TRUE
90+
found <- TRUE
91+
}
92+
}
93+
94+
if (!found) {
95+
abort("Failed to find test with specified description", call = error_call)
96+
}
97+
98+
exprs[include]
99+
}
100+
56101
#' @rdname source_file
57102
#' @export
58103
source_dir <- function(path, pattern = "\\.[rR]$", env = test_env(),

R/test-files.R

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ test_dir <- function(path,
100100
)
101101
}
102102

103-
#' Run all tests in a single file
103+
#' Run tests in a single file
104104
#'
105105
#' Helper, setup, and teardown files located in the same directory as the
106106
#' test will also be run. See `vignette("special-files")` for details.
@@ -109,12 +109,19 @@ test_dir <- function(path,
109109
#' @inheritSection test_dir Environments
110110
#' @param path Path to file.
111111
#' @param ... Additional parameters passed on to `test_dir()`
112+
#' @param desc Optionally, supply a string here to run only a single
113+
#' test that has this `desc`ription.
112114
#' @export
113115
#' @examples
114116
#' path <- testthat_example("success")
115117
#' test_file(path)
118+
#' test_file(path, desc = "some tests have warnings")
116119
#' test_file(path, reporter = "minimal")
117-
test_file <- function(path, reporter = default_compact_reporter(), package = NULL, ...) {
120+
test_file <- function(path,
121+
reporter = default_compact_reporter(),
122+
desc = NULL,
123+
package = NULL,
124+
...) {
118125
if (!file.exists(path)) {
119126
stop("`path` does not exist", call. = FALSE)
120127
}
@@ -124,6 +131,7 @@ test_file <- function(path, reporter = default_compact_reporter(), package = NUL
124131
test_package = package,
125132
test_paths = basename(path),
126133
reporter = reporter,
134+
desc = desc,
127135
...
128136
)
129137
}
@@ -136,9 +144,11 @@ test_files <- function(test_dir,
136144
env = NULL,
137145
stop_on_failure = FALSE,
138146
stop_on_warning = FALSE,
147+
desc = NULL,
139148
wrap = TRUE,
140149
load_package = c("none", "installed", "source"),
141-
parallel = FALSE) {
150+
parallel = FALSE,
151+
error_call = caller_env()) {
142152

143153
if (is_missing(wrap)) {
144154
wrap <- TRUE
@@ -171,8 +181,10 @@ test_files <- function(test_dir,
171181
env = env,
172182
stop_on_failure = stop_on_failure,
173183
stop_on_warning = stop_on_warning,
184+
desc = desc,
174185
wrap = wrap,
175-
load_package = load_package
186+
load_package = load_package,
187+
error_call = error_call
176188
)
177189
}
178190

@@ -186,8 +198,10 @@ test_files_serial <- function(test_dir,
186198
env = NULL,
187199
stop_on_failure = FALSE,
188200
stop_on_warning = FALSE,
201+
desc = NULL,
189202
wrap = TRUE,
190-
load_package = c("none", "installed", "source")) {
203+
load_package = c("none", "installed", "source"),
204+
error_call = caller_env()) {
191205

192206
env <- test_files_setup_env(test_package, test_dir, load_package, env)
193207
# record testing env for mocks
@@ -197,7 +211,14 @@ test_files_serial <- function(test_dir,
197211
reporters <- test_files_reporter(reporter)
198212

199213
with_reporter(reporters$multi,
200-
lapply(test_paths, test_one_file, env = env, wrap = wrap)
214+
lapply(
215+
test_paths,
216+
test_one_file,
217+
env = env,
218+
desc = desc,
219+
wrap = wrap,
220+
error_call = error_call
221+
)
201222
)
202223

203224
test_files_check(reporters$list$get_results(),
@@ -301,12 +322,22 @@ test_files_check <- function(results, stop_on_failure = TRUE, stop_on_warning =
301322
invisible(results)
302323
}
303324

304-
test_one_file <- function(path, env = test_env(), wrap = TRUE) {
325+
test_one_file <- function(path,
326+
env = test_env(),
327+
desc = NULL,
328+
wrap = TRUE,
329+
error_call = caller_env()) {
305330
reporter <- get_reporter()
306331
on.exit(teardown_run(), add = TRUE)
307332

308333
reporter$start_file(path)
309-
source_file(path, env(env), wrap = wrap)
334+
source_file(
335+
path,
336+
env = env(env),
337+
wrap = wrap,
338+
desc = desc,
339+
error_call = error_call
340+
)
310341
reporter$end_context_if_started()
311342
reporter$end_file()
312343
}

man/source_file.Rd

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/test_file.Rd

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

tests/testthat/_snaps/source.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,33 @@
33
Code
44
source_file(test_path("reporters/error-setup.R"), wrap = FALSE)
55
Condition
6-
Error in `source_file()`:
6+
Error:
77
! In path: "reporters/error-setup.R"
88
Caused by error in `h()`:
99
! !
1010

11+
# can find only matching test
12+
13+
Code
14+
filter_desc(code, "baz")
15+
Condition
16+
Error:
17+
! Failed to find test with specified description
18+
19+
# preserve srcrefs
20+
21+
Code
22+
filter_desc(code, "foo")
23+
Output
24+
expression(test_that("foo", {
25+
# this is a comment
26+
}))
27+
28+
# errors if duplicate labels
29+
30+
Code
31+
filter_desc(code, "baz")
32+
Condition
33+
Error:
34+
! Found multiple tests with specified description
35+

tests/testthat/test-source.R

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,40 @@ test_that("source_file wraps error", {
4545
source_file(test_path("reporters/error-setup.R"), wrap = FALSE)
4646
})
4747
})
48+
49+
50+
# filter_label -------------------------------------------------------------
51+
52+
test_that("can find only matching test", {
53+
code <- exprs(
54+
f(),
55+
test_that("foo", {}),
56+
g(),
57+
test_that("bar", {}),
58+
h()
59+
)
60+
expect_equal(filter_desc(code, "foo"), code[c(1, 2)])
61+
expect_equal(filter_desc(code, "bar"), code[c(1, 3, 4)])
62+
expect_snapshot(filter_desc(code, "baz"), error = TRUE)
63+
})
64+
65+
test_that("preserve srcrefs", {
66+
code <- parse(keep.source = TRUE, text = '
67+
test_that("foo", {
68+
# this is a comment
69+
})
70+
')
71+
expect_snapshot(filter_desc(code, "foo"))
72+
})
73+
74+
75+
test_that("errors if duplicate labels", {
76+
code <- exprs(
77+
f(),
78+
test_that("baz", {}),
79+
test_that("baz", {}),
80+
g()
81+
)
82+
83+
expect_snapshot(filter_desc(code, "baz"), error = TRUE)
84+
})

0 commit comments

Comments
 (0)