From 2b7c432ac9b1b20499b17219f59d5294c26a79c0 Mon Sep 17 00:00:00 2001 From: Kyle Meyer Date: Fri, 15 Nov 2024 10:29:44 -0500 Subject: [PATCH] split_on_line_directives: fix handling of single-file package case split_on_line_directives breaks the input at #line directives and returns a named list of lines for each file. For a package with a single file under R/, there is one directive. The bounds calculation is still correct for that case. However, the return value is incorrectly a matrix rather than a list because the mapply call simplifies the result. At this point, this bug is mostly [*] unexposed because this code path is only triggered if utils::getParseData returns NULL, and it should always return a non-NULL result for the single-file package case. The next commit will reorder things, exposing the bug. Tell mapply to not simplify the result. [*] The simplification to a matrix could also happen for multi-file packages in the unlikely event that all files have the same number of lines. --- R/utils.R | 7 ++++++- tests/testthat/test-utils.R | 31 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/R/utils.R b/R/utils.R index 13ee6205..6d01c23e 100644 --- a/R/utils.R +++ b/R/utils.R @@ -96,7 +96,12 @@ split_on_line_directives <- function(lines) { file_starts <- directive_lines + 1 file_ends <- c(directive_lines[-1] - 1, length(lines)) - res <- mapply(function(start, end) lines[start:end], file_starts, file_ends) + res <- mapply( + function(start, end) lines[start:end], + file_starts, + file_ends, + SIMPLIFY = FALSE + ) names(res) <- na.omit(matches$filename) res } diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 8ee62041..90dc0a37 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -72,3 +72,34 @@ test_that("split_on_line_directives returns NULL for input without directive (#5 NULL ) }) + +test_that("split_on_line_directives does not simplify the result (#588)", { + expect_identical( + split_on_line_directives( + c( + '#line 1 "foo.R"', + "abc", + "def" + ) + ), + list( + "foo.R" = c("abc", "def") + ) + ) + expect_identical( + split_on_line_directives( + c( + '#line 1 "foo.R"', + "abc", + "def", + '#line 4 "bar.R"', + "ghi", + "jkl" + ) + ), + list( + "foo.R" = c("abc", "def"), + "bar.R" = c("ghi", "jkl") + ) + ) +})