r-lib / testthat

An R 📦 to make testing 😀
https://testthat.r-lib.org
Other
888 stars 318 forks source link

Test for infinite recursion error? #1944

Open mmuurr opened 6 months ago

mmuurr commented 6 months ago

As part of developing a package there's a specific pattern I want to detect that leads to an infinite recursion error. (If this error ever doesn't happen, then it's likely I broke something in the logic, hence my desire to test for it.)

This test fails:

f <- function() f()
expect_error(f())
# Error: C stack usage 9522952 is too close to the limit

This passes, but is a bit clunky:

f <- function() f()
tryCatch({
  f()
  TRUE
}, error = \(e) {
  FALSE
}) |> expect_false()

Should that first expect_error() test fail, given that the second passes?

({testthat} v3.2.1)

MichaelChirico commented 6 months ago

@mmuurr I agree this looks like a {testthat} bug. For some reason that class of error is not caught. FWIW I might simplify/tighten your workaround as follows:

expect_s3_class(tryCatch(f(), stackOverflowError=identity), "error")
hadley commented 5 months ago

IIRC. this is trickier than it looks because if you've run out of stack space, it's possible that no other code will work. So I'm a bit sceptical we can make this work generally, but @lionel- might know more.

lionel- commented 5 months ago

We generally rely on calling error handlers, i.e. ones that run without unwinding the call stack first. These calling handlers are purposefully not run in the case of a R-level stack overflow error to prevent R from crashing from an actual C-level stack overflow.

We could do something like rlang::try_fetch() which wraps the withCallingHandlers() call in tryCatch(stackOverflowError = ) to catch these.

Or much easier than changing all our condition handling machinery, provide a dedicated expect_no_stack_overflow() for this specific case.