diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 004f6006a..9a8ddd1cf 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -1,10 +1,12 @@ { + "$schema": "https://json.schemastore.org/claude-code-settings.json", "permissions": { "allow": [ "Bash(find:*)", - "Bash(R:*)" + "Bash(R:*)", + "Bash(rm:*)", + "Bash(air format:*)" ], "deny": [] - }, - "$schema": "https://json.schemastore.org/claude-code-settings.json" + } } \ No newline at end of file diff --git a/NEWS.md b/NEWS.md index eeac2a68a..00ee47bf6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # testthat (development version) +* The last snapshot is no longer lost if the snapshot file is missing the final newline (#2092). It's easy to accidentally remove this because there are two trailing new lines in snapshot files and many editors will automatically remove if you touch the file. * New `expect_r6_class()` (#2030). * `expect_*()` functions consistently and rigorously check their inputs (#1754). * `JunitReporter()` no longer fails with `"no applicable method for xml_add_child"` for warnings outside of tests (#1913). Additionally, warnings now save their backtraces. diff --git a/R/snapshot-serialize.R b/R/snapshot-serialize.R index 7057b2145..493be7206 100644 --- a/R/snapshot-serialize.R +++ b/R/snapshot-serialize.R @@ -19,9 +19,13 @@ snap_from_md <- function(lines) { sep <- grepl("^-{3,}", lines) case_group <- cumsum(sep) - # Remove first line and last line, separator, line above and line below + # Remove first line, separator, line above and line below + # Only remove last line if it's empty (to handle missing final newlines) sep_loc <- which(sep) - drop <- c(1, sep_loc, sep_loc + 1, sep_loc - 1, length(lines)) + drop <- c(1, sep_loc, sep_loc + 1, sep_loc - 1) + if (length(lines) > 0 && lines[length(lines)] == "") { + drop <- c(drop, length(lines)) + } cases <- unname(split(lines[-drop], case_group[-drop])) code_unblock <- function(x) paste0(indent_del(x), collapse = "\n") diff --git a/tests/testthat/test-snapshot-serialize.R b/tests/testthat/test-snapshot-serialize.R index d636e8b05..7e10857dc 100644 --- a/tests/testthat/test-snapshot-serialize.R +++ b/tests/testthat/test-snapshot-serialize.R @@ -25,3 +25,22 @@ test_that("snapshots always use \n", { has_cr <- grepl("\r", snap, fixed = TRUE) expect_equal(has_cr, FALSE) }) + +test_that("snap_from_md handles missing final newlines", { + one_newline <- withr::local_tempfile( + fileext = ".md", + lines = c( + "# test_case", + "", + "result1", + "", + "---", + "", + "result2" + ) + ) + expect_equal( + read_snaps(one_newline), + list(test_case = c("result1", "result2")) + ) +})