Skip to content

Commit 7a63280

Browse files
committed
Merged origin/main into expect-s7-class
2 parents b3ea5c2 + 5a8200a commit 7a63280

File tree

10 files changed

+157
-61
lines changed

10 files changed

+157
-61
lines changed

NAMESPACE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,10 @@ export(expect_more_than)
106106
export(expect_named)
107107
export(expect_no_condition)
108108
export(expect_no_error)
109+
export(expect_no_failure)
109110
export(expect_no_match)
110111
export(expect_no_message)
112+
export(expect_no_success)
111113
export(expect_no_warning)
112114
export(expect_null)
113115
export(expect_output)
@@ -120,6 +122,7 @@ export(expect_setequal)
120122
export(expect_silent)
121123
export(expect_snapshot)
122124
export(expect_snapshot_error)
125+
export(expect_snapshot_failure)
123126
export(expect_snapshot_file)
124127
export(expect_snapshot_output)
125128
export(expect_snapshot_value)

NEWS.md

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

33
* New `expect_s7_class()` for testing if an object is an S7 class (#1580).
4+
* `expect_error()` and friends now error if you supply `...` but not `pattern` (#1932).
5+
* New `expect_no_failure()`, `expect_no_success()` and `expect_snapshot_failure()` provide more options for testing expectations.
6+
* `expect_error()` and friends no longer give an uninformative error if they fail inside a magrittr pipe (#1994).
47
* `expect_setequal()` correctly identifies what is missing where (#1962).
58
* `expect_true()` and `expect_false()` give better errors if `actual` isn't a vector (#1996).
69
* `expect_no_*()` expectations no longer incorrectly emit a passing test result if they in fact fail (#1997).

R/expect-condition.R

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,7 @@ expect_warning <- function(object,
163163
...,
164164
inherit = inherit,
165165
info = info,
166-
label = label,
167-
trace_env = caller_env()
166+
label = label
168167
)
169168
} else {
170169
act <- quasi_capture(enquo(object), label, capture_warnings, ignore_deprecation = identical(regexp, NA))
@@ -196,8 +195,7 @@ expect_message <- function(object,
196195
...,
197196
inherit = inherit,
198197
info = info,
199-
label = label,
200-
trace_env = caller_env()
198+
label = label
201199
)
202200
} else {
203201
act <- quasi_capture(enquo(object), label, capture_messages)
@@ -225,8 +223,7 @@ expect_condition <- function(object,
225223
...,
226224
inherit = inherit,
227225
info = info,
228-
label = label,
229-
trace_env = caller_env()
226+
label = label
230227
)
231228
} else {
232229

@@ -256,18 +253,14 @@ expect_condition_matching <- function(base_class,
256253
label = NULL,
257254
trace_env = caller_env(),
258255
error_call = caller_env()) {
259-
check_dots_used(error = function(cnd) {
260-
warn(conditionMessage(cnd), call = error_call)
261-
})
262-
263256
matcher <- cnd_matcher(
264257
base_class,
265258
class,
266259
regexp,
267260
...,
268261
inherit = inherit,
269262
ignore_deprecation = base_class == "warning" && identical(regexp, NA),
270-
error_call = trace_env
263+
error_call = error_call
271264
)
272265

273266
act <- quasi_capture(
@@ -301,6 +294,13 @@ cnd_matcher <- function(base_class,
301294
check_string(class, allow_null = TRUE, call = error_call)
302295
check_string(pattern, allow_null = TRUE, allow_na = TRUE, call = error_call)
303296

297+
if (is.null(pattern) && dots_n(...) > 0) {
298+
cli::cli_abort(
299+
"Can't specify {.arg ...} without {.arg pattern}.",
300+
call = error_call
301+
)
302+
}
303+
304304
function(cnd) {
305305
if (!inherit) {
306306
cnd$parent <- NULL
@@ -318,7 +318,17 @@ cnd_matcher <- function(base_class,
318318
return(FALSE)
319319
}
320320
if (!is.null(pattern) && !isNA(pattern)) {
321-
grepl(pattern, conditionMessage(x), ...)
321+
withCallingHandlers(
322+
grepl(pattern, conditionMessage(x), ...),
323+
error = function(e) {
324+
cli::cli_abort(
325+
"Failed to compare {base_class} to {.arg pattern}.",
326+
parent = e,
327+
call = error_call
328+
)
329+
}
330+
)
331+
322332
} else {
323333
TRUE
324334
}

R/expect-no-condition.R

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,10 @@ expect_no_condition <- function(object,
8282

8383

8484
expect_no_ <- function(base_class,
85-
object,
86-
regexp = NULL,
87-
class = NULL,
88-
error_call = caller_env()) {
85+
object,
86+
regexp = NULL,
87+
class = NULL,
88+
trace_env = caller_env()) {
8989

9090
matcher <- cnd_matcher(
9191
base_class,
@@ -116,7 +116,7 @@ expect_no_ <- function(base_class,
116116
indent_lines(rlang::cnd_message(cnd))
117117
)
118118
message <- format_error_bullets(c(expected, i = actual))
119-
fail(message, trace_env = error_call)
119+
fail(message, trace_env = trace_env)
120120
}
121121
)
122122
}

R/expect-self-test.R

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,56 @@
1+
capture_failure <- new_capture("expectation_failure")
2+
capture_success <- function(expr) {
3+
cnd <- NULL
4+
5+
withCallingHandlers(
6+
expr,
7+
expectation_failure = function(cnd) {
8+
invokeRestart("continue_test")
9+
},
10+
expectation_success = function(cnd) {
11+
cnd <<- cnd
12+
}
13+
)
14+
cnd
15+
}
16+
17+
new_capture("expectation_success")
18+
119
#' Tools for testing expectations
220
#'
3-
#' Use these expectations to test other expectations.
21+
#' @description
22+
#' * `expect_sucess()` and `expect_failure()` check that there's at least
23+
#' one success or failure respectively.
24+
#' * `expect_snapshot_failure()` records the failure message so that you can
25+
#' manually check that it is informative.
26+
#' * `expect_no_success()` and `expect_no_failure()` check that are no
27+
#' successes or failures.
28+
#'
429
#' Use `show_failure()` in examples to print the failure message without
530
#' throwing an error.
631
#'
7-
#' @param expr Expression that evaluates a single expectation.
32+
#' @param expr Code to evalute
833
#' @param message Check that the failure message matches this regexp.
934
#' @param ... Other arguments passed on to [expect_match()].
1035
#' @export
1136
expect_success <- function(expr) {
12-
exp <- capture_expectation(expr)
37+
exp <- capture_success(expr)
1338

1439
if (is.null(exp)) {
15-
fail("no expectation used.")
16-
} else if (!expectation_success(exp)) {
17-
fail(paste0(
18-
"Expectation did not succeed:\n",
19-
exp$message
20-
))
40+
fail("Expectation did not succeed")
41+
} else {
42+
succeed()
43+
}
44+
invisible(NULL)
45+
}
46+
47+
#' @export
48+
#' @rdname expect_success
49+
expect_no_success <- function(expr) {
50+
exp <- capture_success(expr)
51+
52+
if (!is.null(exp)) {
53+
fail("Expectation succeeded")
2154
} else {
2255
succeed()
2356
}
@@ -27,19 +60,31 @@ expect_success <- function(expr) {
2760
#' @export
2861
#' @rdname expect_success
2962
expect_failure <- function(expr, message = NULL, ...) {
30-
exp <- capture_expectation(expr)
63+
exp <- capture_failure(expr)
3164

3265
if (is.null(exp)) {
33-
fail("No expectation used")
34-
return()
35-
}
36-
if (!expectation_failure(exp)) {
3766
fail("Expectation did not fail")
38-
return()
67+
} else if (!is.null(message)) {
68+
expect_match(exp$message, message, ...)
69+
} else {
70+
succeed()
3971
}
72+
invisible(NULL)
73+
}
4074

41-
if (!is.null(message)) {
42-
expect_match(exp$message, message, ...)
75+
#' @export
76+
#' @rdname expect_success
77+
expect_snapshot_failure <- function(expr) {
78+
expect_snapshot_error(expr, "expectation_failure")
79+
}
80+
81+
#' @export
82+
#' @rdname expect_success
83+
expect_no_failure <- function(expr) {
84+
exp <- capture_failure(expr)
85+
86+
if (!is.null(exp)) {
87+
fail("Expectation failed")
4388
} else {
4489
succeed()
4590
}
@@ -67,10 +112,6 @@ show_failure <- function(expr) {
67112
invisible()
68113
}
69114

70-
expect_snapshot_failure <- function(x) {
71-
expect_snapshot_error(x, "expectation_failure")
72-
}
73-
74115
expect_snapshot_reporter <- function(reporter, paths = test_path("reporters/tests.R")) {
75116
local_options(rlang_trace_format_srcrefs = FALSE)
76117
local_rng_version("3.3")

man/expect_success.Rd

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

tests/testthat/_snaps/expect-condition.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,18 @@
2929

3030
`f1()` did not throw a condition with class <bar>.
3131

32-
# unused arguments generate a warning
32+
# unused arguments generate an error
3333

3434
Code
3535
expect_condition(stop("Hi!"), foo = "bar")
3636
Condition
37-
Warning in `expect_condition()`:
38-
Arguments in `...` must be used.
39-
x Problematic argument:
40-
* foo = "bar"
41-
i Did you misspell an argument name?
37+
Error in `expect_condition()`:
38+
! Can't specify `...` without `pattern`.
39+
Code
40+
expect_condition(stop("Hi!"), "x", foo = "bar")
41+
Condition
42+
Error in `expect_condition()`:
43+
! Failed to compare condition to `pattern`.
44+
Caused by error in `grepl()`:
45+
! unused argument (foo = "bar")
4246

tests/testthat/test-expect-condition.R

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ test_that("can capture Throwable conditions from rJava", {
7676
expect_error(throw("foo"), "foo", class = "Throwable")
7777
})
7878

79+
test_that("capture correct trace_env (#1994)", {
80+
# This should fail, not error
81+
expect_failure(expect_error(stop("oops")) %>% expect_warning())
82+
expect_failure(expect_warning(expect_error(stop("oops"))))
83+
})
84+
7985
# expect_warning() ----------------------------------------------------------
8086

8187
test_that("warnings are converted to errors when options('warn') >= 2", {
@@ -217,8 +223,11 @@ test_that("can match parent conditions (#1493)", {
217223
expect_error(expect_error(f(), "Parent message.", inherit = FALSE))
218224
})
219225

220-
test_that("unused arguments generate a warning", {
221-
expect_snapshot(expect_condition(stop("Hi!"), foo = "bar"))
226+
test_that("unused arguments generate an error", {
227+
expect_snapshot(error = TRUE, {
228+
expect_condition(stop("Hi!"), foo = "bar")
229+
expect_condition(stop("Hi!"), "x", foo = "bar")
230+
})
222231
})
223232

224233

tests/testthat/test-expect-no-condition.R

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,13 @@ test_that("expect_no_* conditions behave as expected", {
1414
})
1515

1616
test_that("expect_no_* don't emit success when they fail", {
17+
expect_no_success(expect_no_error(stop("!")))
18+
})
1719

18-
catch_cnds <- function(code) {
19-
cnds <- list()
20-
21-
withCallingHandlers(code, condition = function(cnd) {
22-
cnds[[length(cnds) + 1]] <<- cnd
23-
invokeRestart("continue_test")
24-
})
25-
cnds
26-
}
27-
28-
cnds <- catch_cnds(expect_no_error(stop("!")))
29-
expect_length(cnds, 1)
30-
expect_s3_class(cnds[[1]], "expectation_failure")
20+
test_that("capture correct trace_env (#1994)", {
21+
# This should fail, not error
22+
expect_failure(expect_message({message("a"); warn("b")}) %>% expect_no_warning())
23+
expect_failure(expect_no_message({message("a"); warn("b")}) %>% expect_warning())
3124
})
3225

3326
test_that("unmatched conditions bubble up", {

tests/testthat/test-expect-self-test.R

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,19 @@ test_that("show_failure", {
2727
expect_null(show_failure(NULL))
2828
expect_output(show_failure(expect_true(FALSE)), "FALSE is not TRUE")
2929
})
30+
31+
test_that("can test for presence and absense of failure", {
32+
expect_success(expect_failure(fail()))
33+
expect_success(expect_no_failure(succeed()))
34+
35+
expect_failure(expect_failure(succeed()))
36+
expect_failure(expect_no_failure(fail()))
37+
})
38+
39+
test_that("can test for presence and absense of success", {
40+
expect_success(expect_success(succeed()))
41+
expect_success(expect_no_success(fail()))
42+
43+
expect_failure(expect_success(fail()))
44+
expect_failure(expect_no_success(succeed()))
45+
})

0 commit comments

Comments
 (0)