ravingmantis / unittest

Unit testing for R
4 stars 1 forks source link

Add ut_cmp_warnings #16

Closed lentinj closed 1 month ago

lentinj commented 1 month ago

I've just put this together:

ut_cmp_warnings <- function(code, expected_regexes, ignore.case = FALSE, perl = FALSE, fixed = FALSE) {
    stopifnot(is.character(expected_regexes) || length(expected_regexes) == 0)
    all_warnings <- list()
    rv <- withCallingHandlers(code, warning = function (w) {
        all_warnings <<- c(all_warnings, list(w))
        invokeRestart("muffleWarning")
    })

    if (length(expected_regexes) != length(all_warnings)) {
        return(c(
            paste0("Expected ", length(expected_regexes), " warnings, ", "not ", length(all_warnings), ":"),
            vapply(all_warnings, function (w) w$message, character(1)) ))
    }
    out <- c()
    for (i in seq_along(expected_regexes)) {
        if (!grepl(expected_regexes[[i]], all_warnings[[i]]$message,
                ignore.case = ignore.case, perl = perl, fixed = fixed)) {
            out <- c(all_warnings[[i]]$message, "Did not match:-", expected_regexes[[i]])
        }
    }
    return(if (length(out) == 0) TRUE else out)
}

It expects a character vector of regexes, one per warning, and they should be in order.

Insisting that we provide one regex per-warning is probably reasonable, if they all match you ought still care about the number of warnings. You could do something like rep(regex, count) to say you're expecting count warnings matching regex.

What's more awkward is if you want to check for your warnings, but ignore third-party warnings out of your control. We could instead make sure there is at least one warning matching each regex, but I'm more tempted to say "if you really want to ignore extra warnings, then you're on your own, this isn't something we encourage".

EDIT: Insisting they're in order is also debatable, but it's pretty unlikely you're testing multi-threaded code.

lentinj commented 1 month ago
catch_warnings <- function(expr) {
    ww <- NULL
    wh <- function(w) {
        ww <<- append(ww, w$message)
        invokeRestart("muffleWarning")
    }
    got <- withCallingHandlers(expr, warning=wh)
    list(got=got, warnings=ww)
}
lentinj commented 1 month ago

No, relying on the ordering is bad, but the count still seems useful to check.

lentinj commented 1 month ago

Fixed with https://github.com/ravingmantis/unittest/commit/840f1f4ad7cf0057d4752379231fcfd28883870e