diff --git a/R/edition.R b/R/edition.R index aef968bd0..7712877f6 100644 --- a/R/edition.R +++ b/R/edition.R @@ -27,8 +27,8 @@ edition_deprecate <- function(in_edition, what, instead = NULL) { return() } - warn(c( - paste0("`", what, "` was deprecated in ", edition_name(in_edition), "."), + cli::cli_warn(c( + "{.code {what}} was deprecated in {edition_name(in_edition)}.", i = instead )) } @@ -40,7 +40,7 @@ edition_require <- function(in_edition, what) { return() } - stop(paste0("`", what, "` requires ", edition_name(in_edition), ".")) + cli::cli_abort("{.code {what}} requires {edition_name(in_edition)}.") } edition_name <- function(x) { diff --git a/R/expect-comparison.R b/R/expect-comparison.R index d83e07879..46c6f9a41 100644 --- a/R/expect-comparison.R +++ b/R/expect-comparison.R @@ -39,8 +39,8 @@ expect_compare_ <- function( cmp <- op(act$val, exp$val) if (length(cmp) != 1 || !is.logical(cmp)) { - abort( - "Result of comparison must be a single logical value", + cli::cli_abort( + "Result of comparison must be a single logical value.", call = trace_env ) } @@ -112,14 +112,14 @@ expect_gte <- function(object, expected, label = NULL, expected.label = NULL) { #' @param ... All arguments passed on to `expect_lt()`/`expect_gt()`. #' @keywords internal expect_less_than <- function(...) { - warning("Deprecated: please use `expect_lt()` instead", call. = FALSE) + cli::cli_warn("Deprecated: please use {.fn expect_lt} instead.") expect_lt(...) } #' @rdname expect_less_than #' @export expect_more_than <- function(...) { - warning("Deprecated: please use `expect_gt()` instead", call. = FALSE) + cli::cli_warn("Deprecated: please use {.fn expect_gt} instead.") expect_gt(...) } diff --git a/R/expect-condition.R b/R/expect-condition.R index 6d698d4ca..449692c32 100644 --- a/R/expect-condition.R +++ b/R/expect-condition.R @@ -169,7 +169,7 @@ expect_warning <- function( if (edition_get() >= 3) { if (!missing(all)) { - warn("The `all` argument is deprecated") + cli::cli_warn("The {.arg all} argument is deprecated.") } expect_condition_matching_( diff --git a/R/expect-known.R b/R/expect-known.R index 91523a801..db4ea366f 100644 --- a/R/expect-known.R +++ b/R/expect-known.R @@ -79,7 +79,7 @@ expect_known_output <- function( compare_file <- function(path, lines, ..., update = TRUE, info = NULL) { if (!file.exists(path)) { - warning("Creating reference output", call. = FALSE) + cli::cli_warn("Creating reference output.") brio::write_lines(lines, path) return(pass(NULL)) } @@ -88,11 +88,11 @@ compare_file <- function(path, lines, ..., update = TRUE, info = NULL) { if (update) { brio::write_lines(lines, path) if (!all_utf8(lines)) { - warning("New reference output is not UTF-8 encoded", call. = FALSE) + cli::cli_warn("New reference output is not UTF-8 encoded.") } } if (!all_utf8(old_lines)) { - warning("Reference output is not UTF-8 encoded", call. = FALSE) + cli::cli_warn("Reference output is not UTF-8 encoded.") } comp <- waldo_compare( @@ -178,7 +178,7 @@ expect_known_value <- function( act <- quasi_label(enquo(object), label) if (!file.exists(file)) { - warning("Creating reference value", call. = FALSE) + cli::cli_warn("Creating reference value.") saveRDS(object, file, version = version) } else { ref_val <- readRDS(file) @@ -232,7 +232,7 @@ expect_known_hash <- function(object, hash = NULL) { } if (is.null(hash)) { - warning(paste0("No recorded hash: use ", substr(act_hash, 1, 10))) + 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) diff --git a/R/expect-setequal.R b/R/expect-setequal.R index 095b43419..34e1ea904 100644 --- a/R/expect-setequal.R +++ b/R/expect-setequal.R @@ -131,35 +131,6 @@ expect_in <- function(object, expected) { # Helpers ---------------------------------------------------------------------- -check_map_names <- function( - x, - error_arg = caller_arg(x), - error_call = caller_env() -) { - nms <- names2(x) - - if (anyDuplicated(nms)) { - dups <- unique(nms[duplicated(nms)]) - cli::cli_abort( - c( - "All elements in {.arg {error_arg}} must have unique names.", - x = "Duplicate names: {.str {dups}}" - ), - call = error_call - ) - } - if (any(nms == "")) { - empty <- which(nms == "") - cli::cli_abort( - c( - "All elements in {.arg {error_arg}} must have names.", - x = "Empty names at position{?s}: {empty}" - ), - call = error_call - ) - } -} - check_vector <- function( x, error_arg = caller_arg(x), diff --git a/R/expectation.R b/R/expectation.R index a95fa176f..05322fda5 100644 --- a/R/expectation.R +++ b/R/expectation.R @@ -189,11 +189,9 @@ as.expectation.skip <- function(x, ..., srcref = NULL) { #' @export as.expectation.default <- function(x, srcref = NULL) { - stop( - "Don't know how to convert '", - paste(class(x), collapse = "', '"), - "' to expectation.", - call. = FALSE + cli::cli_abort( + "Don't know how to convert {.cls {class(x)}} to expectation.", + call = NULL ) } diff --git a/R/mock.R b/R/mock.R index 139671620..4a0cdf8dc 100644 --- a/R/mock.R +++ b/R/mock.R @@ -27,9 +27,11 @@ with_mock <- function(..., .env = topenv()) { mock_qual_names <- names(dots) if (all(mock_qual_names == "")) { - warning( - "Not mocking anything. Please use named parameters to specify the functions you want to mock.", - call. = FALSE + cli::cli_warn( + c( + "Not mocking anything.", + "i" = "Please use named parameters to specify the functions you want to mock." + ) ) code_pos <- rep(TRUE, length(dots)) } else { @@ -85,11 +87,8 @@ extract_mocks <- function(funs, .env) { pkg_name <- gsub(pkg_and_name_rx, "\\1", qual_name) if (is_base_pkg(pkg_name)) { - stop( - "Can't mock functions in base packages (", - pkg_name, - ")", - call. = FALSE + cli::cli_abort( + "Can't mock functions in base package {.pkg {pkg_name}}." ) } @@ -102,13 +101,8 @@ extract_mocks <- function(funs, .env) { env <- asNamespace(pkg_name) if (!exists(name, envir = env, mode = "function")) { - stop( - "Function ", - name, - " not found in environment ", - environmentName(env), - ".", - call. = FALSE + cli::cli_abort( + "Function {.fn {name}} not found in environment {environmentName(env)}." ) } mock(name = name, env = env, new = funs[[qual_name]]) diff --git a/R/mock2.R b/R/mock2.R index 1939b6fe5..bf61f55de 100644 --- a/R/mock2.R +++ b/R/mock2.R @@ -185,18 +185,18 @@ local_bindings_rebind <- function(..., .env = .frame, .frame = caller_env()) { invisible() } -dev_package <- function() { +dev_package <- function(call = caller_env()) { if (is_testing() && testing_package() != "") { testing_package() } else { loaded <- loadedNamespaces() is_dev <- map_lgl(loaded, function(x) !is.null(pkgload::dev_meta(x))) if (sum(is_dev) == 0) { - cli::cli_abort("No packages loaded with pkgload") + cli::cli_abort("No packages loaded with pkgload", call = call) } else if (sum(is_dev) == 1) { loaded[is_dev] } else { - cli::cli_abort("Multiple packages loaded with pkgload") + cli::cli_abort("Multiple packages loaded with pkgload", call = call) } } } diff --git a/R/old-school.R b/R/old-school.R index df2683193..b3fcb397d 100644 --- a/R/old-school.R +++ b/R/old-school.R @@ -139,9 +139,8 @@ throws_error <- function(regexp = NULL, ...) { #' @export #' @param amount maximum duration in seconds takes_less_than <- function(amount) { - warning( - "takes_less_than() is deprecated because it is stochastic and unreliable", - call. = FALSE + cli::cli_warn( + "{.fn takes_less_than} is deprecated because it is stochastic and unreliable." ) function(expr) { @@ -165,7 +164,7 @@ takes_less_than <- function(amount) { #' @keywords internal #' @export not <- function(f) { - warning("`not()` is deprecated.", call. = FALSE) + cli::cli_warn("{.fn not} is deprecated.") stopifnot(is.function(f)) negate <- function(expt) { diff --git a/R/parallel-config.R b/R/parallel-config.R index 1082e4c54..1c3b4133f 100644 --- a/R/parallel-config.R +++ b/R/parallel-config.R @@ -8,7 +8,9 @@ find_parallel <- function(path, load_package = "source", package = NULL) { if (toupper(parenv) == "FALSE") { return(FALSE) } - abort("`TESTTHAT_PARALLEL` must be `TRUE` or `FALSE`") + cli::cli_abort( + "{.envvar TESTTHAT_PARALLEL} must be {.code TRUE} or {.code FALSE}." + ) } # Make sure we get the local package package if not "installed" @@ -28,7 +30,7 @@ find_parallel <- function(path, load_package = "source", package = NULL) { if (par) { ed <- as.integer(desc$get_field("Config/testthat/edition", default = 2L)) if (ed < 3) { - inform("Running tests in parallel requires the 3rd edition") + cli::cli_inform("Running tests in parallel requires the 3rd edition.") par <- FALSE } } diff --git a/R/parallel-taskq.R b/R/parallel-taskq.R index 6e903064c..22300ce8b 100644 --- a/R/parallel-taskq.R +++ b/R/parallel-taskq.R @@ -40,7 +40,7 @@ task_q <- R6::R6Class( id <- private$get_next_id() } if (id %in% private$tasks$id) { - stop("Duplicate task id") + cli::cli_abort("Duplicate task id.") } before <- which(private$tasks$idle)[1] private$tasks <- df_add_row( @@ -123,16 +123,11 @@ task_q <- R6::R6Class( private$handle_error(msg, i) } else { file <- private$tasks$args[[i]][[1]] - errmsg <- paste0( - "unknown message from testthat subprocess: ", - msg$code, - ", ", - "in file `", - file, - "`" - ) - abort( - errmsg, + cli::cli_abort( + c( + "Unknown message from testthat subprocess: {msg$code}.", + "i" = "In file {.file {file}}." + ), test_file = file, class = c("testthat_process_error", "testthat_error") ) @@ -211,7 +206,7 @@ task_q <- R6::R6Class( }, handle_error = function(msg, task_no) { - inform("\n") # get out of the progress bar, if any + cat("\n") # get out of the progress bar, if any fun <- private$tasks$fun[[task_no]] file <- private$tasks$args[[task_no]][[1]] if (is.null(fun)) { @@ -220,21 +215,22 @@ task_q <- R6::R6Class( c(private$tasks$startup[[task_no]], msg$stderr), collapse = "\n" ) - abort( - paste0( - "testthat subprocess failed to start, stderr:\n", - msg$error$stderr + cli::cli_abort( + c( + "testthat subprocess failed to start.", + " " = "{no_wrap(msg$error$stderr)}" ), test_file = NULL, - parent = msg$error, - class = c("testthat_process_error", "testthat_error") + class = c("testthat_process_error", "testthat_error"), + call = NULL ) } else { - abort( - paste0("testthat subprocess exited in file `", file, "`"), + cli::cli_abort( + "testthat subprocess exited in file {.file {file}}.", test_file = file, parent = msg$error, - class = c("testthat_process_error", "testthat_error") + class = c("testthat_process_error", "testthat_error"), + call = NULL ) } } diff --git a/R/parallel.R b/R/parallel.R index 0445e50a9..cd07b4e10 100644 --- a/R/parallel.R +++ b/R/parallel.R @@ -46,12 +46,7 @@ test_files_parallel <- function( # TODO: support timeouts. 20-30s for each file by default? num_workers <- min(default_num_cpus(), length(test_paths)) - inform(paste0( - "Starting ", - num_workers, - " test process", - if (num_workers != 1) "es" - )) + cli::cli_inform("Starting {num_workers} test process{?es}.") # Set up work queue ------------------------------------------ queue <- NULL @@ -110,7 +105,10 @@ default_num_cpus <- function() { if (!is.null(ncpus)) { ncpus <- suppressWarnings(as.integer(ncpus)) if (is.na(ncpus)) { - abort("`getOption(Ncpus)` must be an integer") + cli::cli_abort( + "{.code getOption('Ncpus')} must be an integer.", + call = NULL + ) } return(ncpus) } @@ -120,7 +118,7 @@ default_num_cpus <- function() { if (ncpus != "") { ncpus <- suppressWarnings(as.integer(ncpus)) if (is.na(ncpus)) { - abort("TESTTHAT_CPUS must be an integer") + cli::cli_abort("{.envvar TESTTHAT_CPUS} must be an integer.") } return(ncpus) } @@ -155,7 +153,7 @@ parallel_event_loop_smooth <- function(queue, reporters, test_dir) { m <- x$message if (!inherits(m, "testthat_message")) { - message(m) + cli::cli_inform(as.character(m)) next } @@ -195,7 +193,7 @@ parallel_event_loop_chunky <- function(queue, reporters, test_dir) { m <- x$message if (!inherits(m, "testthat_message")) { - message(m) + cli::cli_inform(as.character(m)) next } diff --git a/R/reporter-fail.R b/R/reporter-fail.R index 2649a85a7..c5f6192ee 100644 --- a/R/reporter-fail.R +++ b/R/reporter-fail.R @@ -23,7 +23,7 @@ FailReporter <- R6::R6Class( end_reporter = function() { if (self$failed) { - stop("Failures detected.", call. = FALSE) + cli::cli_abort("Failures detected.") } } ) diff --git a/R/reporter-junit.R b/R/reporter-junit.R index acb28adbb..12442f894 100644 --- a/R/reporter-junit.R +++ b/R/reporter-junit.R @@ -166,7 +166,7 @@ JunitReporter <- R6::R6Class( xml2::write_xml(self$doc, file, format = TRUE) cat(brio::read_file(file), file = self$out) } else { - stop("unsupported output type: ", toString(self$out)) + cli::cli_abort("Unsupported output type: {toString(self$out)}.") } } # end_reporter ), # public diff --git a/R/reporter-stop.R b/R/reporter-stop.R index b24500eaa..bf73bdc54 100644 --- a/R/reporter-stop.R +++ b/R/reporter-stop.R @@ -64,7 +64,7 @@ StopReporter <- R6::R6Class( stop_if_needed = function() { if (self$stop_reporter && self$n_fail > 0) { - abort("Test failed", call = NULL) + cli::cli_abort("Test failed.") } } ) diff --git a/R/reporter-zzz.R b/R/reporter-zzz.R index c67eecb95..e14ee09a4 100644 --- a/R/reporter-zzz.R +++ b/R/reporter-zzz.R @@ -85,26 +85,31 @@ find_reporter <- function(reporter) { reporter$new() } else if (inherits(reporter, "Reporter")) { reporter + } else if (is_string(reporter)) { + find_reporter_one(reporter) } else if (is.character(reporter)) { - if (length(reporter) <= 1L) { - find_reporter_one(reporter) - } else { - MultiReporter$new(reporters = lapply(reporter, find_reporter_one)) - } + reporters <- lapply(reporter, find_reporter_one, call = current_env()) + MultiReporter$new(reporters) } else { - stop("Invalid input", call. = FALSE) + stop_input_type( + reporter, + c( + "a string", + "a character vector", + "a reporter object", + "a reporter class" + ) + ) } } -find_reporter_one <- function(reporter, ...) { - check_string(reporter) - +find_reporter_one <- function(reporter, ..., call = caller_env()) { name <- reporter substr(name, 1, 1) <- toupper(substr(name, 1, 1)) name <- paste0(name, "Reporter") if (!exists(name)) { - stop("Can not find test reporter ", reporter, call. = FALSE) + cli::cli_abort("Cannot find test reporter {.arg {reporter}}.", call = call) } get(name)$new(...) diff --git a/R/skip.R b/R/skip.R index 6214da355..b085db721 100644 --- a/R/skip.R +++ b/R/skip.R @@ -217,7 +217,7 @@ skip_on_os <- function(os, arch = NULL) { if (!is.null(arch) && !is.null(msg)) { if (!is.character(arch)) { - abort("`arch` must be a character vector") + cli::cli_abort("{.arg arch} must be a character vector.") } if (system_arch() %in% arch) { diff --git a/R/snapshot-cleanup.R b/R/snapshot-cleanup.R index 0dd92fdb0..dbd4440dd 100644 --- a/R/snapshot-cleanup.R +++ b/R/snapshot-cleanup.R @@ -6,7 +6,7 @@ snapshot_cleanup <- function( outdated <- snapshot_outdated(path, test_files_seen, snap_files_seen) if (length(outdated) > 0) { - inform(c("Deleting unused snapshots:", outdated)) + cli::cli_inform("Deleting unused snapshots: {.path {outdated}}") unlink(file.path(path, outdated), recursive = TRUE) } diff --git a/R/snapshot-file.R b/R/snapshot-file.R index dda23e068..3dc32c2b3 100644 --- a/R/snapshot-file.R +++ b/R/snapshot-file.R @@ -200,7 +200,7 @@ snapshot_file_equal <- function( trace_env = caller_env() ) { if (!file.exists(path)) { - abort(paste0("`", path, "` not found")) + cli::cli_abort("{.path {path}} not found.") } if (is.null(snap_variant)) { diff --git a/R/snapshot-manage.R b/R/snapshot-manage.R index c843f9046..89f0021d7 100644 --- a/R/snapshot-manage.R +++ b/R/snapshot-manage.R @@ -15,11 +15,11 @@ snapshot_accept <- function(files = NULL, path = "tests/testthat") { changed <- snapshot_meta(files, path) if (nrow(changed) == 0) { - inform("No snapshots to update") + cli::cli_inform("No snapshots to update.") return(invisible()) } - inform(c("Updating snapshots:", changed$name)) + cli::cli_inform("Updating snapshots: {.path {changed$name}}.") unlink(changed$cur) file.rename(changed$new, changed$cur) @@ -50,7 +50,7 @@ snapshot_review <- function(files = NULL, path = "tests/testthat") { changed <- snapshot_meta(files, path) if (nrow(changed) == 0) { - inform("No snapshots to update") + cli::cli_inform("No snapshots to update.") return(invisible()) } @@ -97,12 +97,12 @@ review_app <- function(name, old_path, new_path) { # Handle buttons - after clicking update move input$cases to next case, # and remove current case (for accept/reject). If no cases left, close app shiny::observeEvent(input$reject, { - inform(paste0("Rejecting snapshot: '", new_path[[i()]], "'")) + cli::cli_inform("Rejecting snapshot: {.path {new_path[[i()]]}}.") unlink(new_path[[i()]]) update_cases() }) shiny::observeEvent(input$accept, { - inform(paste0("Accepting snapshot: '", old_path[[i()]], "'")) + cli::cli_inform("Accepting snapshot: {.path {old_path[[i()]]}}.") file.rename(new_path[[i()]], old_path[[i()]]) update_cases() }) @@ -124,7 +124,7 @@ review_app <- function(name, old_path, new_path) { } next_case <- function() { if (all(handled)) { - inform("Review complete") + cli::cli_inform("Review complete.") shiny::stopApp() return() } @@ -140,9 +140,9 @@ review_app <- function(name, old_path, new_path) { } } - inform(c( - "Starting Shiny app for snapshot review", - i = "Use Ctrl + C to quit" + cli::cli_inform(c( + "Starting Shiny app for snapshot review.", + i = "Use {.kbd Ctrl + C} to quit." )) shiny::runApp( shiny::shinyApp(ui, server), diff --git a/R/snapshot-reporter.R b/R/snapshot-reporter.R index cd1b3e673..c226518ff 100644 --- a/R/snapshot-reporter.R +++ b/R/snapshot-reporter.R @@ -205,7 +205,7 @@ local_snapshotter <- function( fail_on_new = fail_on_new ) if (!identical(cleanup, FALSE)) { - warn("`cleanup` is deprecated") + cli::cli_warn("{.arg cleanup} is deprecated.") } withr::local_options( diff --git a/R/snapshot-value.R b/R/snapshot-value.R index 0e0864219..c14026af2 100644 --- a/R/snapshot-value.R +++ b/R/snapshot-value.R @@ -116,21 +116,11 @@ check_roundtrip <- function( tolerance = tolerance ) if (length(check) > 0) { - abort( + cli::cli_abort( c( - paste0( - "`", - label, - "` could not be safely serialized with `style = \"", - style, - "\"`." - ), - " " = paste0( - "Serializing then deserializing the object returned something new:\n\n", - check, - "\n" - ), - i = "You may need to try a different `style`." + "{.code {label}} could not be safely serialized with {.arg style} = {.str {style}}.", + " " = "Serializing then deserializing the object returned something new:\n\n{no_wrap(check)}\n", + i = "You may need to try a different {.arg style}." ), call = error_call ) diff --git a/R/snapshot.R b/R/snapshot.R index 40f39b547..4e016c897 100644 --- a/R/snapshot.R +++ b/R/snapshot.R @@ -408,13 +408,13 @@ local_snapshot_dir <- function(snap_names, .env = parent.frame()) { # if transform() wiped out the full message, don't indent, #1487 indent <- function(x) if (length(x)) paste0(" ", x) else x -check_variant <- function(x) { +check_variant <- function(x, call = caller_env()) { if (is.null(x)) { "_default" } else if (is_string(x)) { x } else { - abort("If supplied, `variant` must be a string") + cli::cli_abort("If supplied, {.arg variant} must be a string.", call = call) } } diff --git a/R/source.R b/R/source.R index bfc8733ef..e13f6247a 100644 --- a/R/source.R +++ b/R/source.R @@ -63,8 +63,8 @@ source_file <- function( withCallingHandlers( invisible(eval(exprs, env)), error = function(err) { - abort( - paste0("In path: ", encodeString(path, quote = '"')), + cli::cli_abort( + "Failed to evaluate {.path {path}}.", parent = err, call = error_call ) @@ -99,8 +99,8 @@ filter_desc <- function(exprs, desc = NULL, error_call = caller_env()) { } if (found) { - abort( - "Found multiple tests with specified description", + cli::cli_abort( + "Found multiple tests with specified description.", call = error_call ) } @@ -110,7 +110,10 @@ filter_desc <- function(exprs, desc = NULL, error_call = caller_env()) { } if (!found) { - abort("Failed to find test with specified description", call = error_call) + cli::cli_abort( + "Failed to find test with specified description.", + call = error_call + ) } exprs[include] @@ -125,9 +128,17 @@ source_dir <- function( chdir = TRUE, wrap = TRUE ) { - files <- normalizePath(sort(dir(path, pattern, full.names = TRUE))) + files <- sort(dir(path, pattern, full.names = TRUE)) + + error_call <- current_env() lapply(files, function(path) { - source_file(path, env = env, chdir = chdir, wrap = wrap) + source_file( + path, + env = env, + chdir = chdir, + wrap = wrap, + error_call = error_call + ) }) } diff --git a/R/srcrefs.R b/R/srcrefs.R index 82934b627..bb9067281 100644 --- a/R/srcrefs.R +++ b/R/srcrefs.R @@ -72,13 +72,13 @@ sys_index <- function(bottom = NULL, top = caller_env()) { } else { bottom_idx <- Position(function(env) identical(bottom, env), frames) if (is.na(bottom_idx)) { - abort("Can't find `bottom` on stack") + cli::cli_abort("Can't find {.arg bottom} on stack.") } } top_idx <- Position(function(env) identical(top, env), frames) if (is.na(top_idx)) { - abort("Can't find `top` on stack") + cli::cli_abort("Can't find {.arg top} on stack.") } seq2(bottom_idx, top_idx) diff --git a/R/test-compiled-code.R b/R/test-compiled-code.R index 6e1ee902d..5593288af 100644 --- a/R/test-compiled-code.R +++ b/R/test-compiled-code.R @@ -14,10 +14,9 @@ expect_cpp_tests_pass <- function(package) { tests_passed <- .Call(run_testthat_tests, FALSE) ), error = function(e) { - warning(sprintf( - "failed to call test entrypoint '%s'", - run_testthat_tests - )) + cli::cli_warn( + "Failed to call test entrypoint {.fn {run_testthat_tests}}." + ) } ) @@ -324,23 +323,20 @@ run_cpp_tests <- function(package) { use_catch <- function(dir = getwd()) { desc_path <- file.path(dir, "DESCRIPTION") if (!file.exists(desc_path)) { - stop("no DESCRIPTION file at path '", desc_path, "'", call. = FALSE) + cli::cli_abort("No DESCRIPTION file at path {.path {desc_path}}.") } desc <- read.dcf(desc_path, all = TRUE) pkg <- desc$Package if (!nzchar(pkg)) { - stop( - "no 'Package' field in DESCRIPTION file '", - desc_path, - "'", - call. = FALSE + cli::cli_abort( + "No {.field Package} field in DESCRIPTION file {.path {desc_path}}." ) } src_dir <- file.path(dir, "src") if (!file.exists(src_dir) && !dir.create(src_dir)) { - stop("failed to create 'src/' directory '", src_dir, "'", call. = FALSE) + cli::cli_abort("Failed to create {.path src/} directory {.path {src_dir}}.") } test_runner_path <- file.path(src_dir, "test-runner.cpp") @@ -353,7 +349,9 @@ use_catch <- function(dir = getwd()) { ) if (!success) { - stop("failed to copy 'test-runner.cpp' to '", src_dir, "'", call. = FALSE) + cli::cli_abort( + "Failed to copy {.file test-runner.cpp} to {.path {src_dir}}." + ) } # Copy the test example. @@ -364,17 +362,16 @@ use_catch <- function(dir = getwd()) { ) if (!success) { - stop("failed to copy 'test-example.cpp' to '", src_dir, "'", call. = FALSE) + cli::cli_abort( + "Failed to copy {.file test-example.cpp} to {.path {src_dir}}." + ) } # Copy the 'test-cpp.R' file. test_dir <- file.path(dir, "tests", "testthat") if (!file.exists(test_dir) && !dir.create(test_dir, recursive = TRUE)) { - stop( - "failed to create 'tests/testthat/' directory '", - test_dir, - "'", - call. = FALSE + cli::cli_abort( + "Failed to create {.path tests/testthat/} directory {.path {test_dir}}." ) } @@ -395,14 +392,11 @@ use_catch <- function(dir = getwd()) { output_path <- file.path(dir, "R", "catch-routine-registration.R") cat(transformed, file = output_path) - message("> Added C++ unit testing infrastructure.") - message("> Please ensure you have 'LinkingTo: testthat' in your DESCRIPTION.") - message("> Please ensure you have 'Suggests: xml2' in your DESCRIPTION.") - message( - "> Please ensure you have 'useDynLib(", - pkg, - ", .registration = TRUE)' in your NAMESPACE." - ) + cli::cli_inform(c( + v = "Added C++ unit testing infrastructure.", + i = "Please ensure you have {.field LinkingTo: testthat} in your DESCRIPTION.", + i = "Please ensure you have {.field Suggests: xml2} in your DESCRIPTION." + )) } get_routine <- function(package, routine) { @@ -435,8 +429,9 @@ get_routine <- function(package, routine) { } # if we got here, we failed to find the symbol -- throw an error - fmt <- "failed to locate routine '%s' in package '%s'" - stop(sprintf(fmt, routine, package), call. = FALSE) + cli::cli_abort( + "Failed to locate routine {.code {routine}} in package {.pkg {package}}." + ) } (function() { diff --git a/R/test-example.R b/R/test-example.R index b80f229c8..d994b5b70 100644 --- a/R/test-example.R +++ b/R/test-example.R @@ -15,7 +15,7 @@ test_examples <- function(path = "../..") { res <- test_examples_source(path) %||% test_examples_installed() if (is.null(res)) { - stop("Could not find examples", call. = FALSE) + cli::cli_abort("Could not find examples.") } invisible(res) } diff --git a/R/test-files.R b/R/test-files.R index cdb6f802e..eb67f6fce 100644 --- a/R/test-files.R +++ b/R/test-files.R @@ -65,7 +65,7 @@ test_dir <- function( start_first = start_first ) if (length(test_paths) == 0) { - abort("No test files found") + cli::cli_abort("No test files found.") } if (!is_missing(wrap)) { @@ -123,7 +123,7 @@ test_file <- function( ... ) { if (!file.exists(path)) { - stop("`path` does not exist", call. = FALSE) + cli::cli_abort("{.arg path} does not exist.") } test_files( @@ -273,7 +273,7 @@ find_load_all_args <- function(path) { args <- parse_expr(args) if (!is_call(args, "list")) { - abort("`Config/testthat/load-all` must be a list.", call = NULL) + cli::cli_abort("{.field Config/testthat/load-all} must be a list.") } args <- as.list(args[-1]) @@ -325,10 +325,10 @@ test_files_check <- function( stop_on_warning = FALSE ) { if (stop_on_failure && !all_passed(results)) { - stop("Test failures", call. = FALSE) + cli::cli_abort("Test failures.") } if (stop_on_warning && any_warnings(results)) { - stop("Tests generated warnings", call. = FALSE) + cli::cli_abort("Tests generated warnings.") } invisible(results) @@ -366,7 +366,10 @@ test_one_file <- function( #' @export teardown_env <- function() { if (is.null(the$teardown_env)) { - abort("`teardown_env()` has not been initialized", .internal = TRUE) + cli::cli_abort( + "{.fn teardown_env} has not been initialized.", + .internal = TRUE + ) } the$teardown_env diff --git a/R/test-package.R b/R/test-package.R index 90154a6c5..d0f7f435a 100644 --- a/R/test-package.R +++ b/R/test-package.R @@ -27,7 +27,7 @@ test_package <- function(package, reporter = check_reporter(), ...) { test_path <- system.file("tests", "testthat", package = package) if (test_path == "") { - inform(paste0("No installed testthat tests found for ", package)) + cli::cli_inform("No installed testthat tests found for {.pkg {package}}.") return(invisible()) } diff --git a/R/test-that.R b/R/test-that.R index e214bd877..a08782dec 100644 --- a/R/test-that.R +++ b/R/test-that.R @@ -39,8 +39,8 @@ test_that <- function(desc, code) { code <- substitute(code) if (edition_get() >= 3) { if (!is_call(code, "{")) { - warn( - "The `code` argument to `test_that()` must be a braced expression to get accurate file-line information for failures.", + cli::cli_warn( + "The {.arg code} argument to {.fn test_that} must be a braced expression to get accurate file-line information for failures.", class = "testthat_braces_warning" ) } diff --git a/R/utils.R b/R/utils.R index 868c46574..2b7a402f8 100644 --- a/R/utils.R +++ b/R/utils.R @@ -57,6 +57,13 @@ in_rcmd_check <- function() { r_version <- function() paste0("R", getRversion()[, 1:2]) +# Supress cli wrapping +no_wrap <- function(x) { + x <- gsub(" ", "\u00a0", x, fixed = TRUE) + x <- gsub("\n", "\f", x, fixed = TRUE) + x +} + paste_c <- function(...) { paste0(c(...), collapse = "") } diff --git a/R/verify-output.R b/R/verify-output.R index 2e3aa3327..99f7af1de 100644 --- a/R/verify-output.R +++ b/R/verify-output.R @@ -167,7 +167,7 @@ output_replay.message <- function(x) { #' @export output_replay.recordedplot <- function(x) { - abort("Plots are not supported") + cli::cli_abort("Plots are not supported.") } diff --git a/tests/testthat/_snaps/examples.md b/tests/testthat/_snaps/examples.md index ad79089ce..894721ebb 100644 --- a/tests/testthat/_snaps/examples.md +++ b/tests/testthat/_snaps/examples.md @@ -3,6 +3,6 @@ Code test_examples("asdf") Condition - Error: - ! Could not find examples + Error in `test_examples()`: + ! Could not find examples. diff --git a/tests/testthat/_snaps/expect-comparison.md b/tests/testthat/_snaps/expect-comparison.md index 8b7000271..e204dd779 100644 --- a/tests/testthat/_snaps/expect-comparison.md +++ b/tests/testthat/_snaps/expect-comparison.md @@ -24,5 +24,5 @@ expect_lt(1:10, 5) Condition Error in `expect_lt()`: - ! Result of comparison must be a single logical value + ! Result of comparison must be a single logical value. diff --git a/tests/testthat/_snaps/parallel.md b/tests/testthat/_snaps/parallel.md new file mode 100644 index 000000000..07184d68b --- /dev/null +++ b/tests/testthat/_snaps/parallel.md @@ -0,0 +1,8 @@ +# good error if bad option + + Code + default_num_cpus() + Condition + Error: + ! `getOption('Ncpus')` must be an integer. + diff --git a/tests/testthat/_snaps/reporter-stop.md b/tests/testthat/_snaps/reporter-stop.md index febb63df5..24210c492 100644 --- a/tests/testthat/_snaps/reporter-stop.md +++ b/tests/testthat/_snaps/reporter-stop.md @@ -53,6 +53,6 @@ Code r$stop_if_needed() Condition - Error: - ! Test failed + Error in `r$stop_if_needed()`: + ! Test failed. diff --git a/tests/testthat/_snaps/reporter-zzz.md b/tests/testthat/_snaps/reporter-zzz.md index dbe7b5c13..f1d7b49b0 100644 --- a/tests/testthat/_snaps/reporter-zzz.md +++ b/tests/testthat/_snaps/reporter-zzz.md @@ -1,8 +1,18 @@ # useful error message if can't find reporter + Code + find_reporter(1) + Condition + Error in `find_reporter()`: + ! `reporter` must be a string, a character vector, a reporter object, or a reporter class, not the number 1. + Code + find_reporter("blah") + Condition + Error in `find_reporter()`: + ! Cannot find test reporter `blah`. Code find_reporter(c("summary", "blah")) Condition - Error: - ! Can not find test reporter blah + Error in `find_reporter()`: + ! Cannot find test reporter `blah`. diff --git a/tests/testthat/_snaps/snapshot-cleanup.md b/tests/testthat/_snaps/snapshot-cleanup.md index 218619ea1..05b0f5ac6 100644 --- a/tests/testthat/_snaps/snapshot-cleanup.md +++ b/tests/testthat/_snaps/snapshot-cleanup.md @@ -3,9 +3,7 @@ Code snapshot_cleanup(dir) Message - Deleting unused snapshots: - * a.md - * b.md + Deleting unused snapshots: 'a.md' and 'b.md' Code snapshot_cleanup(dir, c("a", "b")) diff --git a/tests/testthat/_snaps/snapshot-file.md b/tests/testthat/_snaps/snapshot-file.md index e36419766..33f271748 100644 --- a/tests/testthat/_snaps/snapshot-file.md +++ b/tests/testthat/_snaps/snapshot-file.md @@ -12,7 +12,7 @@ snapshot_file_equal_("doesnt-exist.txt") Condition Error in `snapshot_file_equal()`: - ! `doesnt-exist.txt` not found + ! 'doesnt-exist.txt' not found. # snapshot_hint output differs in R CMD check diff --git a/tests/testthat/_snaps/snapshot-manage.md b/tests/testthat/_snaps/snapshot-manage.md index d6dad619d..2b5b02f6b 100644 --- a/tests/testthat/_snaps/snapshot-manage.md +++ b/tests/testthat/_snaps/snapshot-manage.md @@ -3,56 +3,49 @@ Code snapshot_accept(path = path) Message - Updating snapshots: - * a.md - * b.md + Updating snapshots: 'a.md' and 'b.md'. --- Code snapshot_accept(path = path) Message - No snapshots to update + No snapshots to update. # can accept specific files Code snapshot_accept("a", path = path) Message - Updating snapshots: - * a.md + Updating snapshots: 'a.md'. --- Code snapshot_accept("test/a.txt", path = path) Message - Updating snapshots: - * test/a.txt + Updating snapshots: 'test/a.txt'. --- Code snapshot_accept("test/", path = path) Message - Updating snapshots: - * test/a.txt + Updating snapshots: 'test/a.txt'. # can work with variants Code snapshot_accept(path = path) Message - Updating snapshots: - * foo/a.md + Updating snapshots: 'foo/a.md'. --- Code snapshot_accept("foo/a", path = path) Message - Updating snapshots: - * foo/a.md + Updating snapshots: 'foo/a.md'. # snapshot_reject deletes .new files diff --git a/tests/testthat/_snaps/snapshot-value.md b/tests/testthat/_snaps/snapshot-value.md index 540b60dc9..70ab96884 100644 --- a/tests/testthat/_snaps/snapshot-value.md +++ b/tests/testthat/_snaps/snapshot-value.md @@ -75,12 +75,11 @@ wrapper(NULL, list(), label = "foo", style = "json") Condition Error in `wrapper()`: - ! `foo` could not be safely serialized with `style = "json"`. + ! `foo` could not be safely serialized with `style` = "json". Serializing then deserializing the object returned something new: - - `original` is NULL - `new` is a list - + + `original` is NULL + `new` is a list i You may need to try a different `style`. # expect_snapshot_value validates its inputs diff --git a/tests/testthat/_snaps/source.md b/tests/testthat/_snaps/source.md index 48519c770..1e4b57049 100644 --- a/tests/testthat/_snaps/source.md +++ b/tests/testthat/_snaps/source.md @@ -4,7 +4,7 @@ source_file(test_path("reporters/error-setup.R"), wrap = FALSE) Condition Error: - ! In path: "reporters/error-setup.R" + ! Failed to evaluate 'reporters/error-setup.R'. Caused by error in `h()`: ! ! @@ -32,7 +32,7 @@ filter_desc(code, "baz") Condition Error: - ! Failed to find test with specified description + ! Failed to find test with specified description. # preserve srcrefs @@ -49,5 +49,5 @@ filter_desc(code, "baz") Condition Error: - ! Found multiple tests with specified description + ! Found multiple tests with specified description. diff --git a/tests/testthat/_snaps/test-compiled-code.md b/tests/testthat/_snaps/test-compiled-code.md index 67f4c2e43..60c213e46 100644 --- a/tests/testthat/_snaps/test-compiled-code.md +++ b/tests/testthat/_snaps/test-compiled-code.md @@ -3,8 +3,8 @@ Code get_routine("utils", "no_such_routine") Condition - Error: - ! failed to locate routine 'no_such_routine' in package 'utils' + Error in `get_routine()`: + ! Failed to locate routine `no_such_routine` in package utils. # validates inputs @@ -19,3 +19,12 @@ Error in `run_cpp_tests()`: ! `package` must be a single string, not the number 123. +# useful messaging + + Code + use_catch(path) + Message + v Added C++ unit testing infrastructure. + i Please ensure you have LinkingTo: testthat in your DESCRIPTION. + i Please ensure you have Suggests: xml2 in your DESCRIPTION. + diff --git a/tests/testthat/_snaps/test-files.md b/tests/testthat/_snaps/test-files.md index e23707c0c..9f5c6fdc7 100644 --- a/tests/testthat/_snaps/test-files.md +++ b/tests/testthat/_snaps/test-files.md @@ -3,8 +3,8 @@ Code test_dir(test_path("test_dir"), reporter = "silent") Condition - Error: - ! Test failures + Error in `test_files_check()`: + ! Test failures. # runs all tests and records output @@ -33,29 +33,29 @@ test_dir(path) Condition Error in `test_dir()`: - ! No test files found + ! No test files found. # can control if failures generate errors Code test_error(stop_on_failure = TRUE) Condition - Error: - ! Test failures + Error in `test_files_check()`: + ! Test failures. # can control if warnings errors Code test_warning(stop_on_warning = TRUE) Condition - Error: - ! Tests generated warnings + Error in `test_files_check()`: + ! Tests generated warnings. # complains if file doesn't exist Code test_file("DOESNTEXIST") Condition - Error: - ! `path` does not exist + Error in `test_file()`: + ! `path` does not exist. diff --git a/tests/testthat/_snaps/verify-output.md b/tests/testthat/_snaps/verify-output.md index 222181b75..c0ae6c22c 100644 --- a/tests/testthat/_snaps/verify-output.md +++ b/tests/testthat/_snaps/verify-output.md @@ -4,5 +4,5 @@ verify_output(tempfile(), plot(1:10)) Condition Error in `FUN()`: - ! Plots are not supported + ! Plots are not supported. diff --git a/tests/testthat/test-parallel-setup.R b/tests/testthat/test-parallel-setup.R index f8bfdefb6..2eff8a4d1 100644 --- a/tests/testthat/test-parallel-setup.R +++ b/tests/testthat/test-parallel-setup.R @@ -9,5 +9,5 @@ test_that("error in parallel setup code", { error = function(e) e ) expect_s3_class(err, "testthat_process_error") - expect_match(err$message, "Error in setup", fixed = TRUE) + expect_match(conditionMessage(err), "Error in setup", fixed = TRUE) }) diff --git a/tests/testthat/test-parallel-startup.R b/tests/testthat/test-parallel-startup.R index b2ea8a8f6..240aeff1d 100644 --- a/tests/testthat/test-parallel-startup.R +++ b/tests/testthat/test-parallel-startup.R @@ -9,5 +9,5 @@ test_that("startup error", { error = function(e) e ) expect_s3_class(err, "testthat_process_error") - expect_match(err$message, "This will fail", fixed = TRUE) + expect_match(conditionMessage(err), "This will fail", fixed = TRUE) }) diff --git a/tests/testthat/test-parallel.R b/tests/testthat/test-parallel.R index 2d4c97734..9e6bd1111 100644 --- a/tests/testthat/test-parallel.R +++ b/tests/testthat/test-parallel.R @@ -20,6 +20,11 @@ test_that("detect number of cpus to use", { expect_equal(default_num_cpus(), 13L) }) +test_that("good error if bad option", { + withr::local_options(Ncpus = "bad") + expect_snapshot(default_num_cpus(), error = TRUE) +}) + test_that("ok", { withr::local_envvar(c(TESTTHAT_PARALLEL = "TRUE")) # we cannot run these with the silent reporter, because it is not diff --git a/tests/testthat/test-parallel/startup/R/fail.R b/tests/testthat/test-parallel/startup/R/fail.R index 8f6684c3a..702d692ba 100644 --- a/tests/testthat/test-parallel/startup/R/fail.R +++ b/tests/testthat/test-parallel/startup/R/fail.R @@ -1,3 +1,3 @@ .onLoad <- function(libname, pkgname) { - stop("This will fail when loading the package") + stop("This will fail when loading the package", call. = FALSE) } diff --git a/tests/testthat/test-reporter-zzz.R b/tests/testthat/test-reporter-zzz.R index 6bbf9c1a1..4ac112a28 100644 --- a/tests/testthat/test-reporter-zzz.R +++ b/tests/testthat/test-reporter-zzz.R @@ -5,6 +5,8 @@ test_that("can locate reporter from name", { test_that("useful error message if can't find reporter", { expect_snapshot(error = TRUE, { + find_reporter(1) + find_reporter("blah") find_reporter(c("summary", "blah")) }) }) diff --git a/tests/testthat/test-test-compiled-code.R b/tests/testthat/test-test-compiled-code.R index d9fba9b2b..c60e0dd8a 100644 --- a/tests/testthat/test-test-compiled-code.R +++ b/tests/testthat/test-test-compiled-code.R @@ -14,5 +14,13 @@ test_that("validates inputs", { }) }) +test_that("useful messaging", { + path <- withr::local_tempdir() + writeLines("Package: foo", file.path(path, "DESCRIPTION")) + dir.create(file.path(path, "R")) + + expect_snapshot(use_catch(path)) +}) + skip_if_not_installed("xml2") run_cpp_tests("testthat")