r2rtf icon indicating copy to clipboard operation
r2rtf copied to clipboard

Blank `Rplots.pdf` generated when running snapshot tests interactively from RStudio

Open nanxstats opened this issue 1 year ago • 5 comments

To reproduce the issue:

usethis::create_package("zzz/")
usethis::use_testthat()

Run usethis::use_r("myfun") and put this function into it:

#' @export
myfun <- function(path) {
  head(datasets::iris) |>
    r2rtf::rtf_body() |>
    r2rtf::rtf_encode() |>
    r2rtf::write_rtf(file = path)
}

Run usethis::use_test("myfun") to create this test:

test_that("myfun snapshot", {
  path <- tempfile(fileext = ".rtf")
  myfun(path)

  local_edition(3)
  expect_snapshot_file(path, "myfun.rtf")
})

Run devtools::document() and devtools::load_all().

Clicking the "Run Tests" button or the "Test" button in the Build panel in RStudio will generate a blank, redundant tests/testthat/Rplots.pdf, while no such Rplots.pdf is generated when running devtools::test() or devtools::test_active_file() in the R console.

Reproduced under macOS, Windows, and Posit Cloud.

nanxstats avatar May 30 '24 22:05 nanxstats

The culprit is in these two places where graphics::par() and graphics::strwidth() were called:

https://github.com/Merck/r2rtf/blob/307c112e83c84a8521229f75dd145dfc57493c3c/R/rtf_strwidth.R#L56

https://github.com/Merck/r2rtf/blob/307c112e83c84a8521229f75dd145dfc57493c3c/R/rtf_strwidth.R#L110-L115

By replacing them both with a constant number, the problem goes away. Looks like by calling these functions in graphics, a PDF device is somehow triggered when running the tests in RStudio interactively.

nanxstats avatar May 31 '24 01:05 nanxstats

This unit test using graphics::strwidth() also needs side effect isolation, otherwise, Rplots.pdf will be generated:

https://github.com/Merck/r2rtf/blob/307c112e83c84a8521229f75dd145dfc57493c3c/tests/testthat/test-independent-testing-rtf_strwidth.R#L18-L30

nanxstats avatar May 31 '24 01:05 nanxstats

It seems it only happens while running unit test. I did not see the RPlots.pdf is created by running the code above in an interactive R sessions.

Guess a graphic device is initiated when devtools::test() detected graphics package is used. As I do see a RPlots.pdf file is created if we call pdf().

I am OK to live with it.

elong0527 avatar Jun 02 '24 03:06 elong0527

I should have been clearer - this only happens when you click the "Run Tests" button above the code editor or the "Test" button in the Build panel in RStudio, but not when you send the code into the R console.

Regardless, I'd say it will be productive to get this fixed, because every package that have tests with underlying code using r2rtf will get this unavoidable side effect - and it can be confusing and annoying. For example, see previous discussions:

https://github.com/Merck/metalite.ae/pull/75 https://github.com/Merck/metalite.ae/pull/73

nanxstats avatar Jun 02 '24 06:06 nanxstats

So my solution in #228 did not fully meet expectations. I tried another solution involving safe.dev.off() from rgl but it did not work.

The main problem is, I can't seem to solve this problem without using a non-default graphics device like in #228. However, if we use a non-default graphics device, it will change the calculated string width results from the original vanilla implementation by calling strwidth() directly. So I'm marking this as won't fix.

Part of this complexity seems to originate from the existence of RStudioGD and how it works, but I'm not sure if there is sufficient documentation for me to understand it properly.

nanxstats avatar Feb 17 '25 06:02 nanxstats