Skip to content

Commit 6d165ab

Browse files
committed
Merge commit 'fa29578e09f9eeafc6b9822364e29b07c8bd7a8c'
2 parents 560dd01 + fa29578 commit 6d165ab

File tree

162 files changed

+2723
-894
lines changed

Some content is hidden

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

162 files changed

+2723
-894
lines changed

.claude/settings.local.json

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

CLAUDE.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,23 @@ testthat is R's most popular unit testing framework, used by thousands of CRAN p
88

99
## Key Development Commands
1010

11-
### Testing
12-
- `devtools::test()` or `Ctrl/Cmd+Shift+T` in RStudio - Run all tests
13-
- `devtools::test_file("tests/testthat/test-filename.R")` - Run tests in a specific file
14-
- `testthat::test_local()` - Run tests for local source package
15-
- `testthat::test_package("testthat")` - Run tests for installed package
16-
- `R CMD check` - Full package check including tests
11+
General advice:
12+
* When running R from the console, always run it with `--quiet --vanilla`
13+
* Always run `air format .` after generating code
14+
15+
### Development tools
1716

18-
### Building and Installation
19-
- `devtools::load_all()` or `Ctrl/Cmd+Shift+L` - Load package for development
20-
- `devtools::document()` - Generate documentation
17+
- `devtools::test()` - Run all tests
18+
- `devtools::test_file("tests/testthat/test-filename.R")` - Run tests in a specific file
19+
- DO NOT USE `devtools::test_active_file()`
20+
- `devtools::load_all()` - Load package for development
2121
- `devtools::check()` - Run R CMD check
2222
- `devtools::install()` - Install package locally
2323

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

2630
### Main Components

DESCRIPTION

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,23 @@ BugReports: https://github.com/r-lib/testthat/issues
1717
Depends:
1818
R (>= 4.1.0)
1919
Imports:
20-
brio (>= 1.1.3),
21-
callr (>= 3.7.3),
22-
cli (>= 3.6.1),
23-
desc (>= 1.4.2),
24-
evaluate (>= 1.0.1),
25-
jsonlite (>= 1.8.7),
26-
lifecycle (>= 1.0.3),
20+
brio (>= 1.1.5),
21+
callr (>= 3.7.6),
22+
cli (>= 3.6.5),
23+
desc (>= 1.4.3),
24+
evaluate (>= 1.0.4),
25+
jsonlite (>= 2.0.0),
26+
lifecycle (>= 1.0.4),
2727
magrittr (>= 2.0.3),
2828
methods,
29-
pkgload (>= 1.3.2.1),
29+
pkgload (>= 1.4.0),
3030
praise (>= 1.0.0),
31-
processx (>= 3.8.2),
32-
ps (>= 1.7.5),
33-
R6 (>= 2.5.1),
34-
rlang (>= 1.1.1),
31+
processx (>= 3.8.6),
32+
ps (>= 1.9.1),
33+
R6 (>= 2.6.1),
34+
rlang (>= 1.1.6),
3535
utils,
36-
waldo (>= 0.6.0),
36+
waldo (>= 0.6.2),
3737
withr (>= 3.0.2)
3838
Suggests:
3939
covr,

NAMESPACE

Lines changed: 3 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)
@@ -114,6 +115,7 @@ export(expect_no_warning)
114115
export(expect_null)
115116
export(expect_output)
116117
export(expect_output_file)
118+
export(expect_r6_class)
117119
export(expect_reference)
118120
export(expect_s3_class)
119121
export(expect_s4_class)
@@ -228,5 +230,6 @@ import(rlang)
228230
importFrom(R6,R6Class)
229231
importFrom(brio,readLines)
230232
importFrom(brio,writeLines)
233+
importFrom(lifecycle,deprecated)
231234
importFrom(magrittr,"%>%")
232235
useDynLib(testthat, .registration = TRUE)

NEWS.md

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

3+
* 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).
4+
* Power `expect_mapequal()` with `waldo::compare(list_as_map = TRUE)` (#1521).
5+
* 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.)
6+
* `expect_snapshot()` no longer skips on CRAN, as that skips the rest of the test. Instead it just returns, neither succeeding nor failing (#1585).
7+
* Interrupting a test now prints the test name. This makes it easier to tell where a very slow test might be hanging (#1464)
8+
* Parallel testthat now does not ignore test files with syntax errors (#1360).
9+
* `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.
10+
* `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.
11+
* `describe()` now correctly scopes `skip()` (#2007).
12+
* `ParallelProgressReporter` now respect `max_failures` (#1162).
13+
* 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.
14+
* New `expect_r6_class()` (#2030).
15+
* `expect_*()` functions consistently and rigorously check their inputs (#1754).
16+
* `JunitReporter()` no longer fails with `"no applicable method for xml_add_child"` for warnings outside of tests (#1913). Additionally, warnings now save their backtraces.
17+
* `JunitReporter()` strips ANSI escapes in more placese (#1852, #2032).
18+
* `try_again()` is now publicised. The first argument is now the number of retries, not tries (#2050).
19+
* `vignette("custom-expectations)` has been overhauled to make it much clearer how to create high-quality expectations (#2113, #2132, #2072).
20+
* `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).
21+
* `expect_snapshot_value()` can now handle expressions that generate `-` (#1678) or zero length atomic vectors (#2042).
22+
* `expect_matches()` failures should be a little easier to read (#2135).
323
* New `local_on_cran(TRUE)` allows you to simulate how your tests will run on CRAN (#2112).
424
* `expect_no_*()` now executes the entire code block, rather than stopping at the first message or warning (#1991).
525
* `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/auto-test.R

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,18 @@
11
#' Watches code and tests for changes, rerunning tests as appropriate.
22
#'
3+
#' @description
4+
#' `r lifecycle::badge("superseded")`
5+
#'
36
#' The idea behind `auto_test()` is that you just leave it running while
47
#' you develop your code. Every time you save a file it will be automatically
58
#' tested and you can easily see if your changes have caused any test
6-
#' failures.
9+
#' failures.
710
#'
811
#' The current strategy for rerunning tests is as follows:
912
#'
1013
#' - if any code has changed, then those files are reloaded and all tests
1114
#' rerun
1215
#' - otherwise, each new or modified test is run
13-
#'
14-
#' In the future, `auto_test()` might implement one of the following more
15-
#' intelligent alternatives:
16-
#'
17-
#' - Use codetools to build up dependency tree and then rerun tests only
18-
#' when a dependency changes.
19-
#' - Mimic ruby's autotest and rerun only failing tests until they pass,
20-
#' and then rerun all tests.
21-
#
2216
#' @seealso [auto_test_package()]
2317
#' @export
2418
#' @param code_path path to directory containing code
@@ -27,7 +21,7 @@
2721
#' @param env environment in which to execute test suite.
2822
#' @param hash Passed on to [watch()]. When FALSE, uses less accurate
2923
#' modification time stamps, but those are faster for large files.
30-
#' @keywords debugging
24+
#' @keywords internal
3125
auto_test <- function(
3226
code_path,
3327
test_path,
@@ -67,15 +61,12 @@ auto_test <- function(
6761
watch(c(code_path, test_path), watcher, hash = hash)
6862
}
6963

70-
#' Watches a package for changes, rerunning tests as appropriate.
71-
#'
7264
#' @param pkg path to package
7365
#' @export
7466
#' @param reporter test reporter to use
7567
#' @param hash Passed on to [watch()]. When FALSE, uses less accurate
7668
#' modification time stamps, but those are faster for large files.
77-
#' @keywords debugging
78-
#' @seealso [auto_test()] for details on how method works
69+
#' @rdname auto_test
7970
auto_test_package <- function(
8071
pkg = ".",
8172
reporter = default_reporter(),

R/compare.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ compare <- function(x, y, ...) {
1616
}
1717

1818
comparison <- function(equal = TRUE, message = "Equal") {
19-
stopifnot(is.logical(equal), length(equal) == 1)
20-
stopifnot(is.character(message))
19+
check_bool(equal)
20+
check_character(message)
2121

2222
structure(
2323
list(

R/deprec-condition.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ capture_warnings <- function(code, ignore_deprecation = FALSE) {
129129
}
130130

131131
get_messages <- function(x) {
132-
vapply(x, cnd_message, FUN.VALUE = character(1))
132+
map_chr(x, cnd_message)
133133
}
134134

135135
#' Is an error informative?

R/describe.R

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -56,43 +56,17 @@
5656
#' it("can handle division by 0") #not yet implemented
5757
#' })
5858
#' })
59-
6059
describe <- function(description, code) {
61-
check_string(description, allow_empty = FALSE)
62-
describe_description <- description
63-
64-
# prepares a new environment for each it-block
65-
describe_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)
69-
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()
60+
local_description_push(description)
8161

82-
test_code(
83-
description,
84-
code,
85-
env = env,
86-
reporter = reporter,
87-
skip_on_empty = FALSE
88-
)
62+
test_code(code, parent.frame(), skip_on_empty = FALSE)
8963
}
9064

9165
#' @export
9266
#' @rdname describe
9367
it <- function(description, code = NULL) {
94-
check_string(description, allow_empty = FALSE)
68+
local_description_push(description)
9569

9670
code <- substitute(code)
97-
describe_it(description, code, env = parent.frame())
71+
test_code(code, env = parent.frame(), skip_on_empty = FALSE)
9872
}

R/expect-comparison.R

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,31 @@ 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)) {
4042
abort("Result of comparison must be a single logical value")
4143
}
4244
if (!isTRUE(cmp)) {
45+
digits <- max(
46+
digits(act$val),
47+
digits(exp$val),
48+
min_digits(act$val, exp$val)
49+
)
4350
msg <- sprintf(
44-
"%s is %s %s. Difference: %.3g",
51+
"%s is %s %s.\n%s - %s = %s %s 0",
4552
act$lab,
4653
msg,
4754
exp$lab,
48-
act$val - exp$val
55+
num_exact(act$val, digits),
56+
num_exact(exp$val, digits),
57+
num_exact(act$val - exp$val, digits),
58+
negated_op
4959
)
5060
return(fail(msg, trace_env = trace_env))
5161
}
@@ -54,35 +64,35 @@ expect_compare_ <- function(
5464
#' @export
5565
#' @rdname comparison-expectations
5666
expect_lt <- function(object, expected, label = NULL, expected.label = NULL) {
57-
act <- quasi_label(enquo(object), label, arg = "object")
58-
exp <- quasi_label(enquo(expected), expected.label, arg = "expected")
67+
act <- quasi_label(enquo(object), label)
68+
exp <- quasi_label(enquo(expected), expected.label)
5969

6070
expect_compare_("<", act, exp)
6171
}
6272

6373
#' @export
6474
#' @rdname comparison-expectations
6575
expect_lte <- function(object, expected, label = NULL, expected.label = NULL) {
66-
act <- quasi_label(enquo(object), label, arg = "object")
67-
exp <- quasi_label(enquo(expected), expected.label, arg = "expected")
76+
act <- quasi_label(enquo(object), label)
77+
exp <- quasi_label(enquo(expected), expected.label)
6878

6979
expect_compare_("<=", act, exp)
7080
}
7181

7282
#' @export
7383
#' @rdname comparison-expectations
7484
expect_gt <- function(object, expected, label = NULL, expected.label = NULL) {
75-
act <- quasi_label(enquo(object), label, arg = "object")
76-
exp <- quasi_label(enquo(expected), expected.label, arg = "expected")
85+
act <- quasi_label(enquo(object), label)
86+
exp <- quasi_label(enquo(expected), expected.label)
7787

7888
expect_compare_(">", act, exp)
7989
}
8090

8191
#' @export
8292
#' @rdname comparison-expectations
8393
expect_gte <- function(object, expected, label = NULL, expected.label = NULL) {
84-
act <- quasi_label(enquo(object), label, arg = "object")
85-
exp <- quasi_label(enquo(expected), expected.label, arg = "expected")
94+
act <- quasi_label(enquo(object), label)
95+
exp <- quasi_label(enquo(expected), expected.label)
8696

8797
expect_compare_(">=", act, exp)
8898
}
@@ -109,3 +119,39 @@ expect_more_than <- function(...) {
109119
warning("Deprecated: please use `expect_gt()` instead", call. = FALSE)
110120
expect_gt(...)
111121
}
122+
123+
124+
# Helpers -----------------------------------------------------------------
125+
126+
num_exact <- function(x, digits = 6) {
127+
sprintf(paste0("%0.", digits, "f"), x)
128+
}
129+
130+
min_digits <- function(x, y, tolerance = testthat_tolerance()) {
131+
if (is.integer(x) && is.integer(y)) {
132+
return(0L)
133+
}
134+
135+
attributes(x) <- NULL
136+
attributes(y) <- NULL
137+
138+
n <- digits(abs(x - y))
139+
if (!is.null(tolerance)) {
140+
n <- min(n, digits(tolerance))
141+
}
142+
143+
as.integer(n) + 1L
144+
}
145+
146+
digits <- function(x) {
147+
x <- x[!is.na(x) & x != 0]
148+
if (length(x) == 0) {
149+
return(0)
150+
}
151+
scale <- -log10(min(x))
152+
if (scale <= 0) {
153+
0L
154+
} else {
155+
ceiling(round(scale, digits = 2))
156+
}
157+
}

0 commit comments

Comments
 (0)