Skip to content

Commit a4685c4

Browse files
committed
Merge branch 'main' into issue_2106
2 parents 65314c2 + f56ecfd commit a4685c4

File tree

230 files changed

+5347
-2560
lines changed

Some content is hidden

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

230 files changed

+5347
-2560
lines changed

.Rbuildignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,8 @@
2020
^\.github/workflows/R\.yaml$
2121
^\.github/workflows/pr-commands\.yaml$
2222
^CRAN-SUBMISSION$
23+
^[\.]?air\.toml$
24+
^\.vscode$
25+
^\.git-blame-ignore-rev$
26+
^CLAUDE\.md$
27+
^\.claude$

.claude/settings.local.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(find:*)",
5+
"Bash(R:*)"
6+
],
7+
"deny": []
8+
},
9+
"$schema": "https://json.schemastore.org/claude-code-settings.json"
10+
}

.git-blame-ignore-rev

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# This file lists revisions of large-scale formatting/style changes so that
2+
# they can be excluded from git blame results.
3+
#
4+
# To set this file as the default ignore file for git blame, run:
5+
# $ git config blame.ignoreRevsFile .git-blame-ignore-revs
6+
7+
# https://github.com/r-lib/testthat/pull/2121
8+
13d17788e5d3a54fa83beed25e325703608f8b9f

.vscode/extensions.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"recommendations": [
3+
"Posit.air-vscode"
4+
]
5+
}

.vscode/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"[r]": {
3+
"editor.formatOnSave": true,
4+
"editor.defaultFormatter": "Posit.air-vscode"
5+
}
6+
}

CLAUDE.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## About This Project
6+
7+
testthat is R's most popular unit testing framework, used by thousands of CRAN packages. It provides functions to make testing R code as fun and addictive as possible, with clear expectations, visual progress indicators, and seamless integration with R package development workflows.
8+
9+
## Key Development Commands
10+
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
16+
17+
- `devtools::test()` - Run all tests
18+
- `devtools::test_file("tests/testthat/test-filename.R")` - Run tests in a specific file
19+
- `devtools::load_all()` - Load package for development
20+
- `devtools::document()` - Generate documentation
21+
- `devtools::check()` - Run R CMD check
22+
- `devtools::install()` - Install package locally
23+
24+
## Core Architecture
25+
26+
### Main Components
27+
28+
1. **Core Testing Functions** (`R/test-that.R`, `R/test-package.R`):
29+
- `test_that()` - The fundamental testing function
30+
- `test_local()`, `test_package()`, `test_check()` - Different ways to run test suites
31+
32+
2. **Expectations** (`R/expect-*.R`):
33+
- Modular expectation functions (equality, conditions, types, etc.)
34+
- Each expectation type has its own file following the pattern `expect-[type].R`
35+
36+
3. **Reporters** (`R/reporter*.R`):
37+
- Different output formats for test results
38+
- Object-oriented design with base `Reporter` class
39+
- Includes check, debug, progress, summary, JUnit, TAP formats
40+
41+
4. **Snapshot Testing** (`R/snapshot*.R`):
42+
- Value snapshots, file snapshots, output snapshots
43+
- Automatic management and comparison of expected outputs
44+
45+
5. **Parallel Testing** (`R/parallel*.R`):
46+
- Multi-core test execution
47+
- Configuration via `Config/testthat/parallel: true` in DESCRIPTION
48+
49+
6. **Mocking** (`R/mock*.R`, `R/mock2*.R`):
50+
- Function mocking capabilities
51+
- Both legacy (`mock.R`) and modern (`mock2*.R`) implementations
52+
53+
### Key Design Patterns
54+
55+
- **Editions**: testthat has different "editions" with varying behavior, controlled by `Config/testthat/edition`
56+
- **Reporters**: Extensible reporting system using R6 classes
57+
- **Lazy Evaluation**: Expectations use substitute() and lazy evaluation for better error messages
58+
- **C++ Integration**: Core functionality implemented in C++ for performance
59+
60+
### File Organization
61+
62+
- `R/` - All R source code, organized by functionality
63+
- `src/` - C++ source code and Makevars
64+
- `inst/include/testthat/` - C++ headers for other packages to use
65+
- `tests/testthat/` - Package's own comprehensive test suite
66+
- `vignettes/` - Documentation on testing concepts and workflows
67+
68+
### Important Configuration
69+
70+
The package uses several DESCRIPTION fields for configuration:
71+
- `Config/testthat/edition: 3` - Sets testthat edition
72+
- `Config/testthat/parallel: true` - Enables parallel testing
73+
- `Config/testthat/start-first` - Tests to run first in parallel mode
74+
75+
### C++ Testing Infrastructure
76+
77+
testthat provides C++ testing capabilities via Catch framework:
78+
- Headers in `inst/include/testthat/`
79+
- Test runner infrastructure in `src/test-runner.cpp`
80+
- Integration with R's testing system
81+
82+
### Snapshot Testing Workflow
83+
84+
- Snapshots stored in `tests/testthat/_snaps/`
85+
- Different snapshot types: values, files, output
86+
- Version-specific snapshots for different R versions
87+
- Use `testthat::snapshot_accept()` to update snapshots
88+
89+
This codebase prioritizes backward compatibility, comprehensive testing, and clear, descriptive error messages to help R developers write better tests.

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: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ export(expect_s3_class)
119119
export(expect_s4_class)
120120
export(expect_s7_class)
121121
export(expect_setequal)
122+
export(expect_shape)
122123
export(expect_silent)
123124
export(expect_snapshot)
124125
export(expect_snapshot_error)
@@ -144,29 +145,27 @@ export(is.expectation)
144145
export(is_a)
145146
export(is_checking)
146147
export(is_equivalent_to)
147-
export(is_false)
148148
export(is_identical_to)
149149
export(is_informative_error)
150150
export(is_less_than)
151151
export(is_more_than)
152-
export(is_null)
153152
export(is_parallel)
154153
export(is_snapshot)
155154
export(is_testing)
156-
export(is_true)
157155
export(it)
158156
export(local_edition)
159157
export(local_mock)
160158
export(local_mocked_bindings)
159+
export(local_on_cran)
161160
export(local_reproducible_output)
162161
export(local_snapshotter)
163162
export(local_test_context)
164163
export(local_test_directory)
165164
export(make_expectation)
166-
export(matches)
167165
export(mock_output_sequence)
168166
export(new_expectation)
169167
export(not)
168+
export(pass)
170169
export(prints_text)
171170
export(quasi_label)
172171
export(run_cpp_tests)
@@ -229,5 +228,6 @@ import(rlang)
229228
importFrom(R6,R6Class)
230229
importFrom(brio,readLines)
231230
importFrom(brio,writeLines)
231+
importFrom(lifecycle,deprecated)
232232
importFrom(magrittr,"%>%")
233233
useDynLib(testthat, .registration = TRUE)

NEWS.md

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

3+
* `expect_*()` functions consistently and rigorously check their inputs (#1754).
4+
* `JunitReporter()` no longer fails with `"no applicable method for xml_add_child"` for warnings outside of tests (#1913). Additionally, warnings now save their backtraces.
5+
* `JunitReporter()` strips ANSI escapes in more placese (#1852, #2032).
6+
* `try_again()` is now publicised. The first argument is now the number of retries, not tries (#2050).
7+
* `vignette("custom-expectations)` has been overhauled to make it much clearer how to create high-quality expectations (#2113, #2132, #2072).
8+
* `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).
9+
* `expect_snapshot_value()` can now handle expressions that generate `-` (#1678) or zero length atomic vectors (#2042).
10+
* `expect_matches()` failures should be a little easier to read (#2135).
11+
* New `local_on_cran(TRUE)` allows you to simulate how your tests will run on CRAN (#2112).
12+
* `expect_no_*()` now executes the entire code block, rather than stopping at the first message or warning (#1991).
13+
* `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 (#)
14+
* New `pass()` function to use in place of `succeed()` (#2113).
15+
* `expectation()` is now a combination of `new_expectation()` and `exp_signal()` (#2125).
16+
* `is_null()`/`matches()` deprecated in 2.0.0 (2017-12-19) and `is_true()`/`is_false()` deprecated in 2.1.0 (2019-04-23) have been removed (#2109).
17+
* `local_edition()` now gives a useful error for bad values (#1547).
318
* testthat now requires R 4.1.
419
* `expect_s4_class()` now supports unquoting (@stibu81, #2064).
520
* `it()` now finds the correct evaluation environment in more cases (@averissimo, #2085).
621
* Fixed an issue preventing compilation from succeeding due to deprecation / removal of `std::uncaught_exception()` (@kevinushey, #2047).
722
* New `skip_unless_r()` to skip running tests on unsuitable versions of R, e.g. `skip_unless_r(">= 4.1.0")` to skip tests that require, say, `...names` (@MichaelChirico, #2022)
823
* `skip_on_os()` gains an option `"emscripten"` of the `os` argument to skip tests on Emscripten (@eitsupi, #2103).
24+
* New expectation, `expect_shape()`, for testing the shape (i.e., the `length()`, `nrow()`, `ncol()`, or `dim()`), all in one place (#1423, @michaelchirico).
925

1026
# testthat 3.2.3
1127

R/auto-test.R

Lines changed: 30 additions & 22 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,10 +21,14 @@
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
31-
auto_test <- function(code_path, test_path, reporter = default_reporter(),
32-
env = test_env(),
33-
hash = TRUE) {
24+
#' @keywords internal
25+
auto_test <- function(
26+
code_path,
27+
test_path,
28+
reporter = default_reporter(),
29+
env = test_env(),
30+
hash = TRUE
31+
) {
3432
reporter <- find_reporter(reporter)
3533
code_path <- normalizePath(code_path)
3634
test_path <- normalizePath(test_path)
@@ -63,16 +61,17 @@ auto_test <- function(code_path, test_path, reporter = default_reporter(),
6361
watch(c(code_path, test_path), watcher, hash = hash)
6462
}
6563

66-
#' Watches a package for changes, rerunning tests as appropriate.
67-
#'
6864
#' @param pkg path to package
6965
#' @export
7066
#' @param reporter test reporter to use
7167
#' @param hash Passed on to [watch()]. When FALSE, uses less accurate
7268
#' modification time stamps, but those are faster for large files.
73-
#' @keywords debugging
74-
#' @seealso [auto_test()] for details on how method works
75-
auto_test_package <- function(pkg = ".", reporter = default_reporter(), hash = TRUE) {
69+
#' @rdname auto_test
70+
auto_test_package <- function(
71+
pkg = ".",
72+
reporter = default_reporter(),
73+
hash = TRUE
74+
) {
7675
reporter <- find_reporter(reporter)
7776

7877
path <- pkgload::pkg_path(pkg)
@@ -86,7 +85,12 @@ auto_test_package <- function(pkg = ".", reporter = default_reporter(), hash = T
8685
# Start by loading all code and running all tests
8786
withr::local_envvar("NOT_CRAN" = "true")
8887
pkgload::load_all(path)
89-
test_dir(test_path, package = package, reporter = reporter$clone(deep = TRUE), stop_on_failure = FALSE)
88+
test_dir(
89+
test_path,
90+
package = package,
91+
reporter = reporter$clone(deep = TRUE),
92+
stop_on_failure = FALSE
93+
)
9094

9195
# Next set up watcher to monitor changes
9296
watcher <- function(added, deleted, modified) {
@@ -106,7 +110,11 @@ auto_test_package <- function(pkg = ".", reporter = default_reporter(), hash = T
106110
cat("Changed code: ", paste0(basename(code), collapse = ", "), "\n")
107111
cat("Rerunning all tests\n")
108112
pkgload::load_all(path, quiet = TRUE)
109-
test_dir(test_path, package = package, reporter = reporter$clone(deep = TRUE))
113+
test_dir(
114+
test_path,
115+
package = package,
116+
reporter = reporter$clone(deep = TRUE)
117+
)
110118
} else if (length(tests) > 0) {
111119
# If test changes, rerun just that test
112120
cat("Rerunning tests: ", paste0(basename(tests), collapse = ", "), "\n")
@@ -115,7 +123,7 @@ auto_test_package <- function(pkg = ".", reporter = default_reporter(), hash = T
115123
test_dir = test_path,
116124
test_package = package,
117125
test_paths = tests,
118-
env = env,
126+
env = env,
119127
reporter = reporter$clone(deep = TRUE)
120128
)
121129
}

0 commit comments

Comments
 (0)