From 36d0a8b39ae46a69eb18167327c322cc7e95a434 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Wed, 30 Jul 2025 12:46:21 -0500 Subject: [PATCH 01/20] Explore auto-labelling with values --- R/expect-equality.R | 4 +-- R/expect-setequal.R | 20 ++++++------- R/quasi-label.R | 50 ++++++++++++++++++++++++++++--- tests/testthat/test-quasi-label.R | 2 +- 4 files changed, 58 insertions(+), 18 deletions(-) diff --git a/R/expect-equality.R b/R/expect-equality.R index 8f9f39c65..17a83c78a 100644 --- a/R/expect-equality.R +++ b/R/expect-equality.R @@ -136,12 +136,10 @@ expect_waldo_equal_ <- function( ) if (length(comp) != 0) { msg <- sprintf( - "%s (%s) not %s to %s (%s).\n\n%s", + "%s not %s to %s.\n\n%s", act$lab, - "`actual`", type, exp$lab, - "`expected`", paste0(comp, collapse = "\n\n") ) return(fail(msg, info = info, trace_env = trace_env)) diff --git a/R/expect-setequal.R b/R/expect-setequal.R index 2b42b78d7..200eab9a2 100644 --- a/R/expect-setequal.R +++ b/R/expect-setequal.R @@ -24,8 +24,8 @@ #' show_failure(expect_mapequal(x, list(a = 1, b = "x"))) #' show_failure(expect_mapequal(x, list(a = 1, b = 2, c = 3))) expect_setequal <- function(object, expected) { - act <- quasi_label(enquo(object), arg = "object") - exp <- quasi_label(enquo(expected), arg = "expected") + act <- quasi_label(enquo(object)) + exp <- quasi_label(enquo(expected)) if (!is_vector(act$val) || !is_vector(exp$val)) { abort("`object` and `expected` must both be vectors") @@ -41,9 +41,9 @@ expect_setequal <- function(object, expected) { if (length(exp_miss) || length(act_miss)) { return(fail(paste0( act$lab, - " (`actual`) and ", + " and ", exp$lab, - " (`expected`) don't have the same values.\n", + " don't have the same values.\n", if (length(act_miss)) { paste0("* Only in `actual`: ", values(act_miss), "\n") }, @@ -76,8 +76,8 @@ is_vector <- function(x) is.list(x) || (is.atomic(x) && !is.null(x)) #' @export #' @rdname expect_setequal expect_mapequal <- function(object, expected) { - act <- quasi_label(enquo(object), arg = "object") - exp <- quasi_label(enquo(expected), arg = "expected") + act <- quasi_label(enquo(object)) + exp <- quasi_label(enquo(expected)) if (!is_vector(act$val) || !is_vector(exp$val)) { abort("`object` and `expected` must both be vectors") @@ -126,8 +126,8 @@ check_names_ok <- function(x, label) { #' @export #' @rdname expect_setequal expect_contains <- function(object, expected) { - act <- quasi_label(enquo(object), arg = "object") - exp <- quasi_label(enquo(expected), arg = "expected") + act <- quasi_label(enquo(object)) + exp <- quasi_label(enquo(expected)) if (!is_vector(act$val) || !is_vector(exp$val)) { abort("`object` and `expected` must both be vectors") @@ -152,8 +152,8 @@ expect_contains <- function(object, expected) { #' @export #' @rdname expect_setequal expect_in <- function(object, expected) { - act <- quasi_label(enquo(object), arg = "object") - exp <- quasi_label(enquo(expected), arg = "expected") + act <- quasi_label(enquo(object)) + exp <- quasi_label(enquo(expected)) if (!is_vector(act$val) || !is_vector(exp$val)) { abort("`object` and `expected` must both be vectors") diff --git a/R/quasi-label.R b/R/quasi-label.R index b59fc7ea2..feb4eb28b 100644 --- a/R/quasi-label.R +++ b/R/quasi-label.R @@ -41,11 +41,10 @@ quasi_label <- function(quo, label = NULL, arg = "quo") { } expr <- quo_get_expr(quo) + value <- eval_bare(expr, quo_get_env(quo)) + label <- label %||% auto_label(expr, value, arg) - new_actual( - eval_bare(expr, quo_get_env(quo)), - label %||% expr_label(expr) - ) + new_actual(value, label) } new_actual <- function(value, label) { @@ -66,6 +65,49 @@ quasi_capture <- function(.quo, .label, .capture, ...) { act } +auto_label <- function(expr, value, arg) { + if (is.call(expr) || is.name(expr)) { + label <- expr_label(expr) + if (is_simple(value)) { + paste0(label, " (", simple_format(value), ")") + } else { + label + } + } else if (is_simple(expr)) { + paste0("`", arg, "` (", simple_format(expr), ")") + } else { + paste0("`", arg, "`") + } +} + +# expect_true(NULL) + +is_simple <- function(x) { + if (is.null(x)) { + return(TRUE) + } + if (!is.atomic(x)) { + return(FALSE) + } + if (length(x) != 1) { + return(FALSE) + } + + if (is.character(x)) { + !grepl("\n", x) && nchar(x) < 100 + } else if (is.logical(x) || is.numeric(x)) { + TRUE + } +} + +simple_format <- function(x) { + if (is.character(x)) { + encodeString(x, quote = '"') + } else { + format(x) + } +} + expr_label <- function(x) { if (is_syntactic_literal(x)) { deparse1(x) diff --git a/tests/testthat/test-quasi-label.R b/tests/testthat/test-quasi-label.R index 2dab0f8b0..807900ae0 100644 --- a/tests/testthat/test-quasi-label.R +++ b/tests/testthat/test-quasi-label.R @@ -1,5 +1,5 @@ test_that("atomic scalars deparsed to single values", { - expect_equal(expr_label(NULL), "NULL") + expect_equal(expr_label(NULL, "expected"), "NULL") expect_equal(expr_label(TRUE), "TRUE") expect_equal(expr_label(1L), "1L") expect_equal(expr_label(1), "1") From 4414dda01e6b070d1d773469e0617b3a38fec7c5 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Thu, 31 Jul 2025 08:03:12 -0500 Subject: [PATCH 02/20] Simplify label; update tests --- R/expect-setequal.R | 4 +- R/quasi-label.R | 32 +++++----- tests/testthat/_snaps/expect-equality.md | 8 +-- tests/testthat/_snaps/expect-setequal.md | 18 ++++-- tests/testthat/_snaps/reporter-progress.md | 68 ++++++++++------------ tests/testthat/test-expect-equality.R | 9 +-- tests/testthat/test-expect-setequal.R | 26 +++++++-- tests/testthat/test-quasi-label.R | 16 ++++- 8 files changed, 103 insertions(+), 78 deletions(-) diff --git a/R/expect-setequal.R b/R/expect-setequal.R index 200eab9a2..2fafe37b1 100644 --- a/R/expect-setequal.R +++ b/R/expect-setequal.R @@ -41,9 +41,9 @@ expect_setequal <- function(object, expected) { if (length(exp_miss) || length(act_miss)) { return(fail(paste0( act$lab, - " and ", + " doesn't have the same values as ", exp$lab, - " don't have the same values.\n", + ".\n", if (length(act_miss)) { paste0("* Only in `actual`: ", values(act_miss), "\n") }, diff --git a/R/quasi-label.R b/R/quasi-label.R index feb4eb28b..d0705f432 100644 --- a/R/quasi-label.R +++ b/R/quasi-label.R @@ -42,7 +42,7 @@ quasi_label <- function(quo, label = NULL, arg = "quo") { expr <- quo_get_expr(quo) value <- eval_bare(expr, quo_get_env(quo)) - label <- label %||% auto_label(expr, value, arg) + label <- label %||% auto_label(expr, value) new_actual(value, label) } @@ -65,28 +65,26 @@ quasi_capture <- function(.quo, .label, .capture, ...) { act } -auto_label <- function(expr, value, arg) { +auto_label <- function(expr, value) { if (is.call(expr) || is.name(expr)) { label <- expr_label(expr) - if (is_simple(value)) { - paste0(label, " (", simple_format(value), ")") + if (can_inline(value)) { + paste0(label, " (", as_label(value), ")") } else { label } - } else if (is_simple(expr)) { - paste0("`", arg, "` (", simple_format(expr), ")") + # } else if (is_simple(expr)) { + # simple_format(expr) } else { - paste0("`", arg, "`") + as_label(expr) } } -# expect_true(NULL) - -is_simple <- function(x) { +can_inline <- function(x) { if (is.null(x)) { return(TRUE) } - if (!is.atomic(x)) { + if (!is.atomic(x) || !is.vector(x)) { return(FALSE) } if (length(x) != 1) { @@ -94,18 +92,16 @@ is_simple <- function(x) { } if (is.character(x)) { - !grepl("\n", x) && nchar(x) < 100 + is.na(x) || (!grepl("\n", x) && nchar(x) < 100) } else if (is.logical(x) || is.numeric(x)) { TRUE + } else { + FALSE } } -simple_format <- function(x) { - if (is.character(x)) { - encodeString(x, quote = '"') - } else { - format(x) - } +is_date_time <- function(x) { + inherits(x, "Date") || inherits(x, "POSIXct") } expr_label <- function(x) { diff --git a/tests/testthat/_snaps/expect-equality.md b/tests/testthat/_snaps/expect-equality.md index 68c0622b2..e141183c1 100644 --- a/tests/testthat/_snaps/expect-equality.md +++ b/tests/testthat/_snaps/expect-equality.md @@ -1,24 +1,24 @@ # provide useful feedback on failure - 1 (`actual`) not identical to "a" (`expected`). + `x` (1) not identical to "a". `actual` is a double vector (1) `expected` is a character vector ('a') --- - 1 (`actual`) not equal to "a" (`expected`). + `x` (1) not equal to "a". `actual` is a double vector (1) `expected` is a character vector ('a') --- - 1 not identical to "a". + `x` (1) not identical to "a". Types not compatible: double is not character --- - 1 not equal to "a". + `x` (1) not equal to "a". Types not compatible: double is not character diff --git a/tests/testthat/_snaps/expect-setequal.md b/tests/testthat/_snaps/expect-setequal.md index 87ccd0fe9..c7ae0d591 100644 --- a/tests/testthat/_snaps/expect-setequal.md +++ b/tests/testthat/_snaps/expect-setequal.md @@ -1,39 +1,45 @@ # useful message on failure - "actual" (`actual`) and "expected" (`expected`) don't have the same values. + "actual" doesn't have the same values as "expected". * Only in `actual`: "actual" * Only in `expected`: "expected" --- - 1:2 (`actual`) and 2 (`expected`) don't have the same values. + `x` doesn't have the same values as `y` (2). * Only in `actual`: 1 --- - 2 (`actual`) and 2:3 (`expected`) don't have the same values. + `x` (2) doesn't have the same values as `y`. * Only in `expected`: 3 --- - 1:2 (`actual`) and 2:3 (`expected`) don't have the same values. + `x` doesn't have the same values as `y`. * Only in `actual`: 1 * Only in `expected`: 3 --- - c("a", "a") (`actual`) and c("b", "b", "b") (`expected`) don't have the same values. + `x` doesn't have the same values as `y`. * Only in `actual`: "a" * Only in `expected`: "b" +--- + + `x` doesn't have the same values as c("a", "b", "c", "d"). + * Only in `expected`: "d" + + # truncates long vectors - 1:2 (`actual`) and 1:50 (`expected`) don't have the same values. + `x` doesn't have the same values as `y`. * Only in `expected`: 3, 4, 5, 6, 7, 8, 9, 10, 11, ... diff --git a/tests/testthat/_snaps/reporter-progress.md b/tests/testthat/_snaps/reporter-progress.md index 1c2ef66b4..075eb5552 100644 --- a/tests/testthat/_snaps/reporter-progress.md +++ b/tests/testthat/_snaps/reporter-progress.md @@ -268,25 +268,22 @@ x 1. +-testthat::expect_s3_class(foo(), "foo") 2. | \-testthat::quasi_label(enquo(object), arg = "object") - 3. | +-testthat:::new_actual(...) - 4. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 5. \-foo() + 3. | \-rlang::eval_bare(expr, quo_get_env(quo)) + 4. \-foo() Error ('reporters/backtraces.R:13:10'): errors thrown from a quasi-labelled argument are entraced (deep case) Error in `foo()`: foo Backtrace: - x - 1. +-testthat::expect_s3_class(f(), "foo") - 2. | \-testthat::quasi_label(enquo(object), arg = "object") - 3. | +-testthat:::new_actual(...) - 4. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 5. \-f() - 6. \-g() - 7. +-testthat::expect_s3_class(foo(), "foo") - 8. | \-testthat::quasi_label(enquo(object), arg = "object") - 9. | +-testthat:::new_actual(...) - 10. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 11. \-foo() + x + 1. +-testthat::expect_s3_class(f(), "foo") + 2. | \-testthat::quasi_label(enquo(object), arg = "object") + 3. | \-rlang::eval_bare(expr, quo_get_env(quo)) + 4. \-f() + 5. \-g() + 6. +-testthat::expect_s3_class(foo(), "foo") + 7. | \-testthat::quasi_label(enquo(object), arg = "object") + 8. | \-rlang::eval_bare(expr, quo_get_env(quo)) + 9. \-foo() Error ('reporters/backtraces.R:21:10'): errors thrown from a quasi-labelled argument are entraced (deep deep case) Error in `bar()`: foobar @@ -296,10 +293,9 @@ 2. \-g() 3. +-testthat::expect_s3_class(foo(), "foo") 4. | \-testthat::quasi_label(enquo(object), arg = "object") - 5. | +-testthat:::new_actual(...) - 6. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 7. \-foo() - 8. \-bar() + 5. | \-rlang::eval_bare(expr, quo_get_env(quo)) + 6. \-foo() + 7. \-bar() Error ('reporters/backtraces.R:32:16'): failed expect_error() prints a backtrace Error in `signaller()`: bar @@ -399,25 +395,22 @@ x 1. +-testthat::expect_s3_class(foo(), "foo") 2. | \-testthat::quasi_label(enquo(object), arg = "object") - 3. | +-testthat:::new_actual(...) - 4. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 5. \-foo() + 3. | \-rlang::eval_bare(expr, quo_get_env(quo)) + 4. \-foo() Error ('reporters/backtraces.R:13:10'): errors thrown from a quasi-labelled argument are entraced (deep case) Error in `foo()`: foo Backtrace: - x - 1. +-testthat::expect_s3_class(f(), "foo") - 2. | \-testthat::quasi_label(enquo(object), arg = "object") - 3. | +-testthat:::new_actual(...) - 4. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 5. \-f() - 6. \-g() - 7. +-testthat::expect_s3_class(foo(), "foo") - 8. | \-testthat::quasi_label(enquo(object), arg = "object") - 9. | +-testthat:::new_actual(...) - 10. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 11. \-foo() + x + 1. +-testthat::expect_s3_class(f(), "foo") + 2. | \-testthat::quasi_label(enquo(object), arg = "object") + 3. | \-rlang::eval_bare(expr, quo_get_env(quo)) + 4. \-f() + 5. \-g() + 6. +-testthat::expect_s3_class(foo(), "foo") + 7. | \-testthat::quasi_label(enquo(object), arg = "object") + 8. | \-rlang::eval_bare(expr, quo_get_env(quo)) + 9. \-foo() Error ('reporters/backtraces.R:21:10'): errors thrown from a quasi-labelled argument are entraced (deep deep case) Error in `bar()`: foobar @@ -427,10 +420,9 @@ 2. \-g() 3. +-testthat::expect_s3_class(foo(), "foo") 4. | \-testthat::quasi_label(enquo(object), arg = "object") - 5. | +-testthat:::new_actual(...) - 6. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 7. \-foo() - 8. \-bar() + 5. | \-rlang::eval_bare(expr, quo_get_env(quo)) + 6. \-foo() + 7. \-bar() Error ('reporters/backtraces.R:32:16'): failed expect_error() prints a backtrace Error in `signaller()`: bar diff --git a/tests/testthat/test-expect-equality.R b/tests/testthat/test-expect-equality.R index 2176a0b4b..a21914e27 100644 --- a/tests/testthat/test-expect-equality.R +++ b/tests/testthat/test-expect-equality.R @@ -65,13 +65,14 @@ test_that("provide useful feedback on failure", { local_output_override() local_edition(3) - expect_snapshot_error(expect_identical(1, "a")) - expect_snapshot_error(expect_equal(1, "a")) + x <- 1 + expect_snapshot_failure(expect_identical(x, "a")) + expect_snapshot_failure(expect_equal(x, "a")) local_edition(2) withr::local_options(testthat.edition_ignore = TRUE) - expect_snapshot_error(expect_identical(1, "a")) - expect_snapshot_error(expect_equal(1, "a")) + expect_snapshot_failure(expect_identical(x, "a")) + expect_snapshot_failure(expect_equal(x, "a")) }) test_that("default labels use unquoting", { diff --git a/tests/testthat/test-expect-setequal.R b/tests/testthat/test-expect-setequal.R index 96c8ae569..8d6cdf91a 100644 --- a/tests/testthat/test-expect-setequal.R +++ b/tests/testthat/test-expect-setequal.R @@ -32,16 +32,32 @@ test_that("error for non-vectors", { test_that("useful message on failure", { expect_snapshot_failure(expect_setequal("actual", "expected")) - expect_snapshot_failure(expect_setequal(1:2, 2)) - expect_snapshot_failure(expect_setequal(2, 2:3)) - expect_snapshot_failure(expect_setequal(1:2, 2:3)) + x <- 1:2 + y <- 2 + expect_snapshot_failure(expect_setequal(x, y)) + + x <- 2 + y <- 2:3 + expect_snapshot_failure(expect_setequal(x, y)) + + x <- 1:2 + y <- 2:3 + expect_snapshot_failure(expect_setequal(x, y)) # doesn't repeat values - expect_snapshot_failure(expect_setequal(c("a", "a"), c("b", "b", "b"))) + x <- c("a", "a") + y <- c("b", "b", "b") + expect_snapshot_failure(expect_setequal(x, y)) + + # still looks good when expected is inlined + x <- c("a", "b", "c") + expect_snapshot_failure(expect_setequal(x, c("a", "b", "c", "d"))) }) test_that("truncates long vectors", { - expect_snapshot_failure(expect_setequal(1:2, 1:50)) + x <- 1:2 + y <- 1:50 + expect_snapshot_failure(expect_setequal(x, y)) }) # mapequal ---------------------------------------------------------------- diff --git a/tests/testthat/test-quasi-label.R b/tests/testthat/test-quasi-label.R index 807900ae0..702be1445 100644 --- a/tests/testthat/test-quasi-label.R +++ b/tests/testthat/test-quasi-label.R @@ -1,5 +1,19 @@ +test_that("shows value iif simple", { + # symbols and calls shown + expect_equal(auto_label(quote(x), TRUE), "`x` (TRUE)") + expect_equal(auto_label(quote(f()), TRUE), "f() (TRUE)") + expect_equal(auto_label(quote(f()), NA_character_), "f() (NA_character_)") + # long arguments truncated + expect_equal(auto_label(call2("f", !!!letters), TRUE), "f(...) (TRUE)") + + df <- data.frame(x = 1:100) + expect_equal(auto_label(quote(f()), df), "f()") + expect_equal(auto_label(quote(f()), "x\ny"), "f()") + expect_equal(auto_label(quote(f()), strrep("x", 100)), "f()") +}) + test_that("atomic scalars deparsed to single values", { - expect_equal(expr_label(NULL, "expected"), "NULL") + expect_equal(expr_label(NULL), "NULL") expect_equal(expr_label(TRUE), "TRUE") expect_equal(expr_label(1L), "1L") expect_equal(expr_label(1), "1") From 3444a77f6d9c3ff3e491d52b60b4ff2bdd4ee39c Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Thu, 31 Jul 2025 08:06:07 -0500 Subject: [PATCH 03/20] Revert accidental change --- R/expect-setequal.R | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/R/expect-setequal.R b/R/expect-setequal.R index 2fafe37b1..6d2f85b77 100644 --- a/R/expect-setequal.R +++ b/R/expect-setequal.R @@ -24,8 +24,8 @@ #' show_failure(expect_mapequal(x, list(a = 1, b = "x"))) #' show_failure(expect_mapequal(x, list(a = 1, b = 2, c = 3))) expect_setequal <- function(object, expected) { - act <- quasi_label(enquo(object)) - exp <- quasi_label(enquo(expected)) + act <- quasi_label(enquo(object), arg = "object") + exp <- quasi_label(enquo(expected), arg = "expected") if (!is_vector(act$val) || !is_vector(exp$val)) { abort("`object` and `expected` must both be vectors") @@ -76,8 +76,8 @@ is_vector <- function(x) is.list(x) || (is.atomic(x) && !is.null(x)) #' @export #' @rdname expect_setequal expect_mapequal <- function(object, expected) { - act <- quasi_label(enquo(object)) - exp <- quasi_label(enquo(expected)) + act <- quasi_label(enquo(object), arg = "object") + exp <- quasi_label(enquo(expected), arg = "expected") if (!is_vector(act$val) || !is_vector(exp$val)) { abort("`object` and `expected` must both be vectors") @@ -126,8 +126,8 @@ check_names_ok <- function(x, label) { #' @export #' @rdname expect_setequal expect_contains <- function(object, expected) { - act <- quasi_label(enquo(object)) - exp <- quasi_label(enquo(expected)) + act <- quasi_label(enquo(object), arg = "object") + exp <- quasi_label(enquo(expected), arg = "expected") if (!is_vector(act$val) || !is_vector(exp$val)) { abort("`object` and `expected` must both be vectors") @@ -152,8 +152,8 @@ expect_contains <- function(object, expected) { #' @export #' @rdname expect_setequal expect_in <- function(object, expected) { - act <- quasi_label(enquo(object)) - exp <- quasi_label(enquo(expected)) + act <- quasi_label(enquo(object), arg = "object") + exp <- quasi_label(enquo(expected), arg = "expected") if (!is_vector(act$val) || !is_vector(exp$val)) { abort("`object` and `expected` must both be vectors") From 118cf2095f017155841394e2c877df9e47622bce Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Thu, 31 Jul 2025 08:08:55 -0500 Subject: [PATCH 04/20] Simplify --- R/quasi-label.R | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/R/quasi-label.R b/R/quasi-label.R index e1e81f501..0af6ce4fa 100644 --- a/R/quasi-label.R +++ b/R/quasi-label.R @@ -73,10 +73,8 @@ auto_label <- function(expr, value) { } else { label } - # } else if (is_simple(expr)) { - # simple_format(expr) } else { - as_label(expr) + expr_label(expr) } } @@ -100,10 +98,6 @@ can_inline <- function(x) { } } -is_date_time <- function(x) { - inherits(x, "Date") || inherits(x, "POSIXct") -} - expr_label <- function(x) { if (is_syntactic_literal(x)) { deparse1(x) From 60d0eb7635bd2921529f18b219f520cc07629926 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Thu, 31 Jul 2025 08:14:00 -0500 Subject: [PATCH 05/20] Adjust set_equal and friends --- R/expect-setequal.R | 16 ++++++++-------- tests/testthat/_snaps/expect-setequal.md | 24 ++++++++++++------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/R/expect-setequal.R b/R/expect-setequal.R index 6d2f85b77..340798015 100644 --- a/R/expect-setequal.R +++ b/R/expect-setequal.R @@ -138,11 +138,11 @@ expect_contains <- function(object, expected) { if (any(exp_miss)) { return(fail(paste0( act$lab, - " (`actual`) doesn't fully contain all the values in ", + " doesn't fully contain all the values in ", exp$lab, - " (`expected`).\n", - paste0("* Missing from `actual`: ", values(exp$val[exp_miss]), "\n"), - paste0("* Present in `actual`: ", values(act$val), "\n") + ".\n", + paste0("* Missing from ", act$lab, ": ", values(exp$val[exp_miss]), "\n"), + paste0("* Present in ", act$lab, ": ", values(act$val), "\n") ))) } @@ -164,11 +164,11 @@ expect_in <- function(object, expected) { if (any(act_miss)) { return(fail(paste0( act$lab, - " (`actual`) isn't fully contained within ", + " isn't fully contained within ", exp$lab, - " (`expected`).\n", - paste0("* Missing from `expected`: ", values(act$val[act_miss]), "\n"), - paste0("* Present in `expected`: ", values(exp$val), "\n") + ".\n", + paste0("* Missing from ", act$lab, ": ", values(act$val[act_miss]), "\n"), + paste0("* Present in ", act$lab, ": ", values(exp$val), "\n") ))) } diff --git a/tests/testthat/_snaps/expect-setequal.md b/tests/testthat/_snaps/expect-setequal.md index c7ae0d591..1106047bb 100644 --- a/tests/testthat/_snaps/expect-setequal.md +++ b/tests/testthat/_snaps/expect-setequal.md @@ -45,29 +45,29 @@ # expect_contains() gives useful message on failure - `x1` (`actual`) doesn't fully contain all the values in `x2` (`expected`). - * Missing from `actual`: "d" - * Present in `actual`: "a", "b", "c" + `x1` doesn't fully contain all the values in `x2`. + * Missing from `x1`: "d" + * Present in `x1`: "a", "b", "c" --- - `x1` (`actual`) doesn't fully contain all the values in `x3` (`expected`). - * Missing from `actual`: "d", "e" - * Present in `actual`: "a", "b", "c" + `x1` doesn't fully contain all the values in `x3`. + * Missing from `x1`: "d", "e" + * Present in `x1`: "a", "b", "c" # expect_in() gives useful message on failure - `x1` (`actual`) isn't fully contained within `x2` (`expected`). - * Missing from `expected`: "a" - * Present in `expected`: "b", "c" + `x1` isn't fully contained within `x2`. + * Missing from `x1`: "a" + * Present in `x1`: "b", "c" --- - `x1` (`actual`) isn't fully contained within `x3` (`expected`). - * Missing from `expected`: "a", "b" - * Present in `expected`: "d", "e" + `x1` isn't fully contained within `x3`. + * Missing from `x1`: "a", "b" + * Present in `x1`: "d", "e" From 3c421932954b036578fdf3e1dc8cac4da9ea2b34 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 08:24:40 -0500 Subject: [PATCH 06/20] Update snaps --- tests/testthat/_snaps/expect-comparison.md | 8 +- tests/testthat/_snaps/expect-inheritance.md | 2 +- tests/testthat/_snaps/expect-named.md | 12 +- tests/testthat/_snaps/reporter-progress.md | 296 ++------------------ tests/testthat/_snaps/try-again.md | 2 +- 5 files changed, 31 insertions(+), 289 deletions(-) diff --git a/tests/testthat/_snaps/expect-comparison.md b/tests/testthat/_snaps/expect-comparison.md index e204dd779..13457c6df 100644 --- a/tests/testthat/_snaps/expect-comparison.md +++ b/tests/testthat/_snaps/expect-comparison.md @@ -1,21 +1,21 @@ # useful output when numbers are very small - 1.1 * x is not less than `x`. + 1.1 * x (1.1e-05) is not less than `x` (1e-05). 0.0000110 - 0.0000100 = 0.0000010 > 0 --- - `x` is not strictly greater than 1.1 * x. + `x` (1e-05) is not strictly greater than 1.1 * x (1.1e-05). 0.0000100 - 0.0000110 = -0.0000010 <= 0 # useful output when difference is zero - `x` is not strictly less than 100. + `x` (100) is not strictly less than 100. 100.0 - 100.0 = 0.0 >= 0 # useful output when differnce is large - `x` is not strictly less than 0.001. + `x` (100) is not strictly less than 0.001. 100.000 - 0.001 = 99.999 >= 0 # comparison must yield a single logical diff --git a/tests/testthat/_snaps/expect-inheritance.md b/tests/testthat/_snaps/expect-inheritance.md index 3df13de95..3708ecfbb 100644 --- a/tests/testthat/_snaps/expect-inheritance.md +++ b/tests/testthat/_snaps/expect-inheritance.md @@ -49,7 +49,7 @@ # expect_r6_class generates useful failures - `x` is not an R6 object. + `x` (1) is not an R6 object. # expect_r6_class validates its inputs diff --git a/tests/testthat/_snaps/expect-named.md b/tests/testthat/_snaps/expect-named.md index 3a54b0219..d9d14b6d0 100644 --- a/tests/testthat/_snaps/expect-named.md +++ b/tests/testthat/_snaps/expect-named.md @@ -1,39 +1,39 @@ # provide useful feedback on failure - Names of c(a = 1) (`actual`) and c("a", "b") (`expected`) don't have the same values. + Names of c(a = 1) (c(a = 1)) doesn't have the same values as c("a", "b"). * Only in `expected`: "b" --- - Names of c(a = 1, b = 1) (`actual`) and c("a") (`expected`) don't have the same values. + Names of c(a = 1, b = 1) doesn't have the same values as c("a") ("a"). * Only in `actual`: "b" --- - Names of c(a = 1) (`actual`) and c("b") (`expected`) don't have the same values. + Names of c(a = 1) (c(a = 1)) doesn't have the same values as c("b") ("b"). * Only in `actual`: "a" * Only in `expected`: "b" --- - Names of c(a = 1) (`actual`) is not equal to c("a", "b") (`expected`). + Names of c(a = 1) (c(a = 1)) is not equal to c("a", "b"). `actual`: "a" `expected`: "a" "b" --- - Names of c(a = 1, b = 1) (`actual`) is not equal to c("a") (`expected`). + Names of c(a = 1, b = 1) is not equal to c("a") ("a"). `actual`: "a" "b" `expected`: "a" --- - Names of c(a = 1) (`actual`) is not equal to c("b") (`expected`). + Names of c(a = 1) (c(a = 1)) is not equal to c("b") ("b"). `actual`: "a" `expected`: "b" diff --git a/tests/testthat/_snaps/reporter-progress.md b/tests/testthat/_snaps/reporter-progress.md index 90e94940e..7b11c84c2 100644 --- a/tests/testthat/_snaps/reporter-progress.md +++ b/tests/testthat/_snaps/reporter-progress.md @@ -133,156 +133,6 @@ -------------------------------------------------------------------------------- Maximum number of failures exceeded; quitting at end of file. i Increase this number with (e.g.) `testthat::set_max_fails(Inf)` - <<<<<<< HEAD - - == Results ===================================================================== - -- Failed tests ---------------------------------------------------------------- - Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. - - `actual`: FALSE - `expected`: TRUE - - [ FAIL 11 | WARN 0 | SKIP 0 | PASS 0 ] - == Terminated early ============================================================ - - No one gets it right on their first try - ||||||| Overhaul `expect_matches()` (#2138) - - == Results ===================================================================== - -- Failed tests ---------------------------------------------------------------- - Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). - - `actual`: FALSE - `expected`: TRUE - - Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). - - `actual`: FALSE - `expected`: TRUE - - [ FAIL 11 | WARN 0 | SKIP 0 | PASS 0 ] - == Terminated early ============================================================ - - No one gets it right on their first try - ======= - >>>>>>> 608decce7eb4bd198c0ff28dae0eb9b0c72e040d # can fully suppress incremental updates @@ -344,63 +194,23 @@ Backtrace: x 1. +-testthat::expect_s3_class(foo(), "foo") - <<<<<<< HEAD - 2. | \-testthat::quasi_label(enquo(object), arg = "object") + 2. | \-testthat::quasi_label(enquo(object)) 3. | \-rlang::eval_bare(expr, quo_get_env(quo)) 4. \-foo() - ||||||| Overhaul `expect_matches()` (#2138) - 2. | \-testthat::quasi_label(enquo(object), arg = "object") - 3. | +-testthat:::labelled_value(...) - 4. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 5. \-foo() - ======= - 2. | \-testthat::quasi_label(enquo(object)) - 3. | +-testthat:::labelled_value(...) - 4. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 5. \-foo() - >>>>>>> 608decce7eb4bd198c0ff28dae0eb9b0c72e040d Error ('reporters/backtraces.R:13:10'): errors thrown from a quasi-labelled argument are entraced (deep case) Error in `foo()`: foo Backtrace: - <<<<<<< HEAD x 1. +-testthat::expect_s3_class(f(), "foo") - 2. | \-testthat::quasi_label(enquo(object), arg = "object") + 2. | \-testthat::quasi_label(enquo(object)) 3. | \-rlang::eval_bare(expr, quo_get_env(quo)) 4. \-f() 5. \-g() 6. +-testthat::expect_s3_class(foo(), "foo") - 7. | \-testthat::quasi_label(enquo(object), arg = "object") + 7. | \-testthat::quasi_label(enquo(object)) 8. | \-rlang::eval_bare(expr, quo_get_env(quo)) 9. \-foo() - ||||||| Overhaul `expect_matches()` (#2138) - x - 1. +-testthat::expect_s3_class(f(), "foo") - 2. | \-testthat::quasi_label(enquo(object), arg = "object") - 3. | +-testthat:::labelled_value(...) - 4. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 5. \-f() - 6. \-g() - 7. +-testthat::expect_s3_class(foo(), "foo") - 8. | \-testthat::quasi_label(enquo(object), arg = "object") - 9. | +-testthat:::labelled_value(...) - 10. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 11. \-foo() - ======= - x - 1. +-testthat::expect_s3_class(f(), "foo") - 2. | \-testthat::quasi_label(enquo(object)) - 3. | +-testthat:::labelled_value(...) - 4. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 5. \-f() - 6. \-g() - 7. +-testthat::expect_s3_class(foo(), "foo") - 8. | \-testthat::quasi_label(enquo(object)) - 9. | +-testthat:::labelled_value(...) - 10. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 11. \-foo() - >>>>>>> 608decce7eb4bd198c0ff28dae0eb9b0c72e040d Error ('reporters/backtraces.R:21:10'): errors thrown from a quasi-labelled argument are entraced (deep deep case) Error in `bar()`: foobar @@ -409,24 +219,10 @@ 1. \-f() 2. \-g() 3. +-testthat::expect_s3_class(foo(), "foo") - <<<<<<< HEAD - 4. | \-testthat::quasi_label(enquo(object), arg = "object") + 4. | \-testthat::quasi_label(enquo(object)) 5. | \-rlang::eval_bare(expr, quo_get_env(quo)) 6. \-foo() 7. \-bar() - ||||||| Overhaul `expect_matches()` (#2138) - 4. | \-testthat::quasi_label(enquo(object), arg = "object") - 5. | +-testthat:::labelled_value(...) - 6. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 7. \-foo() - 8. \-bar() - ======= - 4. | \-testthat::quasi_label(enquo(object)) - 5. | +-testthat:::labelled_value(...) - 6. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 7. \-foo() - 8. \-bar() - >>>>>>> 608decce7eb4bd198c0ff28dae0eb9b0c72e040d Error ('reporters/backtraces.R:32:16'): failed expect_error() prints a backtrace Error in `signaller()`: bar @@ -525,63 +321,23 @@ Backtrace: x 1. +-testthat::expect_s3_class(foo(), "foo") - <<<<<<< HEAD - 2. | \-testthat::quasi_label(enquo(object), arg = "object") + 2. | \-testthat::quasi_label(enquo(object)) 3. | \-rlang::eval_bare(expr, quo_get_env(quo)) 4. \-foo() - ||||||| Overhaul `expect_matches()` (#2138) - 2. | \-testthat::quasi_label(enquo(object), arg = "object") - 3. | +-testthat:::labelled_value(...) - 4. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 5. \-foo() - ======= - 2. | \-testthat::quasi_label(enquo(object)) - 3. | +-testthat:::labelled_value(...) - 4. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 5. \-foo() - >>>>>>> 608decce7eb4bd198c0ff28dae0eb9b0c72e040d Error ('reporters/backtraces.R:13:10'): errors thrown from a quasi-labelled argument are entraced (deep case) Error in `foo()`: foo Backtrace: - <<<<<<< HEAD x 1. +-testthat::expect_s3_class(f(), "foo") - 2. | \-testthat::quasi_label(enquo(object), arg = "object") + 2. | \-testthat::quasi_label(enquo(object)) 3. | \-rlang::eval_bare(expr, quo_get_env(quo)) 4. \-f() 5. \-g() 6. +-testthat::expect_s3_class(foo(), "foo") - 7. | \-testthat::quasi_label(enquo(object), arg = "object") + 7. | \-testthat::quasi_label(enquo(object)) 8. | \-rlang::eval_bare(expr, quo_get_env(quo)) 9. \-foo() - ||||||| Overhaul `expect_matches()` (#2138) - x - 1. +-testthat::expect_s3_class(f(), "foo") - 2. | \-testthat::quasi_label(enquo(object), arg = "object") - 3. | +-testthat:::labelled_value(...) - 4. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 5. \-f() - 6. \-g() - 7. +-testthat::expect_s3_class(foo(), "foo") - 8. | \-testthat::quasi_label(enquo(object), arg = "object") - 9. | +-testthat:::labelled_value(...) - 10. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 11. \-foo() - ======= - x - 1. +-testthat::expect_s3_class(f(), "foo") - 2. | \-testthat::quasi_label(enquo(object)) - 3. | +-testthat:::labelled_value(...) - 4. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 5. \-f() - 6. \-g() - 7. +-testthat::expect_s3_class(foo(), "foo") - 8. | \-testthat::quasi_label(enquo(object)) - 9. | +-testthat:::labelled_value(...) - 10. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 11. \-foo() - >>>>>>> 608decce7eb4bd198c0ff28dae0eb9b0c72e040d Error ('reporters/backtraces.R:21:10'): errors thrown from a quasi-labelled argument are entraced (deep deep case) Error in `bar()`: foobar @@ -590,24 +346,10 @@ 1. \-f() 2. \-g() 3. +-testthat::expect_s3_class(foo(), "foo") - <<<<<<< HEAD - 4. | \-testthat::quasi_label(enquo(object), arg = "object") + 4. | \-testthat::quasi_label(enquo(object)) 5. | \-rlang::eval_bare(expr, quo_get_env(quo)) 6. \-foo() 7. \-bar() - ||||||| Overhaul `expect_matches()` (#2138) - 4. | \-testthat::quasi_label(enquo(object), arg = "object") - 5. | +-testthat:::labelled_value(...) - 6. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 7. \-foo() - 8. \-bar() - ======= - 4. | \-testthat::quasi_label(enquo(object)) - 5. | +-testthat:::labelled_value(...) - 6. | \-rlang::eval_bare(expr, quo_get_env(quo)) - 7. \-foo() - 8. \-bar() - >>>>>>> 608decce7eb4bd198c0ff28dae0eb9b0c72e040d Error ('reporters/backtraces.R:32:16'): failed expect_error() prints a backtrace Error in `signaller()`: bar @@ -817,67 +559,67 @@ x | 11 0 | reporters/fail-many -------------------------------------------------------------------------------- Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). + FALSE is not equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). + FALSE is not equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). + FALSE is not equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). + FALSE is not equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). + FALSE is not equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). + FALSE is not equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). + FALSE is not equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). + FALSE is not equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). + FALSE is not equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). + FALSE is not equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE (`actual`) is not equal to TRUE (`expected`). + FALSE is not equal to TRUE. `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/try-again.md b/tests/testthat/_snaps/try-again.md index 68475e7a9..fce32583c 100644 --- a/tests/testthat/_snaps/try-again.md +++ b/tests/testthat/_snaps/try-again.md @@ -14,7 +14,7 @@ i Expectation failed; trying again (1)... Condition Error: - ! `i` (`actual`) is not equal to 0 (`expected`). + ! `i` (1) is not equal to 0. `actual`: 1.0 `expected`: 0.0 From e73247a359e2a9afc4835a69c1ea435d411ab6a0 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 08:29:08 -0500 Subject: [PATCH 07/20] Use `is_syntactic_literal()` --- R/quasi-label.R | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/R/quasi-label.R b/R/quasi-label.R index e526850ad..ba9d2bc07 100644 --- a/R/quasi-label.R +++ b/R/quasi-label.R @@ -90,22 +90,17 @@ auto_label <- function(expr, value) { } can_inline <- function(x) { - if (is.null(x)) { - return(TRUE) - } - if (!is.atomic(x) || !is.vector(x)) { + if (!is_syntactic_literal(x)) { return(FALSE) } - if (length(x) != 1) { + if (!is.null(dim(x))) { return(FALSE) } if (is.character(x)) { is.na(x) || (!grepl("\n", x) && nchar(x) < 100) - } else if (is.logical(x) || is.numeric(x)) { - TRUE } else { - FALSE + TRUE } } From 130a3737fc1141720c054455faa47a57169b9d6c Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 08:43:49 -0500 Subject: [PATCH 08/20] Tweak constant tests --- tests/testthat/_snaps/expect-constant.md | 30 +++++++----------------- tests/testthat/test-expect-constant.R | 21 +++++++---------- 2 files changed, 16 insertions(+), 35 deletions(-) diff --git a/tests/testthat/_snaps/expect-constant.md b/tests/testthat/_snaps/expect-constant.md index f36c4ce49..dd87eff5d 100644 --- a/tests/testthat/_snaps/expect-constant.md +++ b/tests/testthat/_snaps/expect-constant.md @@ -1,35 +1,21 @@ # logical tests act as expected - FALSE is not equal to TRUE. + `df` is not equal to TRUE. - `actual`: FALSE - `expected`: TRUE + `actual` is an S3 object of class , a list + `expected` is a logical vector (TRUE) --- - TRUE is not equal to FALSE. + `df` is not equal to FALSE. - `actual`: TRUE - `expected`: FALSE - -# can compare non-vectors - - quote(x) is not equal to TRUE. - - `actual` is a symbol - `expected` is a logical vector (TRUE) + `actual` is an S3 object of class , a list + `expected` is a logical vector (FALSE) # expect_null works - 1L is not equal to FALSE. - - `actual` is an integer vector (1) - `expected` is NULL - ---- - - environment() is not equal to FALSE. + `df` is not equal to FALSE. - `actual` is an environment + `actual` is an S3 object of class , a list `expected` is NULL diff --git a/tests/testthat/test-expect-constant.R b/tests/testthat/test-expect-constant.R index b26ea3c9d..a5cfd00e1 100644 --- a/tests/testthat/test-expect-constant.R +++ b/tests/testthat/test-expect-constant.R @@ -1,11 +1,11 @@ test_that("logical tests act as expected", { - local_output_override() + df <- data.frame(1:10) expect_success(expect_true(TRUE)) - expect_success(expect_false(FALSE)) + expect_snapshot_failure(expect_true(df)) - expect_snapshot_failure(expect_true(FALSE)) - expect_snapshot_failure(expect_false(TRUE)) + expect_success(expect_false(FALSE)) + expect_snapshot_failure(expect_false(df)) }) test_that("logical tests ignore attributes", { @@ -13,22 +13,17 @@ test_that("logical tests ignore attributes", { expect_success(expect_false(c(a = FALSE))) }) -test_that("can compare non-vectors", { - local_output_override() - expect_snapshot_failure(expect_true(quote(x))) -}) - test_that("additional info returned in message", { expect_failure(expect_true(FALSE, "NOPE"), "\nNOPE") expect_failure(expect_false(TRUE, "YUP"), "\nYUP") }) test_that("expect_null works", { - local_output_override() + x <- NULL + df <- data.frame(1:10) - expect_success(expect_null(NULL)) - expect_snapshot_failure(expect_null(1L)) - expect_snapshot_failure(expect_null(environment())) + expect_success(expect_null(x)) + expect_snapshot_failure(expect_null(df)) }) test_that("returns the input value", { From da93c3525eda5fe5de79c07f22c665dd82c184e3 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 08:58:38 -0500 Subject: [PATCH 09/20] Add test for failure message --- tests/testthat/_snaps/expect-shape.md | 4 ++++ tests/testthat/test-expect-shape.R | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/testthat/_snaps/expect-shape.md b/tests/testthat/_snaps/expect-shape.md index 95f5f7d66..732352fba 100644 --- a/tests/testthat/_snaps/expect-shape.md +++ b/tests/testthat/_snaps/expect-shape.md @@ -1,3 +1,7 @@ +# generates actionable failure message + + `x` has length 10, not length 2. + # expect_length validates its inputs Code diff --git a/tests/testthat/test-expect-shape.R b/tests/testthat/test-expect-shape.R index 4b1742879..3c21b61b5 100644 --- a/tests/testthat/test-expect-shape.R +++ b/tests/testthat/test-expect-shape.R @@ -1,10 +1,15 @@ test_that("length computed correctly", { expect_success(expect_length(1, 1)) - expect_failure(expect_length(1, 2), "has length 1, not length 2.") expect_success(expect_length(1:10, 10)) expect_success(expect_length(letters[1:5], 5)) }) +test_that("generates actionable failure message", { + x <- 1:10 + expect_snapshot_failure(expect_length(x, 2)) + expect_length(x, 15) +}) + test_that("uses S4 length method", { A <- setClass("ExpectLengthA", slots = c(x = "numeric", y = "numeric")) setMethod("length", "ExpectLengthA", function(x) 5L) From 788b3758b7b8c9cefb07b55148411693fd8043ff Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 10:18:11 -0500 Subject: [PATCH 10/20] Reframe to expected + actual --- CLAUDE.md | 18 ++-- R/expect-comparison.R | 54 ++++++----- R/expect-condition.R | 21 ++-- R/expect-equality.R | 18 +++- R/expect-inheritance.R | 102 ++++++++++++++------ R/expect-invisible.R | 10 +- R/expect-known.R | 6 +- R/expect-match.R | 2 +- R/expect-named.R | 2 +- R/expect-output.R | 8 +- R/expect-reference.R | 2 +- R/expect-self-test.R | 6 +- R/expect-shape.R | 40 +++++--- R/expect-silent.R | 6 +- R/quasi-label.R | 2 +- tests/testthat/_snaps/expect-comparison.md | 82 ++++++++++++++-- tests/testthat/_snaps/expect-condition.md | 67 +++++++++++-- tests/testthat/_snaps/expect-constant.md | 6 +- tests/testthat/_snaps/expect-equality.md | 101 ++++++++++++++++++- tests/testthat/_snaps/expect-inheritance.md | 52 ++++++++-- tests/testthat/_snaps/expect-invisible.md | 6 +- tests/testthat/_snaps/expect-match.md | 2 +- tests/testthat/_snaps/expect-named.md | 6 +- tests/testthat/_snaps/expect-output.md | 2 +- tests/testthat/_snaps/expect-self-test.md | 2 +- tests/testthat/_snaps/expect-shape.md | 36 ++++--- tests/testthat/_snaps/reporter-check.md | 8 +- tests/testthat/_snaps/reporter-junit.md | 4 +- tests/testthat/_snaps/reporter-progress.md | 56 +++++------ tests/testthat/_snaps/reporter-rstudio.md | 4 +- tests/testthat/_snaps/reporter-stop.md | 4 +- tests/testthat/_snaps/reporter-summary.md | 12 +-- tests/testthat/_snaps/reporter-tap.md | 4 +- tests/testthat/_snaps/reporter-teamcity.md | 4 +- tests/testthat/_snaps/try-again.md | 2 +- tests/testthat/test-expect-comparison.R | 24 ++--- tests/testthat/test-expect-condition.R | 20 ++-- tests/testthat/test-expect-constant.R | 4 +- tests/testthat/test-expect-equality.R | 26 ++--- tests/testthat/test-expect-inheritance.R | 18 ++-- tests/testthat/test-expect-invisible.R | 4 +- tests/testthat/test-expect-known.R | 26 +++-- tests/testthat/test-expect-match.R | 4 +- tests/testthat/test-expect-named.R | 4 +- tests/testthat/test-expect-no-condition.R | 4 +- tests/testthat/test-expect-output.R | 4 +- tests/testthat/test-expect-reference.R | 2 +- tests/testthat/test-expect-self-test.R | 22 ++--- tests/testthat/test-expect-setequal.R | 30 ++++-- tests/testthat/test-expect-silent.R | 6 +- tests/testthat/test-expect-vector.R | 2 +- tests/testthat/test-expectation.R | 4 +- tests/testthat/test-old-school.R | 2 +- tests/testthat/test-snapshot-file.R | 2 +- tests/testthat/test-snapshot-reporter.R | 8 +- tests/testthat/test-snapshot.R | 2 +- 56 files changed, 683 insertions(+), 292 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 0852e7cdd..86ffcdeba 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,18 +12,24 @@ General advice: * When running R from the console, always run it with `--quiet --vanilla` * Always run `air format .` after generating code -### Development tools +### Testing -- `devtools::test()` - Run all tests -- `devtools::test_file("tests/testthat/test-filename.R")` - Run tests in a specific file +- Use `devtools::test()` to run all tests +- Use `devtools::test_file("tests/testthat/test-filename.R")` to run tests in a specific file - DO NOT USE `devtools::test_active_file()` -- `devtools::load_all()` - Load package for development -- `devtools::check()` - Run R CMD check -- `devtools::install()` - Install package locally +- All testing functions automatically loads code; you don't have to. + +- You can accept + +- All new code should have an accompanying test. +- Tests for `R/{name}.R` go in `tests/testthat/test-{name}.R`. +- If there are existing tests, place new tests next to similar existing tests. ### Documentation - Always run `devtools::document()` after changing any roxygen2 docs. +- Every user facing function should be exported and have roxygen2 documentation. +- Whenever you add a new documentation file, make sure to also add it to `_pkgdown.yml`. Run `pkgdown::check_pkgdown()` to check that it was added correctly. ## Core Architecture diff --git a/R/expect-comparison.R b/R/expect-comparison.R index 46c6f9a41..afb1172fc 100644 --- a/R/expect-comparison.R +++ b/R/expect-comparison.R @@ -28,14 +28,7 @@ expect_compare_ <- function( operator <- match.arg(operator) op <- match.fun(operator) - msg <- c( - "<" = "not strictly less than", - "<=" = "not less than", - ">" = "not strictly greater than", - ">=" = "not greater than" - )[[operator]] - - negated_op <- switch(operator, "<" = ">=", "<=" = ">", ">" = "<=", ">=" = "<") + actual_op <- switch(operator, "<" = ">=", "<=" = ">", ">" = "<=", ">=" = "<") cmp <- op(act$val, exp$val) if (length(cmp) != 1 || !is.logical(cmp)) { @@ -45,22 +38,35 @@ expect_compare_ <- function( ) } if (!isTRUE(cmp)) { - digits <- max( - digits(act$val), - digits(exp$val), - min_digits(act$val, exp$val) - ) - msg <- sprintf( - "%s is %s %s.\n%s - %s = %s %s 0", - act$lab, - msg, - exp$lab, - num_exact(act$val, digits), - num_exact(exp$val, digits), - num_exact(act$val - exp$val, digits), - negated_op - ) - return(fail(msg, trace_env = trace_env)) + diff <- act$val - exp$val + msg1 <- sprintf("Expected %s %s %s.", act$lab, operator, exp$lab) + + if (is.nan(diff)) { + msg2 <- "Actual values are incomparable." + msg3 <- NULL + } else if (is.na(diff)) { + msg2 <- "Actual comparison is NA." + msg3 <- NULL + } else { + digits <- max( + digits(act$val), + digits(exp$val), + min_digits(act$val, exp$val) + ) + + msg2 <- sprintf( + "Actual %s %s %s", + num_exact(act$val, digits), + actual_op, + num_exact(exp$val, digits) + ) + msg3 <- sprintf( + "Difference %s %s 0", + num_exact(act$val - exp$val, digits), + actual_op + ) + } + return(fail(c(msg1, msg2, msg3), trace_env = trace_env)) } pass(act$val) } diff --git a/R/expect-condition.R b/R/expect-condition.R index 449692c32..d840809d2 100644 --- a/R/expect-condition.R +++ b/R/expect-condition.R @@ -440,10 +440,10 @@ compare_condition_3e <- function(cond_type, cond_class, cond, lab, expected) { if (expected) { if (is.null(cond)) { if (is.null(cond_class)) { - sprintf("%s did not throw the expected %s.", lab, cond_type) + sprintf("Expected %s to throw a %s.", lab, cond_type) } else { sprintf( - "%s did not throw a %s with class <%s>.", + "Expected %s to throw a %s with class <%s>.", lab, cond_type, cond_class @@ -455,11 +455,11 @@ compare_condition_3e <- function(cond_type, cond_class, cond, lab, expected) { } else { if (!is.null(cond)) { sprintf( - "%s threw an unexpected %s.\nMessage: %s\nClass: %s", + "Expected %s to not throw a %s.\nActual <%s>:\n%s", lab, cond_type, - cnd_message(cond), - paste(class(cond), collapse = "/") + paste(class(cond), collapse = "/"), + cnd_message(cond) ) } else { NULL @@ -493,7 +493,7 @@ compare_condition_2e <- function( # Otherwise we're definitely expecting a condition if (is.null(cond)) { - return(sprintf("%s did not throw an %s.", lab, cond_type)) + return(sprintf("Expected %s to throw a %s.", lab, cond_type)) } matches <- cnd_matches_2e(cond, class, regexp, inherit, ...) @@ -562,7 +562,12 @@ compare_messages <- function( # Expecting no messages if (identical(regexp, NA)) { if (length(messages) > 0) { - return(sprintf("%s generated %s:\n%s", lab, cond_type, bullets)) + return(sprintf( + "Expected %s to not generate %s.\nActually generated:\n%s", + lab, + cond_type, + bullets + )) } else { return() } @@ -570,7 +575,7 @@ compare_messages <- function( # Otherwise we're definitely expecting messages if (length(messages) == 0) { - return(sprintf("%s did not produce any %s.", lab, cond_type)) + return(sprintf("Expected %s to produce %s.", lab, cond_type)) } if (is.null(regexp)) { diff --git a/R/expect-equality.R b/R/expect-equality.R index 1094b2c8c..a3e1e2a44 100644 --- a/R/expect-equality.R +++ b/R/expect-equality.R @@ -77,7 +77,12 @@ expect_equal <- function( } if (!comp$equal) { - msg <- sprintf("%s not equal to %s.\n%s", act$lab, exp$lab, comp$message) + msg <- sprintf( + "Expected %s to equal %s.\nActual:\n%s", + act$lab, + exp$lab, + comp$message + ) return(fail(msg, info = info)) } pass(act$val) @@ -113,7 +118,12 @@ expect_identical <- function( } if (!ident) { - msg <- sprintf("%s not identical to %s.\n%s", act$lab, exp$lab, msg) + msg <- sprintf( + "Expected %s to be identical to %s.\n%s", + act$lab, + exp$lab, + msg + ) return(fail(msg, info = info)) } pass(act$val) @@ -138,7 +148,7 @@ expect_waldo_equal_ <- function( ) if (length(comp) != 0) { msg <- sprintf( - "%s is not %s to %s.\n\n%s", + "Expected %s to be %s to %s.\n\n%s", act$lab, type, exp$lab, @@ -193,7 +203,7 @@ expect_equivalent <- function( comp <- compare(act$val, exp$val, ..., check.attributes = FALSE) if (!comp$equal) { msg <- sprintf( - "%s not equivalent to %s.\n%s", + "Expected %s to be equivalent to %s.\n%s", act$lab, exp$lab, comp$message diff --git a/R/expect-inheritance.R b/R/expect-inheritance.R index 2eff09871..08b965ea7 100644 --- a/R/expect-inheritance.R +++ b/R/expect-inheritance.R @@ -71,10 +71,10 @@ expect_type <- function(object, type) { if (!identical(act_type, type)) { msg <- sprintf( - "%s has type %s, not %s.", + "Expected %s to have type %s.\nActual type: %s", act$lab, - format_class(act_type), - format_class(type) + format_class(type), + format_class(act_type) ) return(fail(msg)) } @@ -95,24 +95,31 @@ expect_s3_class <- function(object, class, exact = FALSE) { if (identical(class, NA)) { if (isS3(object)) { - msg <- sprintf("%s is an S3 object", act$lab) + msg <- sprintf("Expected %s to not be an S3 object.", act$lab) return(fail(msg)) } } else if (is.character(class)) { if (!isS3(act$val)) { - return(fail(sprintf("%s is not an S3 object", act$lab))) + msg <- c( + sprintf("Expected %s to be an S3 object.", act$lab), + sprintf("Actually is a %s object.", oo_type(act$val)) + ) + return(fail(msg)) } else if (exact) { if (!identical(class(act$val), class)) { - msg <- sprintf("%s has class %s, not %s.", act$lab, act$class, exp_lab) + msg <- sprintf( + "Expected %s to have class %s.\nActual class: %s", + act$lab, + exp_lab, + act$class + ) return(fail(msg)) } } else { if (!inherits(act$val, class)) { - msg <- sprintf( - "%s inherits from %s not %s.", - act$lab, - act$class, - exp_lab + msg <- c( + sprintf("Expected %s to inherit from %s.", act$lab, exp_lab), + sprintf("Actual class: %s", act$class) ) return(fail(msg)) } @@ -133,19 +140,21 @@ expect_s4_class <- function(object, class) { if (identical(class, NA)) { if (isS4(object)) { - msg <- sprintf("%s is an S4 object", act$lab) + msg <- sprintf("Expected %s to not be an S4 object.", act$lab) return(fail(msg)) } } else if (is.character(class)) { if (!isS4(act$val)) { - return(fail(sprintf("%s is not an S4 object", act$lab))) + msg <- c( + sprintf("Expected %s to be an S4 object.", act$lab), + sprintf("Actually is a %s object.", oo_type(act$val)) + ) + return(fail(msg)) } else { if (!methods::is(act$val, class)) { - msg <- sprintf( - "%s inherits from %s not %s.", - act$lab, - act$class, - exp_lab + msg <- c( + sprintf("Expected %s to inherit from %s.", act$lab, exp_lab), + sprintf("Actual class: %s", act$class) ) return(fail(msg)) } @@ -164,13 +173,20 @@ expect_r6_class <- function(object, class) { check_string(class) if (!inherits(act$val, "R6")) { - return(fail(sprintf("%s is not an R6 object.", act$lab))) + msg <- c( + sprintf("Expected %s to be an R6 object.", act$lab), + sprintf("Actually is a %s object.", oo_type(act$val)) + ) + return(fail(msg)) } if (!inherits(act$val, class)) { act_class <- format_class(class(act$val)) exp_class <- format_class(class) - msg <- sprintf("%s inherits from %s not %s.", act$lab, act_class, exp_class) + msg <- c( + sprintf("Expected %s to inherit from %s.", act$lab, exp_class), + sprintf("Actual class: %s", act_class) + ) return(fail(msg)) } @@ -188,17 +204,21 @@ expect_s7_class <- function(object, class) { act <- quasi_label(enquo(object)) if (!S7::S7_inherits(object)) { - return(fail(sprintf("%s is not an S7 object", act$lab))) + msg <- c( + sprintf("Expected %s to be an S7 object.", act$lab), + sprintf("Actually is a %s object.", oo_type(act$val)) + ) + return(fail(msg)) } if (!S7::S7_inherits(object, class)) { - obj_class <- setdiff(base::class(object), "S7_object") - class_desc <- paste0("<", obj_class, ">", collapse = "/") - msg <- sprintf( - "%s inherits from %s not <%s>.", - act$lab, - class_desc, - attr(class, "name", TRUE) + exp_class <- attr(class, "name", TRUE) + act_class <- setdiff(base::class(object), "S7_object") + act_class_desc <- paste0("<", act_class, ">", collapse = "/") + + msg <- c( + sprintf("Expected %s to inherit from <%s>.", act$lab, exp_class), + sprintf("Actual class: %s", act_class_desc) ) return(fail(msg)) } @@ -239,10 +259,10 @@ expect_is <- function(object, class, info = NULL, label = NULL) { if (!inherits(act$val, class)) { msg <- sprintf( - "%s inherits from `%s` not `%s`.", + "Expected %s to inherit from `%s`.\nActual inheritance: `%s`", act$lab, - act$class, - exp_lab + exp_lab, + act$class ) return(fail(msg, info = info)) } @@ -256,3 +276,23 @@ isS3 <- function(x) is.object(x) && !isS4(x) format_class <- function(x) { paste0(encodeString(x, quote = "'"), collapse = "/") } + +oo_type <- function(x) { + if (!is.object(x)) { + "base" + } else if (!isS4(x)) { + if (inherits(x, "R6")) { + "R6" + } else if (inherits(x, "S7")) { + "S7" + } else { + "S3" + } + } else { + if (!is(x, "refClass")) { + "S4" + } else { + "RC" + } + } +} diff --git a/R/expect-invisible.R b/R/expect-invisible.R index e69a89524..e7fd1f111 100644 --- a/R/expect-invisible.R +++ b/R/expect-invisible.R @@ -25,7 +25,10 @@ expect_invisible <- function(call, label = NULL) { vis <- withVisible(call) if (!identical(vis$visible, FALSE)) { - msg <- sprintf("%s returns visibly, not invisibly.", lab) + msg <- sprintf( + "Expected %s to return invisibly.\nActually returned visibly.", + lab + ) return(fail(msg)) } pass(vis$value) @@ -38,7 +41,10 @@ expect_visible <- function(call, label = NULL) { vis <- withVisible(call) if (!identical(vis$visible, TRUE)) { - msg <- sprintf("%s returns invisibly, not visibly.", lab) + msg <- sprintf( + "Expected %s to return visibly.\nActually returned invisibly.", + lab + ) return(fail(msg)) } pass(vis$value) diff --git a/R/expect-known.R b/R/expect-known.R index db4ea366f..98f32c866 100644 --- a/R/expect-known.R +++ b/R/expect-known.R @@ -235,7 +235,11 @@ expect_known_hash <- function(object, hash = NULL) { cli::cli_warn("No recorded hash: use {substr(act_hash, 1, 10)}.") } else { if (hash != act_hash) { - msg <- sprintf("Value hashes to %s, not %s", act_hash, hash) + msg <- sprintf( + "Expected value to hash to %s.\nActual hash: %s", + hash, + act_hash + ) return(fail(msg)) } } diff --git a/R/expect-match.R b/R/expect-match.R index d612f1cf9..945b74c9b 100644 --- a/R/expect-match.R +++ b/R/expect-match.R @@ -46,7 +46,7 @@ expect_match <- function( check_bool(all) if (length(object) == 0) { - return(fail(sprintf("%s is empty.", act$lab), info = info)) + return(fail(sprintf("Expected %s to not be empty.", act$lab), info = info)) } expect_match_( diff --git a/R/expect-named.R b/R/expect-named.R index 6f9e63f1b..69e334676 100644 --- a/R/expect-named.R +++ b/R/expect-named.R @@ -75,7 +75,7 @@ normalise_names <- function(x, ignore.order = FALSE, ignore.case = FALSE) { expect_has_names_ <- function(act, trace_env = caller_env()) { act_names <- names(act$val) if (identical(act_names, NULL)) { - msg <- sprintf("%s does not have names.", act$lab) + msg <- sprintf("Expected %s to have names.", act$lab) return(fail(msg, trace_env = trace_env)) } return(pass(act$val)) diff --git a/R/expect-output.R b/R/expect-output.R index 65c16e950..d5aaf0f68 100644 --- a/R/expect-output.R +++ b/R/expect-output.R @@ -36,13 +36,17 @@ expect_output <- function( if (identical(regexp, NA)) { if (!identical(act$cap, "")) { - msg <- sprintf("%s produced output.\n%s", act$lab, encodeString(act$cap)) + msg <- sprintf( + "Expected %s to produce no output.\nActual output:\n%s", + act$lab, + encodeString(act$cap) + ) return(fail(msg, info = info)) } pass(act$val) } else if (is.null(regexp) || identical(act$cap, "")) { if (identical(act$cap, "")) { - msg <- sprintf("%s produced no output", act$lab) + msg <- sprintf("Expected %s to produce output.", act$lab) return(fail(msg, info = info)) } pass(act$val) diff --git a/R/expect-reference.R b/R/expect-reference.R index e325085c4..6f23b3c7d 100644 --- a/R/expect-reference.R +++ b/R/expect-reference.R @@ -27,7 +27,7 @@ expect_reference <- function( exp <- quasi_label(enquo(expected), expected.label) if (!is_reference(act$val, exp$val)) { - msg <- sprintf("%s not a reference to %s.", act$lab, exp$lab) + msg <- sprintf("Expected %s to be a reference to %s.", act$lab, exp$lab) return(fail(msg, info = info)) } pass(act$val) diff --git a/R/expect-self-test.R b/R/expect-self-test.R index bddf26646..45c4eb77d 100644 --- a/R/expect-self-test.R +++ b/R/expect-self-test.R @@ -50,14 +50,14 @@ expect_success <- function(expr) { return(fail("Expectation did not succeed")) } else if (status$n_success > 1) { return(fail(sprintf( - "Expectation succeeded %i times, instead of once", + "Expected expectation to succeed once.\nActually succeeded: %i times", status$n_success ))) } if (status$n_failure > 0) { return(fail(sprintf( - "Expectation failed %i times, instead of zero", + "Expected expectation to not fail.\nActually failed: %i times", status$n_failure ))) } @@ -79,7 +79,7 @@ expect_failure <- function(expr, message = NULL, ...) { if (status$n_success != 0) { return(fail(sprintf( - "Expectation succeeded %i times, instead of never", + "Expected expectation to never succeed.\nActually succeeded: %i times", status$n_success ))) } diff --git a/R/expect-shape.R b/R/expect-shape.R index 964230fd5..fd90246ed 100644 --- a/R/expect-shape.R +++ b/R/expect-shape.R @@ -28,7 +28,12 @@ expect_length <- function(object, n) { act$n <- length(act$val) if (act$n != n) { - msg <- sprintf("%s has length %i, not length %i.", act$lab, act$n, n) + msg <- sprintf( + "Expected %s to have length %i.\nActual length: %i", + act$lab, + n, + act$n + ) return(fail(msg)) } pass(act$val) @@ -46,7 +51,7 @@ expect_shape = function(object, ..., nrow, ncol, dim) { dim_object <- base::dim(object) if (is.null(dim_object)) { - return(fail(sprintf("%s has no dimensions.", act$lab))) + return(fail(sprintf("Expected %s to have dimensions.", act$lab))) } if (!missing(nrow)) { @@ -54,20 +59,33 @@ expect_shape = function(object, ..., nrow, ncol, dim) { act$nrow <- dim_object[1L] if (!identical(as.integer(act$nrow), as.integer(nrow))) { - msg <- sprintf("%s has %i rows, not %i.", act$lab, act$nrow, nrow) + msg <- sprintf( + "Expected %s to have %i rows.\nActual rows: %i", + act$lab, + nrow, + act$nrow + ) return(fail(msg)) } } else if (!missing(ncol)) { check_number_whole(ncol, allow_na = TRUE) if (length(dim_object) == 1L) { - return(fail(sprintf("%s has only one dimension.", act$lab))) + return(fail(sprintf( + "Expected %s to have more than one dimension.", + act$lab + ))) } act$ncol <- dim_object[2L] if (!identical(as.integer(act$ncol), as.integer(ncol))) { - msg <- sprintf("%s has %i columns, not %i.", act$lab, act$ncol, ncol) + msg <- sprintf( + "Expected %s to have %i columns.\nActual columns: %i", + act$lab, + ncol, + act$ncol + ) return(fail(msg)) } } else { @@ -79,19 +97,19 @@ expect_shape = function(object, ..., nrow, ncol, dim) { if (length(act$dim) != length(dim)) { return(fail(sprintf( - "%s has %i dimensions, not %i.", + "Expected %s to have %i dimensions.\nActual dimensions: %i", act$lab, - length(act$dim), - length(dim) + length(dim), + length(act$dim) ))) } if (!identical(as.integer(act$dim), as.integer(dim))) { msg <- sprintf( - "%s has dim (%s), not (%s).", + "Expected %s to have dim (%s).\nActual dim: (%s)", act$lab, - toString(act$dim), - toString(dim) + toString(dim), + toString(act$dim) ) return(fail(msg)) } diff --git a/R/expect-silent.R b/R/expect-silent.R index 0d409cf96..f94c6df3f 100644 --- a/R/expect-silent.R +++ b/R/expect-silent.R @@ -27,7 +27,11 @@ expect_silent <- function(object) { ) if (length(outputs) != 0) { - msg <- sprintf("%s produced %s.", act$lab, paste(outputs, collapse = ", ")) + msg <- sprintf( + "Expected %s to run silently.\nActually produced: %s", + act$lab, + paste(outputs, collapse = ", ") + ) return(fail(msg)) } pass(act$cap$result) diff --git a/R/quasi-label.R b/R/quasi-label.R index ba9d2bc07..3e519715a 100644 --- a/R/quasi-label.R +++ b/R/quasi-label.R @@ -93,7 +93,7 @@ can_inline <- function(x) { if (!is_syntactic_literal(x)) { return(FALSE) } - if (!is.null(dim(x))) { + if (!is.null(dim(x)) || !is.null(attributes(x))) { return(FALSE) } diff --git a/tests/testthat/_snaps/expect-comparison.md b/tests/testthat/_snaps/expect-comparison.md index 13457c6df..9d6bf536e 100644 --- a/tests/testthat/_snaps/expect-comparison.md +++ b/tests/testthat/_snaps/expect-comparison.md @@ -1,22 +1,88 @@ +# basic comparisons work + + Expected 10 < 10. + Actual 10.0 >= 10.0 + Difference 0.0 >= 0 + +--- + + Expected 10 > 10. + Actual 10.0 <= 10.0 + Difference 0.0 <= 0 + # useful output when numbers are very small - 1.1 * x (1.1e-05) is not less than `x` (1e-05). - 0.0000110 - 0.0000100 = 0.0000010 > 0 + Expected 1.1 * x (1.1e-05) <= `x` (1e-05). + Actual 0.0000110 > 0.0000100 + Difference 0.0000010 > 0 --- - `x` (1e-05) is not strictly greater than 1.1 * x (1.1e-05). - 0.0000100 - 0.0000110 = -0.0000010 <= 0 + Expected `x` (1e-05) > 1.1 * x (1.1e-05). + Actual 0.0000100 <= 0.0000110 + Difference -0.0000010 <= 0 # useful output when difference is zero - `x` (100) is not strictly less than 100. - 100.0 - 100.0 = 0.0 >= 0 + Expected `x` (100) < 100. + Actual 100.0 >= 100.0 + Difference 0.0 >= 0 # useful output when differnce is large - `x` (100) is not strictly less than 0.001. - 100.000 - 0.001 = 99.999 >= 0 + Expected `x` (100) < 0.001. + Actual 100.000 >= 0.001 + Difference 99.999 >= 0 + +# comparisons with Inf work + + Expected Inf < Inf. + Actual values are incomparable. + +--- + + Expected Inf > Inf. + Actual values are incomparable. + +# comparisons with NA work + + Expected 10 < NA_real_. + Actual comparison is NA. + +--- + + Expected NA_real_ < 10. + Actual comparison is NA. + +--- + + Expected NA_real_ < NA_real_. + Actual comparison is NA. + +--- + + Expected NA_real_ <= NA_real_. + Actual comparison is NA. + +--- + + Expected 10 > NA_real_. + Actual comparison is NA. + +--- + + Expected NA_real_ > 10. + Actual comparison is NA. + +--- + + Expected NA_real_ > NA_real_. + Actual comparison is NA. + +--- + + Expected NA_real_ >= NA_real_. + Actual comparison is NA. # comparison must yield a single logical diff --git a/tests/testthat/_snaps/expect-condition.md b/tests/testthat/_snaps/expect-condition.md index ae4a570f0..654070de7 100644 --- a/tests/testthat/_snaps/expect-condition.md +++ b/tests/testthat/_snaps/expect-condition.md @@ -1,10 +1,16 @@ # regexp = NULL checks for presence of error - `{ ... }` did not throw the expected error. + Expected `f()` to throw a error. + +# regexp = NA checks for absence of error + + Expected `stop("Yes")` to not throw a error. + Actual : + Yes # regexp = string matches for error message - "OK" did not throw the expected error. + Expected "OK" to throw a error. # expect_error validates its inputs @@ -26,9 +32,9 @@ # message method is called when expecting error - `fb()` threw an unexpected error. - Message: dispatched! - Class: foobar/rlang_error/error/condition + Expected `fb()` to not throw a error. + Actual : + dispatched! # expect_warning validates its inputs @@ -53,6 +59,13 @@ Error in `expect_warning()`: ! `all` must be `TRUE` or `FALSE`, not the string "yes". +# regexp = NA checks for absence of message + + Expected `message("!")` to not throw a message. + Actual : + ! + + # expect_message validates its inputs Code @@ -78,7 +91,7 @@ # condition class is included in failure - `f1()` did not throw a condition with class . + Expected `f1()` to throw a condition with class . # expect_condition validates its inputs @@ -136,3 +149,45 @@ * Unused arguments: `pattern` and `fixed`. i Did you mean to use `regexp` so `...` is passed to `grepl()`? +# other conditions are swallowed + + `f("error")` threw an error with unexpected message. + Expected match: "not a match" + Actual message: "error" + +--- + + `f("warning")` produced unexpected warnings. + Expected match: not a match + Actual values: + * warning + +--- + + `f("message")` produced unexpected messages. + Expected match: not a match + Actual values: + * message + + +--- + + `f("condition")` threw an condition with unexpected message. + Expected match: "not a match" + Actual message: "signal" + +--- + + `f("error")` threw an error with unexpected class. + Expected class: not a match + Actual class: simpleError/error/condition + Message: error + +--- + + `f("message")` threw an condition with unexpected class. + Expected class: not a match + Actual class: simpleMessage/message/condition + Message: message + + diff --git a/tests/testthat/_snaps/expect-constant.md b/tests/testthat/_snaps/expect-constant.md index dd87eff5d..3dccf45ff 100644 --- a/tests/testthat/_snaps/expect-constant.md +++ b/tests/testthat/_snaps/expect-constant.md @@ -1,20 +1,20 @@ # logical tests act as expected - `df` is not equal to TRUE. + Expected `df` to be equal to TRUE. `actual` is an S3 object of class , a list `expected` is a logical vector (TRUE) --- - `df` is not equal to FALSE. + Expected `df` to be equal to FALSE. `actual` is an S3 object of class , a list `expected` is a logical vector (FALSE) # expect_null works - `df` is not equal to FALSE. + Expected `df` to be equal to FALSE. `actual` is an S3 object of class , a list `expected` is NULL diff --git a/tests/testthat/_snaps/expect-equality.md b/tests/testthat/_snaps/expect-equality.md index 849fb6977..64e2d4846 100644 --- a/tests/testthat/_snaps/expect-equality.md +++ b/tests/testthat/_snaps/expect-equality.md @@ -1,27 +1,120 @@ +# basical principles of equality hold + + Expected 1 to equal 2. + Actual: + 1/1 mismatches + [1] 1 - 2 == -1 + +--- + + Expected 1 to be identical to 2. + 1/1 mismatches + [1] 1 - 2 == -1 + +--- + + Expected 1 to be equal to 2. + + `actual`: 1.0 + `expected`: 2.0 + +--- + + Expected 1 to be identical to 2. + + `actual`: 1.0 + `expected`: 2.0 + +# expect_equal() ignores numeric type; expect_identical() does not + + Expected 1 to be identical to 1L. + Objects equal but not identical + +--- + + Expected 1 to be identical to 1L. + + `actual` is a double vector (1) + `expected` is an integer vector (1) + +# can control numeric tolerance + + Expected `x1` (1) to equal `x2` (1.000001). + Actual: + 1/1 mismatches + [1] 1 - 1 == -1e-06 + +--- + + Expected `x1` (1) to be equal to `x2` (1.000001). + + `actual`: 1.0000000 + `expected`: 1.0000010 + # provide useful feedback on failure - `x` (1) is not identical to "a". + Expected `x` (1) to be identical to "a". `actual` is a double vector (1) `expected` is a character vector ('a') --- - `x` (1) is not equal to "a". + Expected `x` (1) to be equal to "a". `actual` is a double vector (1) `expected` is a character vector ('a') --- - `x` (1) not identical to "a". + Expected `x` (1) to be identical to "a". Types not compatible: double is not character --- - `x` (1) not equal to "a". + Expected `x` (1) to equal "a". + Actual: Types not compatible: double is not character +# default labels use unquoting + + Expected 1 to equal 2. + Actual: + 1/1 mismatches + [1] 1 - 2 == -1 + +# % is not treated as sprintf format specifier (#445) + + Expected "+" to be equal to "%". + + `actual`: "+" + `expected`: "%" + +--- + + Expected "%" to be equal to "+". + + `actual`: "%" + `expected`: "+" + +# useful message if objects equal but not identical + + Expected `f` to be identical to `g`. + Names: 1 string mismatch + Length mismatch: comparison on first 1 components + Component 1: Modes of target, current: function, numeric + Component 1: target, current do not match when deparsed + Component 1: 'current' is not an environment + +# attributes for object (#452) + + Expected `oops` (structure(0, oops = "oops")) to equal 0. + Actual: + Attributes: < Modes: list, NULL > + Attributes: < Lengths: 1, 0 > + Attributes: < names for target but not for current > + Attributes: < current is not list-like > + # expect_equal validates its inputs Code diff --git a/tests/testthat/_snaps/expect-inheritance.md b/tests/testthat/_snaps/expect-inheritance.md index 3708ecfbb..9de5b7f8e 100644 --- a/tests/testthat/_snaps/expect-inheritance.md +++ b/tests/testthat/_snaps/expect-inheritance.md @@ -1,3 +1,8 @@ +# expect_type checks typeof + + Expected `x` to have type 'double'. + Actual type: 'integer' + # expect_type validates its inputs Code @@ -6,17 +11,38 @@ Error in `expect_type()`: ! `type` must be a single string, not a character vector. +# expect_is checks class + + Expected factor("a") to inherit from `'character'`. + Actual inheritance: `'factor'` + +# expect_s3/s4_class fails if appropriate type + + Expected `x1` (1) to be an S3 object. + Actually is a base object. + +--- + + Expected `x2` to be an S3 object. + Actually is a S4 object. + +--- + + Expected `x3` to be an S4 object. + Actually is a S3 object. + # expect_s[34]_class can check not S3/S4 - factor() is an S3 object + Expected factor() to not be an S3 object. --- - A() is an S4 object + Expected A() to not be an S4 object. # test_s4_class respects class hierarchy - C() inherits from 'C'/'A'/'B'/'list'/'vector' not 'D'. + Expected C() to inherit from 'D'. + Actual class: 'C'/'A'/'B'/'list'/'vector' # expect_s3_class validates its inputs @@ -33,11 +59,18 @@ # test_s3_class respects class hierarchy - `x` inherits from 'a'/'b' not 'c'. + Expected `x` to inherit from 'c'. + Actual class: 'a'/'b' --- - `x` inherits from 'a'/'b' not 'c'/'d'. + Expected `x` to inherit from 'c'/'d'. + Actual class: 'a'/'b' + +# test_s3_class can request exact match + + Expected `x` to have class 'a'. + Actual class: 'a'/'b' # expect_s4_class validates its inputs @@ -49,7 +82,8 @@ # expect_r6_class generates useful failures - `x` (1) is not an R6 object. + Expected `x` (1) to be an R6 object. + Actually is a base object. # expect_r6_class validates its inputs @@ -61,11 +95,13 @@ # can check with actual class - Foo() inherits from not . + Expected Foo() to inherit from . + Actual class: --- - Baz() inherits from / not . + Expected Baz() to inherit from . + Actual class: / # expect_s7_class validates its inputs diff --git a/tests/testthat/_snaps/expect-invisible.md b/tests/testthat/_snaps/expect-invisible.md index bdd7b69fc..765d28632 100644 --- a/tests/testthat/_snaps/expect-invisible.md +++ b/tests/testthat/_snaps/expect-invisible.md @@ -1,8 +1,10 @@ # generates useful failure messages - invisible(1) returns invisibly, not visibly. + Expected invisible(1) to return visibly. + Actually returned invisibly. --- - 1 returns visibly, not invisibly. + Expected 1 to return invisibly. + Actually returned visibly. diff --git a/tests/testthat/_snaps/expect-match.md b/tests/testthat/_snaps/expect-match.md index 5f762a381..054641e5b 100644 --- a/tests/testthat/_snaps/expect-match.md +++ b/tests/testthat/_snaps/expect-match.md @@ -1,6 +1,6 @@ # generates useful failure messages - `zero` is empty. + Expected `zero` to not be empty. --- diff --git a/tests/testthat/_snaps/expect-named.md b/tests/testthat/_snaps/expect-named.md index d9d14b6d0..5acd1b3a4 100644 --- a/tests/testthat/_snaps/expect-named.md +++ b/tests/testthat/_snaps/expect-named.md @@ -19,21 +19,21 @@ --- - Names of c(a = 1) (c(a = 1)) is not equal to c("a", "b"). + Names of Expected c(a = 1) (c(a = 1)) to be equal to c("a", "b"). `actual`: "a" `expected`: "a" "b" --- - Names of c(a = 1, b = 1) is not equal to c("a") ("a"). + Names of Expected c(a = 1, b = 1) to be equal to c("a") ("a"). `actual`: "a" "b" `expected`: "a" --- - Names of c(a = 1) (c(a = 1)) is not equal to c("b") ("b"). + Names of Expected c(a = 1) (c(a = 1)) to be equal to c("b") ("b"). `actual`: "a" `expected`: "b" diff --git a/tests/testthat/_snaps/expect-output.md b/tests/testthat/_snaps/expect-output.md index 71af3d211..a98584399 100644 --- a/tests/testthat/_snaps/expect-output.md +++ b/tests/testthat/_snaps/expect-output.md @@ -5,7 +5,7 @@ --- - "a" produced no output + Expected "a" to produce output. # expect_output validates its inputs diff --git a/tests/testthat/_snaps/expect-self-test.md b/tests/testthat/_snaps/expect-self-test.md index 93c8b3249..95d318aa8 100644 --- a/tests/testthat/_snaps/expect-self-test.md +++ b/tests/testthat/_snaps/expect-self-test.md @@ -17,7 +17,7 @@ show_failure(expect_true(FALSE)) Output Failed expectation: - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/expect-shape.md b/tests/testthat/_snaps/expect-shape.md index 732352fba..5b3fb542a 100644 --- a/tests/testthat/_snaps/expect-shape.md +++ b/tests/testthat/_snaps/expect-shape.md @@ -1,6 +1,7 @@ # generates actionable failure message - `x` has length 10, not length 2. + Expected `x` to have length 2. + Actual length: 10 # expect_length validates its inputs @@ -12,51 +13,60 @@ # dim compared correctly - matrix(nrow = 6, ncol = 3) has dim (6, 3), not (6, 2). + Expected matrix(nrow = 6, ncol = 3) to have dim (6, 2). + Actual dim: (6, 3) --- - matrix(nrow = 6, ncol = 3) has dim (6, 3), not (7, 3). + Expected matrix(nrow = 6, ncol = 3) to have dim (7, 3). + Actual dim: (6, 3) --- - array(dim = 1:3) has 3 dimensions, not 2. + Expected array(dim = 1:3) to have 2 dimensions. + Actual dimensions: 3 --- - array(dim = 1:3) has 3 dimensions, not 4. + Expected array(dim = 1:3) to have 4 dimensions. + Actual dimensions: 3 # nrow compared correctly - matrix(nrow = 5, ncol = 5) has 5 rows, not 6. + Expected matrix(nrow = 5, ncol = 5) to have 6 rows. + Actual rows: 5 --- - 1 has no dimensions. + Expected 1 to have dimensions. # ncol compared correctly - matrix(nrow = 5, ncol = 5) has 5 columns, not 7. + Expected matrix(nrow = 5, ncol = 5) to have 7 columns. + Actual columns: 5 --- - array(1) has only one dimension. + Expected array(1) to have more than one dimension. --- - array(integer()) has only one dimension. + Expected array(integer()) to have more than one dimension. # NA handling (e.g. dbplyr) - `x` has NA rows, not 10. + Expected `x` to have 10 rows. + Actual rows: NA --- - `x` has 10 columns, not NA. + Expected `x` to have NA columns. + Actual columns: 10 --- - `x` has dim (NA, 10), not (10, NA). + Expected `x` to have dim (10, NA). + Actual dim: (NA, 10) # checks inputs arguments, diff --git a/tests/testthat/_snaps/reporter-check.md b/tests/testthat/_snaps/reporter-check.md index 3e77908d7..4c665b494 100644 --- a/tests/testthat/_snaps/reporter-check.md +++ b/tests/testthat/_snaps/reporter-check.md @@ -15,12 +15,12 @@ == Failed tests ================================================================ -- Failure ('reporters/tests.R:12:3'): Failure:1 ------------------------------- - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE -- Failure ('reporters/tests.R:16:8'): Failure:2a ------------------------------ - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE @@ -71,12 +71,12 @@ == Failed tests ================================================================ -- Failure ('reporters/tests.R:12:3'): Failure:1 ------------------------------- - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE -- Failure ('reporters/tests.R:16:8'): Failure:2a ------------------------------ - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/reporter-junit.md b/tests/testthat/_snaps/reporter-junit.md index ab306b8c6..d7d151251 100644 --- a/tests/testthat/_snaps/reporter-junit.md +++ b/tests/testthat/_snaps/reporter-junit.md @@ -7,13 +7,13 @@ - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/reporter-progress.md b/tests/testthat/_snaps/reporter-progress.md index 7b11c84c2..3514f28c8 100644 --- a/tests/testthat/_snaps/reporter-progress.md +++ b/tests/testthat/_snaps/reporter-progress.md @@ -66,67 +66,67 @@ x | 11 0 | reporters/fail-many -------------------------------------------------------------------------------- Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE @@ -283,7 +283,7 @@ 26. \-f(x - 1) Failure ('reporters/backtraces.R:62:6'): (code run outside of `test_that()`) - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE @@ -295,7 +295,7 @@ 4. \-testthat::expect_true(FALSE) Failure ('reporters/backtraces.R:67:3'): nested expectations get backtraces - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE @@ -403,7 +403,7 @@ 26. \-f(x - 1) Failure ('reporters/backtraces.R:62:6'): (code run outside of `test_that()`) - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE @@ -415,7 +415,7 @@ 4. \-testthat::expect_true(FALSE) Failure ('reporters/backtraces.R:67:3'): nested expectations get backtraces - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE @@ -461,13 +461,13 @@ [ FAIL 2 | WARN 0 | SKIP 0 | PASS 1 ] -- Failure ('reporters/tests.R:12:3'): Failure:1 ------------------------------- - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE -- Failure ('reporters/tests.R:16:8'): Failure:2a ------------------------------ - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE @@ -559,67 +559,67 @@ x | 11 0 | reporters/fail-many -------------------------------------------------------------------------------- Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/reporter-rstudio.md b/tests/testthat/_snaps/reporter-rstudio.md index 09a1440e3..cca38ad56 100644 --- a/tests/testthat/_snaps/reporter-rstudio.md +++ b/tests/testthat/_snaps/reporter-rstudio.md @@ -1,7 +1,7 @@ # reporter basics works - 'reporters/tests.R:12:3' [failure] Failure:1. FALSE is not equal to TRUE. - 'reporters/tests.R:16:8' [failure] Failure:2a. FALSE is not equal to TRUE. + 'reporters/tests.R:12:3' [failure] Failure:1. Expected FALSE to be equal to TRUE. + 'reporters/tests.R:16:8' [failure] Failure:2a. Expected FALSE to be equal to TRUE. 'reporters/tests.R:23:3' [error] Error:1. Error in `eval(code, test_env)`: stop 'reporters/tests.R:29:8' [error] errors get tracebacks. Error in `h()`: ! 'reporters/tests.R:37:3' [skip] explicit skips are reported. Reason: skip diff --git a/tests/testthat/_snaps/reporter-stop.md b/tests/testthat/_snaps/reporter-stop.md index d572608f2..f814c9d6c 100644 --- a/tests/testthat/_snaps/reporter-stop.md +++ b/tests/testthat/_snaps/reporter-stop.md @@ -1,13 +1,13 @@ # produces useful output -- Failure ('reporters/tests.R:12:3'): Failure:1 ------------------------------- - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE -- Failure ('reporters/tests.R:16:8'): Failure:2a ------------------------------ - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/reporter-summary.md b/tests/testthat/_snaps/reporter-summary.md index d4234adf4..888a8c107 100644 --- a/tests/testthat/_snaps/reporter-summary.md +++ b/tests/testthat/_snaps/reporter-summary.md @@ -19,13 +19,13 @@ == Failed ====================================================================== -- 1. Failure ('reporters/tests.R:12:3'): Failure:1 ---------------------------- - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE -- 2. Failure ('reporters/tests.R:16:8'): Failure:2a --------------------------- - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE @@ -68,13 +68,13 @@ == Failed ====================================================================== -- 1. Failure ('reporters/tests.R:12:3'): Failure:1 ---------------------------- - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE -- 2. Failure ('reporters/tests.R:16:8'): Failure:2a --------------------------- - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE @@ -117,13 +117,13 @@ == Failed ====================================================================== -- 1. Failure ('reporters/tests.R:12:3'): Failure:1 ---------------------------- - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE -- 2. Failure ('reporters/tests.R:16:8'): Failure:2a --------------------------- - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/reporter-tap.md b/tests/testthat/_snaps/reporter-tap.md index 1eaa4a848..b4642dbaf 100644 --- a/tests/testthat/_snaps/reporter-tap.md +++ b/tests/testthat/_snaps/reporter-tap.md @@ -5,12 +5,12 @@ ok 1 Success # Context Failures not ok 2 Failure:1 - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE not ok 3 Failure:2a - FALSE is not equal to TRUE. + Expected FALSE to be equal to TRUE. `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/reporter-teamcity.md b/tests/testthat/_snaps/reporter-teamcity.md index f7239bf64..fc65f4e96 100644 --- a/tests/testthat/_snaps/reporter-teamcity.md +++ b/tests/testthat/_snaps/reporter-teamcity.md @@ -12,13 +12,13 @@ ##teamcity[testSuiteStarted name='Failures'] ##teamcity[testSuiteStarted name='Failure:1'] ##teamcity[testStarted name='expectation 1'] - ##teamcity[testFailed name='expectation 1' message='FALSE is not equal to TRUE.' details='|n`actual`: FALSE|n`expected`: TRUE '] + ##teamcity[testFailed name='expectation 1' message='Expected FALSE to be equal to TRUE.' details='|n`actual`: FALSE|n`expected`: TRUE '] ##teamcity[testFinished name='expectation 1'] ##teamcity[testSuiteFinished name='Failure:1'] ##teamcity[testSuiteStarted name='Failure:2a'] ##teamcity[testStarted name='expectation 1'] - ##teamcity[testFailed name='expectation 1' message='FALSE is not equal to TRUE.' details='|n`actual`: FALSE|n`expected`: TRUE |nBacktrace:|n x|n 1. \-f()|n 2. \-testthat::expect_true(FALSE)'] + ##teamcity[testFailed name='expectation 1' message='Expected FALSE to be equal to TRUE.' details='|n`actual`: FALSE|n`expected`: TRUE |nBacktrace:|n x|n 1. \-f()|n 2. \-testthat::expect_true(FALSE)'] ##teamcity[testFinished name='expectation 1'] ##teamcity[testSuiteFinished name='Failure:2a'] diff --git a/tests/testthat/_snaps/try-again.md b/tests/testthat/_snaps/try-again.md index fce32583c..569a6749b 100644 --- a/tests/testthat/_snaps/try-again.md +++ b/tests/testthat/_snaps/try-again.md @@ -14,7 +14,7 @@ i Expectation failed; trying again (1)... Condition Error: - ! `i` (1) is not equal to 0. + ! Expected `i` (1) to be equal to 0. `actual`: 1.0 `expected`: 0.0 diff --git a/tests/testthat/test-expect-comparison.R b/tests/testthat/test-expect-comparison.R index b1ea3e279..05868c486 100644 --- a/tests/testthat/test-expect-comparison.R +++ b/tests/testthat/test-expect-comparison.R @@ -1,10 +1,10 @@ test_that("basic comparisons work", { expect_success(expect_lt(10, 11)) - expect_failure(expect_lt(10, 10)) + expect_snapshot_failure(expect_lt(10, 10)) expect_success(expect_lte(10, 10)) expect_success(expect_gt(11, 10)) - expect_failure(expect_gt(10, 10)) + expect_snapshot_failure(expect_gt(10, 10)) expect_success(expect_gte(10, 10)) }) @@ -31,24 +31,24 @@ test_that("comparison result object invisibly", { test_that("comparisons with Inf work", { expect_success(expect_lt(10, Inf)) - expect_failure(expect_lt(Inf, Inf)) + expect_snapshot_failure(expect_lt(Inf, Inf)) expect_success(expect_lte(Inf, Inf)) expect_success(expect_gt(Inf, 10)) - expect_failure(expect_gt(Inf, Inf)) + expect_snapshot_failure(expect_gt(Inf, Inf)) expect_success(expect_gte(Inf, Inf)) }) test_that("comparisons with NA work", { - expect_failure(expect_lt(10, NA_real_)) - expect_failure(expect_lt(NA_real_, 10)) - expect_failure(expect_lt(NA_real_, NA_real_)) - expect_failure(expect_lte(NA_real_, NA_real_)) + expect_snapshot_failure(expect_lt(10, NA_real_)) + expect_snapshot_failure(expect_lt(NA_real_, 10)) + expect_snapshot_failure(expect_lt(NA_real_, NA_real_)) + expect_snapshot_failure(expect_lte(NA_real_, NA_real_)) - expect_failure(expect_gt(10, NA_real_)) - expect_failure(expect_gt(NA_real_, 10)) - expect_failure(expect_gt(NA_real_, NA_real_)) - expect_failure(expect_gte(NA_real_, NA_real_)) + expect_snapshot_failure(expect_gt(10, NA_real_)) + expect_snapshot_failure(expect_gt(NA_real_, 10)) + expect_snapshot_failure(expect_gt(NA_real_, NA_real_)) + expect_snapshot_failure(expect_gte(NA_real_, NA_real_)) }) test_that("comparisons with more complicated objects work", { diff --git a/tests/testthat/test-expect-condition.R b/tests/testthat/test-expect-condition.R index aefa2b8b3..c397aa7d5 100644 --- a/tests/testthat/test-expect-condition.R +++ b/tests/testthat/test-expect-condition.R @@ -5,12 +5,14 @@ test_that("returns condition or value", { test_that("regexp = NULL checks for presence of error", { expect_success(expect_error(stop())) - expect_snapshot_failure(expect_error({})) + + f <- function() {} + expect_snapshot_failure(expect_error(f())) }) test_that("regexp = NA checks for absence of error", { expect_success(expect_error({}, NA)) - expect_failure(expect_error(stop("Yes"), NA)) + expect_snapshot_failure(expect_error(stop("Yes"), NA)) }) test_that("regexp = string matches for error message", { @@ -147,7 +149,7 @@ test_that("expect_warning validates its inputs", { test_that("regexp = NA checks for absence of message", { expect_success(expect_message({}, NA)) - expect_failure(expect_message(message("!"), NA)) + expect_snapshot_failure(expect_message(message("!"), NA)) }) test_that("expect_message validates its inputs", { @@ -306,14 +308,14 @@ test_that("other conditions are swallowed", { local_edition(2) # if condition text doesn't match, expectation fails (not errors) - expect_failure(expect_error(f("error"), "not a match")) - expect_failure(expect_warning(f("warning"), "not a match")) - expect_failure(expect_message(f("message"), "not a match")) - expect_failure(expect_condition(f("condition"), "not a match")) + expect_snapshot_failure(expect_error(f("error"), "not a match")) + expect_snapshot_failure(expect_warning(f("warning"), "not a match")) + expect_snapshot_failure(expect_message(f("message"), "not a match")) + expect_snapshot_failure(expect_condition(f("condition"), "not a match")) # if error/condition class doesn't match, expectation fails - expect_failure(expect_error(f("error"), class = "not a match")) - expect_failure(expect_condition(f("message"), class = "not a match")) + expect_snapshot_failure(expect_error(f("error"), class = "not a match")) + expect_snapshot_failure(expect_condition(f("message"), class = "not a match")) # expect_message() and expect_warning() swallow all messages/warnings expect_message(expect_message(f("message", "message")), NA) diff --git a/tests/testthat/test-expect-constant.R b/tests/testthat/test-expect-constant.R index a5cfd00e1..e8f657b95 100644 --- a/tests/testthat/test-expect-constant.R +++ b/tests/testthat/test-expect-constant.R @@ -14,8 +14,8 @@ test_that("logical tests ignore attributes", { }) test_that("additional info returned in message", { - expect_failure(expect_true(FALSE, "NOPE"), "\nNOPE") - expect_failure(expect_false(TRUE, "YUP"), "\nYUP") + expect_snapshot_failure(expect_true(FALSE, "NOPE")) + expect_snapshot_failure(expect_false(TRUE, "YUP")) }) test_that("expect_null works", { diff --git a/tests/testthat/test-expect-equality.R b/tests/testthat/test-expect-equality.R index a8f33665c..6da455e35 100644 --- a/tests/testthat/test-expect-equality.R +++ b/tests/testthat/test-expect-equality.R @@ -1,25 +1,25 @@ test_that("basical principles of equality hold", { local_edition(2) expect_success(expect_equal(1, 1)) - expect_failure(expect_equal(1, 2)) + expect_snapshot_failure(expect_equal(1, 2)) expect_success(expect_identical(1, 1)) - expect_failure(expect_identical(1, 2)) + expect_snapshot_failure(expect_identical(1, 2)) local_edition(3) expect_success(expect_equal(1, 1)) - expect_failure(expect_equal(1, 2)) + expect_snapshot_failure(expect_equal(1, 2)) expect_success(expect_identical(1, 1)) - expect_failure(expect_identical(1, 2)) + expect_snapshot_failure(expect_identical(1, 2)) }) test_that("expect_equal() ignores numeric type; expect_identical() does not", { local_edition(2) expect_success(expect_equal(1, 1L)) - expect_failure(expect_identical(1, 1L)) + expect_snapshot_failure(expect_identical(1, 1L)) local_edition(3) expect_success(expect_equal(1, 1L)) - expect_failure(expect_identical(1, 1L)) + expect_snapshot_failure(expect_identical(1, 1L)) }) test_that("returns value", { @@ -39,7 +39,7 @@ test_that("can control numeric tolerance", { x2 <- x1 + 1e-6 local_edition(2) - expect_failure(expect_equal(x1, x2)) + expect_snapshot_failure(expect_equal(x1, x2)) expect_success(expect_equal(x1, x2, tolerance = 1e-5)) expect_success(expect_equivalent(x1, x2, tolerance = 1e-5)) @@ -48,7 +48,7 @@ test_that("can control numeric tolerance", { expect_success(expect_equal(x1, x2, tol = 1e-5)) local_edition(3) - expect_failure(expect_equal(x1, x2)) + expect_snapshot_failure(expect_equal(x1, x2)) expect_success(expect_equal(x1, x2, tolerance = 1e-5)) }) @@ -79,12 +79,12 @@ test_that("default labels use unquoting", { local_edition(2) x <- 2 - expect_failure(expect_equal(1, !!x), "1 not equal to 2", fixed = TRUE) + expect_snapshot_failure(expect_equal(1, !!x)) }) test_that("% is not treated as sprintf format specifier (#445)", { - expect_failure(expect_equal("+", "%")) - expect_failure(expect_equal("%", "+")) + expect_snapshot_failure(expect_equal("+", "%")) + expect_snapshot_failure(expect_equal("%", "+")) expect_equal("%", "%") }) @@ -121,7 +121,7 @@ test_that("useful message if objects equal but not identical", { g <- function() x environment(g) <- globalenv() - expect_failure(expect_identical(f, g)) + expect_snapshot_failure(expect_identical(f, g)) }) test_that("attributes for object (#452)", { @@ -129,7 +129,7 @@ test_that("attributes for object (#452)", { oops <- structure(0, oops = "oops") expect_equal(oops, oops) - expect_failure(expect_equal(oops, 0)) + expect_snapshot_failure(expect_equal(oops, 0)) expect_equal(as.numeric(oops), 0) }) diff --git a/tests/testthat/test-expect-inheritance.R b/tests/testthat/test-expect-inheritance.R index 04d0a60ac..a727dad63 100644 --- a/tests/testthat/test-expect-inheritance.R +++ b/tests/testthat/test-expect-inheritance.R @@ -1,6 +1,8 @@ test_that("expect_type checks typeof", { expect_success(expect_type(factor("a"), "integer")) - expect_failure(expect_type(factor("a"), "double")) + + x <- factor("a") + expect_snapshot_failure(expect_type(x, "double")) }) test_that("expect_type validates its inputs", { @@ -13,15 +15,19 @@ test_that("expect_is checks class", { local_edition(2) expect_success(expect_is(factor("a"), "factor")) - expect_failure(expect_is(factor("a"), "integer")) + expect_snapshot_failure(expect_is(factor("a"), "integer")) }) test_that("expect_s3/s4_class fails if appropriate type", { A <- methods::setClass("A", contains = "list") - expect_failure(expect_s3_class(1, "double"), "not an S3 object") - expect_failure(expect_s3_class(A(), "double"), "not an S3 object") - expect_failure(expect_s4_class(factor(), "double"), "not an S4 object") + x1 <- 1 + x2 <- A() + x3 <- factor("a") + + expect_snapshot_failure(expect_s3_class(x1, "double")) + expect_snapshot_failure(expect_s3_class(x2, "double")) + expect_snapshot_failure(expect_s4_class(x3, "double")) }) test_that("expect_s[34]_class can check not S3/S4", { @@ -65,7 +71,7 @@ test_that("test_s3_class respects class hierarchy", { test_that("test_s3_class can request exact match", { x <- structure(list(), class = c("a", "b")) - expect_failure(expect_s3_class(x, "a", exact = TRUE)) + expect_snapshot_failure(expect_s3_class(x, "a", exact = TRUE)) expect_success(expect_s3_class(x, c("a", "b"), exact = TRUE)) }) diff --git a/tests/testthat/test-expect-invisible.R b/tests/testthat/test-expect-invisible.R index b2b0a2c81..08075c5e0 100644 --- a/tests/testthat/test-expect-invisible.R +++ b/tests/testthat/test-expect-invisible.R @@ -1,9 +1,9 @@ test_that("basic principles of visibility hold", { expect_success(expect_invisible(x <- 10)) - expect_failure(expect_invisible(x)) + expect_snapshot_failure(expect_invisible(x)) expect_success(expect_visible(x)) - expect_failure(expect_visible(x <- 1)) + expect_snapshot_failure(expect_visible(x <- 1)) }) test_that("generates useful failure messages", { diff --git a/tests/testthat/test-expect-known.R b/tests/testthat/test-expect-known.R index ea0aec954..7146e63d2 100644 --- a/tests/testthat/test-expect-known.R +++ b/tests/testthat/test-expect-known.R @@ -24,17 +24,21 @@ test_that("ignores incomplete last line", { writeLines("Hi!", file) expect_success(expect_known_output(cat("Hi!"), file)) expect_success(expect_known_output(cat("Hi!\n"), file)) - expect_failure(expect_known_output(cat("Hi!\n\n"), file)) - expect_failure(expect_known_output(cat("oops"), file)) + expect_snapshot_failure(expect_known_output(cat("Hi!\n\n"), file)) + expect_snapshot_failure(expect_known_output(cat("oops"), file)) }) test_that("updates by default", { file <- withr::local_tempfile() writeLines("Hi!", file) - expect_failure(expect_known_output(cat("oops"), file, update = FALSE)) + expect_snapshot_failure(expect_known_output( + cat("oops"), + file, + update = FALSE + )) expect_equal(readLines(file), "Hi!") - expect_failure(expect_known_output(cat("oops"), file, update = TRUE)) + expect_snapshot_failure(expect_known_output(cat("oops"), file, update = TRUE)) expect_success(expect_known_output(cat("oops"), file)) }) @@ -55,7 +59,7 @@ test_that("Warning for non-UTF-8 reference files", { writeBin(x, tmp) suppressWarnings( - expect_failure( + expect_snapshot_failure( expect_known_output("foobar", tmp, update = FALSE) ) ) @@ -69,7 +73,7 @@ test_that("correctly matches to a file", { expect_success(expect_known_value(x, "one.rds")) x <- 2 - expect_failure(expect_known_value(x, "one.rds", update = FALSE)) + expect_snapshot_failure(expect_known_value(x, "one.rds", update = FALSE)) }) test_that("first run is successful", { @@ -89,11 +93,15 @@ test_that("equal_to_ref does not overwrite existing", { expect_success(expect_equal_to_reference(ref_obj1, tmp_rds)) # Failure does not update object - expect_failure(expect_equal_to_reference(ref_obj2, tmp_rds)) + expect_snapshot_failure(expect_equal_to_reference(ref_obj2, tmp_rds)) expect_equal(readRDS(tmp_rds), ref_obj1) # Now failure does update object - expect_failure(expect_equal_to_reference(ref_obj2, tmp_rds, update = TRUE)) + expect_snapshot_failure(expect_equal_to_reference( + ref_obj2, + tmp_rds, + update = TRUE + )) expect_success(expect_equal_to_reference(ref_obj2, tmp_rds)) }) @@ -131,5 +139,5 @@ test_that("empty hash succeeds with warning", { test_that("only succeeds if hash is correct", { expect_success(expect_known_hash(1:10, "c08951d2c2")) - expect_failure(expect_known_hash(1:10, "c08951d2c3")) + expect_snapshot_failure(expect_known_hash(1:10, "c08951d2c3")) }) diff --git a/tests/testthat/test-expect-match.R b/tests/testthat/test-expect-match.R index 9e417c30d..0d5c3384c 100644 --- a/tests/testthat/test-expect-match.R +++ b/tests/testthat/test-expect-match.R @@ -33,10 +33,10 @@ test_that("expect_no_match validates its inputs", { }) test_that("extra arguments passed onto grepl", { - expect_failure(expect_match("\\s", "\\s")) + expect_snapshot_failure(expect_match("\\s", "\\s")) expect_success(expect_match("\\s", "\\s", fixed = TRUE)) - expect_failure(expect_match("test", "TEST")) + expect_snapshot_failure(expect_match("test", "TEST")) expect_success(expect_match("test", "TEST", ignore.case = TRUE)) }) diff --git a/tests/testthat/test-expect-named.R b/tests/testthat/test-expect-named.R index c25bedc69..51fa50c95 100644 --- a/tests/testthat/test-expect-named.R +++ b/tests/testthat/test-expect-named.R @@ -1,11 +1,11 @@ test_that("expected_named verifies presence of names", { expect_success(expect_named(c(a = 1))) - expect_failure(expect_named(1:10)) + expect_snapshot_failure(expect_named(1:10)) }) test_that("expected_named verifies actual of names", { expect_success(expect_named(c(a = 1), "a")) - expect_failure(expect_named(c(a = 1), "b")) + expect_snapshot_failure(expect_named(c(a = 1), "b")) }) test_that("expected_named optionally ignores case", { diff --git a/tests/testthat/test-expect-no-condition.R b/tests/testthat/test-expect-no-condition.R index fbfbb7af8..66ac4ac77 100644 --- a/tests/testthat/test-expect-no-condition.R +++ b/tests/testthat/test-expect-no-condition.R @@ -21,7 +21,7 @@ test_that("expect_no_* pass with pure code", { test_that("expect_no_ continues execution", { b <- 1 - expect_failure(expect_no_warning({ + expect_snapshot_failure(expect_no_warning({ warning("x") b <- 2 })) @@ -29,7 +29,7 @@ test_that("expect_no_ continues execution", { }) test_that("expect_no_* don't emit success when they fail", { - expect_failure(expect_no_error(stop("!"))) + expect_snapshot_failure(expect_no_error(stop("!"))) }) test_that("capture correct trace_env (#1994)", { diff --git a/tests/testthat/test-expect-output.R b/tests/testthat/test-expect-output.R index 7eea1f901..c98144463 100644 --- a/tests/testthat/test-expect-output.R +++ b/tests/testthat/test-expect-output.R @@ -3,11 +3,11 @@ g <- function() cat("!") test_that("expect = NA checks for no output", { expect_success(expect_output(f(), NA)) - expect_failure(expect_output(g(), NA), "produced output") + expect_snapshot_failure(expect_output(g(), NA)) }) test_that("expect = NULL checks for some output", { - expect_failure(expect_output(f(), NULL), "produced no output") + expect_snapshot_failure(expect_output(f(), NULL)) expect_success(expect_output(g(), NULL)) }) diff --git a/tests/testthat/test-expect-reference.R b/tests/testthat/test-expect-reference.R index b71a620e2..1e804beeb 100644 --- a/tests/testthat/test-expect-reference.R +++ b/tests/testthat/test-expect-reference.R @@ -2,7 +2,7 @@ test_that("succeeds only when same object", { local_edition(2) x <- y <- 1 expect_success(expect_reference(x, y)) - expect_failure(expect_reference(x, 1)) + expect_snapshot_failure(expect_reference(x, 1)) }) test_that("returns value", { diff --git a/tests/testthat/test-expect-self-test.R b/tests/testthat/test-expect-self-test.R index 5eb2820e0..870d3a12b 100644 --- a/tests/testthat/test-expect-self-test.R +++ b/tests/testthat/test-expect-self-test.R @@ -1,14 +1,14 @@ test_that("expect_failure() requires 1 failure and zero successes", { expect_success(expect_failure(fail())) - expect_failure(expect_failure({})) - expect_failure(expect_failure(pass(NULL))) - expect_failure(expect_failure({ + expect_snapshot_failure(expect_failure({})) + expect_snapshot_failure(expect_failure(pass(NULL))) + expect_snapshot_failure(expect_failure({ pass(NULL) fail() })) - expect_failure(expect_failure({ + expect_snapshot_failure(expect_failure({ fail() # Following succeed/fail are never reached pass(NULL) @@ -18,21 +18,19 @@ test_that("expect_failure() requires 1 failure and zero successes", { test_that("expect_failure() can optionally match message", { expect_success(expect_failure(fail("apple"), "apple")) - expect_failure(expect_failure(fail("apple"), "banana")) - expect_snapshot_failure(expect_failure(fail("apple"), "banana")) }) test_that("expect_success() requires 1 success and zero failures", { expect_success(expect_success(pass(NULL))) - expect_failure(expect_success({})) - expect_failure(expect_success(fail())) - expect_failure(expect_success({ + expect_snapshot_failure(expect_success({})) + expect_snapshot_failure(expect_success(fail())) + expect_snapshot_failure(expect_success({ pass(NULL) fail() })) - expect_failure(expect_success({ + expect_snapshot_failure(expect_success({ pass(NULL) pass(NULL) })) @@ -81,7 +79,7 @@ test_that("expect_no are deprecated", { test_that("expect_no still work", { withr::local_options(lifecycle_verbosity = "quiet") expect_success(expect_no_failure(pass(NULL))) - expect_failure(expect_no_failure(fail())) + expect_snapshot_failure(expect_no_failure(fail())) expect_success(expect_no_success(fail())) - expect_failure(expect_no_success(pass(NULL))) + expect_snapshot_failure(expect_no_success(pass(NULL))) }) diff --git a/tests/testthat/test-expect-setequal.R b/tests/testthat/test-expect-setequal.R index db306744c..e57b7ab81 100644 --- a/tests/testthat/test-expect-setequal.R +++ b/tests/testthat/test-expect-setequal.R @@ -6,8 +6,8 @@ test_that("ignores order and duplicates", { }) test_that("checks both directions of containment", { - expect_failure(expect_setequal(letters, letters[-1])) - expect_failure(expect_setequal(letters[-1], letters)) + expect_snapshot_failure(expect_setequal(letters, letters[-1])) + expect_snapshot_failure(expect_setequal(letters[-1], letters)) }) test_that("truncates long differences", { @@ -76,9 +76,15 @@ test_that("ignores order recursively", { }) test_that("error if any names are duplicated", { - expect_failure(expect_mapequal(list(a = 1, b = 2, b = 3), list(b = 2, a = 1))) - expect_failure(expect_mapequal(list(a = 1, b = 2), list(b = 3, b = 2, a = 1))) - expect_failure(expect_mapequal( + expect_snapshot_failure(expect_mapequal( + list(a = 1, b = 2, b = 3), + list(b = 2, a = 1) + )) + expect_snapshot_failure(expect_mapequal( + list(a = 1, b = 2), + list(b = 3, b = 2, a = 1) + )) + expect_snapshot_failure(expect_mapequal( list(a = 1, b = 2, b = 3), list(b = 3, b = 2, a = 1) )) @@ -89,17 +95,23 @@ test_that("handling NULLs", { }) test_that("fail if names don't match", { - expect_failure(expect_mapequal(list(a = 1, b = 2), list(a = 1))) - expect_failure(expect_mapequal(list(a = 1), list(a = 1, b = 2))) + expect_snapshot_failure(expect_mapequal(list(a = 1, b = 2), list(a = 1))) + expect_snapshot_failure(expect_mapequal(list(a = 1), list(a = 1, b = 2))) }) test_that("fails if values don't match", { - expect_failure(expect_mapequal(list(a = 1, b = 2), list(a = 1, b = 3))) + expect_snapshot_failure(expect_mapequal( + list(a = 1, b = 2), + list(a = 1, b = 3) + )) }) test_that("fails if unnamed values in different location if any unnamed values", { expect_success(expect_mapequal(list(1, b = 2, c = 3), list(1, c = 3, b = 2))) - expect_failure(expect_mapequal(list(1, b = 2, c = 3), list(b = 2, 1, c = 3))) + expect_snapshot_failure(expect_mapequal( + list(1, b = 2, c = 3), + list(b = 2, 1, c = 3) + )) }) # contains ---------------------------------------------------------------- diff --git a/tests/testthat/test-expect-silent.R b/tests/testthat/test-expect-silent.R index 2c3e0c7d7..9a279813c 100644 --- a/tests/testthat/test-expect-silent.R +++ b/tests/testthat/test-expect-silent.R @@ -1,7 +1,7 @@ test_that("checks for any type of output", { - expect_failure(expect_silent(warning("!"))) - expect_failure(expect_silent(message("!"))) - expect_failure(expect_silent(print("!"))) + expect_snapshot_failure(expect_silent(warning("!"))) + expect_snapshot_failure(expect_silent(message("!"))) + expect_snapshot_failure(expect_silent(print("!"))) expect_success(expect_silent("")) }) diff --git a/tests/testthat/test-expect-vector.R b/tests/testthat/test-expect-vector.R index 110e13858..62bd13980 100644 --- a/tests/testthat/test-expect-vector.R +++ b/tests/testthat/test-expect-vector.R @@ -2,7 +2,7 @@ test_that("basic properties upheld", { skip_if_not_installed("vctrs", "0.1.0.9002") expect_success(expect_vector(1:10, size = 10)) - expect_failure(expect_vector(1:10, size = 5)) + expect_snapshot_failure(expect_vector(1:10, size = 5)) }) test_that("expect_vector validates its inputs", { diff --git a/tests/testthat/test-expectation.R b/tests/testthat/test-expectation.R index 3e63e2ca2..dcda6c724 100644 --- a/tests/testthat/test-expectation.R +++ b/tests/testthat/test-expectation.R @@ -23,10 +23,10 @@ test_that("can subclass expectation", { test_that("`expect()` and `exp_signal()` signal expectations", { expect_success(expect(TRUE, "")) - expect_failure(expect(FALSE, "")) + expect_snapshot_failure(expect(FALSE, "")) expect_success(exp_signal(new_expectation("success", ""))) - expect_failure(exp_signal(new_expectation("failure", ""))) + expect_snapshot_failure(exp_signal(new_expectation("failure", ""))) }) test_that("conditionMessage() is called during conversion", { diff --git a/tests/testthat/test-old-school.R b/tests/testthat/test-old-school.R index 40ad9783b..5b09d6cff 100644 --- a/tests/testthat/test-old-school.R +++ b/tests/testthat/test-old-school.R @@ -14,7 +14,7 @@ test_that("old school comparisons still work", { local_edition(2L) expect_success(expect_that(10, is_less_than(11))) - expect_failure(expect_that(10, is_more_than(11))) + expect_snapshot_failure(expect_that(10, is_more_than(11))) }) test_that("old school equality tests still work", { diff --git a/tests/testthat/test-snapshot-file.R b/tests/testthat/test-snapshot-file.R index fe5fcb459..47c9f1b1b 100644 --- a/tests/testthat/test-snapshot-file.R +++ b/tests/testthat/test-snapshot-file.R @@ -56,7 +56,7 @@ test_that("basic workflow", { # fails if changed snapper$start_file("snapshot-6", "test") path2 <- write_tmp_lines(letters[-1]) - expect_failure(expect_snapshot_file(path2, "letters.txt")) + expect_snapshot_failure(expect_snapshot_file(path2, "letters.txt")) snapper$end_file() }) diff --git a/tests/testthat/test-snapshot-reporter.R b/tests/testthat/test-snapshot-reporter.R index c20f47ea0..38bca9c23 100644 --- a/tests/testthat/test-snapshot-reporter.R +++ b/tests/testthat/test-snapshot-reporter.R @@ -32,7 +32,7 @@ test_that("basic workflow", { # fails if changed snapper$start_file("snapshot-2", "test") - expect_failure(expect_snapshot_output("y")) + expect_snapshot_failure(expect_snapshot_output("y")) snapper$end_file() expect_true(file.exists(file.path(path, "snapshot-2.md"))) expect_true(file.exists(file.path(path, "snapshot-2.new.md"))) @@ -63,7 +63,7 @@ test_that("only create new files for changed variants", { # failure in default snapper$start_file("variants", "test") - expect_failure(expect_snapshot_output("y")) + expect_snapshot_failure(expect_snapshot_output("y")) expect_success(expect_snapshot_output("x", variant = "a")) expect_success(expect_snapshot_output("x", variant = "b")) snapper$end_file() @@ -77,7 +77,7 @@ test_that("only create new files for changed variants", { snapper$start_file("variants", "test") expect_success(expect_snapshot_output("x")) expect_success(expect_snapshot_output("x", variant = "a")) - expect_failure(expect_snapshot_output("y", variant = "b")) + expect_snapshot_failure(expect_snapshot_output("y", variant = "b")) snapper$end_file() expect_setequal( snapper$snap_files(), @@ -95,7 +95,7 @@ test_that("only reverting change in variant deletes .new", { # failure snapper$start_file("v", "test") - expect_failure(expect_snapshot_output("y", variant = "a")) + expect_snapshot_failure(expect_snapshot_output("y", variant = "a")) snapper$end_file() expect_setequal(snapper$snap_files(), c("a/v.md", "b/v.md", "a/v.new.md")) diff --git a/tests/testthat/test-snapshot.R b/tests/testthat/test-snapshot.R index cb8aaeff9..64ef73c12 100644 --- a/tests/testthat/test-snapshot.R +++ b/tests/testthat/test-snapshot.R @@ -66,7 +66,7 @@ test_that("can scrub output/messages/warnings/errors", { test_that("always checks error status", { expect_error(expect_snapshot(stop("!"), error = FALSE)) - expect_failure(expect_snapshot(print("!"), error = TRUE)) + expect_snapshot_failure(expect_snapshot(print("!"), error = TRUE)) }) test_that("can capture error/warning messages", { From ce8a22467065dbfe3b955f4d697d4ad66967814b Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 10:59:06 -0500 Subject: [PATCH 11/20] Don't include values in message --- R/expect-invisible.R | 12 +-- R/expect-match.R | 20 ++-- R/quasi-label.R | 32 +----- tests/testthat/_snaps/expect-comparison.md | 8 +- tests/testthat/_snaps/expect-constant.md | 16 +++ tests/testthat/_snaps/expect-equality.md | 21 ++-- tests/testthat/_snaps/expect-inheritance.md | 16 +-- tests/testthat/_snaps/expect-invisible.md | 12 ++- tests/testthat/_snaps/expect-known.md | 62 +++++++++++ tests/testthat/_snaps/expect-match.md | 47 ++++++--- tests/testthat/_snaps/expect-named.md | 23 +++-- tests/testthat/_snaps/expect-no-condition.md | 12 +++ tests/testthat/_snaps/expect-output.md | 15 ++- tests/testthat/_snaps/expect-reference.md | 4 + tests/testthat/_snaps/expect-self-test.md | 48 ++++++++- tests/testthat/_snaps/expect-setequal.md | 103 ++++++++++++++++++- tests/testthat/_snaps/expect-shape.md | 16 +-- tests/testthat/_snaps/expect-silent.md | 15 +++ tests/testthat/_snaps/expect-vector.md | 4 + tests/testthat/_snaps/expectation.md | 8 ++ tests/testthat/_snaps/old-school.md | 6 ++ tests/testthat/_snaps/quasi-label.md | 8 +- tests/testthat/_snaps/snapshot-reporter.md | 7 ++ tests/testthat/_snaps/snapshot.md | 4 + tests/testthat/_snaps/try-again.md | 2 +- tests/testthat/test-quasi-label.R | 14 --- tests/testthat/test-snapshot-reporter.R | 2 +- 27 files changed, 409 insertions(+), 128 deletions(-) create mode 100644 tests/testthat/_snaps/expect-known.md create mode 100644 tests/testthat/_snaps/expect-reference.md create mode 100644 tests/testthat/_snaps/expect-silent.md create mode 100644 tests/testthat/_snaps/expectation.md create mode 100644 tests/testthat/_snaps/old-school.md create mode 100644 tests/testthat/_snaps/snapshot-reporter.md diff --git a/R/expect-invisible.R b/R/expect-invisible.R index e7fd1f111..9b1c5fe31 100644 --- a/R/expect-invisible.R +++ b/R/expect-invisible.R @@ -25,9 +25,9 @@ expect_invisible <- function(call, label = NULL) { vis <- withVisible(call) if (!identical(vis$visible, FALSE)) { - msg <- sprintf( - "Expected %s to return invisibly.\nActually returned visibly.", - lab + msg <- c( + sprintf("Expected %s to return invisibly.", lab), + "Actually returned visibly." ) return(fail(msg)) } @@ -41,9 +41,9 @@ expect_visible <- function(call, label = NULL) { vis <- withVisible(call) if (!identical(vis$visible, TRUE)) { - msg <- sprintf( - "Expected %s to return visibly.\nActually returned invisibly.", - lab + msg <- c( + sprintf("Expected %s to return visibly.", lab), + "Actually returned invisibly." ) return(fail(msg)) } diff --git a/R/expect-match.R b/R/expect-match.R index 945b74c9b..8b7b22324 100644 --- a/R/expect-match.R +++ b/R/expect-match.R @@ -106,7 +106,7 @@ expect_match_ <- function( info = NULL, label = NULL, negate = FALSE, - title = "Text", + title = "text", trace_env = caller_env() ) { matches <- grepl(regexp, act$val, perl = perl, fixed = fixed, ...) @@ -119,27 +119,27 @@ expect_match_ <- function( text <- encodeString(act$val) if (length(act$val) == 1) { - values <- paste0(title, ': "', text, '"') which <- "" + values <- text } else { bullet <- ifelse( condition, cli::col_green(cli::symbol$tick), cli::col_red(cli::symbol$cross) ) - values <- paste0(title, ":\n", paste0(bullet, " ", text, collapse = "\n")) - which <- if (all) "Every element of " else "Some element of " + values <- paste0(bullet, " ", text, collapse = "\n") + which <- if (all) "every element of " else "some element of " } - match <- if (negate) "matches" else "does not match" + match <- if (negate) "not to match" else "to match" - msg <- sprintf( - "%s%s %s %s %s.\n%s", + exp_msg <- sprintf( + "Expected %s%s %s %s %s.", which, act$lab, match, if (fixed) "string" else "regexp", - encodeString(regexp, quote = '"'), - values + encodeString(regexp, quote = '"') ) - return(fail(msg, info = info, trace_env = trace_env)) + act_msg <- c(paste0("Actual ", title, ':'), text) + return(fail(c(exp_msg, act_msg), info = info, trace_env = trace_env)) } diff --git a/R/quasi-label.R b/R/quasi-label.R index 3e519715a..0390da8b4 100644 --- a/R/quasi-label.R +++ b/R/quasi-label.R @@ -53,7 +53,7 @@ quasi_label <- function(quo, label = NULL, arg = NULL) { expr <- quo_get_expr(quo) value <- eval_bare(expr, quo_get_env(quo)) - label <- label %||% auto_label(expr, value) + label <- label %||% expr_label(expr) labelled_value(value, label) } @@ -76,34 +76,6 @@ quasi_capture <- function(.quo, .label, .capture, ...) { act } -auto_label <- function(expr, value) { - if (is.call(expr) || is.name(expr)) { - label <- expr_label(expr) - if (can_inline(value)) { - paste0(label, " (", as_label(value), ")") - } else { - label - } - } else { - expr_label(expr) - } -} - -can_inline <- function(x) { - if (!is_syntactic_literal(x)) { - return(FALSE) - } - if (!is.null(dim(x)) || !is.null(attributes(x))) { - return(FALSE) - } - - if (is.character(x)) { - is.na(x) || (!grepl("\n", x) && nchar(x) < 100) - } else { - TRUE - } -} - expr_label <- function(x) { if (is_syntactic_literal(x)) { deparse1(x) @@ -128,7 +100,7 @@ expr_label <- function(x) { x <- call2(x[[1]], quote(expr = ...)) } } - deparse1(x) + paste0("`", deparse1(x), "`") } else { # Any other object that's been inlined in x <- deparse(x) diff --git a/tests/testthat/_snaps/expect-comparison.md b/tests/testthat/_snaps/expect-comparison.md index 9d6bf536e..d3d05e1a3 100644 --- a/tests/testthat/_snaps/expect-comparison.md +++ b/tests/testthat/_snaps/expect-comparison.md @@ -12,25 +12,25 @@ # useful output when numbers are very small - Expected 1.1 * x (1.1e-05) <= `x` (1e-05). + Expected `1.1 * x` <= `x`. Actual 0.0000110 > 0.0000100 Difference 0.0000010 > 0 --- - Expected `x` (1e-05) > 1.1 * x (1.1e-05). + Expected `x` > `1.1 * x`. Actual 0.0000100 <= 0.0000110 Difference -0.0000010 <= 0 # useful output when difference is zero - Expected `x` (100) < 100. + Expected `x` < 100. Actual 100.0 >= 100.0 Difference 0.0 >= 0 # useful output when differnce is large - Expected `x` (100) < 0.001. + Expected `x` < 0.001. Actual 100.000 >= 0.001 Difference 99.999 >= 0 diff --git a/tests/testthat/_snaps/expect-constant.md b/tests/testthat/_snaps/expect-constant.md index 3dccf45ff..372e7e1f2 100644 --- a/tests/testthat/_snaps/expect-constant.md +++ b/tests/testthat/_snaps/expect-constant.md @@ -12,6 +12,22 @@ `actual` is an S3 object of class , a list `expected` is a logical vector (FALSE) +# additional info returned in message + + Expected FALSE to be equal to TRUE. + + `actual`: FALSE + `expected`: TRUE + NOPE + +--- + + Expected TRUE to be equal to FALSE. + + `actual`: TRUE + `expected`: FALSE + YUP + # expect_null works Expected `df` to be equal to FALSE. diff --git a/tests/testthat/_snaps/expect-equality.md b/tests/testthat/_snaps/expect-equality.md index 64e2d4846..3e806d5d8 100644 --- a/tests/testthat/_snaps/expect-equality.md +++ b/tests/testthat/_snaps/expect-equality.md @@ -39,40 +39,40 @@ # can control numeric tolerance - Expected `x1` (1) to equal `x2` (1.000001). + Expected `x1` to equal `x2`. Actual: 1/1 mismatches [1] 1 - 1 == -1e-06 --- - Expected `x1` (1) to be equal to `x2` (1.000001). + Expected `x1` to be equal to `x2`. `actual`: 1.0000000 `expected`: 1.0000010 # provide useful feedback on failure - Expected `x` (1) to be identical to "a". + Expected `x` to be identical to "a". `actual` is a double vector (1) `expected` is a character vector ('a') --- - Expected `x` (1) to be equal to "a". + Expected `x` to be equal to "a". `actual` is a double vector (1) `expected` is a character vector ('a') --- - Expected `x` (1) to be identical to "a". + Expected `x` to be identical to "a". Types not compatible: double is not character --- - Expected `x` (1) to equal "a". + Expected `x` to equal "a". Actual: Types not compatible: double is not character @@ -100,15 +100,12 @@ # useful message if objects equal but not identical Expected `f` to be identical to `g`. - Names: 1 string mismatch - Length mismatch: comparison on first 1 components - Component 1: Modes of target, current: function, numeric - Component 1: target, current do not match when deparsed - Component 1: 'current' is not an environment + names for target but not for current + Length mismatch: comparison on first 0 components # attributes for object (#452) - Expected `oops` (structure(0, oops = "oops")) to equal 0. + Expected `oops` to equal 0. Actual: Attributes: < Modes: list, NULL > Attributes: < Lengths: 1, 0 > diff --git a/tests/testthat/_snaps/expect-inheritance.md b/tests/testthat/_snaps/expect-inheritance.md index 9de5b7f8e..ecfaf3cfc 100644 --- a/tests/testthat/_snaps/expect-inheritance.md +++ b/tests/testthat/_snaps/expect-inheritance.md @@ -13,12 +13,12 @@ # expect_is checks class - Expected factor("a") to inherit from `'character'`. + Expected `factor("a")` to inherit from `'character'`. Actual inheritance: `'factor'` # expect_s3/s4_class fails if appropriate type - Expected `x1` (1) to be an S3 object. + Expected `x1` to be an S3 object. Actually is a base object. --- @@ -33,15 +33,15 @@ # expect_s[34]_class can check not S3/S4 - Expected factor() to not be an S3 object. + Expected `factor()` to not be an S3 object. --- - Expected A() to not be an S4 object. + Expected `A()` to not be an S4 object. # test_s4_class respects class hierarchy - Expected C() to inherit from 'D'. + Expected `C()` to inherit from 'D'. Actual class: 'C'/'A'/'B'/'list'/'vector' # expect_s3_class validates its inputs @@ -82,7 +82,7 @@ # expect_r6_class generates useful failures - Expected `x` (1) to be an R6 object. + Expected `x` to be an R6 object. Actually is a base object. # expect_r6_class validates its inputs @@ -95,12 +95,12 @@ # can check with actual class - Expected Foo() to inherit from . + Expected `Foo()` to inherit from . Actual class: --- - Expected Baz() to inherit from . + Expected `Baz()` to inherit from . Actual class: / # expect_s7_class validates its inputs diff --git a/tests/testthat/_snaps/expect-invisible.md b/tests/testthat/_snaps/expect-invisible.md index 765d28632..04cfe873b 100644 --- a/tests/testthat/_snaps/expect-invisible.md +++ b/tests/testthat/_snaps/expect-invisible.md @@ -1,6 +1,16 @@ +# basic principles of visibility hold + + Expected `x` to return invisibly. + Actually returned visibly. + +--- + + Expected `x <- 1` to return visibly. + Actually returned invisibly. + # generates useful failure messages - Expected invisible(1) to return visibly. + Expected `invisible(1)` to return visibly. Actually returned invisibly. --- diff --git a/tests/testthat/_snaps/expect-known.md b/tests/testthat/_snaps/expect-known.md new file mode 100644 index 000000000..420d2057b --- /dev/null +++ b/tests/testthat/_snaps/expect-known.md @@ -0,0 +1,62 @@ +# ignores incomplete last line + + Results have changed from known value recorded in '/tmp/RtmppktJm1/file13b4b50b67fc'. + + `old`: "Hi!" + `new`: "Hi!" "" + +--- + + Results have changed from known value recorded in '/tmp/RtmppktJm1/file13b4b50b67fc'. + + `old`: "Hi!" "" + `new`: "oops" + +# updates by default + + Results have changed from known value recorded in '/tmp/RtmppktJm1/file13b4b249dd6d5'. + + `old`: "Hi!" + `new`: "oops" + +--- + + Results have changed from known value recorded in '/tmp/RtmppktJm1/file13b4b249dd6d5'. + + `old`: "Hi!" + `new`: "oops" + +# Warning for non-UTF-8 reference files + + Results have changed from known value recorded in '/tmp/RtmppktJm1/file13b4b3b0e2961'. + + `old`: "éáíöü" + `new`: + +# correctly matches to a file + + `x` has changed from known value recorded in 'one.rds'. + 1/1 mismatches + [1] 2 - 1 == 1 + +# equal_to_ref does not overwrite existing + + `ref_obj2` has changed from known value recorded in '/tmp/RtmppktJm1/file13b4b10c668bf.rds'. + 3/3 mismatches (average diff: 1) + [1] 2 - 1 == 1 + [2] 3 - 2 == 1 + [3] 4 - 3 == 1 + +--- + + `ref_obj2` has changed from known value recorded in '/tmp/RtmppktJm1/file13b4b10c668bf.rds'. + 3/3 mismatches (average diff: 1) + [1] 2 - 1 == 1 + [2] 3 - 2 == 1 + [3] 4 - 3 == 1 + +# only succeeds if hash is correct + + Expected value to hash to c08951d2c3. + Actual hash: c08951d2c2 + diff --git a/tests/testthat/_snaps/expect-match.md b/tests/testthat/_snaps/expect-match.md index 054641e5b..3bc59b0a4 100644 --- a/tests/testthat/_snaps/expect-match.md +++ b/tests/testthat/_snaps/expect-match.md @@ -4,24 +4,25 @@ --- - `one` ("bcde") does not match regexp "asdf". - Text: "bcde" + Expected `one` to match regexp "asdf". + Actual text: + bcde --- - Every element of `many` does not match regexp "a". - Text: - ✔ a - ✔ a - ✖ b + Expected every element of `many` to match regexp "a". + Actual text: + a + a + b --- - Some element of `many` does not match regexp "c". - Text: - ✖ a - ✖ a - ✖ b + Expected some element of `many` to match regexp "c". + Actual text: + a + a + b # expect_match validates its inputs @@ -79,13 +80,27 @@ Error in `expect_no_match()`: ! `all` must be `TRUE` or `FALSE`, not the number 1. +# extra arguments passed onto grepl + + Expected "\\s" to match regexp "\\s". + Actual text: + \\s + +--- + + Expected "test" to match regexp "TEST". + Actual text: + test + # expect_no_match works - `x` ("te*st") matches string "e*". - Text: "te*st" + Expected `x` not to match string "e*". + Actual text: + te*st --- - `x` ("test") matches regexp "TEST". - Text: "test" + Expected `x` not to match regexp "TEST". + Actual text: + test diff --git a/tests/testthat/_snaps/expect-named.md b/tests/testthat/_snaps/expect-named.md index 5acd1b3a4..35683b7eb 100644 --- a/tests/testthat/_snaps/expect-named.md +++ b/tests/testthat/_snaps/expect-named.md @@ -1,39 +1,50 @@ +# expected_named verifies presence of names + + Expected `1:10` to have names. + +# expected_named verifies actual of names + + Names of Expected `c(a = 1)` to be equal to "b". + + `actual`: "a" + `expected`: "b" + # provide useful feedback on failure - Names of c(a = 1) (c(a = 1)) doesn't have the same values as c("a", "b"). + Names of `c(a = 1)` doesn't have the same values as `c("a", "b")`. * Only in `expected`: "b" --- - Names of c(a = 1, b = 1) doesn't have the same values as c("a") ("a"). + Names of `c(a = 1, b = 1)` doesn't have the same values as `c("a")`. * Only in `actual`: "b" --- - Names of c(a = 1) (c(a = 1)) doesn't have the same values as c("b") ("b"). + Names of `c(a = 1)` doesn't have the same values as `c("b")`. * Only in `actual`: "a" * Only in `expected`: "b" --- - Names of Expected c(a = 1) (c(a = 1)) to be equal to c("a", "b"). + Names of Expected `c(a = 1)` to be equal to `c("a", "b")`. `actual`: "a" `expected`: "a" "b" --- - Names of Expected c(a = 1, b = 1) to be equal to c("a") ("a"). + Names of Expected `c(a = 1, b = 1)` to be equal to `c("a")`. `actual`: "a" "b" `expected`: "a" --- - Names of Expected c(a = 1) (c(a = 1)) to be equal to c("b") ("b"). + Names of Expected `c(a = 1)` to be equal to `c("b")`. `actual`: "a" `expected`: "b" diff --git a/tests/testthat/_snaps/expect-no-condition.md b/tests/testthat/_snaps/expect-no-condition.md index 1b1cdbeed..d355bedde 100644 --- a/tests/testthat/_snaps/expect-no-condition.md +++ b/tests/testthat/_snaps/expect-no-condition.md @@ -35,6 +35,18 @@ i Actually got a with text: message +# expect_no_ continues execution + + Expected `{ ... }` to run without any warnings. + i Actually got a with text: + x + +# expect_no_* don't emit success when they fail + + Expected `stop("!")` to run without any errors. + i Actually got a with text: + ! + # matched conditions give informative message Code diff --git a/tests/testthat/_snaps/expect-output.md b/tests/testthat/_snaps/expect-output.md index a98584399..a8b18d8fc 100644 --- a/tests/testthat/_snaps/expect-output.md +++ b/tests/testthat/_snaps/expect-output.md @@ -1,7 +1,18 @@ +# expect = NA checks for no output + + Expected `g()` to produce no output. + Actual output: + ! + +# expect = NULL checks for some output + + Expected `f()` to produce output. + # expect = string checks for match - `g()` does not match regexp "x". - Output: "!" + Expected `g()` to match regexp "x". + Actual Output: + ! --- diff --git a/tests/testthat/_snaps/expect-reference.md b/tests/testthat/_snaps/expect-reference.md new file mode 100644 index 000000000..953f137cc --- /dev/null +++ b/tests/testthat/_snaps/expect-reference.md @@ -0,0 +1,4 @@ +# succeeds only when same object + + Expected `x` to be a reference to 1. + diff --git a/tests/testthat/_snaps/expect-self-test.md b/tests/testthat/_snaps/expect-self-test.md index 95d318aa8..a5981088f 100644 --- a/tests/testthat/_snaps/expect-self-test.md +++ b/tests/testthat/_snaps/expect-self-test.md @@ -1,7 +1,43 @@ +# expect_failure() requires 1 failure and zero successes + + Expectation did not fail + +--- + + Expectation did not fail + +--- + + Expected expectation to never succeed. + Actually succeeded: 1 times + +--- + + Expectation failed more than once + # expect_failure() can optionally match message - Failure message does not match regexp "banana". - Text: "apple" + Expected Failure message to match regexp "banana". + Actual text: + apple + +# expect_success() requires 1 success and zero failures + + Expectation did not succeed + +--- + + Expectation did not succeed + +--- + + Expected expectation to not fail. + Actually failed: 1 times + +--- + + Expected expectation to succeed once. + Actually succeeded: 2 times # errors in expect_success bubble up @@ -37,3 +73,11 @@ `expect_no_success()` was deprecated in testthat 3.3.0. i Please use `expect_failure()` instead. +# expect_no still work + + Expectation failed + +--- + + Expectation succeeded + diff --git a/tests/testthat/_snaps/expect-setequal.md b/tests/testthat/_snaps/expect-setequal.md index 352503c2a..bb2ff35a9 100644 --- a/tests/testthat/_snaps/expect-setequal.md +++ b/tests/testthat/_snaps/expect-setequal.md @@ -1,3 +1,15 @@ +# checks both directions of containment + + `letters` doesn't have the same values as `letters[-1]`. + * Only in `actual`: "a" + + +--- + + `letters[-1]` doesn't have the same values as `letters`. + * Only in `expected`: "a" + + # warns if both inputs are named Code @@ -28,13 +40,13 @@ --- - `x` doesn't have the same values as `y` (2). + `x` doesn't have the same values as `y`. * Only in `actual`: 1 --- - `x` (2) doesn't have the same values as `y`. + `x` doesn't have the same values as `y`. * Only in `expected`: 3 @@ -54,7 +66,7 @@ --- - `x` doesn't have the same values as c("a", "b", "c", "d"). + `x` doesn't have the same values as `c("a", "b", "c", "d")`. * Only in `expected`: "d" @@ -64,6 +76,91 @@ * Only in `expected`: 3, 4, 5, 6, 7, 8, 9, 10, 11, ... +# error if any names are duplicated + + Expected `list(a = 1, b = 2, b = 3)` to be equal to `list(b = 2, a = 1)`. + + `actual` is length 3 + `expected` is length 2 + + `names(actual)`: "a" "b" "b" + `names(expected)`: "a" "b" + + `actual[[3]]` is a double vector (3) + `expected[[3]]` is absent + +--- + + Expected `list(a = 1, b = 2)` to be equal to `list(b = 3, b = 2, a = 1)`. + + `actual` is length 2 + `expected` is length 3 + + `names(actual)`: "a" "b" + `names(expected)`: "a" "b" "b" + + `actual[[2]]`: 2.0 + `expected[[2]]`: 3.0 + + `actual[[3]]` is absent + `expected[[3]]` is a double vector (2) + +--- + + Expected `list(a = 1, b = 2, b = 3)` to be equal to `list(b = 3, b = 2, a = 1)`. + + `actual[[2]]`: 2.0 + `expected[[2]]`: 3.0 + + `actual[[3]]`: 3.0 + `expected[[3]]`: 2.0 + +# fail if names don't match + + Expected `list(a = 1, b = 2)` to be equal to `list(a = 1)`. + + `actual` is length 2 + `expected` is length 1 + + `names(actual)`: "a" "b" + `names(expected)`: "a" + + `actual$b` is a double vector (2) + `expected$b` is absent + +--- + + Expected `list(a = 1)` to be equal to `list(a = 1, b = 2)`. + + `actual` is length 1 + `expected` is length 2 + + `names(actual)`: "a" + `names(expected)`: "a" "b" + + `actual$b` is absent + `expected$b` is a double vector (2) + +# fails if values don't match + + Expected `list(a = 1, b = 2)` to be equal to `list(a = 1, b = 3)`. + + `actual$b`: 2.0 + `expected$b`: 3.0 + +# fails if unnamed values in different location if any unnamed values + + Expected `list(1, b = 2, c = 3)` to be equal to `list(b = 2, 1, c = 3)`. + + `names(actual)`: "" "b" "c" + `names(expected)`: "b" "" "c" + + `actual[[1]]`: 1.0 + `expected[[1]]`: 2.0 + + `actual[[2]]`: 2.0 + `expected[[2]]`: 1.0 + # expect_contains() gives useful message on failure `x1` doesn't fully contain all the values in `x2`. diff --git a/tests/testthat/_snaps/expect-shape.md b/tests/testthat/_snaps/expect-shape.md index 5b3fb542a..b9dfcf917 100644 --- a/tests/testthat/_snaps/expect-shape.md +++ b/tests/testthat/_snaps/expect-shape.md @@ -13,27 +13,27 @@ # dim compared correctly - Expected matrix(nrow = 6, ncol = 3) to have dim (6, 2). + Expected `matrix(nrow = 6, ncol = 3)` to have dim (6, 2). Actual dim: (6, 3) --- - Expected matrix(nrow = 6, ncol = 3) to have dim (7, 3). + Expected `matrix(nrow = 6, ncol = 3)` to have dim (7, 3). Actual dim: (6, 3) --- - Expected array(dim = 1:3) to have 2 dimensions. + Expected `array(dim = 1:3)` to have 2 dimensions. Actual dimensions: 3 --- - Expected array(dim = 1:3) to have 4 dimensions. + Expected `array(dim = 1:3)` to have 4 dimensions. Actual dimensions: 3 # nrow compared correctly - Expected matrix(nrow = 5, ncol = 5) to have 6 rows. + Expected `matrix(nrow = 5, ncol = 5)` to have 6 rows. Actual rows: 5 --- @@ -42,16 +42,16 @@ # ncol compared correctly - Expected matrix(nrow = 5, ncol = 5) to have 7 columns. + Expected `matrix(nrow = 5, ncol = 5)` to have 7 columns. Actual columns: 5 --- - Expected array(1) to have more than one dimension. + Expected `array(1)` to have more than one dimension. --- - Expected array(integer()) to have more than one dimension. + Expected `array(integer())` to have more than one dimension. # NA handling (e.g. dbplyr) diff --git a/tests/testthat/_snaps/expect-silent.md b/tests/testthat/_snaps/expect-silent.md new file mode 100644 index 000000000..983506e3f --- /dev/null +++ b/tests/testthat/_snaps/expect-silent.md @@ -0,0 +1,15 @@ +# checks for any type of output + + Expected `warning("!")` to run silently. + Actually produced: warnings + +--- + + Expected `message("!")` to run silently. + Actually produced: messages + +--- + + Expected `print("!")` to run silently. + Actually produced: output + diff --git a/tests/testthat/_snaps/expect-vector.md b/tests/testthat/_snaps/expect-vector.md index abcd78437..2fbc0df83 100644 --- a/tests/testthat/_snaps/expect-vector.md +++ b/tests/testthat/_snaps/expect-vector.md @@ -1,3 +1,7 @@ +# basic properties upheld + + `\`1:10\`` must have size 5, not size 10. + # expect_vector validates its inputs Code diff --git a/tests/testthat/_snaps/expectation.md b/tests/testthat/_snaps/expectation.md new file mode 100644 index 000000000..f2fe199e3 --- /dev/null +++ b/tests/testthat/_snaps/expectation.md @@ -0,0 +1,8 @@ +# `expect()` and `exp_signal()` signal expectations + + + +--- + + + diff --git a/tests/testthat/_snaps/old-school.md b/tests/testthat/_snaps/old-school.md new file mode 100644 index 000000000..d5410cab9 --- /dev/null +++ b/tests/testthat/_snaps/old-school.md @@ -0,0 +1,6 @@ +# old school comparisons still work + + Expected `x` > `expected`. + Actual 10.0 <= 11.0 + Difference -1.0 <= 0 + diff --git a/tests/testthat/_snaps/quasi-label.md b/tests/testthat/_snaps/quasi-label.md index 56cb164d1..853a3b923 100644 --- a/tests/testthat/_snaps/quasi-label.md +++ b/tests/testthat/_snaps/quasi-label.md @@ -4,23 +4,23 @@ expr_label(quote(foo(a = "this is a long argument", b = "this is a long argument", c = "this is a long argument"))) Output - [1] "foo(...)" + [1] "`foo(...)`" Code expr_label(quote(arg + arg + arg + arg + arg + arg + arg + arg + arg + arg + arg + arg)) Output - [1] "... + arg" + [1] "`... + arg`" Code expr_label(quote(arg + (arg + arg + arg + arg + arg + arg + arg + arg + arg + arg + arg))) Output - [1] "arg + ..." + [1] "`arg + ...`" Code expr_label(quote(function(a, b, c) { a + b + c })) Output - [1] "function(a, b, c) ..." + [1] "`function(a, b, c) ...`" # informative error for missing arg diff --git a/tests/testthat/_snaps/snapshot-reporter.md b/tests/testthat/_snaps/snapshot-reporter.md new file mode 100644 index 000000000..4d0b6fe51 --- /dev/null +++ b/tests/testthat/_snaps/snapshot-reporter.md @@ -0,0 +1,7 @@ +# `expect_error()` can fail inside `expect_snapshot()` + + Code + err$message + Output + [1] "Expected NULL to throw a error." + diff --git a/tests/testthat/_snaps/snapshot.md b/tests/testthat/_snaps/snapshot.md index defaf88d6..740958885 100644 --- a/tests/testthat/_snaps/snapshot.md +++ b/tests/testthat/_snaps/snapshot.md @@ -96,6 +96,10 @@ Output [1] "****" +# always checks error status + + Expected `print("!")` to throw a error. + # can capture error/warning messages This is an error diff --git a/tests/testthat/_snaps/try-again.md b/tests/testthat/_snaps/try-again.md index 569a6749b..6f50b6bce 100644 --- a/tests/testthat/_snaps/try-again.md +++ b/tests/testthat/_snaps/try-again.md @@ -14,7 +14,7 @@ i Expectation failed; trying again (1)... Condition Error: - ! Expected `i` (1) to be equal to 0. + ! Expected `i` to be equal to 0. `actual`: 1.0 `expected`: 0.0 diff --git a/tests/testthat/test-quasi-label.R b/tests/testthat/test-quasi-label.R index 702be1445..2dab0f8b0 100644 --- a/tests/testthat/test-quasi-label.R +++ b/tests/testthat/test-quasi-label.R @@ -1,17 +1,3 @@ -test_that("shows value iif simple", { - # symbols and calls shown - expect_equal(auto_label(quote(x), TRUE), "`x` (TRUE)") - expect_equal(auto_label(quote(f()), TRUE), "f() (TRUE)") - expect_equal(auto_label(quote(f()), NA_character_), "f() (NA_character_)") - # long arguments truncated - expect_equal(auto_label(call2("f", !!!letters), TRUE), "f(...) (TRUE)") - - df <- data.frame(x = 1:100) - expect_equal(auto_label(quote(f()), df), "f()") - expect_equal(auto_label(quote(f()), "x\ny"), "f()") - expect_equal(auto_label(quote(f()), strrep("x", 100)), "f()") -}) - test_that("atomic scalars deparsed to single values", { expect_equal(expr_label(NULL), "NULL") expect_equal(expr_label(TRUE), "TRUE") diff --git a/tests/testthat/test-snapshot-reporter.R b/tests/testthat/test-snapshot-reporter.R index 38bca9c23..694d7fc21 100644 --- a/tests/testthat/test-snapshot-reporter.R +++ b/tests/testthat/test-snapshot-reporter.R @@ -174,5 +174,5 @@ test_that("`expect_error()` can fail inside `expect_snapshot()`", { reporter = NULL ) err <- out[[1]]$results[[1]] - expect_match(err$message, "did not throw the expected error") + expect_snapshot(err$message) }) From 41da0731c588096a62d76664b139cbe6aa2d0533 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 11:23:18 -0500 Subject: [PATCH 12/20] Iterating on `expect_named()` --- R/expect-equality.R | 4 +-- R/expect-named.R | 9 +++--- R/expect-setequal.R | 6 +--- tests/testthat/_snaps/expect-named.md | 14 ++++----- tests/testthat/test-expect-named.R | 41 +++++++++------------------ 5 files changed, 27 insertions(+), 47 deletions(-) diff --git a/R/expect-equality.R b/R/expect-equality.R index a3e1e2a44..09cc1a2e1 100644 --- a/R/expect-equality.R +++ b/R/expect-equality.R @@ -136,8 +136,7 @@ expect_waldo_equal_ <- function( exp, info = NULL, ..., - trace_env = caller_env(), - error_prefix = NULL + trace_env = caller_env() ) { comp <- waldo_compare( act$val, @@ -154,7 +153,6 @@ expect_waldo_equal_ <- function( exp$lab, paste0(comp, collapse = "\n\n") ) - msg <- paste0(error_prefix, msg) return(fail(msg, info = info, trace_env = trace_env)) } pass(act$val) diff --git a/R/expect-named.R b/R/expect-named.R index 69e334676..4f8cb10c6 100644 --- a/R/expect-named.R +++ b/R/expect-named.R @@ -35,6 +35,7 @@ expect_named <- function( check_bool(ignore.order) check_bool(ignore.case) + act <- quasi_label(enquo(object), label) if (missing(expected)) { @@ -47,11 +48,11 @@ expect_named <- function( act_names <- normalise_names(names(act$val), ignore.order, ignore.case) if (ignore.order) { - act <- labelled_value(act_names, act$lab) - return(expect_setequal_(act, exp, error_prefix = "Names of ")) + act <- labelled_value(act_names, paste0("names(", act$lab, ")")) + return(expect_setequal_(act, exp)) } else { - act <- labelled_value(act_names, act$lab) - return(expect_waldo_equal_("equal", act, exp, error_prefix = "Names of ")) + act <- labelled_value(act_names, paste0("names(", act$lab, ")")) + return(expect_waldo_equal_("equal", act, exp)) } pass(act$val) diff --git a/R/expect-setequal.R b/R/expect-setequal.R index 9c46a8354..0436f0448 100644 --- a/R/expect-setequal.R +++ b/R/expect-setequal.R @@ -40,17 +40,13 @@ expect_setequal <- function(object, expected) { expect_setequal_ <- function( act, exp, - trace_env = caller_env(), - error_prefix = NULL + trace_env = caller_env() ) { act_miss <- unique(act$val[!act$val %in% exp$val]) exp_miss <- unique(exp$val[!exp$val %in% act$val]) if (length(exp_miss) || length(act_miss)) { msg <- paste0( - if (!is.null(error_prefix)) { - error_prefix - }, act$lab, " doesn't have the same values as ", exp$lab, diff --git a/tests/testthat/_snaps/expect-named.md b/tests/testthat/_snaps/expect-named.md index 35683b7eb..c635c68d4 100644 --- a/tests/testthat/_snaps/expect-named.md +++ b/tests/testthat/_snaps/expect-named.md @@ -4,47 +4,47 @@ # expected_named verifies actual of names - Names of Expected `c(a = 1)` to be equal to "b". + Expected names(`c(a = 1)`) to be equal to "b". `actual`: "a" `expected`: "b" # provide useful feedback on failure - Names of `c(a = 1)` doesn't have the same values as `c("a", "b")`. + names(`x1`) doesn't have the same values as `c("a", "b")`. * Only in `expected`: "b" --- - Names of `c(a = 1, b = 1)` doesn't have the same values as `c("a")`. + names(`x2`) doesn't have the same values as "a". * Only in `actual`: "b" --- - Names of `c(a = 1)` doesn't have the same values as `c("b")`. + names(`x1`) doesn't have the same values as "b". * Only in `actual`: "a" * Only in `expected`: "b" --- - Names of Expected `c(a = 1)` to be equal to `c("a", "b")`. + Expected names(`x1`) to be equal to `c("a", "b")`. `actual`: "a" `expected`: "a" "b" --- - Names of Expected `c(a = 1, b = 1)` to be equal to `c("a")`. + Expected names(`x2`) to be equal to "a". `actual`: "a" "b" `expected`: "a" --- - Names of Expected `c(a = 1)` to be equal to `c("b")`. + Expected names(`x1`) to be equal to `c("b")`. `actual`: "a" `expected`: "b" diff --git a/tests/testthat/test-expect-named.R b/tests/testthat/test-expect-named.R index 51fa50c95..8a79e92e2 100644 --- a/tests/testthat/test-expect-named.R +++ b/tests/testthat/test-expect-named.R @@ -8,38 +8,23 @@ test_that("expected_named verifies actual of names", { expect_snapshot_failure(expect_named(c(a = 1), "b")) }) -test_that("expected_named optionally ignores case", { - expect_success(expect_named(c(a = 1), "A", ignore.case = TRUE)) -}) - -test_that("expected_named optionally ignores order", { - expect_success(expect_named( - c(a = 1, b = 2), - c("b", "a"), - ignore.order = TRUE - )) +test_that("expected_named optionally ignores order and case", { + x <- c(a = 1, b = 2) + expect_success(expect_named(x, c("A", "B"), ignore.case = TRUE)) + expect_success(expect_named(x, c("b", "a"), ignore.order = TRUE)) }) test_that("provide useful feedback on failure", { - expect_snapshot_error( - expect_named(c(a = 1), c("a", "b"), ignore.order = TRUE) - ) - expect_snapshot_error( - expect_named(c(a = 1, b = 1), c("a"), ignore.order = TRUE) - ) - expect_snapshot_error( - expect_named(c(a = 1), c("b"), ignore.order = TRUE) - ) + x1 <- c(a = 1) + x2 <- c(a = 1, b = 2) - expect_snapshot_error( - expect_named(c(a = 1), c("a", "b"), ignore.order = FALSE) - ) - expect_snapshot_error( - expect_named(c(a = 1, b = 1), c("a"), ignore.order = FALSE) - ) - expect_snapshot_error( - expect_named(c(a = 1), c("b"), ignore.order = FALSE) - ) + expect_snapshot_failure(expect_named(x1, c("a", "b"), ignore.order = TRUE)) + expect_snapshot_failure(expect_named(x2, "a", ignore.order = TRUE)) + expect_snapshot_failure(expect_named(x1, "b", ignore.order = TRUE)) + + expect_snapshot_failure(expect_named(x1, c("a", "b"), ignore.order = FALSE)) + expect_snapshot_failure(expect_named(x2, "a", ignore.order = FALSE)) + expect_snapshot_failure(expect_named(x1, c("b"), ignore.order = FALSE)) }) test_that("expect_named validates its inputs", { From 9104922fb54f6663fbc5d3cbc777e4b170ae3ed8 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 14:30:22 -0500 Subject: [PATCH 13/20] More polishing --- R/expect-comparison.R | 28 +++---- R/expect-condition.R | 17 ++-- R/expect-no-condition.R | 11 ++- R/expect-output.R | 2 +- R/expect-setequal.R | 46 +++++------ R/expect-shape.R | 48 +++++------ R/expect-silent.R | 7 +- tests/testthat/_snaps/expect-no-condition.md | 24 +++--- .../_snaps/expect-no-condition.new.md | 80 +++++++++++++++++++ tests/testthat/_snaps/expect-output.md | 2 +- tests/testthat/_snaps/expect-setequal.md | 75 +++++++---------- tests/testthat/_snaps/expect-shape.md | 24 +++--- tests/testthat/_snaps/expect-silent.md | 6 +- tests/testthat/test-expect-shape.R | 1 - 14 files changed, 208 insertions(+), 163 deletions(-) create mode 100644 tests/testthat/_snaps/expect-no-condition.new.md diff --git a/R/expect-comparison.R b/R/expect-comparison.R index afb1172fc..40e16d09f 100644 --- a/R/expect-comparison.R +++ b/R/expect-comparison.R @@ -39,14 +39,12 @@ expect_compare_ <- function( } if (!isTRUE(cmp)) { diff <- act$val - exp$val - msg1 <- sprintf("Expected %s %s %s.", act$lab, operator, exp$lab) + msg_exp <- sprintf("Expected %s %s %s.", act$lab, operator, exp$lab) if (is.nan(diff)) { - msg2 <- "Actual values are incomparable." - msg3 <- NULL + msg_act <- "Actual values are incomparable." } else if (is.na(diff)) { - msg2 <- "Actual comparison is NA." - msg3 <- NULL + msg_act <- "Actual comparison is NA." } else { digits <- max( digits(act$val), @@ -54,19 +52,17 @@ expect_compare_ <- function( min_digits(act$val, exp$val) ) - msg2 <- sprintf( - "Actual %s %s %s", - num_exact(act$val, digits), - actual_op, - num_exact(exp$val, digits) - ) - msg3 <- sprintf( - "Difference %s %s 0", - num_exact(act$val - exp$val, digits), - actual_op + msg_act <- c( + sprintf( + "Actual %s %s %s", + num_exact(act$val, digits), + actual_op, + num_exact(exp$val, digits) + ), + sprintf("Difference %s %s 0", num_exact(diff, digits), actual_op) ) } - return(fail(c(msg1, msg2, msg3), trace_env = trace_env)) + return(fail(c(msg_exp, msg_act), trace_env = trace_env)) } pass(act$val) } diff --git a/R/expect-condition.R b/R/expect-condition.R index d840809d2..1d24032f8 100644 --- a/R/expect-condition.R +++ b/R/expect-condition.R @@ -454,12 +454,9 @@ compare_condition_3e <- function(cond_type, cond_class, cond, lab, expected) { } } else { if (!is.null(cond)) { - sprintf( - "Expected %s to not throw a %s.\nActual <%s>:\n%s", - lab, - cond_type, - paste(class(cond), collapse = "/"), - cnd_message(cond) + c( + sprintf("Expected %s to not throw a %s.", lab, cond_type), + actual_condition(cond) ) } else { NULL @@ -630,3 +627,11 @@ check_condition_dots <- function( call = error_call ) } + +actual_condition <- function(cond) { + sprintf( + "Actual <%s>:\n%s", + paste(class(cond), collapse = "/"), + cnd_message(cond) + ) +} diff --git a/R/expect-no-condition.R b/R/expect-no-condition.R index bd0376a0b..a253ab43c 100644 --- a/R/expect-no-condition.R +++ b/R/expect-no-condition.R @@ -108,9 +108,9 @@ expect_no_ <- function( act <- quasi_capture(enquo(object), NULL, capture) if (!is.null(first_match)) { - expected <- paste0( + exp_msg <- paste0( "Expected ", - quo_label(enquo(object)), + act$lab, " to run without any ", base_class, "s", @@ -118,14 +118,13 @@ expect_no_ <- function( if (!is.null(regexp)) paste0(" matching pattern '", regexp, "'"), "." ) - actual <- paste0( + act_msg <- paste0( "Actually got a <", class(first_match)[[1]], - "> with text:\n", + "> with message:\n", indent_lines(rlang::cnd_message(first_match)) ) - message <- format_error_bullets(c(expected, i = actual)) - return(fail(message, trace_env = trace_env)) + return(fail(c(exp_msg, act_msg), trace_env = trace_env)) } pass(act$val) diff --git a/R/expect-output.R b/R/expect-output.R index d5aaf0f68..4b120a62b 100644 --- a/R/expect-output.R +++ b/R/expect-output.R @@ -52,6 +52,6 @@ expect_output <- function( pass(act$val) } else { act <- labelled_value(act$cap, act$lab) - expect_match_(act, enc2native(regexp), ..., title = "Output") + expect_match_(act, enc2native(regexp), ..., title = "output") } } diff --git a/R/expect-setequal.R b/R/expect-setequal.R index 0436f0448..49e74a648 100644 --- a/R/expect-setequal.R +++ b/R/expect-setequal.R @@ -46,19 +46,17 @@ expect_setequal_ <- function( exp_miss <- unique(exp$val[!exp$val %in% act$val]) if (length(exp_miss) || length(act_miss)) { - msg <- paste0( + msg_exp <- sprintf( + "Expected %s to have the same values as %s.", act$lab, - " doesn't have the same values as ", - exp$lab, - ".\n", - if (length(act_miss)) { - paste0("* Only in `actual`: ", values(act_miss), "\n") - }, - if (length(exp_miss)) { - paste0("* Only in `expected`: ", values(exp_miss), "\n") - } + exp$lab ) - return(fail(msg, trace_env = trace_env)) + msg_act <- c( + if (length(act_miss)) sprintf("Needs: %s", values(act_miss)), + if (length(exp_miss)) sprintf("Extra: %s", values(exp_miss)) + ) + + return(fail(c(msg_exp, msg_act), trace_env = trace_env)) } pass(act$val) } @@ -101,14 +99,13 @@ expect_contains <- function(object, expected) { exp_miss <- !exp$val %in% act$val if (any(exp_miss)) { - return(fail(paste0( + msg_exp <- sprintf( + "Expected %s to contain all values in %s.", act$lab, - " doesn't fully contain all the values in ", - exp$lab, - ".\n", - paste0("* Missing from ", act$lab, ": ", values(exp$val[exp_miss]), "\n"), - paste0("* Present in ", act$lab, ": ", values(act$val), "\n") - ))) + exp$lab + ) + msg_act <- sprintf("Missing: %s", values(exp$val[exp_miss])) + fail(c(msg_exp, msg_act)) } pass(act$val) @@ -125,14 +122,13 @@ expect_in <- function(object, expected) { act_miss <- !act$val %in% exp$val if (any(act_miss)) { - return(fail(paste0( + msg_exp <- sprintf( + "Expected all values in %s to be in %s.", act$lab, - " isn't fully contained within ", - exp$lab, - ".\n", - paste0("* Missing from ", act$lab, ": ", values(act$val[act_miss]), "\n"), - paste0("* Present in ", act$lab, ": ", values(exp$val), "\n") - ))) + exp$lab + ) + msg_act <- sprintf("Extra: %s", values(act$val[act_miss])) + fail(c(msg_exp, msg_act)) } pass(act$val) diff --git a/R/expect-shape.R b/R/expect-shape.R index fd90246ed..570d94330 100644 --- a/R/expect-shape.R +++ b/R/expect-shape.R @@ -28,11 +28,9 @@ expect_length <- function(object, n) { act$n <- length(act$val) if (act$n != n) { - msg <- sprintf( - "Expected %s to have length %i.\nActual length: %i", - act$lab, - n, - act$n + msg <- c( + sprintf("Expected %s to have length %i.", act$lab, n), + sprintf("Actual length: %i.", act$n) ) return(fail(msg)) } @@ -59,11 +57,9 @@ expect_shape = function(object, ..., nrow, ncol, dim) { act$nrow <- dim_object[1L] if (!identical(as.integer(act$nrow), as.integer(nrow))) { - msg <- sprintf( - "Expected %s to have %i rows.\nActual rows: %i", - act$lab, - nrow, - act$nrow + msg <- c( + sprintf("Expected %s to have %i rows.", act$lab, nrow), + sprintf("Actual rows: %i.", act$nrow) ) return(fail(msg)) } @@ -71,20 +67,16 @@ expect_shape = function(object, ..., nrow, ncol, dim) { check_number_whole(ncol, allow_na = TRUE) if (length(dim_object) == 1L) { - return(fail(sprintf( - "Expected %s to have more than one dimension.", - act$lab - ))) + msg <- sprintf("Expected %s to have more than one dimension.", act$lab) + return(fail(msg)) } act$ncol <- dim_object[2L] if (!identical(as.integer(act$ncol), as.integer(ncol))) { - msg <- sprintf( - "Expected %s to have %i columns.\nActual columns: %i", - act$lab, - ncol, - act$ncol + msg <- c( + sprintf("Expected %s to have %i columns.", act$lab, ncol), + sprintf("Actual columns: %i.", act$ncol) ) return(fail(msg)) } @@ -96,20 +88,16 @@ expect_shape = function(object, ..., nrow, ncol, dim) { act$dim <- dim_object if (length(act$dim) != length(dim)) { - return(fail(sprintf( - "Expected %s to have %i dimensions.\nActual dimensions: %i", - act$lab, - length(dim), - length(act$dim) - ))) + msg <- c( + sprintf("Expected %s to have %i dimensions.", act$lab, length(dim)), + sprintf("Actual dimensions: %i.", length(act$dim)) + ) } if (!identical(as.integer(act$dim), as.integer(dim))) { - msg <- sprintf( - "Expected %s to have dim (%s).\nActual dim: (%s)", - act$lab, - toString(dim), - toString(act$dim) + msg <- c( + sprintf("Expected %s to have dim (%s).", act$lab, toString(dim)), + sprintf("Actual dim: (%s).", toString(act$dim)) ) return(fail(msg)) } diff --git a/R/expect-silent.R b/R/expect-silent.R index f94c6df3f..e29d508f4 100644 --- a/R/expect-silent.R +++ b/R/expect-silent.R @@ -27,10 +27,9 @@ expect_silent <- function(object) { ) if (length(outputs) != 0) { - msg <- sprintf( - "Expected %s to run silently.\nActually produced: %s", - act$lab, - paste(outputs, collapse = ", ") + msg <- c( + sprintf("Expected %s to run silently.", act$lab), + sprintf("Actually produced: %s.", paste(outputs, collapse = ", ")) ) return(fail(msg)) } diff --git a/tests/testthat/_snaps/expect-no-condition.md b/tests/testthat/_snaps/expect-no-condition.md index d355bedde..49d8d963b 100644 --- a/tests/testthat/_snaps/expect-no-condition.md +++ b/tests/testthat/_snaps/expect-no-condition.md @@ -1,50 +1,50 @@ # expect_no_* conditions behave as expected Expected `stop("error")` to run without any errors. - i Actually got a with text: + Actually got a with text: error --- Expected `warning("warning")` to run without any warnings. - i Actually got a with text: + Actually got a with text: warning --- Expected `message("message")` to run without any messages. - i Actually got a with text: + Actually got a with text: message --- Expected `abort("error")` to run without any errors. - i Actually got a with text: + Actually got a with text: error --- Expected `warn("warning")` to run without any warnings. - i Actually got a with text: + Actually got a with text: warning --- Expected `inform("message")` to run without any messages. - i Actually got a with text: + Actually got a with text: message # expect_no_ continues execution Expected `{ ... }` to run without any warnings. - i Actually got a with text: + Actually got a with text: x # expect_no_* don't emit success when they fail Expected `stop("!")` to run without any errors. - i Actually got a with text: + Actually got a with text: ! # matched conditions give informative message @@ -54,27 +54,27 @@ Condition Error: ! Expected `foo()` to run without any warnings. - i Actually got a with text: + Actually got a with text: This is a problem! Code expect_no_warning(foo(), message = "problem") Condition Error: ! Expected `foo()` to run without any warnings matching pattern 'problem'. - i Actually got a with text: + Actually got a with text: This is a problem! Code expect_no_warning(foo(), class = "test") Condition Error: ! Expected `foo()` to run without any warnings of class 'test'. - i Actually got a with text: + Actually got a with text: This is a problem! Code expect_no_warning(foo(), message = "problem", class = "test") Condition Error: ! Expected `foo()` to run without any warnings of class 'test' matching pattern 'problem'. - i Actually got a with text: + Actually got a with text: This is a problem! diff --git a/tests/testthat/_snaps/expect-no-condition.new.md b/tests/testthat/_snaps/expect-no-condition.new.md new file mode 100644 index 000000000..93cd251d9 --- /dev/null +++ b/tests/testthat/_snaps/expect-no-condition.new.md @@ -0,0 +1,80 @@ +# expect_no_* conditions behave as expected + + Expected `stop("error")` to run without any errors. + Actually got a with message: + error + +--- + + Expected `warning("warning")` to run without any warnings. + Actually got a with message: + warning + +--- + + Expected `message("message")` to run without any messages. + Actually got a with message: + message + + +--- + + Expected `abort("error")` to run without any errors. + Actually got a with message: + error + +--- + + Expected `warn("warning")` to run without any warnings. + Actually got a with message: + warning + +--- + + Expected `inform("message")` to run without any messages. + Actually got a with message: + message + +# expect_no_ continues execution + + Expected `{ ... }` to run without any warnings. + Actually got a with message: + x + +# expect_no_* don't emit success when they fail + + Expected `stop("!")` to run without any errors. + Actually got a with message: + ! + +# matched conditions give informative message + + Code + expect_no_warning(foo()) + Condition + Error: + ! Expected `foo()` to run without any warnings. + Actually got a with message: + This is a problem! + Code + expect_no_warning(foo(), message = "problem") + Condition + Error: + ! Expected `foo()` to run without any warnings matching pattern 'problem'. + Actually got a with message: + This is a problem! + Code + expect_no_warning(foo(), class = "test") + Condition + Error: + ! Expected `foo()` to run without any warnings of class 'test'. + Actually got a with message: + This is a problem! + Code + expect_no_warning(foo(), message = "problem", class = "test") + Condition + Error: + ! Expected `foo()` to run without any warnings of class 'test' matching pattern 'problem'. + Actually got a with message: + This is a problem! + diff --git a/tests/testthat/_snaps/expect-output.md b/tests/testthat/_snaps/expect-output.md index a8b18d8fc..8255bc8be 100644 --- a/tests/testthat/_snaps/expect-output.md +++ b/tests/testthat/_snaps/expect-output.md @@ -11,7 +11,7 @@ # expect = string checks for match Expected `g()` to match regexp "x". - Actual Output: + Actual output: ! --- diff --git a/tests/testthat/_snaps/expect-setequal.md b/tests/testthat/_snaps/expect-setequal.md index bb2ff35a9..2e1fdbadb 100644 --- a/tests/testthat/_snaps/expect-setequal.md +++ b/tests/testthat/_snaps/expect-setequal.md @@ -1,14 +1,12 @@ # checks both directions of containment - `letters` doesn't have the same values as `letters[-1]`. - * Only in `actual`: "a" - + Expected `letters` to have the same values as `letters[-1]`. + Needs: "a" --- - `letters[-1]` doesn't have the same values as `letters`. - * Only in `expected`: "a" - + Expected `letters[-1]` to have the same values as `letters`. + Extra: "a" # warns if both inputs are named @@ -33,48 +31,41 @@ # useful message on failure - "actual" doesn't have the same values as "expected". - * Only in `actual`: "actual" - * Only in `expected`: "expected" - + Expected "actual" to have the same values as "expected". + Needs: "actual" + Extra: "expected" --- - `x` doesn't have the same values as `y`. - * Only in `actual`: 1 - + Expected `x` to have the same values as `y`. + Needs: 1 --- - `x` doesn't have the same values as `y`. - * Only in `expected`: 3 - + Expected `x` to have the same values as `y`. + Extra: 3 --- - `x` doesn't have the same values as `y`. - * Only in `actual`: 1 - * Only in `expected`: 3 - + Expected `x` to have the same values as `y`. + Needs: 1 + Extra: 3 --- - `x` doesn't have the same values as `y`. - * Only in `actual`: "a" - * Only in `expected`: "b" - + Expected `x` to have the same values as `y`. + Needs: "a" + Extra: "b" --- - `x` doesn't have the same values as `c("a", "b", "c", "d")`. - * Only in `expected`: "d" - + Expected `x` to have the same values as `c("a", "b", "c", "d")`. + Extra: "d" # truncates long vectors - `x` doesn't have the same values as `y`. - * Only in `expected`: 3, 4, 5, 6, 7, 8, 9, 10, 11, ... - + Expected `x` to have the same values as `y`. + Extra: 3, 4, 5, 6, 7, 8, 9, 10, 11, ... # error if any names are duplicated @@ -163,29 +154,21 @@ # expect_contains() gives useful message on failure - `x1` doesn't fully contain all the values in `x2`. - * Missing from `x1`: "d" - * Present in `x1`: "a", "b", "c" - + Expected `x1` to contain all values in `x2`. + Missing: "d" --- - `x1` doesn't fully contain all the values in `x3`. - * Missing from `x1`: "d", "e" - * Present in `x1`: "a", "b", "c" - + Expected `x1` to contain all values in `x3`. + Missing: "d", "e" # expect_in() gives useful message on failure - `x1` isn't fully contained within `x2`. - * Missing from `x1`: "a" - * Present in `x1`: "b", "c" - + Expected all values in `x1` to be in `x2`. + Extra: "a" --- - `x1` isn't fully contained within `x3`. - * Missing from `x1`: "a", "b" - * Present in `x1`: "d", "e" - + Expected all values in `x1` to be in `x3`. + Extra: "a", "b" diff --git a/tests/testthat/_snaps/expect-shape.md b/tests/testthat/_snaps/expect-shape.md index b9dfcf917..8786ea343 100644 --- a/tests/testthat/_snaps/expect-shape.md +++ b/tests/testthat/_snaps/expect-shape.md @@ -1,7 +1,7 @@ # generates actionable failure message Expected `x` to have length 2. - Actual length: 10 + Actual length: 10. # expect_length validates its inputs @@ -14,27 +14,27 @@ # dim compared correctly Expected `matrix(nrow = 6, ncol = 3)` to have dim (6, 2). - Actual dim: (6, 3) + Actual dim: (6, 3). --- Expected `matrix(nrow = 6, ncol = 3)` to have dim (7, 3). - Actual dim: (6, 3) + Actual dim: (6, 3). --- - Expected `array(dim = 1:3)` to have 2 dimensions. - Actual dimensions: 3 + Expected `array(dim = 1:3)` to have dim (1, 2). + Actual dim: (1, 2, 3). --- - Expected `array(dim = 1:3)` to have 4 dimensions. - Actual dimensions: 3 + Expected `array(dim = 1:3)` to have dim (1, 2, 3, 4). + Actual dim: (1, 2, 3). # nrow compared correctly Expected `matrix(nrow = 5, ncol = 5)` to have 6 rows. - Actual rows: 5 + Actual rows: 5. --- @@ -43,7 +43,7 @@ # ncol compared correctly Expected `matrix(nrow = 5, ncol = 5)` to have 7 columns. - Actual columns: 5 + Actual columns: 5. --- @@ -56,17 +56,17 @@ # NA handling (e.g. dbplyr) Expected `x` to have 10 rows. - Actual rows: NA + Actual rows: NA. --- Expected `x` to have NA columns. - Actual columns: 10 + Actual columns: 10. --- Expected `x` to have dim (10, NA). - Actual dim: (NA, 10) + Actual dim: (NA, 10). # checks inputs arguments, diff --git a/tests/testthat/_snaps/expect-silent.md b/tests/testthat/_snaps/expect-silent.md index 983506e3f..2f873f089 100644 --- a/tests/testthat/_snaps/expect-silent.md +++ b/tests/testthat/_snaps/expect-silent.md @@ -1,15 +1,15 @@ # checks for any type of output Expected `warning("!")` to run silently. - Actually produced: warnings + Actually produced: warnings. --- Expected `message("!")` to run silently. - Actually produced: messages + Actually produced: messages. --- Expected `print("!")` to run silently. - Actually produced: output + Actually produced: output. diff --git a/tests/testthat/test-expect-shape.R b/tests/testthat/test-expect-shape.R index 3c21b61b5..ce0de5a11 100644 --- a/tests/testthat/test-expect-shape.R +++ b/tests/testthat/test-expect-shape.R @@ -7,7 +7,6 @@ test_that("length computed correctly", { test_that("generates actionable failure message", { x <- 1:10 expect_snapshot_failure(expect_length(x, 2)) - expect_length(x, 15) }) test_that("uses S4 length method", { From 61f8babd6966a0f283553c018e9c2a79c917d1a5 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 14:45:15 -0500 Subject: [PATCH 14/20] Revert expect-known changes --- tests/testthat/test-expect-known.R | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/tests/testthat/test-expect-known.R b/tests/testthat/test-expect-known.R index 7146e63d2..ea0aec954 100644 --- a/tests/testthat/test-expect-known.R +++ b/tests/testthat/test-expect-known.R @@ -24,21 +24,17 @@ test_that("ignores incomplete last line", { writeLines("Hi!", file) expect_success(expect_known_output(cat("Hi!"), file)) expect_success(expect_known_output(cat("Hi!\n"), file)) - expect_snapshot_failure(expect_known_output(cat("Hi!\n\n"), file)) - expect_snapshot_failure(expect_known_output(cat("oops"), file)) + expect_failure(expect_known_output(cat("Hi!\n\n"), file)) + expect_failure(expect_known_output(cat("oops"), file)) }) test_that("updates by default", { file <- withr::local_tempfile() writeLines("Hi!", file) - expect_snapshot_failure(expect_known_output( - cat("oops"), - file, - update = FALSE - )) + expect_failure(expect_known_output(cat("oops"), file, update = FALSE)) expect_equal(readLines(file), "Hi!") - expect_snapshot_failure(expect_known_output(cat("oops"), file, update = TRUE)) + expect_failure(expect_known_output(cat("oops"), file, update = TRUE)) expect_success(expect_known_output(cat("oops"), file)) }) @@ -59,7 +55,7 @@ test_that("Warning for non-UTF-8 reference files", { writeBin(x, tmp) suppressWarnings( - expect_snapshot_failure( + expect_failure( expect_known_output("foobar", tmp, update = FALSE) ) ) @@ -73,7 +69,7 @@ test_that("correctly matches to a file", { expect_success(expect_known_value(x, "one.rds")) x <- 2 - expect_snapshot_failure(expect_known_value(x, "one.rds", update = FALSE)) + expect_failure(expect_known_value(x, "one.rds", update = FALSE)) }) test_that("first run is successful", { @@ -93,15 +89,11 @@ test_that("equal_to_ref does not overwrite existing", { expect_success(expect_equal_to_reference(ref_obj1, tmp_rds)) # Failure does not update object - expect_snapshot_failure(expect_equal_to_reference(ref_obj2, tmp_rds)) + expect_failure(expect_equal_to_reference(ref_obj2, tmp_rds)) expect_equal(readRDS(tmp_rds), ref_obj1) # Now failure does update object - expect_snapshot_failure(expect_equal_to_reference( - ref_obj2, - tmp_rds, - update = TRUE - )) + expect_failure(expect_equal_to_reference(ref_obj2, tmp_rds, update = TRUE)) expect_success(expect_equal_to_reference(ref_obj2, tmp_rds)) }) @@ -139,5 +131,5 @@ test_that("empty hash succeeds with warning", { test_that("only succeeds if hash is correct", { expect_success(expect_known_hash(1:10, "c08951d2c2")) - expect_snapshot_failure(expect_known_hash(1:10, "c08951d2c3")) + expect_failure(expect_known_hash(1:10, "c08951d2c3")) }) From f3291e7ace22cdd7650aded91224f5793746334d Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 14:47:57 -0500 Subject: [PATCH 15/20] Show everything in snapshot. Fix failures --- R/expect-self-test.R | 3 +- R/snapshot.R | 42 ++- tests/testthat/_snaps/expect-comparison.md | 140 ++++++--- tests/testthat/_snaps/expect-condition.md | 119 +++++--- tests/testthat/_snaps/expect-constant.md | 64 +++-- tests/testthat/_snaps/expect-equality.md | 194 ++++++++----- tests/testthat/_snaps/expect-inheritance.md | 114 ++++++-- tests/testthat/_snaps/expect-invisible.md | 32 ++- tests/testthat/_snaps/expect-known.md | 62 ---- tests/testthat/_snaps/expect-match.md | 84 ++++-- tests/testthat/_snaps/expect-named.md | 83 ++++-- tests/testthat/_snaps/expect-no-condition.md | 93 ++++-- .../_snaps/expect-no-condition.new.md | 80 ------ tests/testthat/_snaps/expect-output.md | 32 ++- tests/testthat/_snaps/expect-reference.md | 6 +- tests/testthat/_snaps/expect-self-test.md | 89 ++++-- tests/testthat/_snaps/expect-setequal.md | 266 ++++++++++++------ tests/testthat/_snaps/expect-shape.md | 98 +++++-- tests/testthat/_snaps/expect-silent.md | 24 +- tests/testthat/_snaps/expect-vector.md | 6 +- tests/testthat/_snaps/expectation.md | 8 +- tests/testthat/_snaps/old-school.md | 10 +- tests/testthat/_snaps/snapshot.md | 6 +- tests/testthat/test-quasi-label.R | 2 +- tests/testthat/test-snapshot-file.R | 2 +- tests/testthat/test-snapshot-reporter.R | 8 +- 26 files changed, 1080 insertions(+), 587 deletions(-) delete mode 100644 tests/testthat/_snaps/expect-known.md delete mode 100644 tests/testthat/_snaps/expect-no-condition.new.md diff --git a/R/expect-self-test.R b/R/expect-self-test.R index 45c4eb77d..942e3c053 100644 --- a/R/expect-self-test.R +++ b/R/expect-self-test.R @@ -94,7 +94,8 @@ expect_failure <- function(expr, message = NULL, ...) { #' @export #' @rdname expect_success expect_snapshot_failure <- function(expr) { - expect_snapshot_condition_("expectation_failure", expr) + expr <- enquo0(expr) + expect_snapshot_(expr, error = TRUE, error_class = "expectation_failure") } #' Test for absence of success or failure diff --git a/R/snapshot.R b/R/snapshot.R index fb860c1e2..af98c24d9 100644 --- a/R/snapshot.R +++ b/R/snapshot.R @@ -68,18 +68,38 @@ expect_snapshot <- function( variant = NULL, cnd_class = FALSE ) { - check_bool(cran) - check_bool(error) - check_bool(cnd_class) - edition_require(3, "expect_snapshot()") + + x <- enquo0(x) + expect_snapshot_( + x, + cran = cran, + error = error, + transform = transform, + variant = variant, + cnd_class = cnd_class + ) +} + +expect_snapshot_ <- function( + x, + cran = TRUE, + error = FALSE, + error_class = NULL, + transform = NULL, + variant = NULL, + cnd_class = FALSE, + error_frame = caller_env() +) { + check_bool(cran, call = error_frame) + check_bool(error, call = error_frame) + check_bool(cnd_class, call = error_frame) + variant <- check_variant(variant) if (!is.null(transform)) { transform <- as_function(transform) } - x <- enquo0(x) - # Execute code, capturing last error state <- new_environment(list(error = NULL)) replay <- function(x) { @@ -95,7 +115,13 @@ expect_snapshot <- function( ) # Use expect_error() machinery to confirm that error is as expected - msg <- compare_condition_3e("error", NULL, state$error, quo_label(x), error) + msg <- compare_condition_3e( + cond_type = "error", + cond_class = error_class, + cond = state$error, + lab = quo_label(x), + expected = error + ) if (!is.null(msg)) { if (error) { return(fail(msg, trace = state$error[["trace"]])) @@ -112,7 +138,7 @@ expect_snapshot <- function( save = function(x) paste0(x, collapse = "\n"), load = function(x) split_by_line(x)[[1]], variant = variant, - trace_env = caller_env() + trace_env = error_frame ) } diff --git a/tests/testthat/_snaps/expect-comparison.md b/tests/testthat/_snaps/expect-comparison.md index d3d05e1a3..4a52df96a 100644 --- a/tests/testthat/_snaps/expect-comparison.md +++ b/tests/testthat/_snaps/expect-comparison.md @@ -1,88 +1,152 @@ # basic comparisons work - Expected 10 < 10. - Actual 10.0 >= 10.0 - Difference 0.0 >= 0 + Code + expect_lt(10, 10) + Condition + Error: + ! Expected 10 < 10. + Actual 10.0 >= 10.0 + Difference 0.0 >= 0 --- - Expected 10 > 10. - Actual 10.0 <= 10.0 - Difference 0.0 <= 0 + Code + expect_gt(10, 10) + Condition + Error: + ! Expected 10 > 10. + Actual 10.0 <= 10.0 + Difference 0.0 <= 0 # useful output when numbers are very small - Expected `1.1 * x` <= `x`. - Actual 0.0000110 > 0.0000100 - Difference 0.0000010 > 0 + Code + expect_lte(1.1 * x, x) + Condition + Error: + ! Expected `1.1 * x` <= `x`. + Actual 0.0000110 > 0.0000100 + Difference 0.0000010 > 0 --- - Expected `x` > `1.1 * x`. - Actual 0.0000100 <= 0.0000110 - Difference -0.0000010 <= 0 + Code + expect_gt(x, 1.1 * x) + Condition + Error: + ! Expected `x` > `1.1 * x`. + Actual 0.0000100 <= 0.0000110 + Difference -0.0000010 <= 0 # useful output when difference is zero - Expected `x` < 100. - Actual 100.0 >= 100.0 - Difference 0.0 >= 0 + Code + expect_lt(x, 100) + Condition + Error: + ! Expected `x` < 100. + Actual 100.0 >= 100.0 + Difference 0.0 >= 0 # useful output when differnce is large - Expected `x` < 0.001. - Actual 100.000 >= 0.001 - Difference 99.999 >= 0 + Code + expect_lt(x, 0.001) + Condition + Error: + ! Expected `x` < 0.001. + Actual 100.000 >= 0.001 + Difference 99.999 >= 0 # comparisons with Inf work - Expected Inf < Inf. - Actual values are incomparable. + Code + expect_lt(Inf, Inf) + Condition + Error: + ! Expected Inf < Inf. + Actual values are incomparable. --- - Expected Inf > Inf. - Actual values are incomparable. + Code + expect_gt(Inf, Inf) + Condition + Error: + ! Expected Inf > Inf. + Actual values are incomparable. # comparisons with NA work - Expected 10 < NA_real_. - Actual comparison is NA. + Code + expect_lt(10, NA_real_) + Condition + Error: + ! Expected 10 < NA_real_. + Actual comparison is NA. --- - Expected NA_real_ < 10. - Actual comparison is NA. + Code + expect_lt(NA_real_, 10) + Condition + Error: + ! Expected NA_real_ < 10. + Actual comparison is NA. --- - Expected NA_real_ < NA_real_. - Actual comparison is NA. + Code + expect_lt(NA_real_, NA_real_) + Condition + Error: + ! Expected NA_real_ < NA_real_. + Actual comparison is NA. --- - Expected NA_real_ <= NA_real_. - Actual comparison is NA. + Code + expect_lte(NA_real_, NA_real_) + Condition + Error: + ! Expected NA_real_ <= NA_real_. + Actual comparison is NA. --- - Expected 10 > NA_real_. - Actual comparison is NA. + Code + expect_gt(10, NA_real_) + Condition + Error: + ! Expected 10 > NA_real_. + Actual comparison is NA. --- - Expected NA_real_ > 10. - Actual comparison is NA. + Code + expect_gt(NA_real_, 10) + Condition + Error: + ! Expected NA_real_ > 10. + Actual comparison is NA. --- - Expected NA_real_ > NA_real_. - Actual comparison is NA. + Code + expect_gt(NA_real_, NA_real_) + Condition + Error: + ! Expected NA_real_ > NA_real_. + Actual comparison is NA. --- - Expected NA_real_ >= NA_real_. - Actual comparison is NA. + Code + expect_gte(NA_real_, NA_real_) + Condition + Error: + ! Expected NA_real_ >= NA_real_. + Actual comparison is NA. # comparison must yield a single logical diff --git a/tests/testthat/_snaps/expect-condition.md b/tests/testthat/_snaps/expect-condition.md index 654070de7..93675519d 100644 --- a/tests/testthat/_snaps/expect-condition.md +++ b/tests/testthat/_snaps/expect-condition.md @@ -1,16 +1,28 @@ # regexp = NULL checks for presence of error - Expected `f()` to throw a error. + Code + expect_error(f()) + Condition + Error: + ! Expected `f()` to throw a error. # regexp = NA checks for absence of error - Expected `stop("Yes")` to not throw a error. - Actual : - Yes + Code + expect_error(stop("Yes"), NA) + Condition + Error: + ! Expected `stop("Yes")` to not throw a error. + Actual : + Yes # regexp = string matches for error message - Expected "OK" to throw a error. + Code + expect_error("OK", "No") + Condition + Error: + ! Expected "OK" to throw a error. # expect_error validates its inputs @@ -32,9 +44,13 @@ # message method is called when expecting error - Expected `fb()` to not throw a error. - Actual : - dispatched! + Code + expect_error(fb(), NA) + Condition + Error: + ! Expected `fb()` to not throw a error. + Actual : + dispatched! # expect_warning validates its inputs @@ -61,10 +77,13 @@ # regexp = NA checks for absence of message - Expected `message("!")` to not throw a message. - Actual : - ! - + Code + expect_message(message("!"), NA) + Condition + Error: + ! Expected `message("!")` to not throw a message. + Actual : + ! # expect_message validates its inputs @@ -91,7 +110,11 @@ # condition class is included in failure - Expected `f1()` to throw a condition with class . + Code + expect_condition(f1(), class = "bar") + Condition + Error: + ! Expected `f1()` to throw a condition with class . # expect_condition validates its inputs @@ -151,43 +174,65 @@ # other conditions are swallowed - `f("error")` threw an error with unexpected message. - Expected match: "not a match" - Actual message: "error" + Code + expect_error(f("error"), "not a match") + Condition + Error: + ! `f("error")` threw an error with unexpected message. + Expected match: "not a match" + Actual message: "error" --- - `f("warning")` produced unexpected warnings. - Expected match: not a match - Actual values: - * warning + Code + expect_warning(f("warning"), "not a match") + Condition + Error: + ! `f("warning")` produced unexpected warnings. + Expected match: not a match + Actual values: + * warning --- - `f("message")` produced unexpected messages. - Expected match: not a match - Actual values: - * message - + Code + expect_message(f("message"), "not a match") + Condition + Error: + ! `f("message")` produced unexpected messages. + Expected match: not a match + Actual values: + * message --- - `f("condition")` threw an condition with unexpected message. - Expected match: "not a match" - Actual message: "signal" + Code + expect_condition(f("condition"), "not a match") + Condition + Error: + ! `f("condition")` threw an condition with unexpected message. + Expected match: "not a match" + Actual message: "signal" --- - `f("error")` threw an error with unexpected class. - Expected class: not a match - Actual class: simpleError/error/condition - Message: error + Code + expect_error(f("error"), class = "not a match") + Condition + Error: + ! `f("error")` threw an error with unexpected class. + Expected class: not a match + Actual class: simpleError/error/condition + Message: error --- - `f("message")` threw an condition with unexpected class. - Expected class: not a match - Actual class: simpleMessage/message/condition - Message: message - + Code + expect_condition(f("message"), class = "not a match") + Condition + Error: + ! `f("message")` threw an condition with unexpected class. + Expected class: not a match + Actual class: simpleMessage/message/condition + Message: message diff --git a/tests/testthat/_snaps/expect-constant.md b/tests/testthat/_snaps/expect-constant.md index 372e7e1f2..5c01263cf 100644 --- a/tests/testthat/_snaps/expect-constant.md +++ b/tests/testthat/_snaps/expect-constant.md @@ -1,37 +1,57 @@ # logical tests act as expected - Expected `df` to be equal to TRUE. - - `actual` is an S3 object of class , a list - `expected` is a logical vector (TRUE) + Code + expect_true(df) + Condition + Error: + ! Expected `df` to be equal to TRUE. + + `actual` is an S3 object of class , a list + `expected` is a logical vector (TRUE) --- - Expected `df` to be equal to FALSE. - - `actual` is an S3 object of class , a list - `expected` is a logical vector (FALSE) + Code + expect_false(df) + Condition + Error: + ! Expected `df` to be equal to FALSE. + + `actual` is an S3 object of class , a list + `expected` is a logical vector (FALSE) # additional info returned in message - Expected FALSE to be equal to TRUE. - - `actual`: FALSE - `expected`: TRUE - NOPE + Code + expect_true(FALSE, "NOPE") + Condition + Error: + ! Expected FALSE to be equal to TRUE. + + `actual`: FALSE + `expected`: TRUE + NOPE --- - Expected TRUE to be equal to FALSE. - - `actual`: TRUE - `expected`: FALSE - YUP + Code + expect_false(TRUE, "YUP") + Condition + Error: + ! Expected TRUE to be equal to FALSE. + + `actual`: TRUE + `expected`: FALSE + YUP # expect_null works - Expected `df` to be equal to FALSE. - - `actual` is an S3 object of class , a list - `expected` is NULL + Code + expect_null(df) + Condition + Error: + ! Expected `df` to be equal to FALSE. + + `actual` is an S3 object of class , a list + `expected` is NULL diff --git a/tests/testthat/_snaps/expect-equality.md b/tests/testthat/_snaps/expect-equality.md index 3e806d5d8..b023f9540 100644 --- a/tests/testthat/_snaps/expect-equality.md +++ b/tests/testthat/_snaps/expect-equality.md @@ -1,116 +1,184 @@ # basical principles of equality hold - Expected 1 to equal 2. - Actual: - 1/1 mismatches - [1] 1 - 2 == -1 + Code + expect_equal(1, 2) + Condition + Error: + ! Expected 1 to equal 2. + Actual: + 1/1 mismatches + [1] 1 - 2 == -1 --- - Expected 1 to be identical to 2. - 1/1 mismatches - [1] 1 - 2 == -1 + Code + expect_identical(1, 2) + Condition + Error: + ! Expected 1 to be identical to 2. + 1/1 mismatches + [1] 1 - 2 == -1 --- - Expected 1 to be equal to 2. - - `actual`: 1.0 - `expected`: 2.0 + Code + expect_equal(1, 2) + Condition + Error: + ! Expected 1 to be equal to 2. + + `actual`: 1.0 + `expected`: 2.0 --- - Expected 1 to be identical to 2. - - `actual`: 1.0 - `expected`: 2.0 + Code + expect_identical(1, 2) + Condition + Error: + ! Expected 1 to be identical to 2. + + `actual`: 1.0 + `expected`: 2.0 # expect_equal() ignores numeric type; expect_identical() does not - Expected 1 to be identical to 1L. - Objects equal but not identical + Code + expect_identical(1, 1L) + Condition + Error: + ! Expected 1 to be identical to 1L. + Objects equal but not identical --- - Expected 1 to be identical to 1L. - - `actual` is a double vector (1) - `expected` is an integer vector (1) + Code + expect_identical(1, 1L) + Condition + Error: + ! Expected 1 to be identical to 1L. + + `actual` is a double vector (1) + `expected` is an integer vector (1) # can control numeric tolerance - Expected `x1` to equal `x2`. - Actual: - 1/1 mismatches - [1] 1 - 1 == -1e-06 + Code + expect_equal(x1, x2) + Condition + Error: + ! Expected `x1` to equal `x2`. + Actual: + 1/1 mismatches + [1] 1 - 1 == -1e-06 --- - Expected `x1` to be equal to `x2`. - - `actual`: 1.0000000 - `expected`: 1.0000010 + Code + expect_equal(x1, x2) + Condition + Error: + ! Expected `x1` to be equal to `x2`. + + `actual`: 1.0000000 + `expected`: 1.0000010 # provide useful feedback on failure - Expected `x` to be identical to "a". - - `actual` is a double vector (1) - `expected` is a character vector ('a') + Code + expect_identical(x, "a") + Condition + Error: + ! Expected `x` to be identical to "a". + + `actual` is a double vector (1) + `expected` is a character vector ('a') --- - Expected `x` to be equal to "a". - - `actual` is a double vector (1) - `expected` is a character vector ('a') + Code + expect_equal(x, "a") + Condition + Error: + ! Expected `x` to be equal to "a". + + `actual` is a double vector (1) + `expected` is a character vector ('a') --- - Expected `x` to be identical to "a". - Types not compatible: double is not character + Code + expect_identical(x, "a") + Condition + Error: + ! Expected `x` to be identical to "a". + Types not compatible: double is not character --- - Expected `x` to equal "a". - Actual: - Types not compatible: double is not character + Code + expect_equal(x, "a") + Condition + Error: + ! Expected `x` to equal "a". + Actual: + Types not compatible: double is not character # default labels use unquoting - Expected 1 to equal 2. - Actual: - 1/1 mismatches - [1] 1 - 2 == -1 + Code + expect_equal(1, !!x) + Condition + Error: + ! Expected 1 to equal 2. + Actual: + 1/1 mismatches + [1] 1 - 2 == -1 # % is not treated as sprintf format specifier (#445) - Expected "+" to be equal to "%". - - `actual`: "+" - `expected`: "%" + Code + expect_equal("+", "%") + Condition + Error: + ! Expected "+" to be equal to "%". + + `actual`: "+" + `expected`: "%" --- - Expected "%" to be equal to "+". - - `actual`: "%" - `expected`: "+" + Code + expect_equal("%", "+") + Condition + Error: + ! Expected "%" to be equal to "+". + + `actual`: "%" + `expected`: "+" # useful message if objects equal but not identical - Expected `f` to be identical to `g`. - names for target but not for current - Length mismatch: comparison on first 0 components + Code + expect_identical(f, g) + Condition + Error: + ! Expected `f` to be identical to `g`. + names for target but not for current + Length mismatch: comparison on first 0 components # attributes for object (#452) - Expected `oops` to equal 0. - Actual: - Attributes: < Modes: list, NULL > - Attributes: < Lengths: 1, 0 > - Attributes: < names for target but not for current > - Attributes: < current is not list-like > + Code + expect_equal(oops, 0) + Condition + Error: + ! Expected `oops` to equal 0. + Actual: + Attributes: < Modes: list, NULL > + Attributes: < Lengths: 1, 0 > + Attributes: < names for target but not for current > + Attributes: < current is not list-like > # expect_equal validates its inputs diff --git a/tests/testthat/_snaps/expect-inheritance.md b/tests/testthat/_snaps/expect-inheritance.md index ecfaf3cfc..7bed811aa 100644 --- a/tests/testthat/_snaps/expect-inheritance.md +++ b/tests/testthat/_snaps/expect-inheritance.md @@ -1,7 +1,11 @@ # expect_type checks typeof - Expected `x` to have type 'double'. - Actual type: 'integer' + Code + expect_type(x, "double") + Condition + Error: + ! Expected `x` to have type 'double'. + Actual type: 'integer' # expect_type validates its inputs @@ -13,36 +17,64 @@ # expect_is checks class - Expected `factor("a")` to inherit from `'character'`. - Actual inheritance: `'factor'` + Code + expect_is(factor("a"), "integer") + Condition + Error: + ! Expected `factor("a")` to inherit from `'character'`. + Actual inheritance: `'factor'` # expect_s3/s4_class fails if appropriate type - Expected `x1` to be an S3 object. - Actually is a base object. + Code + expect_s3_class(x1, "double") + Condition + Error: + ! Expected `x1` to be an S3 object. + Actually is a base object. --- - Expected `x2` to be an S3 object. - Actually is a S4 object. + Code + expect_s3_class(x2, "double") + Condition + Error: + ! Expected `x2` to be an S3 object. + Actually is a S4 object. --- - Expected `x3` to be an S4 object. - Actually is a S3 object. + Code + expect_s4_class(x3, "double") + Condition + Error: + ! Expected `x3` to be an S4 object. + Actually is a S3 object. # expect_s[34]_class can check not S3/S4 - Expected `factor()` to not be an S3 object. + Code + expect_s3_class(factor(), NA) + Condition + Error: + ! Expected `factor()` to not be an S3 object. --- - Expected `A()` to not be an S4 object. + Code + expect_s4_class(A(), NA) + Condition + Error: + ! Expected `A()` to not be an S4 object. # test_s4_class respects class hierarchy - Expected `C()` to inherit from 'D'. - Actual class: 'C'/'A'/'B'/'list'/'vector' + Code + expect_s4_class(C(), "D") + Condition + Error: + ! Expected `C()` to inherit from 'D'. + Actual class: 'C'/'A'/'B'/'list'/'vector' # expect_s3_class validates its inputs @@ -59,18 +91,30 @@ # test_s3_class respects class hierarchy - Expected `x` to inherit from 'c'. - Actual class: 'a'/'b' + Code + expect_s3_class(x, "c") + Condition + Error: + ! Expected `x` to inherit from 'c'. + Actual class: 'a'/'b' --- - Expected `x` to inherit from 'c'/'d'. - Actual class: 'a'/'b' + Code + expect_s3_class(x, c("c", "d")) + Condition + Error: + ! Expected `x` to inherit from 'c'/'d'. + Actual class: 'a'/'b' # test_s3_class can request exact match - Expected `x` to have class 'a'. - Actual class: 'a'/'b' + Code + expect_s3_class(x, "a", exact = TRUE) + Condition + Error: + ! Expected `x` to have class 'a'. + Actual class: 'a'/'b' # expect_s4_class validates its inputs @@ -82,8 +126,18 @@ # expect_r6_class generates useful failures - Expected `x` to be an R6 object. - Actually is a base object. + Code + expect_r6_class(x, "Student") + Condition + Error: + ! Expected `x` to be an R6 object. + Actually is a base object. + Code + expect_r6_class(person, "Student") + Condition + Error: + ! Expected `person` to inherit from 'Student'. + Actual class: 'Person'/'R6' # expect_r6_class validates its inputs @@ -95,13 +149,21 @@ # can check with actual class - Expected `Foo()` to inherit from . - Actual class: + Code + expect_s7_class(Foo(), class = Bar) + Condition + Error: + ! Expected `Foo()` to inherit from . + Actual class: --- - Expected `Baz()` to inherit from . - Actual class: / + Code + expect_s7_class(Baz(), class = Bar) + Condition + Error: + ! Expected `Baz()` to inherit from . + Actual class: / # expect_s7_class validates its inputs diff --git a/tests/testthat/_snaps/expect-invisible.md b/tests/testthat/_snaps/expect-invisible.md index 04cfe873b..1a8b3812c 100644 --- a/tests/testthat/_snaps/expect-invisible.md +++ b/tests/testthat/_snaps/expect-invisible.md @@ -1,20 +1,36 @@ # basic principles of visibility hold - Expected `x` to return invisibly. - Actually returned visibly. + Code + expect_invisible(x) + Condition + Error: + ! Expected `x` to return invisibly. + Actually returned visibly. --- - Expected `x <- 1` to return visibly. - Actually returned invisibly. + Code + expect_visible(x <- 1) + Condition + Error: + ! Expected `x <- 1` to return visibly. + Actually returned invisibly. # generates useful failure messages - Expected `invisible(1)` to return visibly. - Actually returned invisibly. + Code + expect_visible(invisible(1)) + Condition + Error: + ! Expected `invisible(1)` to return visibly. + Actually returned invisibly. --- - Expected 1 to return invisibly. - Actually returned visibly. + Code + expect_invisible(1) + Condition + Error: + ! Expected 1 to return invisibly. + Actually returned visibly. diff --git a/tests/testthat/_snaps/expect-known.md b/tests/testthat/_snaps/expect-known.md deleted file mode 100644 index 420d2057b..000000000 --- a/tests/testthat/_snaps/expect-known.md +++ /dev/null @@ -1,62 +0,0 @@ -# ignores incomplete last line - - Results have changed from known value recorded in '/tmp/RtmppktJm1/file13b4b50b67fc'. - - `old`: "Hi!" - `new`: "Hi!" "" - ---- - - Results have changed from known value recorded in '/tmp/RtmppktJm1/file13b4b50b67fc'. - - `old`: "Hi!" "" - `new`: "oops" - -# updates by default - - Results have changed from known value recorded in '/tmp/RtmppktJm1/file13b4b249dd6d5'. - - `old`: "Hi!" - `new`: "oops" - ---- - - Results have changed from known value recorded in '/tmp/RtmppktJm1/file13b4b249dd6d5'. - - `old`: "Hi!" - `new`: "oops" - -# Warning for non-UTF-8 reference files - - Results have changed from known value recorded in '/tmp/RtmppktJm1/file13b4b3b0e2961'. - - `old`: "éáíöü" - `new`: - -# correctly matches to a file - - `x` has changed from known value recorded in 'one.rds'. - 1/1 mismatches - [1] 2 - 1 == 1 - -# equal_to_ref does not overwrite existing - - `ref_obj2` has changed from known value recorded in '/tmp/RtmppktJm1/file13b4b10c668bf.rds'. - 3/3 mismatches (average diff: 1) - [1] 2 - 1 == 1 - [2] 3 - 2 == 1 - [3] 4 - 3 == 1 - ---- - - `ref_obj2` has changed from known value recorded in '/tmp/RtmppktJm1/file13b4b10c668bf.rds'. - 3/3 mismatches (average diff: 1) - [1] 2 - 1 == 1 - [2] 3 - 2 == 1 - [3] 4 - 3 == 1 - -# only succeeds if hash is correct - - Expected value to hash to c08951d2c3. - Actual hash: c08951d2c2 - diff --git a/tests/testthat/_snaps/expect-match.md b/tests/testthat/_snaps/expect-match.md index 3bc59b0a4..78ddfc698 100644 --- a/tests/testthat/_snaps/expect-match.md +++ b/tests/testthat/_snaps/expect-match.md @@ -1,28 +1,44 @@ # generates useful failure messages - Expected `zero` to not be empty. + Code + expect_match(zero, "asdf") + Condition + Error: + ! Expected `zero` to not be empty. --- - Expected `one` to match regexp "asdf". - Actual text: - bcde + Code + expect_match(one, "asdf") + Condition + Error: + ! Expected `one` to match regexp "asdf". + Actual text: + bcde --- - Expected every element of `many` to match regexp "a". - Actual text: - a - a - b + Code + expect_match(many, "a") + Condition + Error: + ! Expected every element of `many` to match regexp "a". + Actual text: + a + a + b --- - Expected some element of `many` to match regexp "c". - Actual text: - a - a - b + Code + expect_match(many, "c", all = FALSE) + Condition + Error: + ! Expected some element of `many` to match regexp "c". + Actual text: + a + a + b # expect_match validates its inputs @@ -82,25 +98,41 @@ # extra arguments passed onto grepl - Expected "\\s" to match regexp "\\s". - Actual text: - \\s + Code + expect_match("\\s", "\\s") + Condition + Error: + ! Expected "\\s" to match regexp "\\s". + Actual text: + \\s --- - Expected "test" to match regexp "TEST". - Actual text: - test + Code + expect_match("test", "TEST") + Condition + Error: + ! Expected "test" to match regexp "TEST". + Actual text: + test # expect_no_match works - Expected `x` not to match string "e*". - Actual text: - te*st + Code + expect_no_match(x, "e*", fixed = TRUE) + Condition + Error: + ! Expected `x` not to match string "e*". + Actual text: + te*st --- - Expected `x` not to match regexp "TEST". - Actual text: - test + Code + expect_no_match(x, "TEST", ignore.case = TRUE) + Condition + Error: + ! Expected `x` not to match regexp "TEST". + Actual text: + test diff --git a/tests/testthat/_snaps/expect-named.md b/tests/testthat/_snaps/expect-named.md index c635c68d4..b43522cec 100644 --- a/tests/testthat/_snaps/expect-named.md +++ b/tests/testthat/_snaps/expect-named.md @@ -1,53 +1,82 @@ # expected_named verifies presence of names - Expected `1:10` to have names. + Code + expect_named(1:10) + Condition + Error: + ! Expected `1:10` to have names. # expected_named verifies actual of names - Expected names(`c(a = 1)`) to be equal to "b". - - `actual`: "a" - `expected`: "b" + Code + expect_named(c(a = 1), "b") + Condition + Error: + ! Expected names(`c(a = 1)`) to be equal to "b". + + `actual`: "a" + `expected`: "b" # provide useful feedback on failure - names(`x1`) doesn't have the same values as `c("a", "b")`. - * Only in `expected`: "b" - + Code + expect_named(x1, c("a", "b"), ignore.order = TRUE) + Condition + Error: + ! Expected names(`x1`) to have the same values as `c("a", "b")`. + Extra: "b" --- - names(`x2`) doesn't have the same values as "a". - * Only in `actual`: "b" - + Code + expect_named(x2, "a", ignore.order = TRUE) + Condition + Error: + ! Expected names(`x2`) to have the same values as "a". + Needs: "b" --- - names(`x1`) doesn't have the same values as "b". - * Only in `actual`: "a" - * Only in `expected`: "b" - + Code + expect_named(x1, "b", ignore.order = TRUE) + Condition + Error: + ! Expected names(`x1`) to have the same values as "b". + Needs: "a" + Extra: "b" --- - Expected names(`x1`) to be equal to `c("a", "b")`. - - `actual`: "a" - `expected`: "a" "b" + Code + expect_named(x1, c("a", "b"), ignore.order = FALSE) + Condition + Error: + ! Expected names(`x1`) to be equal to `c("a", "b")`. + + `actual`: "a" + `expected`: "a" "b" --- - Expected names(`x2`) to be equal to "a". - - `actual`: "a" "b" - `expected`: "a" + Code + expect_named(x2, "a", ignore.order = FALSE) + Condition + Error: + ! Expected names(`x2`) to be equal to "a". + + `actual`: "a" "b" + `expected`: "a" --- - Expected names(`x1`) to be equal to `c("b")`. - - `actual`: "a" - `expected`: "b" + Code + expect_named(x1, c("b"), ignore.order = FALSE) + Condition + Error: + ! Expected names(`x1`) to be equal to `c("b")`. + + `actual`: "a" + `expected`: "b" # expect_named validates its inputs diff --git a/tests/testthat/_snaps/expect-no-condition.md b/tests/testthat/_snaps/expect-no-condition.md index 49d8d963b..db95e8406 100644 --- a/tests/testthat/_snaps/expect-no-condition.md +++ b/tests/testthat/_snaps/expect-no-condition.md @@ -1,51 +1,86 @@ # expect_no_* conditions behave as expected - Expected `stop("error")` to run without any errors. - Actually got a with text: - error + Code + expect_no_error(stop("error")) + Condition + Error: + ! Expected `stop("error")` to run without any errors. + Actually got a with message: + error --- - Expected `warning("warning")` to run without any warnings. - Actually got a with text: - warning + Code + expect_no_warning(warning("warning")) + Condition + Error: + ! Expected `warning("warning")` to run without any warnings. + Actually got a with message: + warning --- - Expected `message("message")` to run without any messages. - Actually got a with text: - message - + Code + expect_no_message(message("message")) + Condition + Error: + ! Expected `message("message")` to run without any messages. + Actually got a with message: + message + --- - Expected `abort("error")` to run without any errors. - Actually got a with text: - error + Code + expect_no_error(abort("error")) + Condition + Error: + ! Expected `abort("error")` to run without any errors. + Actually got a with message: + error --- - Expected `warn("warning")` to run without any warnings. - Actually got a with text: - warning + Code + expect_no_warning(warn("warning")) + Condition + Error: + ! Expected `warn("warning")` to run without any warnings. + Actually got a with message: + warning --- - Expected `inform("message")` to run without any messages. - Actually got a with text: - message + Code + expect_no_message(inform("message")) + Condition + Error: + ! Expected `inform("message")` to run without any messages. + Actually got a with message: + message # expect_no_ continues execution - Expected `{ ... }` to run without any warnings. - Actually got a with text: - x + Code + expect_no_warning({ + warning("x") + b <- 2 + }) + Condition + Error: + ! Expected `{ ... }` to run without any warnings. + Actually got a with message: + x # expect_no_* don't emit success when they fail - Expected `stop("!")` to run without any errors. - Actually got a with text: - ! + Code + expect_no_error(stop("!")) + Condition + Error: + ! Expected `stop("!")` to run without any errors. + Actually got a with message: + ! # matched conditions give informative message @@ -54,27 +89,27 @@ Condition Error: ! Expected `foo()` to run without any warnings. - Actually got a with text: + Actually got a with message: This is a problem! Code expect_no_warning(foo(), message = "problem") Condition Error: ! Expected `foo()` to run without any warnings matching pattern 'problem'. - Actually got a with text: + Actually got a with message: This is a problem! Code expect_no_warning(foo(), class = "test") Condition Error: ! Expected `foo()` to run without any warnings of class 'test'. - Actually got a with text: + Actually got a with message: This is a problem! Code expect_no_warning(foo(), message = "problem", class = "test") Condition Error: ! Expected `foo()` to run without any warnings of class 'test' matching pattern 'problem'. - Actually got a with text: + Actually got a with message: This is a problem! diff --git a/tests/testthat/_snaps/expect-no-condition.new.md b/tests/testthat/_snaps/expect-no-condition.new.md deleted file mode 100644 index 93cd251d9..000000000 --- a/tests/testthat/_snaps/expect-no-condition.new.md +++ /dev/null @@ -1,80 +0,0 @@ -# expect_no_* conditions behave as expected - - Expected `stop("error")` to run without any errors. - Actually got a with message: - error - ---- - - Expected `warning("warning")` to run without any warnings. - Actually got a with message: - warning - ---- - - Expected `message("message")` to run without any messages. - Actually got a with message: - message - - ---- - - Expected `abort("error")` to run without any errors. - Actually got a with message: - error - ---- - - Expected `warn("warning")` to run without any warnings. - Actually got a with message: - warning - ---- - - Expected `inform("message")` to run without any messages. - Actually got a with message: - message - -# expect_no_ continues execution - - Expected `{ ... }` to run without any warnings. - Actually got a with message: - x - -# expect_no_* don't emit success when they fail - - Expected `stop("!")` to run without any errors. - Actually got a with message: - ! - -# matched conditions give informative message - - Code - expect_no_warning(foo()) - Condition - Error: - ! Expected `foo()` to run without any warnings. - Actually got a with message: - This is a problem! - Code - expect_no_warning(foo(), message = "problem") - Condition - Error: - ! Expected `foo()` to run without any warnings matching pattern 'problem'. - Actually got a with message: - This is a problem! - Code - expect_no_warning(foo(), class = "test") - Condition - Error: - ! Expected `foo()` to run without any warnings of class 'test'. - Actually got a with message: - This is a problem! - Code - expect_no_warning(foo(), message = "problem", class = "test") - Condition - Error: - ! Expected `foo()` to run without any warnings of class 'test' matching pattern 'problem'. - Actually got a with message: - This is a problem! - diff --git a/tests/testthat/_snaps/expect-output.md b/tests/testthat/_snaps/expect-output.md index 8255bc8be..6a84c3a09 100644 --- a/tests/testthat/_snaps/expect-output.md +++ b/tests/testthat/_snaps/expect-output.md @@ -1,22 +1,38 @@ # expect = NA checks for no output - Expected `g()` to produce no output. - Actual output: - ! + Code + expect_output(g(), NA) + Condition + Error: + ! Expected `g()` to produce no output. + Actual output: + ! # expect = NULL checks for some output - Expected `f()` to produce output. + Code + expect_output(f(), NULL) + Condition + Error: + ! Expected `f()` to produce output. # expect = string checks for match - Expected `g()` to match regexp "x". - Actual output: - ! + Code + expect_output(g(), "x") + Condition + Error: + ! Expected `g()` to match regexp "x". + Actual output: + ! --- - Expected "a" to produce output. + Code + expect_output("a", "x") + Condition + Error: + ! Expected "a" to produce output. # expect_output validates its inputs diff --git a/tests/testthat/_snaps/expect-reference.md b/tests/testthat/_snaps/expect-reference.md index 953f137cc..65b91be88 100644 --- a/tests/testthat/_snaps/expect-reference.md +++ b/tests/testthat/_snaps/expect-reference.md @@ -1,4 +1,8 @@ # succeeds only when same object - Expected `x` to be a reference to 1. + Code + expect_reference(x, 1) + Condition + Error: + ! Expected `x` to be a reference to 1. diff --git a/tests/testthat/_snaps/expect-self-test.md b/tests/testthat/_snaps/expect-self-test.md index a5981088f..ad00dcd84 100644 --- a/tests/testthat/_snaps/expect-self-test.md +++ b/tests/testthat/_snaps/expect-self-test.md @@ -1,43 +1,92 @@ # expect_failure() requires 1 failure and zero successes - Expectation did not fail + Code + expect_failure({ }) + Condition + Error: + ! Expectation did not fail --- - Expectation did not fail + Code + expect_failure(pass(NULL)) + Condition + Error: + ! Expectation did not fail --- - Expected expectation to never succeed. - Actually succeeded: 1 times + Code + expect_failure({ + pass(NULL) + fail() + }) + Condition + Error: + ! Expected expectation to never succeed. + Actually succeeded: 1 times --- - Expectation failed more than once + Code + expect_failure({ + fail() + pass(NULL) + fail() + }) + Condition + Error: + ! Expectation failed more than once # expect_failure() can optionally match message - Expected Failure message to match regexp "banana". - Actual text: - apple + Code + expect_failure(fail("apple"), "banana") + Condition + Error: + ! Expected Failure message to match regexp "banana". + Actual text: + apple # expect_success() requires 1 success and zero failures - Expectation did not succeed + Code + expect_success({ }) + Condition + Error: + ! Expectation did not succeed --- - Expectation did not succeed + Code + expect_success(fail()) + Condition + Error: + ! Expectation did not succeed --- - Expected expectation to not fail. - Actually failed: 1 times + Code + expect_success({ + pass(NULL) + fail() + }) + Condition + Error: + ! Expected expectation to not fail. + Actually failed: 1 times --- - Expected expectation to succeed once. - Actually succeeded: 2 times + Code + expect_success({ + pass(NULL) + pass(NULL) + }) + Condition + Error: + ! Expected expectation to succeed once. + Actually succeeded: 2 times # errors in expect_success bubble up @@ -75,9 +124,17 @@ # expect_no still work - Expectation failed + Code + expect_no_failure(fail()) + Condition + Error: + ! Expectation failed --- - Expectation succeeded + Code + expect_no_success(pass(NULL)) + Condition + Error: + ! Expectation succeeded diff --git a/tests/testthat/_snaps/expect-setequal.md b/tests/testthat/_snaps/expect-setequal.md index 2e1fdbadb..1afdfdb9d 100644 --- a/tests/testthat/_snaps/expect-setequal.md +++ b/tests/testthat/_snaps/expect-setequal.md @@ -1,12 +1,20 @@ # checks both directions of containment - Expected `letters` to have the same values as `letters[-1]`. - Needs: "a" + Code + expect_setequal(letters, letters[-1]) + Condition + Error: + ! Expected `letters` to have the same values as `letters[-1]`. + Needs: "a" --- - Expected `letters[-1]` to have the same values as `letters`. - Extra: "a" + Code + expect_setequal(letters[-1], letters) + Condition + Error: + ! Expected `letters[-1]` to have the same values as `letters`. + Extra: "a" # warns if both inputs are named @@ -31,144 +39,216 @@ # useful message on failure - Expected "actual" to have the same values as "expected". - Needs: "actual" - Extra: "expected" + Code + expect_setequal("actual", "expected") + Condition + Error: + ! Expected "actual" to have the same values as "expected". + Needs: "actual" + Extra: "expected" --- - Expected `x` to have the same values as `y`. - Needs: 1 + Code + expect_setequal(x, y) + Condition + Error: + ! Expected `x` to have the same values as `y`. + Needs: 1 --- - Expected `x` to have the same values as `y`. - Extra: 3 + Code + expect_setequal(x, y) + Condition + Error: + ! Expected `x` to have the same values as `y`. + Extra: 3 --- - Expected `x` to have the same values as `y`. - Needs: 1 - Extra: 3 + Code + expect_setequal(x, y) + Condition + Error: + ! Expected `x` to have the same values as `y`. + Needs: 1 + Extra: 3 --- - Expected `x` to have the same values as `y`. - Needs: "a" - Extra: "b" + Code + expect_setequal(x, y) + Condition + Error: + ! Expected `x` to have the same values as `y`. + Needs: "a" + Extra: "b" --- - Expected `x` to have the same values as `c("a", "b", "c", "d")`. - Extra: "d" + Code + expect_setequal(x, c("a", "b", "c", "d")) + Condition + Error: + ! Expected `x` to have the same values as `c("a", "b", "c", "d")`. + Extra: "d" # truncates long vectors - Expected `x` to have the same values as `y`. - Extra: 3, 4, 5, 6, 7, 8, 9, 10, 11, ... + Code + expect_setequal(x, y) + Condition + Error: + ! Expected `x` to have the same values as `y`. + Extra: 3, 4, 5, 6, 7, 8, 9, 10, 11, ... # error if any names are duplicated - Expected `list(a = 1, b = 2, b = 3)` to be equal to `list(b = 2, a = 1)`. - - `actual` is length 3 - `expected` is length 2 - - `names(actual)`: "a" "b" "b" - `names(expected)`: "a" "b" - - `actual[[3]]` is a double vector (3) - `expected[[3]]` is absent + Code + expect_mapequal(list(a = 1, b = 2, b = 3), list(b = 2, a = 1)) + Condition + Error: + ! Expected `list(a = 1, b = 2, b = 3)` to be equal to `list(b = 2, a = 1)`. + + `actual` is length 3 + `expected` is length 2 + + `names(actual)`: "a" "b" "b" + `names(expected)`: "a" "b" + + `actual[[3]]` is a double vector (3) + `expected[[3]]` is absent --- - Expected `list(a = 1, b = 2)` to be equal to `list(b = 3, b = 2, a = 1)`. - - `actual` is length 2 - `expected` is length 3 - - `names(actual)`: "a" "b" - `names(expected)`: "a" "b" "b" - - `actual[[2]]`: 2.0 - `expected[[2]]`: 3.0 - - `actual[[3]]` is absent - `expected[[3]]` is a double vector (2) + Code + expect_mapequal(list(a = 1, b = 2), list(b = 3, b = 2, a = 1)) + Condition + Error: + ! Expected `list(a = 1, b = 2)` to be equal to `list(b = 3, b = 2, a = 1)`. + + `actual` is length 2 + `expected` is length 3 + + `names(actual)`: "a" "b" + `names(expected)`: "a" "b" "b" + + `actual[[2]]`: 2.0 + `expected[[2]]`: 3.0 + + `actual[[3]]` is absent + `expected[[3]]` is a double vector (2) --- - Expected `list(a = 1, b = 2, b = 3)` to be equal to `list(b = 3, b = 2, a = 1)`. - - `actual[[2]]`: 2.0 - `expected[[2]]`: 3.0 - - `actual[[3]]`: 3.0 - `expected[[3]]`: 2.0 + Code + expect_mapequal(list(a = 1, b = 2, b = 3), list(b = 3, b = 2, a = 1)) + Condition + Error: + ! Expected `list(a = 1, b = 2, b = 3)` to be equal to `list(b = 3, b = 2, a = 1)`. + + `actual[[2]]`: 2.0 + `expected[[2]]`: 3.0 + + `actual[[3]]`: 3.0 + `expected[[3]]`: 2.0 # fail if names don't match - Expected `list(a = 1, b = 2)` to be equal to `list(a = 1)`. - - `actual` is length 2 - `expected` is length 1 - - `names(actual)`: "a" "b" - `names(expected)`: "a" - - `actual$b` is a double vector (2) - `expected$b` is absent + Code + expect_mapequal(list(a = 1, b = 2), list(a = 1)) + Condition + Error: + ! Expected `list(a = 1, b = 2)` to be equal to `list(a = 1)`. + + `actual` is length 2 + `expected` is length 1 + + `names(actual)`: "a" "b" + `names(expected)`: "a" + + `actual$b` is a double vector (2) + `expected$b` is absent --- - Expected `list(a = 1)` to be equal to `list(a = 1, b = 2)`. - - `actual` is length 1 - `expected` is length 2 - - `names(actual)`: "a" - `names(expected)`: "a" "b" - - `actual$b` is absent - `expected$b` is a double vector (2) + Code + expect_mapequal(list(a = 1), list(a = 1, b = 2)) + Condition + Error: + ! Expected `list(a = 1)` to be equal to `list(a = 1, b = 2)`. + + `actual` is length 1 + `expected` is length 2 + + `names(actual)`: "a" + `names(expected)`: "a" "b" + + `actual$b` is absent + `expected$b` is a double vector (2) # fails if values don't match - Expected `list(a = 1, b = 2)` to be equal to `list(a = 1, b = 3)`. - - `actual$b`: 2.0 - `expected$b`: 3.0 + Code + expect_mapequal(list(a = 1, b = 2), list(a = 1, b = 3)) + Condition + Error: + ! Expected `list(a = 1, b = 2)` to be equal to `list(a = 1, b = 3)`. + + `actual$b`: 2.0 + `expected$b`: 3.0 # fails if unnamed values in different location if any unnamed values - Expected `list(1, b = 2, c = 3)` to be equal to `list(b = 2, 1, c = 3)`. - - `names(actual)`: "" "b" "c" - `names(expected)`: "b" "" "c" - - `actual[[1]]`: 1.0 - `expected[[1]]`: 2.0 - - `actual[[2]]`: 2.0 - `expected[[2]]`: 1.0 + Code + expect_mapequal(list(1, b = 2, c = 3), list(b = 2, 1, c = 3)) + Condition + Error: + ! Expected `list(1, b = 2, c = 3)` to be equal to `list(b = 2, 1, c = 3)`. + + `names(actual)`: "" "b" "c" + `names(expected)`: "b" "" "c" + + `actual[[1]]`: 1.0 + `expected[[1]]`: 2.0 + + `actual[[2]]`: 2.0 + `expected[[2]]`: 1.0 # expect_contains() gives useful message on failure - Expected `x1` to contain all values in `x2`. - Missing: "d" + Code + expect_contains(x1, x2) + Condition + Error: + ! Expected `x1` to contain all values in `x2`. + Missing: "d" --- - Expected `x1` to contain all values in `x3`. - Missing: "d", "e" + Code + expect_contains(x1, x3) + Condition + Error: + ! Expected `x1` to contain all values in `x3`. + Missing: "d", "e" # expect_in() gives useful message on failure - Expected all values in `x1` to be in `x2`. - Extra: "a" + Code + expect_in(x1, x2) + Condition + Error: + ! Expected all values in `x1` to be in `x2`. + Extra: "a" --- - Expected all values in `x1` to be in `x3`. - Extra: "a", "b" + Code + expect_in(x1, x3) + Condition + Error: + ! Expected all values in `x1` to be in `x3`. + Extra: "a", "b" diff --git a/tests/testthat/_snaps/expect-shape.md b/tests/testthat/_snaps/expect-shape.md index 8786ea343..39dd5a7b5 100644 --- a/tests/testthat/_snaps/expect-shape.md +++ b/tests/testthat/_snaps/expect-shape.md @@ -1,7 +1,11 @@ # generates actionable failure message - Expected `x` to have length 2. - Actual length: 10. + Code + expect_length(x, 2) + Condition + Error: + ! Expected `x` to have length 2. + Actual length: 10. # expect_length validates its inputs @@ -13,60 +17,108 @@ # dim compared correctly - Expected `matrix(nrow = 6, ncol = 3)` to have dim (6, 2). - Actual dim: (6, 3). + Code + expect_shape(matrix(nrow = 6, ncol = 3), dim = c(6L, 2L)) + Condition + Error: + ! Expected `matrix(nrow = 6, ncol = 3)` to have dim (6, 2). + Actual dim: (6, 3). --- - Expected `matrix(nrow = 6, ncol = 3)` to have dim (7, 3). - Actual dim: (6, 3). + Code + expect_shape(matrix(nrow = 6, ncol = 3), dim = c(7L, 3L)) + Condition + Error: + ! Expected `matrix(nrow = 6, ncol = 3)` to have dim (7, 3). + Actual dim: (6, 3). --- - Expected `array(dim = 1:3)` to have dim (1, 2). - Actual dim: (1, 2, 3). + Code + expect_shape(array(dim = 1:3), dim = 1:2) + Condition + Error: + ! Expected `array(dim = 1:3)` to have dim (1, 2). + Actual dim: (1, 2, 3). --- - Expected `array(dim = 1:3)` to have dim (1, 2, 3, 4). - Actual dim: (1, 2, 3). + Code + expect_shape(array(dim = 1:3), dim = 1:4) + Condition + Error: + ! Expected `array(dim = 1:3)` to have dim (1, 2, 3, 4). + Actual dim: (1, 2, 3). # nrow compared correctly - Expected `matrix(nrow = 5, ncol = 5)` to have 6 rows. - Actual rows: 5. + Code + expect_shape(matrix(nrow = 5, ncol = 5), nrow = 6L) + Condition + Error: + ! Expected `matrix(nrow = 5, ncol = 5)` to have 6 rows. + Actual rows: 5. --- - Expected 1 to have dimensions. + Code + expect_shape(1, nrow = 1) + Condition + Error: + ! Expected 1 to have dimensions. # ncol compared correctly - Expected `matrix(nrow = 5, ncol = 5)` to have 7 columns. - Actual columns: 5. + Code + expect_shape(matrix(nrow = 5, ncol = 5), ncol = 7L) + Condition + Error: + ! Expected `matrix(nrow = 5, ncol = 5)` to have 7 columns. + Actual columns: 5. --- - Expected `array(1)` to have more than one dimension. + Code + expect_shape(array(1), ncol = 1) + Condition + Error: + ! Expected `array(1)` to have more than one dimension. --- - Expected `array(integer())` to have more than one dimension. + Code + expect_shape(array(integer()), ncol = 0L) + Condition + Error: + ! Expected `array(integer())` to have more than one dimension. # NA handling (e.g. dbplyr) - Expected `x` to have 10 rows. - Actual rows: NA. + Code + expect_shape(x, nrow = 10L) + Condition + Error: + ! Expected `x` to have 10 rows. + Actual rows: NA. --- - Expected `x` to have NA columns. - Actual columns: 10. + Code + expect_shape(x, ncol = NA_integer_) + Condition + Error: + ! Expected `x` to have NA columns. + Actual columns: 10. --- - Expected `x` to have dim (10, NA). - Actual dim: (NA, 10). + Code + expect_shape(x, dim = c(10L, NA_integer_)) + Condition + Error: + ! Expected `x` to have dim (10, NA). + Actual dim: (NA, 10). # checks inputs arguments, diff --git a/tests/testthat/_snaps/expect-silent.md b/tests/testthat/_snaps/expect-silent.md index 2f873f089..5b6d26a8f 100644 --- a/tests/testthat/_snaps/expect-silent.md +++ b/tests/testthat/_snaps/expect-silent.md @@ -1,15 +1,27 @@ # checks for any type of output - Expected `warning("!")` to run silently. - Actually produced: warnings. + Code + expect_silent(warning("!")) + Condition + Error: + ! Expected `warning("!")` to run silently. + Actually produced: warnings. --- - Expected `message("!")` to run silently. - Actually produced: messages. + Code + expect_silent(message("!")) + Condition + Error: + ! Expected `message("!")` to run silently. + Actually produced: messages. --- - Expected `print("!")` to run silently. - Actually produced: output. + Code + expect_silent(print("!")) + Condition + Error: + ! Expected `print("!")` to run silently. + Actually produced: output. diff --git a/tests/testthat/_snaps/expect-vector.md b/tests/testthat/_snaps/expect-vector.md index 2fbc0df83..31f4ad6a3 100644 --- a/tests/testthat/_snaps/expect-vector.md +++ b/tests/testthat/_snaps/expect-vector.md @@ -1,6 +1,10 @@ # basic properties upheld - `\`1:10\`` must have size 5, not size 10. + Code + expect_vector(1:10, size = 5) + Condition + Error: + ! `\`1:10\`` must have size 5, not size 10. # expect_vector validates its inputs diff --git a/tests/testthat/_snaps/expectation.md b/tests/testthat/_snaps/expectation.md index f2fe199e3..015b97d1f 100644 --- a/tests/testthat/_snaps/expectation.md +++ b/tests/testthat/_snaps/expectation.md @@ -1,8 +1,12 @@ # `expect()` and `exp_signal()` signal expectations - + Code + expect(FALSE, "") + Condition --- - + Code + exp_signal(new_expectation("failure", "")) + Condition diff --git a/tests/testthat/_snaps/old-school.md b/tests/testthat/_snaps/old-school.md index d5410cab9..ef535a7ea 100644 --- a/tests/testthat/_snaps/old-school.md +++ b/tests/testthat/_snaps/old-school.md @@ -1,6 +1,10 @@ # old school comparisons still work - Expected `x` > `expected`. - Actual 10.0 <= 11.0 - Difference -1.0 <= 0 + Code + expect_that(10, is_more_than(11)) + Condition + Error: + ! Expected `x` > `expected`. + Actual 10.0 <= 11.0 + Difference -1.0 <= 0 diff --git a/tests/testthat/_snaps/snapshot.md b/tests/testthat/_snaps/snapshot.md index 740958885..72fc22977 100644 --- a/tests/testthat/_snaps/snapshot.md +++ b/tests/testthat/_snaps/snapshot.md @@ -98,7 +98,11 @@ # always checks error status - Expected `print("!")` to throw a error. + Code + expect_snapshot(print("!"), error = TRUE) + Condition + Error: + ! Expected `print("!")` to throw a error. # can capture error/warning messages diff --git a/tests/testthat/test-quasi-label.R b/tests/testthat/test-quasi-label.R index 2dab0f8b0..91f58ad96 100644 --- a/tests/testthat/test-quasi-label.R +++ b/tests/testthat/test-quasi-label.R @@ -60,7 +60,7 @@ test_that("labelling compound {} expression gives single string", { test_that("can label multiline functions", { expect_equal( expr_label(quote(function(x, y) {})), - "function(x, y) ..." + "`function(x, y) ...`" ) }) diff --git a/tests/testthat/test-snapshot-file.R b/tests/testthat/test-snapshot-file.R index 47c9f1b1b..b4cb3f52e 100644 --- a/tests/testthat/test-snapshot-file.R +++ b/tests/testthat/test-snapshot-file.R @@ -56,7 +56,7 @@ test_that("basic workflow", { # fails if changed snapper$start_file("snapshot-6", "test") path2 <- write_tmp_lines(letters[-1]) - expect_snapshot_failure(expect_snapshot_file(path2, "letters.txt")) + expect_failure(expect_snapshot_file(path2, "letters.txt"), "has changed") snapper$end_file() }) diff --git a/tests/testthat/test-snapshot-reporter.R b/tests/testthat/test-snapshot-reporter.R index 694d7fc21..3b43b7330 100644 --- a/tests/testthat/test-snapshot-reporter.R +++ b/tests/testthat/test-snapshot-reporter.R @@ -32,7 +32,7 @@ test_that("basic workflow", { # fails if changed snapper$start_file("snapshot-2", "test") - expect_snapshot_failure(expect_snapshot_output("y")) + expect_failure(expect_snapshot_output("y")) snapper$end_file() expect_true(file.exists(file.path(path, "snapshot-2.md"))) expect_true(file.exists(file.path(path, "snapshot-2.new.md"))) @@ -63,7 +63,7 @@ test_that("only create new files for changed variants", { # failure in default snapper$start_file("variants", "test") - expect_snapshot_failure(expect_snapshot_output("y")) + expect_failure(expect_snapshot_output("y")) expect_success(expect_snapshot_output("x", variant = "a")) expect_success(expect_snapshot_output("x", variant = "b")) snapper$end_file() @@ -77,7 +77,7 @@ test_that("only create new files for changed variants", { snapper$start_file("variants", "test") expect_success(expect_snapshot_output("x")) expect_success(expect_snapshot_output("x", variant = "a")) - expect_snapshot_failure(expect_snapshot_output("y", variant = "b")) + expect_failure(expect_snapshot_output("y", variant = "b")) snapper$end_file() expect_setequal( snapper$snap_files(), @@ -95,7 +95,7 @@ test_that("only reverting change in variant deletes .new", { # failure snapper$start_file("v", "test") - expect_snapshot_failure(expect_snapshot_output("y", variant = "a")) + expect_failure(expect_snapshot_output("y", variant = "a")) snapper$end_file() expect_setequal(snapper$snap_files(), c("a/v.md", "b/v.md", "a/v.new.md")) From fa69ee8ba8a224577bee3a76f8a21807d24df72e Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 14:55:00 -0500 Subject: [PATCH 16/20] Update custom expectations vignette. --- vignettes/custom-expectation.Rmd | 42 +++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/vignettes/custom-expectation.Rmd b/vignettes/custom-expectation.Rmd index ca786a9ef..3575d103b 100644 --- a/vignettes/custom-expectation.Rmd +++ b/vignettes/custom-expectation.Rmd @@ -30,7 +30,10 @@ expect_length <- function(object, n) { # 2. Check if expectations are violated act_n <- length(act$val) if (act_n != n) { - msg <- sprintf("%s has length %i, not length %i.", act$lab, act_n, n) + msg <- c( + sprintf("Expected %s to have length %i.", act$lab, n), + sprintf("Actual length: %i.", act$n) + ) return(fail(msg)) } @@ -41,7 +44,7 @@ expect_length <- function(object, n) { The first step in any expectation is to use `quasi_label()` to capture a "labelled value", i.e. a list that contains both the value (`$val`) for testing and a label (`$lab`) for messaging. This is a pattern that exists for fairly esoteric reasons; you don't need to understand it, just copy and paste it 🙂. -Next you need to check each way that `object` could violate the expectation. In this case, there's only one check, but in more complicated cases there can be multiple checks. In most cases, it's easier to check for violations one by one, using early returns to `fail()`. This makes it easier to write informative failure messages that state both what the object is and what you expected. +Next you need to check each way that `object` could violate the expectation. In this case, there's only one check, but in more complicated cases there can be multiple checks. In most cases, it's easier to check for violations one by one, using early returns to `fail()`. This makes it easier to write informative failure messages that first describe what was expected and then what was actually seen. Also note that you need to use `return(fail())` here. You won't see the problem when interactively testing your function because when run outside of `test_that()`, `fail()` throws an error, causing the function to terminate early. When running inside of `test_that()`, however, `fail()` does not stop execution because we want to collect all failures in a given test. @@ -98,13 +101,19 @@ expect_vector_length <- function(object, n) { # It's non-trivial to check if an object is a vector in base R so we # use an rlang helper if (!rlang::is_vector(act$val)) { - msg <- sprintf("%s is a %s, not a vector", act$lab, typeof(act$val)) + msg <- c( + sprintf("Expected %s to be a vector", act$lab), + sprintf("Actual: %s", typeof(act$val)) + ) return(fail(msg)) } act_n <- length(act$val) if (act_n != n) { - msg <- sprintf("%s has length %i, not length %i.", act$lab, act_n, n) + msg <- c( + sprintf("Expected %s to have length %i.", act$lab, n), + sprintf("Actual length: %i.", act_n) + ) return(fail(msg)) } @@ -131,19 +140,22 @@ expect_s3_class <- function(object, class) { act <- quasi_label(rlang::enquo(object)) if (!is.object(act$val)) { - return(fail(sprintf("%s is not an object.", act$lab))) + msg <- sprintf("Expected %s to be an object.", act$lab) + return(fail(msg)) } if (isS4(act$val)) { - return(fail(sprintf("%s is an S4 object, not an S3 object.", act$lab))) + msg <- c( + sprintf("Expected %s to be an S3 object.", act$lab), + "Actual: S4 object" + ) + return(fail(msg)) } if (!inherits(act$val, class)) { - msg <- sprintf( - "%s inherits from %s not %s.", - act$lab, - paste0(class(object), collapse = "/"), - paste0(class, collapse = "/") + msg <- c( + sprintf("Expected %s to inherit from %s.", act$lab, class), + sprintf("Actual class: %s", class(act$val)) ) return(fail(msg)) } @@ -165,7 +177,13 @@ expect_s3_class(x3, "integer") expect_s3_class(x3, "factor") ``` -Note that I also check that the `class` argument must be a string. This is an error, not a failure, because it suggests you're using the function incorrectly. +Note the variety of messages: + +* When `object` isn't an object, we only need to say what we expect. +* When `object` isn't an S3 object, we know it's an S4 object. +* When `inherits()` is `FALSE`, we provide the actual _class_, since that's most informative. + +I also check that the `class` argument must be a string. This is an error, not a failure, because it suggests you're using the function incorrectly. ```{r} #| error: true From 8e09c6e6f65450c135ee35151491f200acc882d3 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 15:20:50 -0500 Subject: [PATCH 17/20] Improve consistency --- R/expect-condition.R | 9 +- R/expect-equality.R | 24 ++--- R/expect-inheritance.R | 37 +++---- R/expect-invisible.R | 4 +- R/expect-match.R | 6 +- R/expect-no-condition.R | 11 +- R/expect-output.R | 7 +- R/expect-shape.R | 2 +- tests/testthat/_snaps/expect-comparison.md | 8 +- tests/testthat/_snaps/expect-condition.md | 13 +-- tests/testthat/_snaps/expect-constant.md | 12 ++- tests/testthat/_snaps/expect-equality.md | 114 +------------------- tests/testthat/_snaps/expect-inheritance.md | 17 ++- tests/testthat/_snaps/expect-invisible.md | 8 +- tests/testthat/_snaps/expect-named.md | 8 +- tests/testthat/_snaps/expect-self-test.md | 3 +- tests/testthat/_snaps/expect-setequal.md | 14 +-- tests/testthat/_snaps/expect-shape.md | 4 +- tests/testthat/_snaps/reporter-check.md | 12 ++- tests/testthat/_snaps/reporter-junit.md | 8 +- tests/testthat/_snaps/reporter-progress.md | 84 ++++++++++----- tests/testthat/_snaps/reporter-stop.md | 6 +- tests/testthat/_snaps/reporter-summary.md | 18 ++-- tests/testthat/_snaps/reporter-tap.md | 6 +- tests/testthat/_snaps/reporter-teamcity.md | 4 +- tests/testthat/_snaps/try-again.md | 2 +- tests/testthat/test-expect-comparison.R | 11 +- tests/testthat/test-expect-equality.R | 49 +++------ tests/testthat/test-expect-inheritance.R | 8 +- tests/testthat/test-quasi-label.R | 24 +++++ vignettes/custom-expectation.Rmd | 4 +- 31 files changed, 239 insertions(+), 298 deletions(-) diff --git a/R/expect-condition.R b/R/expect-condition.R index 1d24032f8..7698b26c5 100644 --- a/R/expect-condition.R +++ b/R/expect-condition.R @@ -629,9 +629,10 @@ check_condition_dots <- function( } actual_condition <- function(cond) { - sprintf( - "Actual <%s>:\n%s", - paste(class(cond), collapse = "/"), - cnd_message(cond) + paste0( + "Actually got a <", + class(cond)[[1]], + "> with message:\n", + indent_lines(cnd_message(cond)) ) } diff --git a/R/expect-equality.R b/R/expect-equality.R index 09cc1a2e1..004e24c58 100644 --- a/R/expect-equality.R +++ b/R/expect-equality.R @@ -107,22 +107,20 @@ expect_identical <- function( } else { ident <- identical(act$val, exp$val, ...) if (ident) { - msg <- "" + msg_act <- NULL } else { compare <- compare(act$val, exp$val) if (compare$equal) { - msg <- "Objects equal but not identical" + msg_act <- "Objects equal but not identical" } else { - msg <- compare$message + msg_act <- compare$message } } if (!ident) { - msg <- sprintf( - "Expected %s to be identical to %s.\n%s", - act$lab, - exp$lab, - msg + msg <- c( + sprintf("Expected %s to be identical to %s.", act$lab, exp$lab), + msg_act ) return(fail(msg, info = info)) } @@ -146,12 +144,10 @@ expect_waldo_equal_ <- function( y_arg = "expected" ) if (length(comp) != 0) { - msg <- sprintf( - "Expected %s to be %s to %s.\n\n%s", - act$lab, - type, - exp$lab, - paste0(comp, collapse = "\n\n") + msg <- c( + sprintf("Expected %s to be %s to %s.", act$lab, type, exp$lab), + "Differences:", + paste0(comp, collpase = "\n") ) return(fail(msg, info = info, trace_env = trace_env)) } diff --git a/R/expect-inheritance.R b/R/expect-inheritance.R index 08b965ea7..417a4b0b1 100644 --- a/R/expect-inheritance.R +++ b/R/expect-inheritance.R @@ -70,11 +70,9 @@ expect_type <- function(object, type) { act_type <- typeof(act$val) if (!identical(act_type, type)) { - msg <- sprintf( - "Expected %s to have type %s.\nActual type: %s", - act$lab, - format_class(type), - format_class(act_type) + msg <- c( + sprintf("Expected %s to have type %s.", act$lab, format_class(type)), + sprintf("Actual type: %s", format_class(act_type)) ) return(fail(msg)) } @@ -102,16 +100,14 @@ expect_s3_class <- function(object, class, exact = FALSE) { if (!isS3(act$val)) { msg <- c( sprintf("Expected %s to be an S3 object.", act$lab), - sprintf("Actually is a %s object.", oo_type(act$val)) + sprintf("Actual OO type: %s.", oo_type(act$val)) ) return(fail(msg)) } else if (exact) { if (!identical(class(act$val), class)) { - msg <- sprintf( - "Expected %s to have class %s.\nActual class: %s", - act$lab, - exp_lab, - act$class + msg <- c( + sprintf("Expected %s to have class %s.", act$lab, exp_lab), + sprintf("Actual class: %s", act$class) ) return(fail(msg)) } @@ -147,7 +143,7 @@ expect_s4_class <- function(object, class) { if (!isS4(act$val)) { msg <- c( sprintf("Expected %s to be an S4 object.", act$lab), - sprintf("Actually is a %s object.", oo_type(act$val)) + sprintf("Actual OO type: %s.", oo_type(act$val)) ) return(fail(msg)) } else { @@ -175,7 +171,7 @@ expect_r6_class <- function(object, class) { if (!inherits(act$val, "R6")) { msg <- c( sprintf("Expected %s to be an R6 object.", act$lab), - sprintf("Actually is a %s object.", oo_type(act$val)) + sprintf("Actual OO type: %s.", oo_type(act$val)) ) return(fail(msg)) } @@ -206,7 +202,7 @@ expect_s7_class <- function(object, class) { if (!S7::S7_inherits(object)) { msg <- c( sprintf("Expected %s to be an S7 object.", act$lab), - sprintf("Actually is a %s object.", oo_type(act$val)) + sprintf("Actual OO type: %s.", oo_type(act$val)) ) return(fail(msg)) } @@ -279,8 +275,11 @@ format_class <- function(x) { oo_type <- function(x) { if (!is.object(x)) { - "base" - } else if (!isS4(x)) { + return("none") + } + if (isS4(x)) { + "S4" + } else { if (inherits(x, "R6")) { "R6" } else if (inherits(x, "S7")) { @@ -288,11 +287,5 @@ oo_type <- function(x) { } else { "S3" } - } else { - if (!is(x, "refClass")) { - "S4" - } else { - "RC" - } } } diff --git a/R/expect-invisible.R b/R/expect-invisible.R index 9b1c5fe31..9ae1ec596 100644 --- a/R/expect-invisible.R +++ b/R/expect-invisible.R @@ -27,7 +27,7 @@ expect_invisible <- function(call, label = NULL) { if (!identical(vis$visible, FALSE)) { msg <- c( sprintf("Expected %s to return invisibly.", lab), - "Actually returned visibly." + "Actual visibility: visible." ) return(fail(msg)) } @@ -43,7 +43,7 @@ expect_visible <- function(call, label = NULL) { if (!identical(vis$visible, TRUE)) { msg <- c( sprintf("Expected %s to return visibly.", lab), - "Actually returned invisibly." + "Actual visibility: invisible." ) return(fail(msg)) } diff --git a/R/expect-match.R b/R/expect-match.R index 8b7b22324..da62f9586 100644 --- a/R/expect-match.R +++ b/R/expect-match.R @@ -132,7 +132,7 @@ expect_match_ <- function( } match <- if (negate) "not to match" else "to match" - exp_msg <- sprintf( + msg_exp <- sprintf( "Expected %s%s %s %s %s.", which, act$lab, @@ -140,6 +140,6 @@ expect_match_ <- function( if (fixed) "string" else "regexp", encodeString(regexp, quote = '"') ) - act_msg <- c(paste0("Actual ", title, ':'), text) - return(fail(c(exp_msg, act_msg), info = info, trace_env = trace_env)) + msg_act <- c(paste0("Actual ", title, ':'), text) + return(fail(c(msg_exp, msg_act), info = info, trace_env = trace_env)) } diff --git a/R/expect-no-condition.R b/R/expect-no-condition.R index a253ab43c..fce92a4d8 100644 --- a/R/expect-no-condition.R +++ b/R/expect-no-condition.R @@ -108,7 +108,7 @@ expect_no_ <- function( act <- quasi_capture(enquo(object), NULL, capture) if (!is.null(first_match)) { - exp_msg <- paste0( + msg_exp <- paste0( "Expected ", act$lab, " to run without any ", @@ -118,13 +118,8 @@ expect_no_ <- function( if (!is.null(regexp)) paste0(" matching pattern '", regexp, "'"), "." ) - act_msg <- paste0( - "Actually got a <", - class(first_match)[[1]], - "> with message:\n", - indent_lines(rlang::cnd_message(first_match)) - ) - return(fail(c(exp_msg, act_msg), trace_env = trace_env)) + msg_act <- actual_condition(first_match) + return(fail(c(msg_exp, msg_act), trace_env = trace_env)) } pass(act$val) diff --git a/R/expect-output.R b/R/expect-output.R index 4b120a62b..fea13a7a4 100644 --- a/R/expect-output.R +++ b/R/expect-output.R @@ -36,10 +36,9 @@ expect_output <- function( if (identical(regexp, NA)) { if (!identical(act$cap, "")) { - msg <- sprintf( - "Expected %s to produce no output.\nActual output:\n%s", - act$lab, - encodeString(act$cap) + msg <- c( + sprintf("Expected %s to produce no output.", act$lab), + sprintf("Actual output:\n%s", encodeString(act$cap)) ) return(fail(msg, info = info)) } diff --git a/R/expect-shape.R b/R/expect-shape.R index 570d94330..c7c1ae311 100644 --- a/R/expect-shape.R +++ b/R/expect-shape.R @@ -67,7 +67,7 @@ expect_shape = function(object, ..., nrow, ncol, dim) { check_number_whole(ncol, allow_na = TRUE) if (length(dim_object) == 1L) { - msg <- sprintf("Expected %s to have more than one dimension.", act$lab) + msg <- sprintf("Expected %s to have two or more dimensions.", act$lab) return(fail(msg)) } diff --git a/tests/testthat/_snaps/expect-comparison.md b/tests/testthat/_snaps/expect-comparison.md index 4a52df96a..69629ca16 100644 --- a/tests/testthat/_snaps/expect-comparison.md +++ b/tests/testthat/_snaps/expect-comparison.md @@ -1,20 +1,20 @@ # basic comparisons work Code - expect_lt(10, 10) + expect_lt(x, 10) Condition Error: - ! Expected 10 < 10. + ! Expected `x` < 10. Actual 10.0 >= 10.0 Difference 0.0 >= 0 --- Code - expect_gt(10, 10) + expect_gt(x, 10) Condition Error: - ! Expected 10 > 10. + ! Expected `x` > 10. Actual 10.0 <= 10.0 Difference 0.0 <= 0 diff --git a/tests/testthat/_snaps/expect-condition.md b/tests/testthat/_snaps/expect-condition.md index 93675519d..0683dd97a 100644 --- a/tests/testthat/_snaps/expect-condition.md +++ b/tests/testthat/_snaps/expect-condition.md @@ -13,8 +13,8 @@ Condition Error: ! Expected `stop("Yes")` to not throw a error. - Actual : - Yes + Actually got a with message: + Yes # regexp = string matches for error message @@ -49,8 +49,8 @@ Condition Error: ! Expected `fb()` to not throw a error. - Actual : - dispatched! + Actually got a with message: + dispatched! # expect_warning validates its inputs @@ -82,8 +82,9 @@ Condition Error: ! Expected `message("!")` to not throw a message. - Actual : - ! + Actually got a with message: + ! + # expect_message validates its inputs diff --git a/tests/testthat/_snaps/expect-constant.md b/tests/testthat/_snaps/expect-constant.md index 5c01263cf..47c2404c8 100644 --- a/tests/testthat/_snaps/expect-constant.md +++ b/tests/testthat/_snaps/expect-constant.md @@ -5,7 +5,7 @@ Condition Error: ! Expected `df` to be equal to TRUE. - + Differences: `actual` is an S3 object of class , a list `expected` is a logical vector (TRUE) @@ -16,7 +16,7 @@ Condition Error: ! Expected `df` to be equal to FALSE. - + Differences: `actual` is an S3 object of class , a list `expected` is a logical vector (FALSE) @@ -27,9 +27,10 @@ Condition Error: ! Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + NOPE --- @@ -39,9 +40,10 @@ Condition Error: ! Expected TRUE to be equal to FALSE. - + Differences: `actual`: TRUE `expected`: FALSE + YUP # expect_null works @@ -51,7 +53,7 @@ Condition Error: ! Expected `df` to be equal to FALSE. - + Differences: `actual` is an S3 object of class , a list `expected` is NULL diff --git a/tests/testthat/_snaps/expect-equality.md b/tests/testthat/_snaps/expect-equality.md index b023f9540..6a5464551 100644 --- a/tests/testthat/_snaps/expect-equality.md +++ b/tests/testthat/_snaps/expect-equality.md @@ -1,88 +1,3 @@ -# basical principles of equality hold - - Code - expect_equal(1, 2) - Condition - Error: - ! Expected 1 to equal 2. - Actual: - 1/1 mismatches - [1] 1 - 2 == -1 - ---- - - Code - expect_identical(1, 2) - Condition - Error: - ! Expected 1 to be identical to 2. - 1/1 mismatches - [1] 1 - 2 == -1 - ---- - - Code - expect_equal(1, 2) - Condition - Error: - ! Expected 1 to be equal to 2. - - `actual`: 1.0 - `expected`: 2.0 - ---- - - Code - expect_identical(1, 2) - Condition - Error: - ! Expected 1 to be identical to 2. - - `actual`: 1.0 - `expected`: 2.0 - -# expect_equal() ignores numeric type; expect_identical() does not - - Code - expect_identical(1, 1L) - Condition - Error: - ! Expected 1 to be identical to 1L. - Objects equal but not identical - ---- - - Code - expect_identical(1, 1L) - Condition - Error: - ! Expected 1 to be identical to 1L. - - `actual` is a double vector (1) - `expected` is an integer vector (1) - -# can control numeric tolerance - - Code - expect_equal(x1, x2) - Condition - Error: - ! Expected `x1` to equal `x2`. - Actual: - 1/1 mismatches - [1] 1 - 1 == -1e-06 - ---- - - Code - expect_equal(x1, x2) - Condition - Error: - ! Expected `x1` to be equal to `x2`. - - `actual`: 1.0000000 - `expected`: 1.0000010 - # provide useful feedback on failure Code @@ -90,7 +5,7 @@ Condition Error: ! Expected `x` to be identical to "a". - + Differences: `actual` is a double vector (1) `expected` is a character vector ('a') @@ -101,7 +16,7 @@ Condition Error: ! Expected `x` to be equal to "a". - + Differences: `actual` is a double vector (1) `expected` is a character vector ('a') @@ -135,28 +50,6 @@ 1/1 mismatches [1] 1 - 2 == -1 -# % is not treated as sprintf format specifier (#445) - - Code - expect_equal("+", "%") - Condition - Error: - ! Expected "+" to be equal to "%". - - `actual`: "+" - `expected`: "%" - ---- - - Code - expect_equal("%", "+") - Condition - Error: - ! Expected "%" to be equal to "+". - - `actual`: "%" - `expected`: "+" - # useful message if objects equal but not identical Code @@ -164,8 +57,7 @@ Condition Error: ! Expected `f` to be identical to `g`. - names for target but not for current - Length mismatch: comparison on first 0 components + Objects equal but not identical # attributes for object (#452) diff --git a/tests/testthat/_snaps/expect-inheritance.md b/tests/testthat/_snaps/expect-inheritance.md index 7bed811aa..7889909f9 100644 --- a/tests/testthat/_snaps/expect-inheritance.md +++ b/tests/testthat/_snaps/expect-inheritance.md @@ -31,7 +31,7 @@ Condition Error: ! Expected `x1` to be an S3 object. - Actually is a base object. + Actual OO type: none. --- @@ -40,7 +40,7 @@ Condition Error: ! Expected `x2` to be an S3 object. - Actually is a S4 object. + Actual OO type: S4. --- @@ -49,7 +49,7 @@ Condition Error: ! Expected `x3` to be an S4 object. - Actually is a S3 object. + Actual OO type: S3. # expect_s[34]_class can check not S3/S4 @@ -131,7 +131,7 @@ Condition Error: ! Expected `x` to be an R6 object. - Actually is a base object. + Actual OO type: none. Code expect_r6_class(person, "Student") Condition @@ -165,6 +165,15 @@ ! Expected `Baz()` to inherit from . Actual class: / +# informative failure if not S7 + + Code + expect_s7_class(x, Foo) + Condition + Error: + ! Expected `x` to be an S7 object. + Actual OO type: S3. + # expect_s7_class validates its inputs Code diff --git a/tests/testthat/_snaps/expect-invisible.md b/tests/testthat/_snaps/expect-invisible.md index 1a8b3812c..ed32db00f 100644 --- a/tests/testthat/_snaps/expect-invisible.md +++ b/tests/testthat/_snaps/expect-invisible.md @@ -5,7 +5,7 @@ Condition Error: ! Expected `x` to return invisibly. - Actually returned visibly. + Actual visibility: visible. --- @@ -14,7 +14,7 @@ Condition Error: ! Expected `x <- 1` to return visibly. - Actually returned invisibly. + Actual visibility: invisible. # generates useful failure messages @@ -23,7 +23,7 @@ Condition Error: ! Expected `invisible(1)` to return visibly. - Actually returned invisibly. + Actual visibility: invisible. --- @@ -32,5 +32,5 @@ Condition Error: ! Expected 1 to return invisibly. - Actually returned visibly. + Actual visibility: visible. diff --git a/tests/testthat/_snaps/expect-named.md b/tests/testthat/_snaps/expect-named.md index b43522cec..ddcffe4f0 100644 --- a/tests/testthat/_snaps/expect-named.md +++ b/tests/testthat/_snaps/expect-named.md @@ -13,7 +13,7 @@ Condition Error: ! Expected names(`c(a = 1)`) to be equal to "b". - + Differences: `actual`: "a" `expected`: "b" @@ -52,7 +52,7 @@ Condition Error: ! Expected names(`x1`) to be equal to `c("a", "b")`. - + Differences: `actual`: "a" `expected`: "a" "b" @@ -63,7 +63,7 @@ Condition Error: ! Expected names(`x2`) to be equal to "a". - + Differences: `actual`: "a" "b" `expected`: "a" @@ -74,7 +74,7 @@ Condition Error: ! Expected names(`x1`) to be equal to `c("b")`. - + Differences: `actual`: "a" `expected`: "b" diff --git a/tests/testthat/_snaps/expect-self-test.md b/tests/testthat/_snaps/expect-self-test.md index ad00dcd84..3038a68fe 100644 --- a/tests/testthat/_snaps/expect-self-test.md +++ b/tests/testthat/_snaps/expect-self-test.md @@ -103,9 +103,10 @@ Output Failed expectation: Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + # expect_no are deprecated diff --git a/tests/testthat/_snaps/expect-setequal.md b/tests/testthat/_snaps/expect-setequal.md index 1afdfdb9d..dfe6e5e5e 100644 --- a/tests/testthat/_snaps/expect-setequal.md +++ b/tests/testthat/_snaps/expect-setequal.md @@ -110,7 +110,7 @@ Condition Error: ! Expected `list(a = 1, b = 2, b = 3)` to be equal to `list(b = 2, a = 1)`. - + Differences: `actual` is length 3 `expected` is length 2 @@ -127,7 +127,7 @@ Condition Error: ! Expected `list(a = 1, b = 2)` to be equal to `list(b = 3, b = 2, a = 1)`. - + Differences: `actual` is length 2 `expected` is length 3 @@ -147,7 +147,7 @@ Condition Error: ! Expected `list(a = 1, b = 2, b = 3)` to be equal to `list(b = 3, b = 2, a = 1)`. - + Differences: `actual[[2]]`: 2.0 `expected[[2]]`: 3.0 @@ -161,7 +161,7 @@ Condition Error: ! Expected `list(a = 1, b = 2)` to be equal to `list(a = 1)`. - + Differences: `actual` is length 2 `expected` is length 1 @@ -178,7 +178,7 @@ Condition Error: ! Expected `list(a = 1)` to be equal to `list(a = 1, b = 2)`. - + Differences: `actual` is length 1 `expected` is length 2 @@ -195,7 +195,7 @@ Condition Error: ! Expected `list(a = 1, b = 2)` to be equal to `list(a = 1, b = 3)`. - + Differences: `actual$b`: 2.0 `expected$b`: 3.0 @@ -206,7 +206,7 @@ Condition Error: ! Expected `list(1, b = 2, c = 3)` to be equal to `list(b = 2, 1, c = 3)`. - + Differences: `names(actual)`: "" "b" "c" `names(expected)`: "b" "" "c" diff --git a/tests/testthat/_snaps/expect-shape.md b/tests/testthat/_snaps/expect-shape.md index 39dd5a7b5..f2b6c527b 100644 --- a/tests/testthat/_snaps/expect-shape.md +++ b/tests/testthat/_snaps/expect-shape.md @@ -83,7 +83,7 @@ expect_shape(array(1), ncol = 1) Condition Error: - ! Expected `array(1)` to have more than one dimension. + ! Expected `array(1)` to have two or more dimensions. --- @@ -91,7 +91,7 @@ expect_shape(array(integer()), ncol = 0L) Condition Error: - ! Expected `array(integer())` to have more than one dimension. + ! Expected `array(integer())` to have two or more dimensions. # NA handling (e.g. dbplyr) diff --git a/tests/testthat/_snaps/reporter-check.md b/tests/testthat/_snaps/reporter-check.md index 4c665b494..5bba608bf 100644 --- a/tests/testthat/_snaps/reporter-check.md +++ b/tests/testthat/_snaps/reporter-check.md @@ -16,14 +16,16 @@ == Failed tests ================================================================ -- Failure ('reporters/tests.R:12:3'): Failure:1 ------------------------------- Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + -- Failure ('reporters/tests.R:16:8'): Failure:2a ------------------------------ Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Backtrace: x 1. \-f() @@ -72,14 +74,16 @@ == Failed tests ================================================================ -- Failure ('reporters/tests.R:12:3'): Failure:1 ------------------------------- Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + -- Failure ('reporters/tests.R:16:8'): Failure:2a ------------------------------ Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Backtrace: x 1. \-f() diff --git a/tests/testthat/_snaps/reporter-junit.md b/tests/testthat/_snaps/reporter-junit.md index d7d151251..ca10c5d7d 100644 --- a/tests/testthat/_snaps/reporter-junit.md +++ b/tests/testthat/_snaps/reporter-junit.md @@ -8,15 +8,17 @@ Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE - `expected`: TRUE + `expected`: TRUE + Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Backtrace: x 1. \-f() diff --git a/tests/testthat/_snaps/reporter-progress.md b/tests/testthat/_snaps/reporter-progress.md index 3514f28c8..bcaa80a32 100644 --- a/tests/testthat/_snaps/reporter-progress.md +++ b/tests/testthat/_snaps/reporter-progress.md @@ -67,69 +67,80 @@ -------------------------------------------------------------------------------- Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + -------------------------------------------------------------------------------- Maximum number of failures exceeded; quitting at end of file. i Increase this number with (e.g.) `testthat::set_max_fails(Inf)` @@ -284,9 +295,10 @@ Failure ('reporters/backtraces.R:62:6'): (code run outside of `test_that()`) Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Backtrace: x 1. \-f() @@ -296,9 +308,10 @@ Failure ('reporters/backtraces.R:67:3'): nested expectations get backtraces Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Backtrace: x 1. \-f() @@ -404,9 +417,10 @@ Failure ('reporters/backtraces.R:62:6'): (code run outside of `test_that()`) Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Backtrace: x 1. \-f() @@ -416,9 +430,10 @@ Failure ('reporters/backtraces.R:67:3'): nested expectations get backtraces Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Backtrace: x 1. \-f() @@ -462,15 +477,17 @@ -- Failure ('reporters/tests.R:12:3'): Failure:1 ------------------------------- Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + -- Failure ('reporters/tests.R:16:8'): Failure:2a ------------------------------ Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Backtrace: x 1. \-f() @@ -560,69 +577,80 @@ -------------------------------------------------------------------------------- Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Failure ('reporters/fail-many.R:3:5'): Example Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + -------------------------------------------------------------------------------- Maximum number of failures exceeded; quitting at end of file. i Increase this number with (e.g.) `testthat::set_max_fails(Inf)` diff --git a/tests/testthat/_snaps/reporter-stop.md b/tests/testthat/_snaps/reporter-stop.md index f814c9d6c..6047b75ab 100644 --- a/tests/testthat/_snaps/reporter-stop.md +++ b/tests/testthat/_snaps/reporter-stop.md @@ -2,15 +2,17 @@ -- Failure ('reporters/tests.R:12:3'): Failure:1 ------------------------------- Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + -- Failure ('reporters/tests.R:16:8'): Failure:2a ------------------------------ Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Backtrace: x 1. \-f() diff --git a/tests/testthat/_snaps/reporter-summary.md b/tests/testthat/_snaps/reporter-summary.md index 888a8c107..90888b6c5 100644 --- a/tests/testthat/_snaps/reporter-summary.md +++ b/tests/testthat/_snaps/reporter-summary.md @@ -20,15 +20,17 @@ == Failed ====================================================================== -- 1. Failure ('reporters/tests.R:12:3'): Failure:1 ---------------------------- Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + -- 2. Failure ('reporters/tests.R:16:8'): Failure:2a --------------------------- Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Backtrace: x 1. \-f() @@ -69,15 +71,17 @@ == Failed ====================================================================== -- 1. Failure ('reporters/tests.R:12:3'): Failure:1 ---------------------------- Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + -- 2. Failure ('reporters/tests.R:16:8'): Failure:2a --------------------------- Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Backtrace: x 1. \-f() @@ -118,15 +122,17 @@ == Failed ====================================================================== -- 1. Failure ('reporters/tests.R:12:3'): Failure:1 ---------------------------- Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + -- 2. Failure ('reporters/tests.R:16:8'): Failure:2a --------------------------- Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Backtrace: x 1. \-f() diff --git a/tests/testthat/_snaps/reporter-tap.md b/tests/testthat/_snaps/reporter-tap.md index b4642dbaf..681d5f232 100644 --- a/tests/testthat/_snaps/reporter-tap.md +++ b/tests/testthat/_snaps/reporter-tap.md @@ -6,14 +6,16 @@ # Context Failures not ok 2 Failure:1 Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + not ok 3 Failure:2a Expected FALSE to be equal to TRUE. - + Differences: `actual`: FALSE `expected`: TRUE + Backtrace: x 1. \-f() diff --git a/tests/testthat/_snaps/reporter-teamcity.md b/tests/testthat/_snaps/reporter-teamcity.md index fc65f4e96..46f62d9d5 100644 --- a/tests/testthat/_snaps/reporter-teamcity.md +++ b/tests/testthat/_snaps/reporter-teamcity.md @@ -12,13 +12,13 @@ ##teamcity[testSuiteStarted name='Failures'] ##teamcity[testSuiteStarted name='Failure:1'] ##teamcity[testStarted name='expectation 1'] - ##teamcity[testFailed name='expectation 1' message='Expected FALSE to be equal to TRUE.' details='|n`actual`: FALSE|n`expected`: TRUE '] + ##teamcity[testFailed name='expectation 1' message='Expected FALSE to be equal to TRUE.' details='Differences:|n`actual`: FALSE|n`expected`: TRUE '] ##teamcity[testFinished name='expectation 1'] ##teamcity[testSuiteFinished name='Failure:1'] ##teamcity[testSuiteStarted name='Failure:2a'] ##teamcity[testStarted name='expectation 1'] - ##teamcity[testFailed name='expectation 1' message='Expected FALSE to be equal to TRUE.' details='|n`actual`: FALSE|n`expected`: TRUE |nBacktrace:|n x|n 1. \-f()|n 2. \-testthat::expect_true(FALSE)'] + ##teamcity[testFailed name='expectation 1' message='Expected FALSE to be equal to TRUE.' details='Differences:|n`actual`: FALSE|n`expected`: TRUE |n|nBacktrace:|n x|n 1. \-f()|n 2. \-testthat::expect_true(FALSE)'] ##teamcity[testFinished name='expectation 1'] ##teamcity[testSuiteFinished name='Failure:2a'] diff --git a/tests/testthat/_snaps/try-again.md b/tests/testthat/_snaps/try-again.md index 6f50b6bce..623946499 100644 --- a/tests/testthat/_snaps/try-again.md +++ b/tests/testthat/_snaps/try-again.md @@ -15,7 +15,7 @@ Condition Error: ! Expected `i` to be equal to 0. - + Differences: `actual`: 1.0 `expected`: 0.0 diff --git a/tests/testthat/test-expect-comparison.R b/tests/testthat/test-expect-comparison.R index 05868c486..b1a5d0742 100644 --- a/tests/testthat/test-expect-comparison.R +++ b/tests/testthat/test-expect-comparison.R @@ -1,11 +1,12 @@ test_that("basic comparisons work", { - expect_success(expect_lt(10, 11)) - expect_snapshot_failure(expect_lt(10, 10)) - expect_success(expect_lte(10, 10)) + x <- 10 + expect_success(expect_lt(x, 11)) + expect_snapshot_failure(expect_lt(x, 10)) + expect_success(expect_lte(x, 10)) expect_success(expect_gt(11, 10)) - expect_snapshot_failure(expect_gt(10, 10)) - expect_success(expect_gte(10, 10)) + expect_snapshot_failure(expect_gt(x, 10)) + expect_success(expect_gte(x, 10)) }) test_that("useful output when numbers are very small", { diff --git a/tests/testthat/test-expect-equality.R b/tests/testthat/test-expect-equality.R index 6da455e35..ce7d201f1 100644 --- a/tests/testthat/test-expect-equality.R +++ b/tests/testthat/test-expect-equality.R @@ -1,25 +1,25 @@ test_that("basical principles of equality hold", { local_edition(2) expect_success(expect_equal(1, 1)) - expect_snapshot_failure(expect_equal(1, 2)) + expect_failure(expect_equal(1, 2)) expect_success(expect_identical(1, 1)) - expect_snapshot_failure(expect_identical(1, 2)) + expect_failure(expect_identical(1, 2)) local_edition(3) expect_success(expect_equal(1, 1)) - expect_snapshot_failure(expect_equal(1, 2)) + expect_failure(expect_equal(1, 2)) expect_success(expect_identical(1, 1)) - expect_snapshot_failure(expect_identical(1, 2)) + expect_failure(expect_identical(1, 2)) }) test_that("expect_equal() ignores numeric type; expect_identical() does not", { local_edition(2) expect_success(expect_equal(1, 1L)) - expect_snapshot_failure(expect_identical(1, 1L)) + expect_failure(expect_identical(1, 1L)) local_edition(3) expect_success(expect_equal(1, 1L)) - expect_snapshot_failure(expect_identical(1, 1L)) + expect_failure(expect_identical(1, 1L)) }) test_that("returns value", { @@ -39,7 +39,7 @@ test_that("can control numeric tolerance", { x2 <- x1 + 1e-6 local_edition(2) - expect_snapshot_failure(expect_equal(x1, x2)) + expect_failure(expect_equal(x1, x2)) expect_success(expect_equal(x1, x2, tolerance = 1e-5)) expect_success(expect_equivalent(x1, x2, tolerance = 1e-5)) @@ -48,7 +48,7 @@ test_that("can control numeric tolerance", { expect_success(expect_equal(x1, x2, tol = 1e-5)) local_edition(3) - expect_snapshot_failure(expect_equal(x1, x2)) + expect_failure(expect_equal(x1, x2)) expect_success(expect_equal(x1, x2, tolerance = 1e-5)) }) @@ -83,43 +83,20 @@ test_that("default labels use unquoting", { }) test_that("% is not treated as sprintf format specifier (#445)", { - expect_snapshot_failure(expect_equal("+", "%")) - expect_snapshot_failure(expect_equal("%", "+")) - expect_equal("%", "%") + expect_failure(expect_equal("+", "%")) + expect_failure(expect_equal("%", "+")) + expect_success(expect_equal("%", "%")) }) -test_that("is_call_infix() handles complex calls (#1472)", { - expect_false(is_call_infix(quote( - base::any( - c( - veryyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy_long_name = TRUE - ), - na.rm = TRUE - ) - ))) - - withr::local_envvar( - "_R_CHECK_LENGTH_1_LOGIC2_" = "TRUE", - ) - expect_true( - base::any( - c( - veryyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy_long_name = TRUE - ), - na.rm = TRUE - ) - ) -}) - - # 2nd edition --------------------------------------------------- test_that("useful message if objects equal but not identical", { local_edition(2) f <- function() x + environment(f) <- new_environment() g <- function() x - environment(g) <- globalenv() + environment(g) <- new_environment() expect_snapshot_failure(expect_identical(f, g)) }) diff --git a/tests/testthat/test-expect-inheritance.R b/tests/testthat/test-expect-inheritance.R index a727dad63..09b000ce8 100644 --- a/tests/testthat/test-expect-inheritance.R +++ b/tests/testthat/test-expect-inheritance.R @@ -127,7 +127,6 @@ test_that("expect_r6_class validates its inputs", { # expect_s7_class -------------------------------------------------------- test_that("can check with actual class", { - skip_if_not_installed("S7") Foo <- S7::new_class("Foo", package = NULL) Bar <- S7::new_class("Bar", package = NULL) expect_success(expect_s7_class(Foo(), class = Foo)) @@ -137,6 +136,13 @@ test_that("can check with actual class", { expect_snapshot_failure(expect_s7_class(Baz(), class = Bar)) }) +test_that("informative failure if not S7", { + Foo <- S7::new_class("Foo", package = NULL) + + x <- factor() + expect_snapshot_failure(expect_s7_class(x, Foo)) +}) + test_that("expect_s7_class validates its inputs", { expect_snapshot(expect_s7_class(1, 1), error = TRUE) }) diff --git a/tests/testthat/test-quasi-label.R b/tests/testthat/test-quasi-label.R index 91f58ad96..501013be9 100644 --- a/tests/testthat/test-quasi-label.R +++ b/tests/testthat/test-quasi-label.R @@ -10,6 +10,30 @@ test_that("symbols are quoted", { expect_equal(expr_label(quote(a)), "`a`") }) + +test_that("is_call_infix() handles complex calls (#1472)", { + expect_false(is_call_infix(quote( + base::any( + c( + veryyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy_long_name = TRUE + ), + na.rm = TRUE + ) + ))) + + withr::local_envvar( + "_R_CHECK_LENGTH_1_LOGIC2_" = "TRUE", + ) + expect_true( + base::any( + c( + veryyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy_long_name = TRUE + ), + na.rm = TRUE + ) + ) +}) + test_that("long vectors get ...", { long <- "123456789_123456789_123456789_123456789_123456789_123456789_" expect_equal( diff --git a/vignettes/custom-expectation.Rmd b/vignettes/custom-expectation.Rmd index 3575d103b..0b50083fe 100644 --- a/vignettes/custom-expectation.Rmd +++ b/vignettes/custom-expectation.Rmd @@ -103,7 +103,7 @@ expect_vector_length <- function(object, n) { if (!rlang::is_vector(act$val)) { msg <- c( sprintf("Expected %s to be a vector", act$lab), - sprintf("Actual: %s", typeof(act$val)) + sprintf("Actual type: %s", typeof(act$val)) ) return(fail(msg)) } @@ -147,7 +147,7 @@ expect_s3_class <- function(object, class) { if (isS4(act$val)) { msg <- c( sprintf("Expected %s to be an S3 object.", act$lab), - "Actual: S4 object" + "Actual OO type: S4" ) return(fail(msg)) } From ecd50297ebc2cd21f631eb6f8af26acd2825558b Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 15:24:45 -0500 Subject: [PATCH 18/20] Bring back `expect_waldo_constant_` --- R/expect-constant.R | 31 ++++++++++-- tests/testthat/_snaps/expect-constant.md | 10 ++-- tests/testthat/_snaps/expect-self-test.md | 2 +- tests/testthat/_snaps/reporter-check.md | 8 ++-- tests/testthat/_snaps/reporter-debug.md | 4 +- tests/testthat/_snaps/reporter-junit.md | 4 +- tests/testthat/_snaps/reporter-progress.md | 56 +++++++++++----------- tests/testthat/_snaps/reporter-rstudio.md | 4 +- tests/testthat/_snaps/reporter-stop.md | 4 +- tests/testthat/_snaps/reporter-summary.md | 12 ++--- tests/testthat/_snaps/reporter-tap.md | 4 +- tests/testthat/_snaps/reporter-teamcity.md | 4 +- 12 files changed, 84 insertions(+), 59 deletions(-) diff --git a/R/expect-constant.R b/R/expect-constant.R index 65b0570d5..655bf012d 100644 --- a/R/expect-constant.R +++ b/R/expect-constant.R @@ -31,7 +31,7 @@ NULL expect_true <- function(object, info = NULL, label = NULL) { act <- quasi_label(enquo(object), label) exp <- labelled_value(TRUE, "TRUE") - expect_waldo_equal_("equal", act, exp, info = info, ignore_attr = TRUE) + expect_waldo_constant_(act, exp, info = info, ignore_attr = TRUE) } #' @export @@ -39,7 +39,7 @@ expect_true <- function(object, info = NULL, label = NULL) { expect_false <- function(object, info = NULL, label = NULL) { act <- quasi_label(enquo(object), label) exp <- labelled_value(FALSE, "FALSE") - expect_waldo_equal_("equal", act, exp, info = info, ignore_attr = TRUE) + expect_waldo_constant_(act, exp, info = info, ignore_attr = TRUE) } #' Do you expect `NULL`? @@ -59,5 +59,30 @@ expect_false <- function(object, info = NULL, label = NULL) { expect_null <- function(object, info = NULL, label = NULL) { act <- quasi_label(enquo(object), label) exp <- labelled_value(NULL, "FALSE") - expect_waldo_equal_("equal", act, exp, info = info) + expect_waldo_constant_(act, exp, info = info) +} + +expect_waldo_constant_ <- function( + act, + exp, + ..., + info = NULL, + trace_env = caller_env() +) { + comp <- waldo_compare( + act$val, + exp$val, + ..., + x_arg = "actual", + y_arg = "expected" + ) + if (length(comp) != 0) { + msg <- c( + sprintf("Expected %s to be %s.", act$lab, exp$lab), + "Differences:", + paste0(comp, collpase = "\n") + ) + return(fail(msg, info = info, trace_env = trace_env)) + } + pass(act$val) } diff --git a/tests/testthat/_snaps/expect-constant.md b/tests/testthat/_snaps/expect-constant.md index 47c2404c8..36d1a7646 100644 --- a/tests/testthat/_snaps/expect-constant.md +++ b/tests/testthat/_snaps/expect-constant.md @@ -4,7 +4,7 @@ expect_true(df) Condition Error: - ! Expected `df` to be equal to TRUE. + ! Expected `df` to be TRUE. Differences: `actual` is an S3 object of class , a list `expected` is a logical vector (TRUE) @@ -15,7 +15,7 @@ expect_false(df) Condition Error: - ! Expected `df` to be equal to FALSE. + ! Expected `df` to be FALSE. Differences: `actual` is an S3 object of class , a list `expected` is a logical vector (FALSE) @@ -26,7 +26,7 @@ expect_true(FALSE, "NOPE") Condition Error: - ! Expected FALSE to be equal to TRUE. + ! Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE @@ -39,7 +39,7 @@ expect_false(TRUE, "YUP") Condition Error: - ! Expected TRUE to be equal to FALSE. + ! Expected TRUE to be FALSE. Differences: `actual`: TRUE `expected`: FALSE @@ -52,7 +52,7 @@ expect_null(df) Condition Error: - ! Expected `df` to be equal to FALSE. + ! Expected `df` to be FALSE. Differences: `actual` is an S3 object of class , a list `expected` is NULL diff --git a/tests/testthat/_snaps/expect-self-test.md b/tests/testthat/_snaps/expect-self-test.md index 3038a68fe..a475b9bbf 100644 --- a/tests/testthat/_snaps/expect-self-test.md +++ b/tests/testthat/_snaps/expect-self-test.md @@ -102,7 +102,7 @@ show_failure(expect_true(FALSE)) Output Failed expectation: - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/reporter-check.md b/tests/testthat/_snaps/reporter-check.md index 5bba608bf..315e40d16 100644 --- a/tests/testthat/_snaps/reporter-check.md +++ b/tests/testthat/_snaps/reporter-check.md @@ -15,13 +15,13 @@ == Failed tests ================================================================ -- Failure ('reporters/tests.R:12:3'): Failure:1 ------------------------------- - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE -- Failure ('reporters/tests.R:16:8'): Failure:2a ------------------------------ - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE @@ -73,13 +73,13 @@ == Failed tests ================================================================ -- Failure ('reporters/tests.R:12:3'): Failure:1 ------------------------------- - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE -- Failure ('reporters/tests.R:16:8'): Failure:2a ------------------------------ - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/reporter-debug.md b/tests/testthat/_snaps/reporter-debug.md index bcba41d51..c4392e84f 100644 --- a/tests/testthat/_snaps/reporter-debug.md +++ b/tests/testthat/_snaps/reporter-debug.md @@ -1,12 +1,12 @@ # produces consistent output 1: expect_true(FALSE) - 2: expect_waldo_equal_("equal", act, exp, info = info, ignore_attr = TRUE) + 2: expect_waldo_constant_(act, exp, info = info, ignore_attr = TRUE) 3: fail(msg, info = info, trace_env = trace_env) 1: f() 2: expect_true(FALSE) - 3: expect_waldo_equal_("equal", act, exp, info = info, ignore_attr = TRUE) + 3: expect_waldo_constant_(act, exp, info = info, ignore_attr = TRUE) 4: fail(msg, info = info, trace_env = trace_env) 1: stop("stop") diff --git a/tests/testthat/_snaps/reporter-junit.md b/tests/testthat/_snaps/reporter-junit.md index ca10c5d7d..edd7697ef 100644 --- a/tests/testthat/_snaps/reporter-junit.md +++ b/tests/testthat/_snaps/reporter-junit.md @@ -7,14 +7,14 @@ - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/reporter-progress.md b/tests/testthat/_snaps/reporter-progress.md index bcaa80a32..8bca1cf1e 100644 --- a/tests/testthat/_snaps/reporter-progress.md +++ b/tests/testthat/_snaps/reporter-progress.md @@ -66,77 +66,77 @@ x | 11 0 | reporters/fail-many -------------------------------------------------------------------------------- Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE @@ -294,7 +294,7 @@ 26. \-f(x - 1) Failure ('reporters/backtraces.R:62:6'): (code run outside of `test_that()`) - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE @@ -307,7 +307,7 @@ 4. \-testthat::expect_true(FALSE) Failure ('reporters/backtraces.R:67:3'): nested expectations get backtraces - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE @@ -416,7 +416,7 @@ 26. \-f(x - 1) Failure ('reporters/backtraces.R:62:6'): (code run outside of `test_that()`) - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE @@ -429,7 +429,7 @@ 4. \-testthat::expect_true(FALSE) Failure ('reporters/backtraces.R:67:3'): nested expectations get backtraces - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE @@ -476,14 +476,14 @@ [ FAIL 2 | WARN 0 | SKIP 0 | PASS 1 ] -- Failure ('reporters/tests.R:12:3'): Failure:1 ------------------------------- - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE -- Failure ('reporters/tests.R:16:8'): Failure:2a ------------------------------ - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE @@ -576,77 +576,77 @@ x | 11 0 | reporters/fail-many -------------------------------------------------------------------------------- Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE Failure ('reporters/fail-many.R:3:5'): Example - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/reporter-rstudio.md b/tests/testthat/_snaps/reporter-rstudio.md index cca38ad56..7993cf725 100644 --- a/tests/testthat/_snaps/reporter-rstudio.md +++ b/tests/testthat/_snaps/reporter-rstudio.md @@ -1,7 +1,7 @@ # reporter basics works - 'reporters/tests.R:12:3' [failure] Failure:1. Expected FALSE to be equal to TRUE. - 'reporters/tests.R:16:8' [failure] Failure:2a. Expected FALSE to be equal to TRUE. + 'reporters/tests.R:12:3' [failure] Failure:1. Expected FALSE to be TRUE. + 'reporters/tests.R:16:8' [failure] Failure:2a. Expected FALSE to be TRUE. 'reporters/tests.R:23:3' [error] Error:1. Error in `eval(code, test_env)`: stop 'reporters/tests.R:29:8' [error] errors get tracebacks. Error in `h()`: ! 'reporters/tests.R:37:3' [skip] explicit skips are reported. Reason: skip diff --git a/tests/testthat/_snaps/reporter-stop.md b/tests/testthat/_snaps/reporter-stop.md index 6047b75ab..c9225bf2b 100644 --- a/tests/testthat/_snaps/reporter-stop.md +++ b/tests/testthat/_snaps/reporter-stop.md @@ -1,14 +1,14 @@ # produces useful output -- Failure ('reporters/tests.R:12:3'): Failure:1 ------------------------------- - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE -- Failure ('reporters/tests.R:16:8'): Failure:2a ------------------------------ - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/reporter-summary.md b/tests/testthat/_snaps/reporter-summary.md index 90888b6c5..178ca92d2 100644 --- a/tests/testthat/_snaps/reporter-summary.md +++ b/tests/testthat/_snaps/reporter-summary.md @@ -19,14 +19,14 @@ == Failed ====================================================================== -- 1. Failure ('reporters/tests.R:12:3'): Failure:1 ---------------------------- - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE -- 2. Failure ('reporters/tests.R:16:8'): Failure:2a --------------------------- - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE @@ -70,14 +70,14 @@ == Failed ====================================================================== -- 1. Failure ('reporters/tests.R:12:3'): Failure:1 ---------------------------- - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE -- 2. Failure ('reporters/tests.R:16:8'): Failure:2a --------------------------- - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE @@ -121,14 +121,14 @@ == Failed ====================================================================== -- 1. Failure ('reporters/tests.R:12:3'): Failure:1 ---------------------------- - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE -- 2. Failure ('reporters/tests.R:16:8'): Failure:2a --------------------------- - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/reporter-tap.md b/tests/testthat/_snaps/reporter-tap.md index 681d5f232..86ef46f02 100644 --- a/tests/testthat/_snaps/reporter-tap.md +++ b/tests/testthat/_snaps/reporter-tap.md @@ -5,13 +5,13 @@ ok 1 Success # Context Failures not ok 2 Failure:1 - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE not ok 3 Failure:2a - Expected FALSE to be equal to TRUE. + Expected FALSE to be TRUE. Differences: `actual`: FALSE `expected`: TRUE diff --git a/tests/testthat/_snaps/reporter-teamcity.md b/tests/testthat/_snaps/reporter-teamcity.md index 46f62d9d5..6e89dc2fe 100644 --- a/tests/testthat/_snaps/reporter-teamcity.md +++ b/tests/testthat/_snaps/reporter-teamcity.md @@ -12,13 +12,13 @@ ##teamcity[testSuiteStarted name='Failures'] ##teamcity[testSuiteStarted name='Failure:1'] ##teamcity[testStarted name='expectation 1'] - ##teamcity[testFailed name='expectation 1' message='Expected FALSE to be equal to TRUE.' details='Differences:|n`actual`: FALSE|n`expected`: TRUE '] + ##teamcity[testFailed name='expectation 1' message='Expected FALSE to be TRUE.' details='Differences:|n`actual`: FALSE|n`expected`: TRUE '] ##teamcity[testFinished name='expectation 1'] ##teamcity[testSuiteFinished name='Failure:1'] ##teamcity[testSuiteStarted name='Failure:2a'] ##teamcity[testStarted name='expectation 1'] - ##teamcity[testFailed name='expectation 1' message='Expected FALSE to be equal to TRUE.' details='Differences:|n`actual`: FALSE|n`expected`: TRUE |n|nBacktrace:|n x|n 1. \-f()|n 2. \-testthat::expect_true(FALSE)'] + ##teamcity[testFailed name='expectation 1' message='Expected FALSE to be TRUE.' details='Differences:|n`actual`: FALSE|n`expected`: TRUE |n|nBacktrace:|n x|n 1. \-f()|n 2. \-testthat::expect_true(FALSE)'] ##teamcity[testFinished name='expectation 1'] ##teamcity[testSuiteFinished name='Failure:2a'] From cdf59be22cffac1503e4eafbfb81e57e4c25db69 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Mon, 11 Aug 2025 15:31:05 -0500 Subject: [PATCH 19/20] More comparison tweaking --- R/expect-comparison.R | 37 +++---- tests/testthat/_snaps/expect-comparison.md | 110 ++++----------------- tests/testthat/test-expect-comparison.R | 26 +++-- 3 files changed, 56 insertions(+), 117 deletions(-) diff --git a/R/expect-comparison.R b/R/expect-comparison.R index 40e16d09f..3e4081490 100644 --- a/R/expect-comparison.R +++ b/R/expect-comparison.R @@ -41,28 +41,31 @@ expect_compare_ <- function( diff <- act$val - exp$val msg_exp <- sprintf("Expected %s %s %s.", act$lab, operator, exp$lab) + digits <- max( + digits(act$val), + digits(exp$val), + min_digits(act$val, exp$val) + ) + + msg_act <- sprintf( + "Actual comparison: %s %s %s", + num_exact(act$val, digits), + actual_op, + num_exact(exp$val, digits) + ) + if (is.nan(diff)) { - msg_act <- "Actual values are incomparable." + msg_diff <- "Difference: incomparable." } else if (is.na(diff)) { - msg_act <- "Actual comparison is NA." + msg_diff <- "Difference: NA." } else { - digits <- max( - digits(act$val), - digits(exp$val), - min_digits(act$val, exp$val) - ) - - msg_act <- c( - sprintf( - "Actual %s %s %s", - num_exact(act$val, digits), - actual_op, - num_exact(exp$val, digits) - ), - sprintf("Difference %s %s 0", num_exact(diff, digits), actual_op) + msg_diff <- sprintf( + "Difference: %s %s 0", + num_exact(diff, digits), + actual_op ) } - return(fail(c(msg_exp, msg_act), trace_env = trace_env)) + return(fail(c(msg_exp, msg_act, msg_diff), trace_env = trace_env)) } pass(act$val) } diff --git a/tests/testthat/_snaps/expect-comparison.md b/tests/testthat/_snaps/expect-comparison.md index 69629ca16..a8e316a12 100644 --- a/tests/testthat/_snaps/expect-comparison.md +++ b/tests/testthat/_snaps/expect-comparison.md @@ -5,8 +5,8 @@ Condition Error: ! Expected `x` < 10. - Actual 10.0 >= 10.0 - Difference 0.0 >= 0 + Actual comparison: 10.0 >= 10.0 + Difference: 0.0 >= 0 --- @@ -15,8 +15,8 @@ Condition Error: ! Expected `x` > 10. - Actual 10.0 <= 10.0 - Difference 0.0 <= 0 + Actual comparison: 10.0 <= 10.0 + Difference: 0.0 <= 0 # useful output when numbers are very small @@ -25,8 +25,8 @@ Condition Error: ! Expected `1.1 * x` <= `x`. - Actual 0.0000110 > 0.0000100 - Difference 0.0000010 > 0 + Actual comparison: 0.0000110 > 0.0000100 + Difference: 0.0000010 > 0 --- @@ -35,8 +35,8 @@ Condition Error: ! Expected `x` > `1.1 * x`. - Actual 0.0000100 <= 0.0000110 - Difference -0.0000010 <= 0 + Actual comparison: 0.0000100 <= 0.0000110 + Difference: -0.0000010 <= 0 # useful output when difference is zero @@ -45,8 +45,8 @@ Condition Error: ! Expected `x` < 100. - Actual 100.0 >= 100.0 - Difference 0.0 >= 0 + Actual comparison: 100.0 >= 100.0 + Difference: 0.0 >= 0 # useful output when differnce is large @@ -55,98 +55,28 @@ Condition Error: ! Expected `x` < 0.001. - Actual 100.000 >= 0.001 - Difference 99.999 >= 0 + Actual comparison: 100.000 >= 0.001 + Difference: 99.999 >= 0 # comparisons with Inf work Code - expect_lt(Inf, Inf) + expect_lt(x, Inf) Condition Error: - ! Expected Inf < Inf. - Actual values are incomparable. - ---- - - Code - expect_gt(Inf, Inf) - Condition - Error: - ! Expected Inf > Inf. - Actual values are incomparable. + ! Expected `x` < Inf. + Actual comparison: Inf >= Inf + Difference: incomparable. # comparisons with NA work Code - expect_lt(10, NA_real_) - Condition - Error: - ! Expected 10 < NA_real_. - Actual comparison is NA. - ---- - - Code - expect_lt(NA_real_, 10) - Condition - Error: - ! Expected NA_real_ < 10. - Actual comparison is NA. - ---- - - Code - expect_lt(NA_real_, NA_real_) - Condition - Error: - ! Expected NA_real_ < NA_real_. - Actual comparison is NA. - ---- - - Code - expect_lte(NA_real_, NA_real_) - Condition - Error: - ! Expected NA_real_ <= NA_real_. - Actual comparison is NA. - ---- - - Code - expect_gt(10, NA_real_) - Condition - Error: - ! Expected 10 > NA_real_. - Actual comparison is NA. - ---- - - Code - expect_gt(NA_real_, 10) - Condition - Error: - ! Expected NA_real_ > 10. - Actual comparison is NA. - ---- - - Code - expect_gt(NA_real_, NA_real_) - Condition - Error: - ! Expected NA_real_ > NA_real_. - Actual comparison is NA. - ---- - - Code - expect_gte(NA_real_, NA_real_) + expect_lt(x, 10) Condition Error: - ! Expected NA_real_ >= NA_real_. - Actual comparison is NA. + ! Expected `x` < 10. + Actual comparison: NA >= 10.0 + Difference: NA. # comparison must yield a single logical diff --git a/tests/testthat/test-expect-comparison.R b/tests/testthat/test-expect-comparison.R index b1a5d0742..bfb7e0fa1 100644 --- a/tests/testthat/test-expect-comparison.R +++ b/tests/testthat/test-expect-comparison.R @@ -32,24 +32,30 @@ test_that("comparison result object invisibly", { test_that("comparisons with Inf work", { expect_success(expect_lt(10, Inf)) - expect_snapshot_failure(expect_lt(Inf, Inf)) + expect_failure(expect_lt(Inf, Inf)) expect_success(expect_lte(Inf, Inf)) expect_success(expect_gt(Inf, 10)) - expect_snapshot_failure(expect_gt(Inf, Inf)) + expect_failure(expect_gt(Inf, Inf)) expect_success(expect_gte(Inf, Inf)) + + x <- Inf + expect_snapshot_failure(expect_lt(x, Inf)) }) test_that("comparisons with NA work", { - expect_snapshot_failure(expect_lt(10, NA_real_)) - expect_snapshot_failure(expect_lt(NA_real_, 10)) - expect_snapshot_failure(expect_lt(NA_real_, NA_real_)) - expect_snapshot_failure(expect_lte(NA_real_, NA_real_)) + expect_failure(expect_lt(10, NA_real_)) + expect_failure(expect_lt(NA_real_, 10)) + expect_failure(expect_lt(NA_real_, NA_real_)) + expect_failure(expect_lte(NA_real_, NA_real_)) + + expect_failure(expect_gt(10, NA_real_)) + expect_failure(expect_gt(NA_real_, 10)) + expect_failure(expect_gt(NA_real_, NA_real_)) + expect_failure(expect_gte(NA_real_, NA_real_)) - expect_snapshot_failure(expect_gt(10, NA_real_)) - expect_snapshot_failure(expect_gt(NA_real_, 10)) - expect_snapshot_failure(expect_gt(NA_real_, NA_real_)) - expect_snapshot_failure(expect_gte(NA_real_, NA_real_)) + x <- NA_real_ + expect_snapshot_failure(expect_lt(x, 10)) }) test_that("comparisons with more complicated objects work", { From 2931bd9e5830b467beec5e90742a6aa9eeba0d99 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Tue, 12 Aug 2025 07:31:06 -0500 Subject: [PATCH 20/20] More consistentct --- R/expect-condition.R | 2 +- R/expect-constant.R | 2 +- R/expect-equality.R | 9 +- R/expect-inheritance.R | 4 +- R/expect-no-condition.R | 2 +- R/expect-self-test.R | 46 +++--- R/expect-setequal.R | 4 +- R/expect-silent.R | 2 +- tests/testthat/_snaps/expect-condition.md | 72 +--------- tests/testthat/_snaps/expect-constant.md | 2 +- tests/testthat/_snaps/expect-equality.md | 8 +- tests/testthat/_snaps/expect-inheritance.md | 28 ++-- tests/testthat/_snaps/expect-named.md | 8 +- tests/testthat/_snaps/expect-no-condition.md | 35 ++--- tests/testthat/_snaps/expect-self-test.md | 127 +++++------------ tests/testthat/_snaps/expect-setequal.md | 139 +------------------ tests/testthat/_snaps/expect-silent.md | 26 +--- tests/testthat/_snaps/old-school.md | 4 +- tests/testthat/test-compare.R | 11 +- tests/testthat/test-expect-condition.R | 16 ++- tests/testthat/test-expect-named.R | 8 +- tests/testthat/test-expect-no-condition.R | 2 +- tests/testthat/test-expect-self-test.R | 61 ++++++-- tests/testthat/test-expect-setequal.R | 20 +-- tests/testthat/test-expect-silent.R | 15 +- 25 files changed, 216 insertions(+), 437 deletions(-) diff --git a/R/expect-condition.R b/R/expect-condition.R index 7698b26c5..a483483f5 100644 --- a/R/expect-condition.R +++ b/R/expect-condition.R @@ -455,7 +455,7 @@ compare_condition_3e <- function(cond_type, cond_class, cond, lab, expected) { } else { if (!is.null(cond)) { c( - sprintf("Expected %s to not throw a %s.", lab, cond_type), + sprintf("Expected %s to not throw any %ss.", lab, cond_type), actual_condition(cond) ) } else { diff --git a/R/expect-constant.R b/R/expect-constant.R index 655bf012d..e6ca95d25 100644 --- a/R/expect-constant.R +++ b/R/expect-constant.R @@ -58,7 +58,7 @@ expect_false <- function(object, info = NULL, label = NULL) { #' show_failure(expect_null(y)) expect_null <- function(object, info = NULL, label = NULL) { act <- quasi_label(enquo(object), label) - exp <- labelled_value(NULL, "FALSE") + exp <- labelled_value(NULL, "NULL") expect_waldo_constant_(act, exp, info = info) } diff --git a/R/expect-equality.R b/R/expect-equality.R index 004e24c58..c01665603 100644 --- a/R/expect-equality.R +++ b/R/expect-equality.R @@ -77,10 +77,9 @@ expect_equal <- function( } if (!comp$equal) { - msg <- sprintf( - "Expected %s to equal %s.\nActual:\n%s", - act$lab, - exp$lab, + msg <- c( + sprintf("Expected %s to equal %s.", act$lab, exp$lab), + "Differences:", comp$message ) return(fail(msg, info = info)) @@ -89,6 +88,7 @@ expect_equal <- function( } } + #' @export #' @rdname equality-expectations expect_identical <- function( @@ -120,6 +120,7 @@ expect_identical <- function( if (!ident) { msg <- c( sprintf("Expected %s to be identical to %s.", act$lab, exp$lab), + "Differences:", msg_act ) return(fail(msg, info = info)) diff --git a/R/expect-inheritance.R b/R/expect-inheritance.R index 417a4b0b1..16caa7e3d 100644 --- a/R/expect-inheritance.R +++ b/R/expect-inheritance.R @@ -255,7 +255,7 @@ expect_is <- function(object, class, info = NULL, label = NULL) { if (!inherits(act$val, class)) { msg <- sprintf( - "Expected %s to inherit from `%s`.\nActual inheritance: `%s`", + "Expected %s to inherit from %s.\nActual inheritance: %s", act$lab, exp_lab, act$class @@ -270,7 +270,7 @@ expect_is <- function(object, class, info = NULL, label = NULL) { isS3 <- function(x) is.object(x) && !isS4(x) format_class <- function(x) { - paste0(encodeString(x, quote = "'"), collapse = "/") + paste0(encodeString(x, quote = '"'), collapse = "/") } oo_type <- function(x) { diff --git a/R/expect-no-condition.R b/R/expect-no-condition.R index fce92a4d8..f5e85c4ef 100644 --- a/R/expect-no-condition.R +++ b/R/expect-no-condition.R @@ -111,7 +111,7 @@ expect_no_ <- function( msg_exp <- paste0( "Expected ", act$lab, - " to run without any ", + " to not throw any ", base_class, "s", if (!is.null(class)) paste0(" of class '", class, "'"), diff --git a/R/expect-self-test.R b/R/expect-self-test.R index 942e3c053..23ba60be9 100644 --- a/R/expect-self-test.R +++ b/R/expect-self-test.R @@ -46,20 +46,20 @@ capture_success_failure <- function(expr) { expect_success <- function(expr) { status <- capture_success_failure(expr) - if (status$n_success == 0) { - return(fail("Expectation did not succeed")) - } else if (status$n_success > 1) { - return(fail(sprintf( - "Expected expectation to succeed once.\nActually succeeded: %i times", - status$n_success - ))) + if (status$n_success != 1) { + msg <- c( + "Expected code to succeed exactly once.", + sprintf("Actually succeeded %i times", status$n_success) + ) + return(fail(msg)) } if (status$n_failure > 0) { - return(fail(sprintf( - "Expected expectation to not fail.\nActually failed: %i times", - status$n_failure - ))) + msg <- c( + "Expected code to not fail.", + sprintf("Actually failed %i times", status$n_failure) + ) + return(fail(msg)) } pass(NULL) @@ -70,23 +70,25 @@ expect_success <- function(expr) { expect_failure <- function(expr, message = NULL, ...) { status <- capture_success_failure(expr) - if (status$n_failure == 0) { - return(fail("Expectation did not fail")) - } else if (status$n_failure > 1) { - # This should be impossible, but including for completeness - return(fail("Expectation failed more than once")) + if (status$n_failure != 1) { + msg <- c( + "Expected code to fail exactly once.", + sprintf("Actually failed %i times", status$n_failure) + ) + return(fail(msg)) } if (status$n_success != 0) { - return(fail(sprintf( - "Expected expectation to never succeed.\nActually succeeded: %i times", - status$n_success - ))) + msg <- c( + "Expected code to succeed exactly once.", + sprintf("Actually succeeded %i times", status$n_success) + ) + return(fail(msg)) } if (!is.null(message)) { - act <- labelled_value(status$last_failure$message, "Failure message") - return(expect_match_(act, message, ...)) + act <- labelled_value(status$last_failure$message, "failure message") + return(expect_match_(act, message, ..., title = "message")) } pass(NULL) } diff --git a/R/expect-setequal.R b/R/expect-setequal.R index 49e74a648..7e7140439 100644 --- a/R/expect-setequal.R +++ b/R/expect-setequal.R @@ -123,11 +123,11 @@ expect_in <- function(object, expected) { act_miss <- !act$val %in% exp$val if (any(act_miss)) { msg_exp <- sprintf( - "Expected all values in %s to be in %s.", + "Expected %s to only contain values from %s.", act$lab, exp$lab ) - msg_act <- sprintf("Extra: %s", values(act$val[act_miss])) + msg_act <- sprintf("Invalid: %s", values(act$val[act_miss])) fail(c(msg_exp, msg_act)) } diff --git a/R/expect-silent.R b/R/expect-silent.R index e29d508f4..7d96c5fec 100644 --- a/R/expect-silent.R +++ b/R/expect-silent.R @@ -29,7 +29,7 @@ expect_silent <- function(object) { if (length(outputs) != 0) { msg <- c( sprintf("Expected %s to run silently.", act$lab), - sprintf("Actually produced: %s.", paste(outputs, collapse = ", ")) + sprintf("Actual noise: %s.", paste(outputs, collapse = ", ")) ) return(fail(msg)) } diff --git a/tests/testthat/_snaps/expect-condition.md b/tests/testthat/_snaps/expect-condition.md index 0683dd97a..099791f74 100644 --- a/tests/testthat/_snaps/expect-condition.md +++ b/tests/testthat/_snaps/expect-condition.md @@ -12,7 +12,7 @@ expect_error(stop("Yes"), NA) Condition Error: - ! Expected `stop("Yes")` to not throw a error. + ! Expected `stop("Yes")` to not throw any errors. Actually got a with message: Yes @@ -48,7 +48,7 @@ expect_error(fb(), NA) Condition Error: - ! Expected `fb()` to not throw a error. + ! Expected `fb()` to not throw any errors. Actually got a with message: dispatched! @@ -78,10 +78,10 @@ # regexp = NA checks for absence of message Code - expect_message(message("!"), NA) + expect_message(f(), NA) Condition Error: - ! Expected `message("!")` to not throw a message. + ! Expected `f()` to not throw any messages. Actually got a with message: ! @@ -173,67 +173,3 @@ * Unused arguments: `pattern` and `fixed`. i Did you mean to use `regexp` so `...` is passed to `grepl()`? -# other conditions are swallowed - - Code - expect_error(f("error"), "not a match") - Condition - Error: - ! `f("error")` threw an error with unexpected message. - Expected match: "not a match" - Actual message: "error" - ---- - - Code - expect_warning(f("warning"), "not a match") - Condition - Error: - ! `f("warning")` produced unexpected warnings. - Expected match: not a match - Actual values: - * warning - ---- - - Code - expect_message(f("message"), "not a match") - Condition - Error: - ! `f("message")` produced unexpected messages. - Expected match: not a match - Actual values: - * message - ---- - - Code - expect_condition(f("condition"), "not a match") - Condition - Error: - ! `f("condition")` threw an condition with unexpected message. - Expected match: "not a match" - Actual message: "signal" - ---- - - Code - expect_error(f("error"), class = "not a match") - Condition - Error: - ! `f("error")` threw an error with unexpected class. - Expected class: not a match - Actual class: simpleError/error/condition - Message: error - ---- - - Code - expect_condition(f("message"), class = "not a match") - Condition - Error: - ! `f("message")` threw an condition with unexpected class. - Expected class: not a match - Actual class: simpleMessage/message/condition - Message: message - diff --git a/tests/testthat/_snaps/expect-constant.md b/tests/testthat/_snaps/expect-constant.md index 36d1a7646..4e5b980c0 100644 --- a/tests/testthat/_snaps/expect-constant.md +++ b/tests/testthat/_snaps/expect-constant.md @@ -52,7 +52,7 @@ expect_null(df) Condition Error: - ! Expected `df` to be FALSE. + ! Expected `df` to be NULL. Differences: `actual` is an S3 object of class , a list `expected` is NULL diff --git a/tests/testthat/_snaps/expect-equality.md b/tests/testthat/_snaps/expect-equality.md index 6a5464551..9c90c7651 100644 --- a/tests/testthat/_snaps/expect-equality.md +++ b/tests/testthat/_snaps/expect-equality.md @@ -27,6 +27,7 @@ Condition Error: ! Expected `x` to be identical to "a". + Differences: Types not compatible: double is not character --- @@ -36,7 +37,7 @@ Condition Error: ! Expected `x` to equal "a". - Actual: + Differences: Types not compatible: double is not character # default labels use unquoting @@ -46,7 +47,7 @@ Condition Error: ! Expected 1 to equal 2. - Actual: + Differences: 1/1 mismatches [1] 1 - 2 == -1 @@ -57,6 +58,7 @@ Condition Error: ! Expected `f` to be identical to `g`. + Differences: Objects equal but not identical # attributes for object (#452) @@ -66,7 +68,7 @@ Condition Error: ! Expected `oops` to equal 0. - Actual: + Differences: Attributes: < Modes: list, NULL > Attributes: < Lengths: 1, 0 > Attributes: < names for target but not for current > diff --git a/tests/testthat/_snaps/expect-inheritance.md b/tests/testthat/_snaps/expect-inheritance.md index 7889909f9..896bd1cf3 100644 --- a/tests/testthat/_snaps/expect-inheritance.md +++ b/tests/testthat/_snaps/expect-inheritance.md @@ -4,8 +4,8 @@ expect_type(x, "double") Condition Error: - ! Expected `x` to have type 'double'. - Actual type: 'integer' + ! Expected `x` to have type "double". + Actual type: "integer" # expect_type validates its inputs @@ -21,8 +21,8 @@ expect_is(factor("a"), "integer") Condition Error: - ! Expected `factor("a")` to inherit from `'character'`. - Actual inheritance: `'factor'` + ! Expected `factor("a")` to inherit from "character". + Actual inheritance: "factor" # expect_s3/s4_class fails if appropriate type @@ -73,8 +73,8 @@ expect_s4_class(C(), "D") Condition Error: - ! Expected `C()` to inherit from 'D'. - Actual class: 'C'/'A'/'B'/'list'/'vector' + ! Expected `C()` to inherit from "D". + Actual class: "C"/"A"/"B"/"list"/"vector" # expect_s3_class validates its inputs @@ -95,8 +95,8 @@ expect_s3_class(x, "c") Condition Error: - ! Expected `x` to inherit from 'c'. - Actual class: 'a'/'b' + ! Expected `x` to inherit from "c". + Actual class: "a"/"b" --- @@ -104,8 +104,8 @@ expect_s3_class(x, c("c", "d")) Condition Error: - ! Expected `x` to inherit from 'c'/'d'. - Actual class: 'a'/'b' + ! Expected `x` to inherit from "c"/"d". + Actual class: "a"/"b" # test_s3_class can request exact match @@ -113,8 +113,8 @@ expect_s3_class(x, "a", exact = TRUE) Condition Error: - ! Expected `x` to have class 'a'. - Actual class: 'a'/'b' + ! Expected `x` to have class "a". + Actual class: "a"/"b" # expect_s4_class validates its inputs @@ -136,8 +136,8 @@ expect_r6_class(person, "Student") Condition Error: - ! Expected `person` to inherit from 'Student'. - Actual class: 'Person'/'R6' + ! Expected `person` to inherit from "Student". + Actual class: "Person"/"R6" # expect_r6_class validates its inputs diff --git a/tests/testthat/_snaps/expect-named.md b/tests/testthat/_snaps/expect-named.md index ddcffe4f0..1d2007ed3 100644 --- a/tests/testthat/_snaps/expect-named.md +++ b/tests/testthat/_snaps/expect-named.md @@ -1,18 +1,18 @@ # expected_named verifies presence of names Code - expect_named(1:10) + expect_named(x) Condition Error: - ! Expected `1:10` to have names. + ! Expected `x` to have names. # expected_named verifies actual of names Code - expect_named(c(a = 1), "b") + expect_named(x, "b") Condition Error: - ! Expected names(`c(a = 1)`) to be equal to "b". + ! Expected names(`x`) to be equal to "b". Differences: `actual`: "a" `expected`: "b" diff --git a/tests/testthat/_snaps/expect-no-condition.md b/tests/testthat/_snaps/expect-no-condition.md index db95e8406..b88e22e06 100644 --- a/tests/testthat/_snaps/expect-no-condition.md +++ b/tests/testthat/_snaps/expect-no-condition.md @@ -4,7 +4,7 @@ expect_no_error(stop("error")) Condition Error: - ! Expected `stop("error")` to run without any errors. + ! Expected `stop("error")` to not throw any errors. Actually got a with message: error @@ -14,7 +14,7 @@ expect_no_warning(warning("warning")) Condition Error: - ! Expected `warning("warning")` to run without any warnings. + ! Expected `warning("warning")` to not throw any warnings. Actually got a with message: warning @@ -24,7 +24,7 @@ expect_no_message(message("message")) Condition Error: - ! Expected `message("message")` to run without any messages. + ! Expected `message("message")` to not throw any messages. Actually got a with message: message @@ -35,7 +35,7 @@ expect_no_error(abort("error")) Condition Error: - ! Expected `abort("error")` to run without any errors. + ! Expected `abort("error")` to not throw any errors. Actually got a with message: error @@ -45,7 +45,7 @@ expect_no_warning(warn("warning")) Condition Error: - ! Expected `warn("warning")` to run without any warnings. + ! Expected `warn("warning")` to not throw any warnings. Actually got a with message: warning @@ -55,30 +55,17 @@ expect_no_message(inform("message")) Condition Error: - ! Expected `inform("message")` to run without any messages. + ! Expected `inform("message")` to not throw any messages. Actually got a with message: message -# expect_no_ continues execution - - Code - expect_no_warning({ - warning("x") - b <- 2 - }) - Condition - Error: - ! Expected `{ ... }` to run without any warnings. - Actually got a with message: - x - # expect_no_* don't emit success when they fail Code expect_no_error(stop("!")) Condition Error: - ! Expected `stop("!")` to run without any errors. + ! Expected `stop("!")` to not throw any errors. Actually got a with message: ! @@ -88,28 +75,28 @@ expect_no_warning(foo()) Condition Error: - ! Expected `foo()` to run without any warnings. + ! Expected `foo()` to not throw any warnings. Actually got a with message: This is a problem! Code expect_no_warning(foo(), message = "problem") Condition Error: - ! Expected `foo()` to run without any warnings matching pattern 'problem'. + ! Expected `foo()` to not throw any warnings matching pattern 'problem'. Actually got a with message: This is a problem! Code expect_no_warning(foo(), class = "test") Condition Error: - ! Expected `foo()` to run without any warnings of class 'test'. + ! Expected `foo()` to not throw any warnings of class 'test'. Actually got a with message: This is a problem! Code expect_no_warning(foo(), message = "problem", class = "test") Condition Error: - ! Expected `foo()` to run without any warnings of class 'test' matching pattern 'problem'. + ! Expected `foo()` to not throw any warnings of class 'test' matching pattern 'problem'. Actually got a with message: This is a problem! diff --git a/tests/testthat/_snaps/expect-self-test.md b/tests/testthat/_snaps/expect-self-test.md index a475b9bbf..8966de61c 100644 --- a/tests/testthat/_snaps/expect-self-test.md +++ b/tests/testthat/_snaps/expect-self-test.md @@ -1,92 +1,30 @@ -# expect_failure() requires 1 failure and zero successes +# expect_failure() generates a useful error messages Code - expect_failure({ }) + expect_failure(expect_no_failure()) Condition Error: - ! Expectation did not fail - ---- - - Code - expect_failure(pass(NULL)) - Condition - Error: - ! Expectation did not fail - ---- - - Code - expect_failure({ - pass(NULL) - fail() - }) - Condition - Error: - ! Expected expectation to never succeed. - Actually succeeded: 1 times - ---- - - Code - expect_failure({ - fail() - pass(NULL) - fail() - }) - Condition - Error: - ! Expectation failed more than once - -# expect_failure() can optionally match message - - Code - expect_failure(fail("apple"), "banana") - Condition - Error: - ! Expected Failure message to match regexp "banana". - Actual text: - apple - -# expect_success() requires 1 success and zero failures - - Code - expect_success({ }) - Condition - Error: - ! Expectation did not succeed - ---- - + ! Expected code to fail exactly once. + Actually failed 0 times Code - expect_success(fail()) + expect_failure(expect_many_failures()) Condition Error: - ! Expectation did not succeed - ---- - + ! Expected code to fail exactly once. + Actually failed 2 times Code - expect_success({ - pass(NULL) - fail() - }) + expect_failure(expect_has_success()) Condition Error: - ! Expected expectation to not fail. - Actually failed: 1 times - ---- - + ! Expected code to succeed exactly once. + Actually succeeded 1 times Code - expect_success({ - pass(NULL) - pass(NULL) - }) + expect_failure(expect_failure_foo(), "bar") Condition Error: - ! Expected expectation to succeed once. - Actually succeeded: 2 times + ! Expected failure message to match regexp "bar". + Actual message: + foo # errors in expect_success bubble up @@ -108,6 +46,27 @@ `expected`: TRUE +# expect_success() generates a useful error messages + + Code + expect_success(expect_no_success()) + Condition + Error: + ! Expected code to succeed exactly once. + Actually succeeded 0 times + Code + expect_success(expect_many_successes()) + Condition + Error: + ! Expected code to succeed exactly once. + Actually succeeded 2 times + Code + expect_success(expect_has_failure()) + Condition + Error: + ! Expected code to not fail. + Actually failed 1 times + # expect_no are deprecated Code @@ -123,19 +82,3 @@ `expect_no_success()` was deprecated in testthat 3.3.0. i Please use `expect_failure()` instead. -# expect_no still work - - Code - expect_no_failure(fail()) - Condition - Error: - ! Expectation failed - ---- - - Code - expect_no_success(pass(NULL)) - Condition - Error: - ! Expectation succeeded - diff --git a/tests/testthat/_snaps/expect-setequal.md b/tests/testthat/_snaps/expect-setequal.md index dfe6e5e5e..64f29fd50 100644 --- a/tests/testthat/_snaps/expect-setequal.md +++ b/tests/testthat/_snaps/expect-setequal.md @@ -1,21 +1,3 @@ -# checks both directions of containment - - Code - expect_setequal(letters, letters[-1]) - Condition - Error: - ! Expected `letters` to have the same values as `letters[-1]`. - Needs: "a" - ---- - - Code - expect_setequal(letters[-1], letters) - Condition - Error: - ! Expected `letters[-1]` to have the same values as `letters`. - Extra: "a" - # warns if both inputs are named Code @@ -103,119 +85,6 @@ ! Expected `x` to have the same values as `y`. Extra: 3, 4, 5, 6, 7, 8, 9, 10, 11, ... -# error if any names are duplicated - - Code - expect_mapequal(list(a = 1, b = 2, b = 3), list(b = 2, a = 1)) - Condition - Error: - ! Expected `list(a = 1, b = 2, b = 3)` to be equal to `list(b = 2, a = 1)`. - Differences: - `actual` is length 3 - `expected` is length 2 - - `names(actual)`: "a" "b" "b" - `names(expected)`: "a" "b" - - `actual[[3]]` is a double vector (3) - `expected[[3]]` is absent - ---- - - Code - expect_mapequal(list(a = 1, b = 2), list(b = 3, b = 2, a = 1)) - Condition - Error: - ! Expected `list(a = 1, b = 2)` to be equal to `list(b = 3, b = 2, a = 1)`. - Differences: - `actual` is length 2 - `expected` is length 3 - - `names(actual)`: "a" "b" - `names(expected)`: "a" "b" "b" - - `actual[[2]]`: 2.0 - `expected[[2]]`: 3.0 - - `actual[[3]]` is absent - `expected[[3]]` is a double vector (2) - ---- - - Code - expect_mapequal(list(a = 1, b = 2, b = 3), list(b = 3, b = 2, a = 1)) - Condition - Error: - ! Expected `list(a = 1, b = 2, b = 3)` to be equal to `list(b = 3, b = 2, a = 1)`. - Differences: - `actual[[2]]`: 2.0 - `expected[[2]]`: 3.0 - - `actual[[3]]`: 3.0 - `expected[[3]]`: 2.0 - -# fail if names don't match - - Code - expect_mapequal(list(a = 1, b = 2), list(a = 1)) - Condition - Error: - ! Expected `list(a = 1, b = 2)` to be equal to `list(a = 1)`. - Differences: - `actual` is length 2 - `expected` is length 1 - - `names(actual)`: "a" "b" - `names(expected)`: "a" - - `actual$b` is a double vector (2) - `expected$b` is absent - ---- - - Code - expect_mapequal(list(a = 1), list(a = 1, b = 2)) - Condition - Error: - ! Expected `list(a = 1)` to be equal to `list(a = 1, b = 2)`. - Differences: - `actual` is length 1 - `expected` is length 2 - - `names(actual)`: "a" - `names(expected)`: "a" "b" - - `actual$b` is absent - `expected$b` is a double vector (2) - -# fails if values don't match - - Code - expect_mapequal(list(a = 1, b = 2), list(a = 1, b = 3)) - Condition - Error: - ! Expected `list(a = 1, b = 2)` to be equal to `list(a = 1, b = 3)`. - Differences: - `actual$b`: 2.0 - `expected$b`: 3.0 - -# fails if unnamed values in different location if any unnamed values - - Code - expect_mapequal(list(1, b = 2, c = 3), list(b = 2, 1, c = 3)) - Condition - Error: - ! Expected `list(1, b = 2, c = 3)` to be equal to `list(b = 2, 1, c = 3)`. - Differences: - `names(actual)`: "" "b" "c" - `names(expected)`: "b" "" "c" - - `actual[[1]]`: 1.0 - `expected[[1]]`: 2.0 - - `actual[[2]]`: 2.0 - `expected[[2]]`: 1.0 - # expect_contains() gives useful message on failure Code @@ -240,8 +109,8 @@ expect_in(x1, x2) Condition Error: - ! Expected all values in `x1` to be in `x2`. - Extra: "a" + ! Expected `x1` to only contain values from `x2`. + Invalid: "a" --- @@ -249,6 +118,6 @@ expect_in(x1, x3) Condition Error: - ! Expected all values in `x1` to be in `x3`. - Extra: "a", "b" + ! Expected `x1` to only contain values from `x3`. + Invalid: "a", "b" diff --git a/tests/testthat/_snaps/expect-silent.md b/tests/testthat/_snaps/expect-silent.md index 5b6d26a8f..cf5faa507 100644 --- a/tests/testthat/_snaps/expect-silent.md +++ b/tests/testthat/_snaps/expect-silent.md @@ -1,27 +1,9 @@ -# checks for any type of output +# generates useful failure message Code - expect_silent(warning("!")) + expect_silent(f()) Condition Error: - ! Expected `warning("!")` to run silently. - Actually produced: warnings. - ---- - - Code - expect_silent(message("!")) - Condition - Error: - ! Expected `message("!")` to run silently. - Actually produced: messages. - ---- - - Code - expect_silent(print("!")) - Condition - Error: - ! Expected `print("!")` to run silently. - Actually produced: output. + ! Expected `f()` to run silently. + Actual noise: output, warnings, messages. diff --git a/tests/testthat/_snaps/old-school.md b/tests/testthat/_snaps/old-school.md index ef535a7ea..b5e2b9237 100644 --- a/tests/testthat/_snaps/old-school.md +++ b/tests/testthat/_snaps/old-school.md @@ -5,6 +5,6 @@ Condition Error: ! Expected `x` > `expected`. - Actual 10.0 <= 11.0 - Difference -1.0 <= 0 + Actual comparison: 10.0 <= 11.0 + Difference: -1.0 <= 0 diff --git a/tests/testthat/test-compare.R b/tests/testthat/test-compare.R index 87dd9f30a..742765a29 100644 --- a/tests/testthat/test-compare.R +++ b/tests/testthat/test-compare.R @@ -40,7 +40,7 @@ test_that("classes must be identical", { c1 <- "a" c2 <- structure("a", class = "mycharacter") - expect_match(compare(c1, c2)$message, "'character' is not 'mycharacter'") + expect_match(compare(c1, c2)$message, "\"character\" is not \"mycharacter\"") }) test_that("attributes must be identical", { @@ -119,8 +119,11 @@ test_that("classes must be identical", { f1 <- factor("a") f2 <- factor("a", ordered = TRUE) - expect_match(compare(1L, f1)$message, "'integer' is not 'factor'") - expect_match(compare(1L, f2)$message, "'integer' is not 'ordered'/'factor'") + expect_match(compare(1L, f1)$message, "\"integer\" is not \"factor\"") + expect_match( + compare(1L, f2)$message, + "\"integer\" is not \"ordered\"/\"factor\"" + ) }) test_that("attributes must be identical", { @@ -184,7 +187,7 @@ test_that("both POSIXt classes are compatible", { test_that("other classes are not", { expect_match( compare(Sys.time(), 1)$message, - "'POSIXct'/'POSIXt' is not 'numeric'" + "\"POSIXct\"/\"POSIXt\" is not \"numeric\"" ) }) diff --git a/tests/testthat/test-expect-condition.R b/tests/testthat/test-expect-condition.R index c397aa7d5..6627026bc 100644 --- a/tests/testthat/test-expect-condition.R +++ b/tests/testthat/test-expect-condition.R @@ -149,7 +149,9 @@ test_that("expect_warning validates its inputs", { test_that("regexp = NA checks for absence of message", { expect_success(expect_message({}, NA)) - expect_snapshot_failure(expect_message(message("!"), NA)) + + f <- \() message("!") + expect_snapshot_failure(expect_message(f(), NA)) }) test_that("expect_message validates its inputs", { @@ -308,14 +310,14 @@ test_that("other conditions are swallowed", { local_edition(2) # if condition text doesn't match, expectation fails (not errors) - expect_snapshot_failure(expect_error(f("error"), "not a match")) - expect_snapshot_failure(expect_warning(f("warning"), "not a match")) - expect_snapshot_failure(expect_message(f("message"), "not a match")) - expect_snapshot_failure(expect_condition(f("condition"), "not a match")) + expect_failure(expect_error(f("error"), "not a match")) + expect_failure(expect_warning(f("warning"), "not a match")) + expect_failure(expect_message(f("message"), "not a match")) + expect_failure(expect_condition(f("condition"), "not a match")) # if error/condition class doesn't match, expectation fails - expect_snapshot_failure(expect_error(f("error"), class = "not a match")) - expect_snapshot_failure(expect_condition(f("message"), class = "not a match")) + expect_failure(expect_error(f("error"), class = "not a match")) + expect_failure(expect_condition(f("message"), class = "not a match")) # expect_message() and expect_warning() swallow all messages/warnings expect_message(expect_message(f("message", "message")), NA) diff --git a/tests/testthat/test-expect-named.R b/tests/testthat/test-expect-named.R index 8a79e92e2..21dfe4aed 100644 --- a/tests/testthat/test-expect-named.R +++ b/tests/testthat/test-expect-named.R @@ -1,11 +1,15 @@ test_that("expected_named verifies presence of names", { expect_success(expect_named(c(a = 1))) - expect_snapshot_failure(expect_named(1:10)) + + x <- 1:10 + expect_snapshot_failure(expect_named(x)) }) test_that("expected_named verifies actual of names", { expect_success(expect_named(c(a = 1), "a")) - expect_snapshot_failure(expect_named(c(a = 1), "b")) + + x <- c(a = 1) + expect_snapshot_failure(expect_named(x, "b")) }) test_that("expected_named optionally ignores order and case", { diff --git a/tests/testthat/test-expect-no-condition.R b/tests/testthat/test-expect-no-condition.R index 66ac4ac77..eb9a525f2 100644 --- a/tests/testthat/test-expect-no-condition.R +++ b/tests/testthat/test-expect-no-condition.R @@ -21,7 +21,7 @@ test_that("expect_no_* pass with pure code", { test_that("expect_no_ continues execution", { b <- 1 - expect_snapshot_failure(expect_no_warning({ + expect_failure(expect_no_warning({ warning("x") b <- 2 })) diff --git a/tests/testthat/test-expect-self-test.R b/tests/testthat/test-expect-self-test.R index 870d3a12b..4c14bd5e4 100644 --- a/tests/testthat/test-expect-self-test.R +++ b/tests/testthat/test-expect-self-test.R @@ -1,14 +1,14 @@ test_that("expect_failure() requires 1 failure and zero successes", { expect_success(expect_failure(fail())) - expect_snapshot_failure(expect_failure({})) - expect_snapshot_failure(expect_failure(pass(NULL))) - expect_snapshot_failure(expect_failure({ + expect_failure(expect_failure({})) + expect_failure(expect_failure(pass(NULL))) + expect_failure(expect_failure({ pass(NULL) fail() })) - expect_snapshot_failure(expect_failure({ + expect_failure(expect_failure({ fail() # Following succeed/fail are never reached pass(NULL) @@ -18,19 +18,39 @@ test_that("expect_failure() requires 1 failure and zero successes", { test_that("expect_failure() can optionally match message", { expect_success(expect_failure(fail("apple"), "apple")) - expect_snapshot_failure(expect_failure(fail("apple"), "banana")) + expect_failure(expect_failure(fail("apple"), "banana")) +}) + +test_that("expect_failure() generates a useful error messages", { + expect_no_failure <- function() {} + expect_many_failures <- function() { + fail() + fail() + } + expect_has_success <- function() { + fail() + pass(NULL) + } + expect_failure_foo <- function() fail("foo") + + expect_snapshot_failure({ + expect_failure(expect_no_failure()) + expect_failure(expect_many_failures()) + expect_failure(expect_has_success()) + expect_failure(expect_failure_foo(), "bar") + }) }) test_that("expect_success() requires 1 success and zero failures", { expect_success(expect_success(pass(NULL))) - expect_snapshot_failure(expect_success({})) - expect_snapshot_failure(expect_success(fail())) - expect_snapshot_failure(expect_success({ + expect_failure(expect_success({})) + expect_failure(expect_success(fail())) + expect_failure(expect_success({ pass(NULL) fail() })) - expect_snapshot_failure(expect_success({ + expect_failure(expect_success({ pass(NULL) pass(NULL) })) @@ -45,6 +65,25 @@ test_that("show_failure", { expect_snapshot(show_failure(expect_true(FALSE))) }) + +test_that("expect_success() generates a useful error messages", { + expect_no_success <- function() {} + expect_many_successes <- function() { + pass(NULL) + pass(NULL) + } + expect_has_failure <- function() { + fail() + pass(NULL) + } + + expect_snapshot_failure({ + expect_success(expect_no_success()) + expect_success(expect_many_successes()) + expect_success(expect_has_failure()) + }) +}) + test_that("can count successes and failures", { status <- capture_success_failure({}) expect_equal(status$n_success, 0) @@ -79,7 +118,7 @@ test_that("expect_no are deprecated", { test_that("expect_no still work", { withr::local_options(lifecycle_verbosity = "quiet") expect_success(expect_no_failure(pass(NULL))) - expect_snapshot_failure(expect_no_failure(fail())) + expect_failure(expect_no_failure(fail())) expect_success(expect_no_success(fail())) - expect_snapshot_failure(expect_no_success(pass(NULL))) + expect_failure(expect_no_success(pass(NULL))) }) diff --git a/tests/testthat/test-expect-setequal.R b/tests/testthat/test-expect-setequal.R index e57b7ab81..45b031a04 100644 --- a/tests/testthat/test-expect-setequal.R +++ b/tests/testthat/test-expect-setequal.R @@ -6,8 +6,8 @@ test_that("ignores order and duplicates", { }) test_that("checks both directions of containment", { - expect_snapshot_failure(expect_setequal(letters, letters[-1])) - expect_snapshot_failure(expect_setequal(letters[-1], letters)) + expect_failure(expect_setequal(letters, letters[-1])) + expect_failure(expect_setequal(letters[-1], letters)) }) test_that("truncates long differences", { @@ -75,16 +75,16 @@ test_that("ignores order recursively", { expect_success(expect_mapequal(x, y)) }) -test_that("error if any names are duplicated", { - expect_snapshot_failure(expect_mapequal( +test_that("fails when any names are duplicated", { + expect_failure(expect_mapequal( list(a = 1, b = 2, b = 3), list(b = 2, a = 1) )) - expect_snapshot_failure(expect_mapequal( + expect_failure(expect_mapequal( list(a = 1, b = 2), list(b = 3, b = 2, a = 1) )) - expect_snapshot_failure(expect_mapequal( + expect_failure(expect_mapequal( list(a = 1, b = 2, b = 3), list(b = 3, b = 2, a = 1) )) @@ -95,12 +95,12 @@ test_that("handling NULLs", { }) test_that("fail if names don't match", { - expect_snapshot_failure(expect_mapequal(list(a = 1, b = 2), list(a = 1))) - expect_snapshot_failure(expect_mapequal(list(a = 1), list(a = 1, b = 2))) + expect_failure(expect_mapequal(list(a = 1, b = 2), list(a = 1))) + expect_failure(expect_mapequal(list(a = 1), list(a = 1, b = 2))) }) test_that("fails if values don't match", { - expect_snapshot_failure(expect_mapequal( + expect_failure(expect_mapequal( list(a = 1, b = 2), list(a = 1, b = 3) )) @@ -108,7 +108,7 @@ test_that("fails if values don't match", { test_that("fails if unnamed values in different location if any unnamed values", { expect_success(expect_mapequal(list(1, b = 2, c = 3), list(1, c = 3, b = 2))) - expect_snapshot_failure(expect_mapequal( + expect_failure(expect_mapequal( list(1, b = 2, c = 3), list(b = 2, 1, c = 3) )) diff --git a/tests/testthat/test-expect-silent.R b/tests/testthat/test-expect-silent.R index 9a279813c..47be38c54 100644 --- a/tests/testthat/test-expect-silent.R +++ b/tests/testthat/test-expect-silent.R @@ -1,11 +1,20 @@ test_that("checks for any type of output", { - expect_snapshot_failure(expect_silent(warning("!"))) - expect_snapshot_failure(expect_silent(message("!"))) - expect_snapshot_failure(expect_silent(print("!"))) + expect_failure(expect_silent(warning("!"))) + expect_failure(expect_silent(message("!"))) + expect_failure(expect_silent(print("!"))) expect_success(expect_silent("")) }) +test_that("generates useful failure message", { + f <- function() { + warning("warning") + message("message") + cat("output") + } + expect_snapshot_failure(expect_silent(f())) +}) + test_that("returns first argument", { expect_equal(expect_silent(1), 1) })