Nothing
#' Do you expect an S3/S4/R6/S7 object that inherits from this class?
#'
#' @description
#' See <https://adv-r.hadley.nz/oo.html> for an overview of R's OO systems, and
#' the vocabulary used here.
#'
#' * `expect_type(x, type)` checks that `typeof(x)` is `type`.
#' * `expect_s3_class(x, class)` checks that `x` is an S3 object that
#' [inherits()] from `class`
#' * `expect_s3_class(x, NA)` checks that `x` isn't an S3 object.
#' * `expect_s4_class(x, class)` checks that `x` is an S4 object that
#' [is()] `class`.
#' * `expect_s4_class(x, NA)` checks that `x` isn't an S4 object.
#' * `expect_r6_class(x, class)` checks that `x` an R6 object that
#' inherits from `class`.
#' * `expect_s7_class(x, Class)` checks that `x` is an S7 object that
#' [S7::S7_inherits()] from `Class`
#'
#' See [expect_vector()] for testing properties of objects created by vctrs.
#'
#' @param type String giving base type (as returned by [typeof()]).
#' @param class The required type varies depending on the function:
#' * `expect_type()`: a string.
#' * `expect_s3_class()`: a string or character vector. The behaviour of
#' multiple values (i.e. a character vector) is controlled by the
#' `exact` argument.
#' * `expect_s4_class()`: a string.
#' * `expect_r6_class()`: a string.
#' * `expect_s7_class()`: an [S7::S7_class()] object.
#'
#' For historical reasons, `expect_s3_class()` and `expect_s4_class()` also
#' take `NA` to assert that the `object` is not an S3 or S4 object.
#' @inheritParams expect_that
#' @family expectations
#' @examples
#' x <- data.frame(x = 1:10, y = "x", stringsAsFactors = TRUE)
#' # A data frame is an S3 object with class data.frame
#' expect_s3_class(x, "data.frame")
#' show_failure(expect_s4_class(x, "data.frame"))
#' # A data frame is built from a list:
#' expect_type(x, "list")
#'
#' f <- factor(c("a", "b", "c"))
#' o <- ordered(f)
#'
#' # Using multiple class names tests if the object inherits from any of them
#' expect_s3_class(f, c("ordered", "factor"))
#' # Use exact = TRUE to test for exact match
#' show_failure(expect_s3_class(f, c("ordered", "factor"), exact = TRUE))
#' expect_s3_class(o, c("ordered", "factor"), exact = TRUE)
#'
#' # An integer vector is an atomic vector of type "integer"
#' expect_type(x$x, "integer")
#' # It is not an S3 object
#' show_failure(expect_s3_class(x$x, "integer"))
#'
#' # Above, we requested data.frame() converts strings to factors:
#' show_failure(expect_type(x$y, "character"))
#' expect_s3_class(x$y, "factor")
#' expect_type(x$y, "integer")
#' @name inheritance-expectations
NULL
#' @export
#' @rdname inheritance-expectations
expect_type <- function(object, type) {
check_string(type)
act <- quasi_label(enquo(object))
act_type <- typeof(act$val)
if (!identical(act_type, type)) {
fail(c(
sprintf("Expected %s to have type %s.", act$lab, format_class(type)),
sprintf("Actual type: %s", format_class(act_type))
))
} else {
pass()
}
invisible(act$val)
}
#' @export
#' @rdname inheritance-expectations
#' @param exact If `FALSE`, the default, checks that `object` inherits
#' from any element of `class`. If `TRUE`, checks that object has a class
#' that exactly matches `class`.
expect_s3_class <- function(object, class, exact = FALSE) {
check_bool(exact)
act <- quasi_label(enquo(object))
act$class <- format_class(class(act$val))
exp_lab <- format_class(class)
if (identical(class, NA)) {
if (isS3(object)) {
fail(sprintf("Expected %s not to be an S3 object.", act$lab))
} else {
pass()
}
} else if (is.character(class)) {
if (!isS3(act$val)) {
fail(c(
sprintf("Expected %s to be an S3 object.", act$lab),
sprintf("Actual OO type: %s.", oo_type(act$val))
))
} else if (exact && !identical(class(act$val), class)) {
fail(c(
sprintf("Expected %s to have class %s.", act$lab, exp_lab),
sprintf("Actual class: %s.", act$class)
))
} else if (!inherits(act$val, class)) {
fail(c(
sprintf("Expected %s to inherit from %s.", act$lab, exp_lab),
sprintf("Actual class: %s.", act$class)
))
} else {
pass()
}
} else {
stop_input_type(class, c("a character vector", "NA"))
}
invisible(act$val)
}
#' @export
#' @rdname inheritance-expectations
expect_s4_class <- function(object, class) {
act <- quasi_label(enquo(object))
act$class <- format_class(methods::is(act$val))
exp_lab <- format_class(class)
if (identical(class, NA)) {
if (isS4(object)) {
fail(sprintf("Expected %s not to be an S4 object.", act$lab))
} else {
pass()
}
} else if (is.character(class)) {
if (!isS4(act$val)) {
fail(c(
sprintf("Expected %s to be an S4 object.", act$lab),
sprintf("Actual OO type: %s.", oo_type(act$val))
))
} else if (!methods::is(act$val, class)) {
fail(c(
sprintf("Expected %s to inherit from %s.", act$lab, exp_lab),
sprintf("Actual class: %s.", act$class)
))
} else {
pass()
}
} else {
stop_input_type(class, c("a character vector", "NA"))
}
invisible(act$val)
}
#' @export
#' @rdname inheritance-expectations
expect_r6_class <- function(object, class) {
act <- quasi_label(enquo(object))
check_string(class)
if (!inherits(act$val, "R6")) {
fail(c(
sprintf("Expected %s to be an R6 object.", act$lab),
sprintf("Actual OO type: %s.", oo_type(act$val))
))
} else if (!inherits(act$val, class)) {
act_class <- format_class(class(act$val))
exp_class <- format_class(class)
fail(c(
sprintf("Expected %s to inherit from %s.", act$lab, exp_class),
sprintf("Actual class: %s.", act_class)
))
} else {
pass()
}
invisible(act$val)
}
#' @export
#' @rdname inheritance-expectations
expect_s7_class <- function(object, class) {
check_installed("S7")
if (!inherits(class, "S7_class")) {
stop_input_type(class, "an S7 class object")
}
act <- quasi_label(enquo(object))
if (!S7::S7_inherits(object)) {
fail(c(
sprintf("Expected %s to be an S7 object.", act$lab),
sprintf("Actual OO type: %s.", oo_type(act$val))
))
} else if (!S7::S7_inherits(object, class)) {
exp_class <- attr(class, "name", TRUE)
act_class <- setdiff(base::class(object), "S7_object")
act_class_desc <- paste0("<", act_class, ">", collapse = "/")
fail(c(
sprintf("Expected %s to inherit from <%s>.", act$lab, exp_class),
sprintf("Actual class: %s.", act_class_desc)
))
} else {
pass()
}
invisible(act$val)
}
#' Do you expect to inherit from this class?
#'
#' @description
#' `r lifecycle::badge("superseded")`
#'
#' `expect_is()` is an older form that uses [inherits()] without checking
#' whether `x` is S3, S4, or neither. Instead, I'd recommend using
#' [expect_type()], [expect_s3_class()], or [expect_s4_class()] to more clearly
#' convey your intent.
#'
#' @section 3rd edition:
#' `r lifecycle::badge("deprecated")`
#'
#' `expect_is()` is formally deprecated in the 3rd edition.
#'
#' @keywords internal
#' @param class Class name passed to `inherits()`.
#' @inheritParams expect_type
#' @export
expect_is <- function(object, class, info = NULL, label = NULL) {
check_character(class)
edition_deprecate(
3,
"expect_is()",
"Use `expect_type()`, `expect_s3_class()`, or `expect_s4_class()` instead"
)
act <- quasi_label(enquo(object), label)
act$class <- format_class(class(act$val))
exp_lab <- format_class(class(class))
if (!inherits(act$val, class)) {
msg <- sprintf(
"Expected %s to inherit from %s.\nActual inheritance: %s",
act$lab,
exp_lab,
act$class
)
fail(msg, info = info)
} else {
pass()
}
invisible(act$val)
}
# Helpers ----------------------------------------------------------------------
isS3 <- function(x) is.object(x) && !isS4(x)
format_class <- function(x) {
paste0(encodeString(x, quote = '"'), collapse = "/")
}
oo_type <- function(x) {
if (!is.object(x)) {
return("none")
}
if (isS4(x)) {
"S4"
} else {
if (inherits(x, "R6")) {
"R6"
} else if (inherits(x, "S7")) {
"S7"
} else {
"S3"
}
}
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.