From c38d1dd293d63e33e25750d730070e3d39006417 Mon Sep 17 00:00:00 2001 From: Hugo Rodrigues Date: Sat, 9 May 2026 09:36:54 -0400 Subject: [PATCH] test(v0952): make print-output capture robust to cli message handlers The two assertions on lines 86-87 of tests/testthat/test-v0952-vignette-pt.R captured cli output via capture.output(type = "message"). That taps stderr, which works in non-interactive R (CI) but silently returns empty when an interactive session (RStudio, knitr renderer) has installed a custom cli.default_handler that re-routes the message before it reaches stderr. combined ended up empty and grepl("AC", combined) / grepl("CM", combined) returned FALSE. Force the default cli handler off via withr::local_options() and capture the cli stream with testthat::capture_messages(), which uses withCallingHandlers() to intercept the message condition directly. The test now passes under both modes -- including a session that pre-installs a hostile cli.default_handler -- while CI remains green. Co-Authored-By: Claude Opus 4.7 (1M context) --- tests/testthat/test-v0952-vignette-pt.R | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/tests/testthat/test-v0952-vignette-pt.R b/tests/testthat/test-v0952-vignette-pt.R index cbd568b02..80fdb0291 100644 --- a/tests/testthat/test-v0952-vignette-pt.R +++ b/tests/testthat/test-v0952-vignette-pt.R @@ -59,6 +59,16 @@ test_that("Vinheta v09 parses sem erros de sintaxe Rmd", { # ---- ClassificationResult$print: defensive when trace has non-list entries ---- test_that("ClassificationResult$print does not error on scalar/NULL trace entries", { + # cli routes output via getOption("cli.default_handler") if set, else + # via R's message() / message-condition path. Local interactive sessions + # (RStudio, knitr) sometimes install a default handler that re-routes + # messages away from both stderr and the condition system, which made + # the original capture.output(type = "message") + nested capture.output() + # pattern silently return empty locally while passing on CI. Forcing + # the default handler off restores the standard message-condition path + # so testthat::capture_messages() (withCallingHandlers-based) sees it. + withr::local_options(cli.default_handler = NULL, cli.num_colors = 1L) + res <- ClassificationResult$new( system = "WRB 2022", name = "Cambisols", @@ -74,17 +84,12 @@ test_that("ClassificationResult$print does not error on scalar/NULL trace entrie evidence_grade = "A" ) # Should not error - expect_no_error(invisible(capture.output(print(res), type = "message"))) - # cli writes to message stream; capture both - out <- capture.output({ - capture.output(print(res), type = "message") - }) - msg <- capture.output(print(res), type = "message") - combined <- c(out, msg) + expect_no_error(invisible(testthat::capture_messages(print(res)))) + combined <- paste(testthat::capture_messages(print(res)), collapse = "\n") # Scalar/NULL/data.frame entries are skipped in the per-RSG dump, # but CM and AC (proper trace entries) must appear. - expect_true(any(grepl("AC", combined))) - expect_true(any(grepl("CM", combined))) + expect_true(grepl("AC", combined)) + expect_true(grepl("CM", combined)) })