Skip to content

Commit

Permalink
Add expect_error_forwarded(), expect_warning_forwarded(), and `ex…
Browse files Browse the repository at this point in the history
…pect_message_forwarded()`
  • Loading branch information
billdenney committed Feb 15, 2024
1 parent f060cce commit 156feee
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 1 deletion.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ Config/testthat/parallel: true
Config/testthat/start-first: watcher, parallel*
Encoding: UTF-8
Roxygen: list(markdown = TRUE, r6 = FALSE)
RoxygenNote: 7.2.3
RoxygenNote: 7.3.1
3 changes: 3 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export(expect_equal)
export(expect_equal_to_reference)
export(expect_equivalent)
export(expect_error)
export(expect_error_forwarded)
export(expect_failure)
export(expect_false)
export(expect_gt)
Expand All @@ -102,6 +103,7 @@ export(expect_lte)
export(expect_mapequal)
export(expect_match)
export(expect_message)
export(expect_message_forwarded)
export(expect_more_than)
export(expect_named)
export(expect_no_condition)
Expand Down Expand Up @@ -130,6 +132,7 @@ export(expect_type)
export(expect_vector)
export(expect_visible)
export(expect_warning)
export(expect_warning_forwarded)
export(expectation)
export(fail)
export(find_test_scripts)
Expand Down
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# testthat (development version)

* Add new error, warning, and message capturing expectations for conditions from
other packages. `expect_error_forwarded()`, `expect_warning_forwarded()`, and
`expect_message_forwarded()` capture errors, warnings, and messages that come
from other code to match the message that is not in the control of the package
being tested (@billdenney, #1927).

# testthat 3.2.1

* Fix incorrect format string detected by latest R-devel. Fix thanks to
Expand Down
76 changes: 76 additions & 0 deletions R/expect-condition-forwarded.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#' Does code throw an error, warning, or message that is the same as another?
#'
#' @description
#' `expect_error_forwarded()`, `expect_warning_forwarded()`, and
#' `expect_message_forwarded()`, check that code throws an error, warning,
#' message, or condition with a message that matches an `expected` value from an
#' example. These functions are useful to test that a condition matches one
#' from another package that you do not control.
#'
#' @export
#' @family expectations
#' @inheritParams expect_that
#' @return The value of the first argument
expect_error_forwarded <- function(actual, expected, label = NULL) {
message <- error_message(expected)
expect_error({{ actual }}, regexp = message, fixed = TRUE, label = label)
}

#' @export
#' @rdname expect_error_forwarded
expect_warning_forwarded <- function(actual, expected, label = NULL) {
message <- warning_message(expected)
expect_warning({{ actual }}, regexp = message, fixed = TRUE, label = label)
}

#' @export
#' @rdname expect_error_forwarded
expect_message_forwarded <- function(actual, expected, label = NULL) {
message <- message_message(expected)
expect_message({{ actual }}, regexp = message, fixed = TRUE, label = label)
}

error_message <- function(code) {
out <- tryCatch(
{
code
NULL
},
error = function(e) conditionMessage(e)
)
if (is.null(out)) {
stop("No error thrown")
} else {
out
}
}

warning_message <- function(code) {
out <- tryCatch(
{
code
NULL
},
warning = function(e) conditionMessage(e)
)
if (is.null(out)) {
stop("No warning thrown")
} else {
out
}
}

message_message <- function(code) {
out <- tryCatch(
{
code
NULL
},
message = function(e) conditionMessage(e)
)
if (is.null(out)) {
stop("No message thrown")
} else {
out
}
}
4 changes: 4 additions & 0 deletions R/expect-condition.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
#' or condition with a message that matches `regexp`, or a class that inherits
#' from `class`. See below for more details.
#'
#' If you need to test that an error, warning, or message is the same as one
#' given by another package, then see the [expect_error_forwarded()],
#' [expect_warning_forwarded()], and [expect_message_forwarded()] functions.
#'
#' In the 3rd edition, these functions match (at most) a single condition. All
#' additional and non-matching (if `regexp` or `class` are used) conditions
#' will bubble up outside the expectation. If these additional conditions
Expand Down
81 changes: 81 additions & 0 deletions tests/testthat/test-expect-condition-forwarded.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
test_that("expect_error_forwarded general use", {
expect_success(
expect_error_forwarded(
stop(),
stop()
)
)

# Matches
expect_success(
expect_error_forwarded(
stop("foo"),
stop("foo")
)
)
# Does not match
expect_error(
expect_error_forwarded(
stop("foo"),
stop("bar")
)
)

# Matches
expect_success(
expect_warning_forwarded(
warning("foo"),
warning("foo")
)
)
# Does not match
expect_warning(
expect_error(
expect_warning_forwarded(
warning("foo"),
warning("bar")
),
regexp = '`warning("foo")` did not throw the expected warning.',
fixed = TRUE
),
regexp = "foo"
)

# Matches
expect_success(
expect_message_forwarded(
message("foo"),
message("foo")
)
)
# Does not match
expect_message(
expect_error(
expect_message_forwarded(
message("foo"),
message("bar")
),
regexp = '`message("foo")` did not throw the expected message.',
fixed = TRUE
),
regexp = "foo"
)
})

test_that("expect_*_forwarded with no condition generated ", {
expect_error(
expect_error_forwarded(1, 1),
regexp = "No error thrown",
fixed = TRUE
)
expect_error(
expect_warning_forwarded(1, 1),
regexp = "No warning thrown",
fixed = TRUE
)
expect_error(
expect_message_forwarded(1, 1),
regexp = "No message thrown",
fixed = TRUE
)
})

0 comments on commit 156feee

Please sign in to comment.