1212# ' * `expect_s4_class(x, class)` checks that `x` is an S4 object that
1313# ' [is()] `class`.
1414# ' * `expect_s4_class(x, NA)` checks that `x` isn't an S4 object.
15+ # ' * `expect_r6_class(x, class)` checks that `x` an R6 object that
16+ # ' inherits from `class`.
1517# ' * `expect_s7_class(x, Class)` checks that `x` is an S7 object that
1618# ' [S7::S7_inherits()] from `Class`
1719# '
1820# ' See [expect_vector()] for testing properties of objects created by vctrs.
1921# '
2022# ' @param type String giving base type (as returned by [typeof()]).
21- # ' @param class Either a character vector of class names, or
22- # ' for `expect_s3_class()` and `expect_s4_class()`, an `NA` to assert
23- # ' that `object` isn't an S3 or S4 object.
23+ # ' @param class
24+ # ' * `expect_type()`: a single string giving an R base type.
25+ # ' * `expect_s3_class()`: a character vector of class names or `NA` to assert
26+ # ' that `object` isn't an S3 object. If you provide multiple class names,
27+ # ' the test will pass if `object` inherits from any of them, unless
28+ # ' `exact = TRUE`.
29+ # ' * `expect_s4_class()`: a character vector of class names or `NA` to assert
30+ # ' that `object` isn't an S4 object.
31+ # ' * `expect_r6_class()`: a string.
32+ # ' * `expect_s7_class()`: an [S7::S7_class()] object.
2433# ' @inheritParams expect_that
2534# ' @family expectations
2635# ' @examples
3140# ' # A data frame is built from a list:
3241# ' expect_type(x, "list")
3342# '
43+ # ' f <- factor(c("a", "b", "c"))
44+ # ' o <- ordered(f)
45+ # '
46+ # ' # Using multiple class names tests if the object inherits from any of them
47+ # ' expect_s3_class(f, c("ordered", "factor"))
48+ # ' # Use exact = TRUE to test for exact match
49+ # ' show_failure(expect_s3_class(f, c("ordered", "factor"), exact = TRUE))
50+ # ' expect_s3_class(o, c("ordered", "factor"), exact = TRUE)
51+ # '
3452# ' # An integer vector is an atomic vector of type "integer"
3553# ' expect_type(x$x, "integer")
3654# ' # It is not an S3 object
4664# ' @export
4765# ' @rdname inheritance-expectations
4866expect_type <- function (object , type ) {
49- stopifnot(is.character( type ), length( type ) == 1 )
67+ check_string( type )
5068
5169 act <- quasi_label(enquo(object ))
5270 act_type <- typeof(act $ val )
@@ -66,9 +84,11 @@ expect_type <- function(object, type) {
6684# ' @export
6785# ' @rdname inheritance-expectations
6886# ' @param exact If `FALSE`, the default, checks that `object` inherits
69- # ' from `class`. If `TRUE`, checks that object has a class that's identical
70- # ' to `class`.
87+ # ' from any element of `class`. If `TRUE`, checks that object has a class
88+ # ' that's identical to `class`.
7189expect_s3_class <- function (object , class , exact = FALSE ) {
90+ check_bool(exact )
91+
7292 act <- quasi_label(enquo(object ))
7393 act $ class <- format_class(class(act $ val ))
7494 exp_lab <- format_class(class )
@@ -98,36 +118,7 @@ expect_s3_class <- function(object, class, exact = FALSE) {
98118 }
99119 }
100120 } else {
101- abort(" `class` must be a NA or a character vector" )
102- }
103-
104- pass(act $ val )
105- }
106-
107- # ' @export
108- # ' @rdname inheritance-expectations
109- expect_s7_class <- function (object , class ) {
110- check_installed(" S7" )
111- if (! inherits(class , " S7_class" )) {
112- stop_input_type(class , " an S7 class object" )
113- }
114-
115- act <- quasi_label(enquo(object ))
116-
117- if (! S7 :: S7_inherits(object )) {
118- return (fail(sprintf(" %s is not an S7 object" , act $ lab )))
119- }
120-
121- if (! S7 :: S7_inherits(object , class )) {
122- obj_class <- setdiff(base :: class(object ), " S7_object" )
123- class_desc <- paste0(" <" , obj_class , " >" , collapse = " /" )
124- msg <- sprintf(
125- " %s inherits from %s not <%s>." ,
126- act $ lab ,
127- class_desc ,
128- attr(class , " name" , TRUE )
129- )
130- return (fail(msg ))
121+ stop_input_type(class , c(" a character vector" , " NA" ))
131122 }
132123
133124 pass(act $ val )
@@ -160,13 +151,60 @@ expect_s4_class <- function(object, class) {
160151 }
161152 }
162153 } else {
163- abort( " ` class` must be a NA or a character vector" )
154+ stop_input_type( class , c( " a character vector" , " NA " ) )
164155 }
165156
166157 pass(act $ val )
167158}
168159
169- isS3 <- function (x ) is.object(x ) && ! isS4(x )
160+ # ' @export
161+ # ' @rdname inheritance-expectations
162+ expect_r6_class <- function (object , class ) {
163+ act <- quasi_label(enquo(object ))
164+ check_string(class )
165+
166+ if (! inherits(act $ val , " R6" )) {
167+ return (fail(sprintf(" %s is not an R6 object." , act $ lab )))
168+ }
169+
170+ if (! inherits(act $ val , class )) {
171+ act_class <- format_class(class(act $ val ))
172+ exp_class <- format_class(class )
173+ msg <- sprintf(" %s inherits from %s not %s." , act $ lab , act_class , exp_class )
174+ return (fail(msg ))
175+ }
176+
177+ pass(act $ val )
178+ }
179+
180+ # ' @export
181+ # ' @rdname inheritance-expectations
182+ expect_s7_class <- function (object , class ) {
183+ check_installed(" S7" )
184+ if (! inherits(class , " S7_class" )) {
185+ stop_input_type(class , " an S7 class object" )
186+ }
187+
188+ act <- quasi_label(enquo(object ))
189+
190+ if (! S7 :: S7_inherits(object )) {
191+ return (fail(sprintf(" %s is not an S7 object" , act $ lab )))
192+ }
193+
194+ if (! S7 :: S7_inherits(object , class )) {
195+ obj_class <- setdiff(base :: class(object ), " S7_object" )
196+ class_desc <- paste0(" <" , obj_class , " >" , collapse = " /" )
197+ msg <- sprintf(
198+ " %s inherits from %s not <%s>." ,
199+ act $ lab ,
200+ class_desc ,
201+ attr(class , " name" , TRUE )
202+ )
203+ return (fail(msg ))
204+ }
205+
206+ pass(act $ val )
207+ }
170208
171209# ' Does an object inherit from a given class?
172210# '
@@ -175,19 +213,20 @@ isS3 <- function(x) is.object(x) && !isS4(x)
175213# '
176214# ' `expect_is()` is an older form that uses [inherits()] without checking
177215# ' whether `x` is S3, S4, or neither. Instead, I'd recommend using
178- # ' [expect_type()], [expect_s3_class()] or [expect_s4_class()] to more clearly
179- # ' convey your intent.
216+ # ' [expect_type()], [expect_s3_class()], or [expect_s4_class()] to more clearly
217+ # ' convey your intent.
180218# '
181219# ' @section 3rd edition:
182220# ' `r lifecycle::badge("deprecated")`
183221# '
184222# ' `expect_is()` is formally deprecated in the 3rd edition.
185223# '
186224# ' @keywords internal
225+ # ' @param class Class name passed to `inherits()`.
187226# ' @inheritParams expect_type
188227# ' @export
189228expect_is <- function (object , class , info = NULL , label = NULL ) {
190- stopifnot(is.character( class ) )
229+ check_character( class )
191230 edition_deprecate(
192231 3 ,
193232 " expect_is()" ,
@@ -210,6 +249,9 @@ expect_is <- function(object, class, info = NULL, label = NULL) {
210249 pass(act $ val )
211250}
212251
252+ # Helpers ----------------------------------------------------------------------
253+
254+ isS3 <- function (x ) is.object(x ) && ! isS4(x )
213255
214256format_class <- function (x ) {
215257 paste0(encodeString(x , quote = " '" ), collapse = " /" )
0 commit comments