1
votes

I am implementing a helper function that checks the length of the provided parameter against a template and throws an error when the lengths are different. Here is the function:

assert_character_vec_length <- function(x, ...) {
  name   <- as.character(substitute(x))
  lens   <- unlist(list(...))
  lnames <- as.character(substitute(list(...)))[-1]
  lnames <- paste(lnames, collapse=' or ')
  if(!(length(x) %in% lens) | !is.character(x))
    stop(paste0('"', name, '"', ' must be a character vector with length ', lnames))
}

Below is an example of it's usage:

grp <- LETTERS[1:4]
assert_character_vec_length(grp, 3)

Error in assert_character_vec_length(grp, 3) : "grp" must be a character vector with length 3

I am using this inside another function to check if the passed parameters are correct. And I am also writing tests for the function using the testthat library.

When I am comparing the length with a simple number everything works and the test passes:

x <- matrix(1:100, ncol=10)
grp <- LETTERS[1:4]

err1 <- '"grp" must be a character vector with length 10'
expect_error(assert_character_vec_length(grp, 10), err1)

But to my surprise the error message doesn't match when I am using an expression to compare the lengths:

err2 <- '"grp" must be a character vector with length ncol(x)'
expect_error(assert_character_vec_length(grp, ncol(x)), err2)

Error: error$message does not match "\"grp\" must be a character vector with length ncol(x)". Actual value: ""grp" must be a character vector with length ncol(x)"

What did I miss and what is going on here?

1

1 Answers

1
votes

Take a look at ?expect_output:

expect_output(object, regexp = NULL, ..., info = NULL, label = NULL)

The second parameter is named "regexp", and indeed, it's used as a regular expression to test against.

The ( and ) have special meaning in regular expressions, called capturing groups. As written, these ( and ) will not match the literal "(" and ")" characters in the error message.

To make them match literal parentheses, you need to escape them:

err2 <- '"grp" must be a character vector with length ncol\\(x\\)'
expect_error(assert_character_vec_length(grp, ncol(x)), err2)

(Actually, escaping the opening ( will be enough here. But I find it's less confusing to read when the closing parenthesis is escaped too.)