3434# ' })
3535# ' }
3636test_that <- function (desc , code ) {
37- check_string (desc )
37+ local_description_push (desc )
3838
3939 code <- substitute(code )
4040 if (edition_get() > = 3 ) {
@@ -46,23 +46,19 @@ test_that <- function(desc, code) {
4646 }
4747 }
4848
49- # Must initialise interactive reporter before local_test_context()
50- reporter <- get_reporter() %|| % local_interactive_reporter()
51- local_test_context()
52-
53- test_code(
54- desc ,
55- code ,
56- env = parent.frame(),
57- reporter = reporter
58- )
49+ test_code(code , env = parent.frame())
5950}
6051
6152# Access error fields with `[[` rather than `$` because the
6253# `$.Throwable` from the rJava package throws with unknown fields
63- test_code <- function (test , code , env , reporter , skip_on_empty = TRUE ) {
54+ test_code <- function (code , env , reporter = NULL , skip_on_empty = TRUE ) {
55+ # Must initialise interactive reporter before local_test_context()
56+ reporter <- get_reporter() %|| % local_interactive_reporter()
57+ local_test_context()
58+
6459 frame <- caller_env()
6560
61+ test <- test_description()
6662 if (! is.null(test )) {
6763 reporter $ start_test(context = reporter $ .context , test = test )
6864 withr :: defer(reporter $ end_test(context = reporter $ .context , test = test ))
@@ -89,11 +85,6 @@ test_code <- function(test, code, env, reporter, skip_on_empty = TRUE) {
8985 reporter $ add_result(context = reporter $ .context , test = test , result = e )
9086 }
9187
92- # Any error will be assigned to this variable first
93- # In case of stack overflow, no further processing (not even a call to
94- # signalCondition() ) might be possible
95- test_error <- NULL
96-
9788 expressions_opt <- getOption(" expressions" )
9889 expressions_opt_new <- min(expressions_opt + 500L , 500000L )
9990
@@ -104,39 +95,21 @@ test_code <- function(test, code, env, reporter, skip_on_empty = TRUE) {
10495
10596 handle_error <- function (e ) {
10697 handled <<- TRUE
107- # First thing: Collect test error
108- test_error <<- e
10998
11099 # Increase option(expressions) to handle errors here if possible, even in
111- # case of a stack overflow. This is important for the DebugReporter.
112- # Call options() manually, avoid withr overhead.
113- options(expressions = expressions_opt_new )
114- withr :: defer(options(expressions = expressions_opt ))
100+ # case of a stack overflow. This is important for the DebugReporter.
101+ local_options(expressions = expressions_opt_new )
115102
116103 # Add structured backtrace to the expectation
117104 if (can_entrace(e )) {
118105 e <- cnd_entrace(e )
119106 }
120107
121- test_error <<- e
122-
123- # Error will be handled by handle_fatal() if this fails; need to do it here
124- # to be able to debug with the DebugReporter
125108 register_expectation(e , 2 )
126-
127- e [[" handled" ]] <- TRUE
128- test_error <<- e
109+ invokeRestart(" end_test" )
129110 }
130111 handle_fatal <- function (e ) {
131112 handled <<- TRUE
132- # Error caught in handle_error() has precedence
133- if (! is.null(test_error )) {
134- e <- test_error
135- if (isTRUE(e [[" handled" ]])) {
136- return ()
137- }
138- }
139-
140113 register_expectation(e , 0 )
141114 }
142115 handle_expectation <- function (e ) {
@@ -162,7 +135,6 @@ test_code <- function(test, code, env, reporter, skip_on_empty = TRUE) {
162135 }
163136
164137 register_expectation(e , 5 )
165-
166138 tryInvokeRestart(" muffleWarning" )
167139 }
168140 handle_message <- function (e ) {
@@ -175,7 +147,7 @@ test_code <- function(test, code, env, reporter, skip_on_empty = TRUE) {
175147
176148 debug_end <- if (inherits(e , " skip_empty" )) - 1 else 2
177149 register_expectation(e , debug_end )
178- signalCondition( e )
150+ invokeRestart( " end_test " )
179151 }
180152
181153 test_env <- new.env(parent = env )
@@ -185,24 +157,25 @@ test_code <- function(test, code, env, reporter, skip_on_empty = TRUE) {
185157 withr :: local_options(testthat_topenv = test_env )
186158
187159 before <- inspect_state()
188- tryCatch(
189- withCallingHandlers(
190- {
191- eval(code , test_env )
192- if (! handled && ! is.null(test )) {
193- skip_empty()
194- }
195- },
196- expectation = handle_expectation ,
197- skip = handle_skip ,
198- warning = handle_warning ,
199- message = handle_message ,
200- error = handle_error
160+ withRestarts(
161+ tryCatch(
162+ withCallingHandlers(
163+ {
164+ eval(code , test_env )
165+ if (! handled && ! is.null(test )) {
166+ skip_empty()
167+ }
168+ },
169+ expectation = handle_expectation ,
170+ skip = handle_skip ,
171+ warning = handle_warning ,
172+ message = handle_message ,
173+ error = handle_error
174+ ),
175+ # some errors may need handling here, e.g., stack overflow
176+ error = handle_fatal
201177 ),
202- # some errors may need handling here, e.g., stack overflow
203- error = handle_fatal ,
204- # skip silently terminate code
205- skip = function (e ) {}
178+ end_test = function () {}
206179 )
207180 after <- inspect_state()
208181
@@ -215,3 +188,30 @@ test_code <- function(test, code, env, reporter, skip_on_empty = TRUE) {
215188
216189 invisible (ok )
217190}
191+
192+
193+ # Maintain a stack of descriptions
194+ local_description_push <- function (description , frame = caller_env()) {
195+ check_string(description , call = frame )
196+ local_description_set(c(the $ description , description ), frame = frame )
197+ }
198+ local_description_set <- function (
199+ description = character (),
200+ frame = caller_env()
201+ ) {
202+ check_character(description , call = frame )
203+
204+ old <- the $ description
205+ the $ description <- description
206+ withr :: defer(the $ description <- old , frame )
207+
208+ invisible (old )
209+ }
210+
211+ test_description <- function () {
212+ if (length(the $ description ) == 0 ) {
213+ NULL
214+ } else {
215+ paste(the $ description , collapse = " / " )
216+ }
217+ }
0 commit comments