Skip to content

Commit 0f5a03c

Browse files
committed
Merge commit '420f25dd7e34d309d2e21ef8d0d578f9d28e4c8e'
2 parents 1878d97 + 420f25d commit 0f5a03c

File tree

195 files changed

+6856
-1205
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

195 files changed

+6856
-1205
lines changed

CLAUDE.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ General advice:
1818
- `devtools::test_file("tests/testthat/test-filename.R")` - Run tests in a specific file
1919
- DO NOT USE `devtools::test_active_file()`
2020
- `devtools::load_all()` - Load package for development
21-
- `devtools::document()` - Generate documentation
2221
- `devtools::check()` - Run R CMD check
2322
- `devtools::install()` - Install package locally
2423

24+
### Documentation
25+
26+
- Always run `devtools::document()` after changing any roxygen2 docs.
27+
2528
## Core Architecture
2629

2730
### Main Components

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export(ProgressReporter)
4545
export(RStudioReporter)
4646
export(Reporter)
4747
export(SilentReporter)
48+
export(SlowReporter)
4849
export(StopReporter)
4950
export(SummaryReporter)
5051
export(TapReporter)
@@ -191,6 +192,7 @@ export(skip_on_os)
191192
export(skip_on_travis)
192193
export(skip_unless_r)
193194
export(snapshot_accept)
195+
export(snapshot_reject)
194196
export(snapshot_review)
195197
export(source_dir)
196198
export(source_file)

NEWS.md

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

33
* `test_dir()`, `test_file()`, `test_package()`, `test_check()`, `test_local()`, `source_file()` gain a `shuffle` argument uses `sample()` to randomly reorder the top-level expressions in each test file (#1942). This random reordering surfaces dependencies between tests and code outside of any test, as well as dependencies between tests. This helps you find and eliminate unintentional dependencies.
4+
* `snapshot_accept(test)` now works when the test file name contains `.` (#1669).
5+
* `local_mock()` and `with_mock()` have been deprecated because they are no longer permitted in R 4.5.
6+
* `snapshot_review()` now passes `...` on to `shiny::runApp()` (#1928).
7+
* `expect_named()` now gives more informative errors (#2091).
8+
* `expect_*()` functions consistently and rigorously check their inputs (#1754).
9+
* `test_that()` no longer warns about the absence of `{}` since it no longer seems to be necessary.
10+
* `test_that()`, `describe()`, and `it()` can now be arbitrarily nested. Each component will skip only if it and its subtests don't contain any expectations. The interactive stop reporter has been fixed so it doesn't duplicate failures. (#2063, #2188).
11+
* Test filtering now works with `it()`, and the `desc` argument can take a character vector in order to recursively filter subtests (i.e. `it()` nested inside of `describe()`) (#2118).
12+
* New `snapshot_reject()` rejects all modified snapshots by deleting the `.new` variants (#1923).
13+
* New `SlowReporter` makes it easier to find the slowest tests in your package. The easiest way to run it is with `devtools::test(reporter = "slow")` (#1466).
14+
* Power `expect_mapequal()` with `waldo::compare(list_as_map = TRUE)` (#1521).
15+
* On CRAN, `test_that()` now automatically skips if a package is not installed (#1585). Practically, this means that you no longer need to check that suggested packages are installed. (We don't do this in the tidyverse because we think it has limited payoff, but other styles advise differently.)
16+
* `expect_snapshot()` no longer skips on CRAN, as that skips the rest of the test. Instead it just returns, neither succeeding nor failing (#1585).
17+
* Interrupting a test now prints the test name. This makes it easier to tell where a very slow test might be hanging (#1464)
18+
* Parallel testthat now does not ignore test files with syntax errors (#1360).
19+
* `expect_lt()`, `expect_gt()`, and friends have a refined display that is more likely to display the correct number of digits and shows you the actual values compared.
20+
* `describe()`, `it()`, and `test_that()` now have a shared stack of descriptions so that if you nest any inside of each other, any resulting failures will show you the full path.
21+
* `describe()` now correctly scopes `skip()` (#2007).
422
* `ParallelProgressReporter` now respect `max_failures` (#1162).
523
* The last snapshot is no longer lost if the snapshot file is missing the final newline (#2092). It's easy to accidentally remove this because there are two trailing new lines in snapshot files and many editors will automatically remove if you touch the file.
624
* New `expect_r6_class()` (#2030).
7-
* `expect_*()` functions consistently and rigorously check their inputs (#1754).
25+
* `expect_*()` functions consistently and rigorously check their inputs (#1754).
826
* `JunitReporter()` no longer fails with `"no applicable method for xml_add_child"` for warnings outside of tests (#1913). Additionally, warnings now save their backtraces.
927
* `JunitReporter()` strips ANSI escapes in more placese (#1852, #2032).
1028
* `try_again()` is now publicised. The first argument is now the number of retries, not tries (#2050).
1129
* `vignette("custom-expectations)` has been overhauled to make it much clearer how to create high-quality expectations (#2113, #2132, #2072).
1230
* `expect_snapshot()` and friends will now fail when creating a new snapshot on CI. This is usually a signal that you've forgotten to run it locally before committing (#1461).
1331
* `expect_snapshot_value()` can now handle expressions that generate `-` (#1678) or zero length atomic vectors (#2042).
14-
* `expect_matches()` failures should be a little easier to read (#2135).
32+
* `expect_matches()` failures should be a little easier to read (#2135, #2181).
1533
* New `local_on_cran(TRUE)` allows you to simulate how your tests will run on CRAN (#2112).
1634
* `expect_no_*()` now executes the entire code block, rather than stopping at the first message or warning (#1991).
1735
* `expect_no_failures()` and `expect_no_successes()` are now deprecated as `expect_success()` now test for no failures and `expect_failure()` tests for no successes (#)

R/describe.R

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#'
2727
#' @param description description of the feature
2828
#' @param code test code containing the specs
29+
#' @keywords internal
2930
#' @export
3031
#' @examples
3132
#' describe("matrix()", {
@@ -56,43 +57,18 @@
5657
#' it("can handle division by 0") #not yet implemented
5758
#' })
5859
#' })
59-
6060
describe <- function(description, code) {
61-
check_string(description, allow_empty = FALSE)
62-
describe_description <- description
63-
64-
# prepares a new environment for each it-block
65-
describe_environment <- new.env(parent = parent.frame())
66-
describe_environment$it <- function(description, code = NULL) {
67-
check_string(description, allow_empty = FALSE)
68-
code <- substitute(code)
61+
local_description_push(description)
6962

70-
description <- paste0(describe_description, ": ", description)
71-
describe_it(description, code, describe_environment)
72-
}
73-
74-
eval(substitute(code), describe_environment)
75-
invisible()
76-
}
77-
78-
describe_it <- function(description, code, env = parent.frame()) {
79-
reporter <- get_reporter() %||% local_interactive_reporter()
80-
local_test_context()
81-
82-
test_code(
83-
description,
84-
code,
85-
env = env,
86-
reporter = reporter,
87-
skip_on_empty = FALSE
88-
)
63+
code <- substitute(code)
64+
test_code(code, parent.frame())
8965
}
9066

9167
#' @export
9268
#' @rdname describe
9369
it <- function(description, code = NULL) {
94-
check_string(description, allow_empty = FALSE)
70+
local_description_push(description)
9571

9672
code <- substitute(code)
97-
describe_it(description, code, env = parent.frame())
73+
test_code(code, parent.frame())
9874
}

R/edition.R

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ edition_deprecate <- function(in_edition, what, instead = NULL) {
2727
return()
2828
}
2929

30-
warn(c(
31-
paste0("`", what, "` was deprecated in ", edition_name(in_edition), "."),
30+
cli::cli_warn(c(
31+
"{.code {what}} was deprecated in {edition_name(in_edition)}.",
3232
i = instead
3333
))
3434
}
@@ -40,7 +40,7 @@ edition_require <- function(in_edition, what) {
4040
return()
4141
}
4242

43-
stop(paste0("`", what, "` requires ", edition_name(in_edition), "."))
43+
cli::cli_abort("{.code {what}} requires {edition_name(in_edition)}.")
4444
}
4545

4646
edition_name <- function(x) {

R/expect-comparison.R

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#' Does code return a number greater/less than the expected value?
1+
#' Do you expect a number bigger or smaller than this?
22
#'
33
#' @inheritParams expect_equal
44
#' @param object,expected A value to compare and its expected bound.
@@ -31,21 +31,34 @@ expect_compare_ <- function(
3131
msg <- c(
3232
"<" = "not strictly less than",
3333
"<=" = "not less than",
34-
">" = "not strictly more than",
35-
">=" = "not more than"
34+
">" = "not strictly greater than",
35+
">=" = "not greater than"
3636
)[[operator]]
3737

38+
negated_op <- switch(operator, "<" = ">=", "<=" = ">", ">" = "<=", ">=" = "<")
39+
3840
cmp <- op(act$val, exp$val)
3941
if (length(cmp) != 1 || !is.logical(cmp)) {
40-
abort("Result of comparison must be a single logical value")
42+
cli::cli_abort(
43+
"Result of comparison must be a single logical value.",
44+
call = trace_env
45+
)
4146
}
4247
if (!isTRUE(cmp)) {
48+
digits <- max(
49+
digits(act$val),
50+
digits(exp$val),
51+
min_digits(act$val, exp$val)
52+
)
4353
msg <- sprintf(
44-
"%s is %s %s. Difference: %.3g",
54+
"%s is %s %s.\n%s - %s = %s %s 0",
4555
act$lab,
4656
msg,
4757
exp$lab,
48-
act$val - exp$val
58+
num_exact(act$val, digits),
59+
num_exact(exp$val, digits),
60+
num_exact(act$val - exp$val, digits),
61+
negated_op
4962
)
5063
return(fail(msg, trace_env = trace_env))
5164
}
@@ -99,13 +112,49 @@ expect_gte <- function(object, expected, label = NULL, expected.label = NULL) {
99112
#' @param ... All arguments passed on to `expect_lt()`/`expect_gt()`.
100113
#' @keywords internal
101114
expect_less_than <- function(...) {
102-
warning("Deprecated: please use `expect_lt()` instead", call. = FALSE)
115+
cli::cli_warn("Deprecated: please use {.fn expect_lt} instead.")
103116
expect_lt(...)
104117
}
105118

106119
#' @rdname expect_less_than
107120
#' @export
108121
expect_more_than <- function(...) {
109-
warning("Deprecated: please use `expect_gt()` instead", call. = FALSE)
122+
cli::cli_warn("Deprecated: please use {.fn expect_gt} instead.")
110123
expect_gt(...)
111124
}
125+
126+
127+
# Helpers -----------------------------------------------------------------
128+
129+
num_exact <- function(x, digits = 6) {
130+
sprintf(paste0("%0.", digits, "f"), x)
131+
}
132+
133+
min_digits <- function(x, y, tolerance = testthat_tolerance()) {
134+
if (is.integer(x) && is.integer(y)) {
135+
return(0L)
136+
}
137+
138+
attributes(x) <- NULL
139+
attributes(y) <- NULL
140+
141+
n <- digits(abs(x - y))
142+
if (!is.null(tolerance)) {
143+
n <- min(n, digits(tolerance))
144+
}
145+
146+
as.integer(n) + 1L
147+
}
148+
149+
digits <- function(x) {
150+
x <- x[!is.na(x) & x != 0]
151+
if (length(x) == 0) {
152+
return(0)
153+
}
154+
scale <- -log10(min(x))
155+
if (scale <= 0) {
156+
0L
157+
} else {
158+
ceiling(round(scale, digits = 2))
159+
}
160+
}

R/expect-condition.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#' Does code throw an error, warning, message, or other condition?
1+
#' Do you expect an error, warning, message, or other condition?
22
#'
33
#' @description
44
#' `expect_error()`, `expect_warning()`, `expect_message()`, and
@@ -169,7 +169,7 @@ expect_warning <- function(
169169

170170
if (edition_get() >= 3) {
171171
if (!missing(all)) {
172-
warn("The `all` argument is deprecated")
172+
cli::cli_warn("The {.arg all} argument is deprecated.")
173173
}
174174

175175
expect_condition_matching_(

R/expect-constant.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#' Does code return `TRUE` or `FALSE`?
1+
#' Do you expect `TRUE` or `FALSE`?
22
#'
33
#' @description
44
#' These are fall-back expectations that you can use when none of the other
@@ -42,7 +42,7 @@ expect_false <- function(object, info = NULL, label = NULL) {
4242
expect_waldo_equal_("equal", act, exp, info = info, ignore_attr = TRUE)
4343
}
4444

45-
#' Does code return `NULL`?
45+
#' Do you expect `NULL`?
4646
#'
4747
#' This is a special case because `NULL` is a singleton so it's possible
4848
#' check for it either with `expect_equal(x, NULL)` or `expect_type(x, "NULL")`.

R/expect-equality.R

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#' Does code return the expected value?
1+
#' Do you expect this value?
22
#'
33
#' @description
44
#' These functions provide two levels of strictness when comparing a
@@ -126,7 +126,8 @@ expect_waldo_equal_ <- function(
126126
exp,
127127
info = NULL,
128128
...,
129-
trace_env = caller_env()
129+
trace_env = caller_env(),
130+
error_prefix = NULL
130131
) {
131132
comp <- waldo_compare(
132133
act$val,
@@ -145,6 +146,7 @@ expect_waldo_equal_ <- function(
145146
"`expected`",
146147
paste0(comp, collapse = "\n\n")
147148
)
149+
msg <- paste0(error_prefix, msg)
148150
return(fail(msg, info = info, trace_env = trace_env))
149151
}
150152
pass(act$val)

R/expect-inheritance.R

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
#' Does code return an object inheriting from the expected base type, S3 class,
2-
#' or S4 class?
1+
#' Do you expect an S3/S4/R6/S7 object that inherits from this class?
32
#'
43
#' @description
54
#' See <https://adv-r.hadley.nz/oo.html> for an overview of R's OO systems, and
@@ -207,7 +206,7 @@ expect_s7_class <- function(object, class) {
207206
pass(act$val)
208207
}
209208

210-
#' Does an object inherit from a given class?
209+
#' Do you expect to inherit from this class?
211210
#'
212211
#' @description
213212
#' `r lifecycle::badge("superseded")`

0 commit comments

Comments
 (0)