testthat icon indicating copy to clipboard operation
testthat copied to clipboard

Assignment in `expect_no_warning()` does not work if a warning was thrown

Open lschneiderbauer opened this issue 1 year ago • 1 comments

expect_no_warning() seems to behave somewhat inconsistent to the rest of the family (e.g. compared to expect_warning()): Assignment inside the body fails if a warning was thrown.

There was a similar discussion in #998 where this was deemed a bug.

Note the second try, variable b: it's the only case where assignment does not work, in all other cases it works.

library(testthat)
foo_warning <- function() {
  warning("a warning")
  5
}
foo <- function() {
  5
}

expect_warning(a <- foo_warning())
a
#> [1] 5

expect_no_warning(b <- foo_warning())
#> Error: Expected `b <- foo_warning()` to run without any warnings.
#> ℹ Actually got a <simpleWarning> with text:
#>   a warning
b
#> Error: Objekt 'b' nicht gefunden

expect_warning(c <- foo())
#> Error: `c <- foo()` did not produce any warnings.
c
#> [1] 5

expect_no_warning(d <- foo())
d
#> [1] 5

Created on 2024-10-04 with reprex v2.1.1

lschneiderbauer avatar Oct 04 '24 06:10 lschneiderbauer

When rendering the reprex with the expect_condition() and expect_no_condition(), I get similar results:

library(testthat)
foo_warning <- function() {
  warning("a warning")
  5
}
foo <- function() {
  5
}

expect_condition(a <- foo_warning())
a
#> Error: Objekt 'a' nicht gefunden

expect_no_condition(b <- foo_warning())
#> Error: Expected `b <- foo_warning()` to run without any conditions.
#> ℹ Actually got a <simpleWarning> with text:
#>   a warning
b
#> Error: Objekt 'b' nicht gefunden

expect_condition(c <- foo())
#> Error: `c <- foo()` did not throw an condition.
c
#> [1] 5

expect_no_condition(d <- foo())
d
#> [1] 5

Created on 2024-10-04 with reprex v2.1.1

lschneiderbauer avatar Oct 04 '24 06:10 lschneiderbauer

Slightly simpler reprex:

library(testthat)
expect_warning(a <- 1)
#> Error: `a <- 1` did not produce any warnings.
a
#> [1] 1
expect_no_warning({warning("x"); b <- 1})
#> Error: Expected `{ ... }` to run without any warnings.
#> ℹ Actually got a <simpleWarning> with text:
#>   x
b
#> Error: object 'b' not found

Created on 2024-11-05 with reprex v2.1.0

hadley avatar Nov 05 '24 18:11 hadley

But:

library(testthat)
expect_no_warning({b <- 1; warning("x")})
#> Error: Expected `{ ... }` to run without any warnings.
#> ℹ Actually got a <simpleWarning> with text:
#>   x
b
#> [1] 1

i.e. the expectation fails as soon as the warning is detected, and no further code is run.

Looks like we need to apply the same logic in cnd_matcher() to the capture() function inside expect_no_. i.e. use act <- quasi_capture(enquo(object), NULL, matcher) and then inspect act$cap.

hadley avatar Nov 05 '24 18:11 hadley