diff --git a/NEWS.md b/NEWS.md index 6e0df57f6..5be5db263 100644 --- a/NEWS.md +++ b/NEWS.md @@ -55,7 +55,7 @@ within a learnr tutorial (#790). * `#>` is recognized as an output marker and no space is added after `#` (#771). * R code chunks in nested non-R chunks in R markdown don't yield an error - anymore when document is styled, chunks are still not styled (#788). + anymore when document is styled, chunks are still not styled (#788, #794). * `multi_line` attribute in parse table is now integer, not boolean (#782). * style guide used in Addin is verified when set via R option (#789). * improve pkgdown author URLs (#775). diff --git a/R/transform-code.R b/R/transform-code.R index 476c9833d..85d415cb8 100644 --- a/R/transform-code.R +++ b/R/transform-code.R @@ -72,6 +72,10 @@ separate_chunks <- function(lines, filetype) { #' Raw in the sense that these chunks don't contain pure R code, but they #' contain a header and footer of markdown. Only code chunks that have an engine #' whose name matches `engine-pattern` are considered as R code. +#' For every opening, we match the next closing. If there are not the same +#' amount of closing and openings after this matching, we throw an error. +#' Similarly, if there are two openings before a closing, the closing gets +#' matched twice, on which we throw an error. #' @inheritParams separate_chunks #' @param engine_pattern A regular expression that must match the engine name. #' @importFrom rlang abort @@ -85,14 +89,10 @@ identify_raw_chunks <- function(lines, filetype, engine_pattern = get_engine_pat if (filetype == "Rmd") { starts <- grep("^[\t >]*```+\\s*\\{([Rr]( *[ ,].*)?)\\}\\s*$", lines, perl = TRUE) ends <- grep("^[\t >]*```+\\s*$", lines, perl = TRUE) - - if (length(starts) != length(ends)) { - # for each start, match next end, required for nested chunks - ends <- purrr::imap_int(starts, ~ ends[which(ends > .x)[1]]) %>% - na.omit() - if (length(starts) != length(ends)) { - abort("Malformed file!") - } + ends <- purrr::imap_int(starts, ~ ends[which(ends > .x)[1]]) %>% + na.omit() + if (length(starts) != length(ends) || anyDuplicated(ends) != 0) { + abort("Malformed file!") } } else if (filetype == "Rnw") { starts <- grep(pattern$chunk.begin, lines, perl = TRUE) diff --git a/man/identify_raw_chunks.Rd b/man/identify_raw_chunks.Rd index 211ff3315..aee9260ff 100644 --- a/man/identify_raw_chunks.Rd +++ b/man/identify_raw_chunks.Rd @@ -17,5 +17,9 @@ identify_raw_chunks(lines, filetype, engine_pattern = get_engine_pattern()) Raw in the sense that these chunks don't contain pure R code, but they contain a header and footer of markdown. Only code chunks that have an engine whose name matches \code{engine-pattern} are considered as R code. +For every opening, we match the next closing. If there are not the same +amount of closing and openings after this matching, we throw an error. +Similarly, if there are two openings before a closing, the closing gets +matched twice, on which we throw an error. } \keyword{internal} diff --git a/tests/testthat/public-api/xyzfile_rmd/random5.Rmd b/tests/testthat/public-api/xyzfile_rmd/random5.Rmd deleted file mode 100644 index f50c082a4..000000000 --- a/tests/testthat/public-api/xyzfile_rmd/random5.Rmd +++ /dev/null @@ -1,270 +0,0 @@ -Some text -```{r} -# Some R code -f <- function(x) { - x -} -``` -More text before malformed chunk -# More R code -g <- function(y) { - y -} -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} - -``` -Final text -```{r} -```{r} -1 + 2 -``` diff --git a/tests/testthat/public-api/xyzfile_rmd/random7.Rmd b/tests/testthat/public-api/xyzfile_rmd/random7.Rmd new file mode 100644 index 000000000..87c1d73bf --- /dev/null +++ b/tests/testthat/public-api/xyzfile_rmd/random7.Rmd @@ -0,0 +1,23 @@ +Some text +```{r} +# Some R code +f <- function(x) { + x +} +``` +More text before malformed chunk +# More R code +g <- function(y) { + y +} +``` +Final text +```{r} + +``` + +Final text +```{r} +```{r} +1 + 2 +``` diff --git a/tests/testthat/rmd/random3-in.Rmd b/tests/testthat/rmd/random3-in.Rmd new file mode 100644 index 000000000..5ea72f5f4 --- /dev/null +++ b/tests/testthat/rmd/random3-in.Rmd @@ -0,0 +1,17 @@ +Some text +```{r} +# Some R code +f <- function(x) { + x +} +``` +More text before malformed chunk +# More R code +g <- function(y) { + y +} +``` +Final text +```{r} +1 + 2 +``` diff --git a/tests/testthat/rmd/random3-out.Rmd b/tests/testthat/rmd/random3-out.Rmd new file mode 100644 index 000000000..5ea72f5f4 --- /dev/null +++ b/tests/testthat/rmd/random3-out.Rmd @@ -0,0 +1,17 @@ +Some text +```{r} +# Some R code +f <- function(x) { + x +} +``` +More text before malformed chunk +# More R code +g <- function(y) { + y +} +``` +Final text +```{r} +1 + 2 +``` diff --git a/tests/testthat/rmd/random5-in.Rmd b/tests/testthat/rmd/random5-in.Rmd new file mode 100644 index 000000000..d7ff4b206 --- /dev/null +++ b/tests/testthat/rmd/random5-in.Rmd @@ -0,0 +1,24 @@ +Some text +```{r} +# Some R code +f <-function(x) { + x +} +``` +More text before malformed chunk + +# More R code +g <- function(y) { + y +} +``` +Final text +```{r} +f +``` +Final text +```md +````{r} +1 + 2 +```` +``` diff --git a/tests/testthat/rmd/random5-out.Rmd b/tests/testthat/rmd/random5-out.Rmd new file mode 100644 index 000000000..4a90fd2fe --- /dev/null +++ b/tests/testthat/rmd/random5-out.Rmd @@ -0,0 +1,24 @@ +Some text +```{r} +# Some R code +f <- function(x) { + x +} +``` +More text before malformed chunk + +# More R code +g <- function(y) { + y +} +``` +Final text +```{r} +f +``` +Final text +```md +````{r} +1 + 2 +```` +``` diff --git a/tests/testthat/rmd/random6-in.Rmd b/tests/testthat/rmd/random6-in.Rmd new file mode 100644 index 000000000..783c25cdb --- /dev/null +++ b/tests/testthat/rmd/random6-in.Rmd @@ -0,0 +1,20 @@ +Some text +```{r} +# Some R code +f <- function(x) { + x +} +``` + + +Final text +```{r} + 33 +``` + + +Final text +```{SQL} +```{python} +1 + 2 +``` diff --git a/tests/testthat/public-api/xyzfile_rmd/random6.Rmd b/tests/testthat/rmd/random6-out.Rmd similarity index 100% rename from tests/testthat/public-api/xyzfile_rmd/random6.Rmd rename to tests/testthat/rmd/random6-out.Rmd diff --git a/tests/testthat/test-cache-high-level-api.R b/tests/testthat/test-cache-high-level-api.R index 19b0fb699..034c6c2cd 100644 --- a/tests/testthat/test-cache-high-level-api.R +++ b/tests/testthat/test-cache-high-level-api.R @@ -28,7 +28,7 @@ test_that("activated cache brings speedup on style_text() API on character vecto text, text, fun = style_text ) - expect_gt(n, 55) + expect_gt(n, 40) }) test_that("activated cache brings speedup on style_text() API on character scalar", { @@ -120,7 +120,7 @@ capture.output(test_that("no speedup when tranformer changes", { first <- system.time(style_text(text, transformers = t1)) t1 <- tidyverse_style(indent_by = 4) second <- system.time(style_text(text, transformers = t1)) - expect_false(first["elapsed"] / 1.2 > second["elapsed"]) + expect_false(first["elapsed"] / 1.3 > second["elapsed"]) })) diff --git a/tests/testthat/test-public_api.R b/tests/testthat/test-public_api.R index 6e13f1ba3..6e31de6fa 100644 --- a/tests/testthat/test-public_api.R +++ b/tests/testthat/test-public_api.R @@ -136,22 +136,14 @@ test_that("styler can style Rmd file", { }) test_that("styler handles malformed Rmd file and invalid R code in chunk", { - capture.output(expect_warning( - style_file(testthat_file("public-api", "xyzfile_rmd", "random3.Rmd"), strict = FALSE), - NA - )) - - capture_output(expect_warning( - style_file(testthat_file("public-api", "xyzfile_rmd", "random4.Rmd"), strict = FALSE) - )) - capture_output(expect_warning( - style_file(testthat_file("public-api", "xyzfile_rmd", "random5.Rmd"), strict = FALSE) + style_file(testthat_file("public-api", "xyzfile_rmd", "random4.Rmd"), strict = FALSE), + "3: " )) capture_output(expect_warning( - style_file(testthat_file("public-api", "xyzfile_rmd", "random6.Rmd"), strict = FALSE), - NA + style_file(testthat_file("public-api", "xyzfile_rmd", "random7.Rmd"), strict = FALSE), + "Malformed file" )) }) diff --git a/tests/testthat/test-rmd.R b/tests/testthat/test-rmd.R index 820b59bf0..fe44364c2 100644 --- a/tests/testthat/test-rmd.R +++ b/tests/testthat/test-rmd.R @@ -28,4 +28,24 @@ test_that("can style .Rmd files", { filetype = "Rmd", write_tree = FALSE ), NA) + + ## new 3-5 + expect_warning(test_collection("rmd", "random3", + transformer = transform_mixed, + transformer_fun = style_text, + filetype = "Rmd", + write_tree = FALSE + ), NA) + expect_warning(test_collection("rmd", "random5", + transformer = transform_mixed, + transformer_fun = style_text, + filetype = "Rmd", + write_tree = FALSE + ), NA) + expect_warning(test_collection("rmd", "random6", + transformer = transform_mixed, + transformer_fun = style_text, + filetype = "Rmd", + write_tree = FALSE + ), NA) })