Skip to content

Commit 4066f6c

Browse files
committed
Use a desription stack
1 parent 22fafa4 commit 4066f6c

File tree

14 files changed

+58
-43
lines changed

14 files changed

+58
-43
lines changed

.claude/settings.local.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
{
2+
"$schema": "https://json.schemastore.org/claude-code-settings.json",
23
"permissions": {
34
"allow": [
45
"Bash(find:*)",
5-
"Bash(R:*)"
6+
"Bash(R:*)",
7+
"Bash(air format:*)"
68
],
79
"deny": []
8-
},
9-
"$schema": "https://json.schemastore.org/claude-code-settings.json"
10+
}
1011
}

NEWS.md

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

3+
* `describe()`, `it()`, and `test_that()` now have a shared stack of descriptions so that if you nest any inside of each other, any resulting failures will show you the full path (#)
4+
* `describe()` now correctly scopes `skip()` (#2007).
35
* `expect_*()` functions consistently and rigorously check their inputs (#1754).
46
* `JunitReporter()` no longer fails with `"no applicable method for xml_add_child"` for warnings outside of tests (#1913). Additionally, warnings now save their backtraces.
57
* `JunitReporter()` strips ANSI escapes in more placese (#1852, #2032).

R/describe.R

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,29 +56,17 @@
5656
#' it("can handle division by 0") #not yet implemented
5757
#' })
5858
#' })
59-
6059
describe <- function(description, code) {
61-
check_string(description, allow_empty = FALSE)
62-
describe_description <- description
63-
64-
# prepares a new environment for each it-block
65-
describe_env <- new.env(parent = parent.frame())
66-
describe_env$it <- function(description, code = NULL) {
67-
check_string(description, allow_empty = FALSE)
68-
description <- paste0(describe_description, ": ", description)
69-
70-
code <- substitute(code)
71-
test_code(description, code, env = describe_env, skip_on_empty = FALSE)
72-
}
60+
local_description_push(description)
7361

74-
test_code(description, code, describe_env, skip_on_empty = FALSE)
62+
test_code(code, parent.frame(), skip_on_empty = FALSE)
7563
}
7664

7765
#' @export
7866
#' @rdname describe
7967
it <- function(description, code = NULL) {
80-
check_string(description, allow_empty = FALSE)
68+
local_description_push(description)
8169

8270
code <- substitute(code)
83-
test_code(description, code, env = parent.frame(), skip_on_empty = FALSE)
71+
test_code(code, env = parent.frame(), skip_on_empty = FALSE)
8472
}

R/expect-self-test.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ expect_snapshot_reporter <- function(
158158
reporter,
159159
paths = test_path("reporters/tests.R")
160160
) {
161+
161162
local_options(rlang_trace_format_srcrefs = FALSE)
162163
withr::local_seed(1014)
163164

R/reporter-zzz.R

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ get_reporter <- function() {
3636
#' @rdname reporter-accessors
3737
#' @export
3838
with_reporter <- function(reporter, code, start_end_reporter = TRUE) {
39+
# Ensure we don't propagate the local description to the new reporter
40+
local_description_set()
3941
reporter <- find_reporter(reporter)
4042

4143
old <- set_reporter(reporter)

R/snapshot-reporter.R

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ SnapshotReporter <- R6::R6Class(
3535
},
3636

3737
start_test = function(context, test) {
38-
if (is.character(test)) {
39-
self$test <- gsub("\n", "", test)
38+
if (is.null(test)) {
39+
return()
4040
}
41+
42+
self$test <- paste0(gsub("\n", "", test), collapse = " / ")
4143
},
4244

4345
# Called by expectation

R/source.R

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ source_file <- function(
5555
withr::local_options(testthat_topenv = env, testthat_path = path)
5656
if (wrap) {
5757
invisible(test_code(
58-
test = NULL,
5958
code = exprs,
6059
env = env,
6160
reporter = get_reporter() %||% StopReporter$new()

R/test-example.R

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,24 +47,23 @@ test_examples_installed <- function(package = testing_package()) {
4747
#' @export
4848
#' @rdname test_examples
4949
test_rd <- function(rd, title = attr(rd, "Rdfile")) {
50-
test_example(rd, title)
50+
test_example(rd, title %||% "example")
5151
}
5252

5353
#' @export
5454
#' @rdname test_examples
5555
test_example <- function(path, title = path) {
56+
local_description_push(title)
57+
5658
ex_path <- withr::local_tempfile(pattern = "test_example-", fileext = ".R")
5759
tools::Rd2ex(path, ex_path)
5860
if (!file.exists(ex_path)) {
5961
return(invisible(FALSE))
6062
}
6163

62-
env <- new.env(parent = globalenv())
63-
6464
ok <- test_code(
65-
test = title,
6665
code = parse(ex_path, encoding = "UTF-8"),
67-
env = env,
66+
env = globalenv(),
6867
reporter = get_reporter() %||% StopReporter$new(),
6968
skip_on_empty = FALSE
7069
)

R/test-that.R

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
#' })
3535
#' }
3636
test_that <- function(desc, code) {
37-
check_string(desc)
37+
local_description_push(desc)
3838

3939
code <- substitute(code)
4040
if (edition_get() >= 3) {
@@ -46,18 +46,19 @@ test_that <- function(desc, code) {
4646
}
4747
}
4848

49-
test_code(desc, code, env = parent.frame())
49+
test_code(code, env = parent.frame())
5050
}
5151

5252
# Access error fields with `[[` rather than `$` because the
5353
# `$.Throwable` from the rJava package throws with unknown fields
54-
test_code <- function(test, code, env, reporter = NULL, skip_on_empty = TRUE) {
54+
test_code <- function(code, env, reporter = NULL, skip_on_empty = TRUE) {
5555
# Must initialise interactive reporter before local_test_context()
5656
reporter <- get_reporter() %||% local_interactive_reporter()
5757
local_test_context()
5858

5959
frame <- caller_env()
6060

61+
test <- test_description()
6162
if (!is.null(test)) {
6263
reporter$start_test(context = reporter$.context, test = test)
6364
withr::defer(reporter$end_test(context = reporter$.context, test = test))
@@ -210,3 +211,30 @@ test_code <- function(test, code, env, reporter = NULL, skip_on_empty = TRUE) {
210211

211212
invisible(ok)
212213
}
214+
215+
216+
# Maintain a stack of descriptions
217+
local_description_push <- function(description, frame = caller_env()) {
218+
check_string(description, call = frame)
219+
local_description_set(c(the$description, description), frame = frame)
220+
}
221+
local_description_set <- function(
222+
description = character(),
223+
frame = caller_env()
224+
) {
225+
check_character(description, call = frame)
226+
227+
old <- the$description
228+
the$description <- description
229+
withr::defer(the$description <- old, frame)
230+
231+
invisible(old)
232+
}
233+
234+
test_description <- function() {
235+
if (length(the$description) == 0) {
236+
NULL
237+
} else {
238+
paste(the$description, collapse = " / ")
239+
}
240+
}

R/testthat-package.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
NULL
2020

2121
the <- new.env(parent = emptyenv())
22-
22+
the$description <- character()
2323

2424
# The following block is used by usethis to automatically manage
2525
# roxygen namespace tags. Modify with care!

0 commit comments

Comments
 (0)