toy_pkg <- function(desc_extra = character(), env = parent.frame()) {
pkg <- withr::local_tempdir(.local_envir = env)
dir.create(file.path(pkg, "vignettes"))
writeLines(c("Package: toy", "Title: Toy", "Version: 0.0.1", "Description: Toy.",
"License: MIT", desc_extra), file.path(pkg, "DESCRIPTION"))
pkg
}
html_vig <- function(title = "A") {
c("---", paste0("title: ", title), "output: rmarkdown::html_vignette",
"vignette: >", paste0(" %\\VignetteIndexEntry{", title, "}"), " %\\VignetteEngine{knitr::rmarkdown}",
"---", "", "Text.")
}
test_that("DESCRIPTION gets a version bound and, for a development version, Remotes", {
pkg <- toy_pkg(c("Suggests:", " albersdown,", " testthat",
"Config/Needs/website: albersdown, bbuchsbaum/albersdown"))
withr::local_dir(pkg)
suppressMessages(.ensure_vignette_deps(version = "2.0.0.9000"))
desc <- readLines("DESCRIPTION")
expect_true(" albersdown (>= 2.0.0.9000)," %in% desc)
d <- read.dcf("DESCRIPTION")
expect_identical(trimws(strsplit(d[, "Config/Needs/website"], ",")[[1]]), "bbuchsbaum/albersdown")
expect_identical(unname(trimws(d[, "Remotes"])), "bbuchsbaum/albersdown")
expect_identical(d[, "VignetteBuilder"], c(VignetteBuilder = "knitr"))
# idempotent
expect_false(suppressMessages(.ensure_vignette_deps(version = "2.0.0.9000")))
expect_identical(readLines("DESCRIPTION"), desc)
# the Remotes note is said, with its check NOTE
writeLines(c("Package: toy", "Title: Toy", "Version: 0.0.1"), "DESCRIPTION")
msg <- paste(testthat::capture_messages(.ensure_vignette_deps(version = "2.0.0.9000")), collapse = "")
expect_match(msg, "Remotes: bbuchsbaum/albersdown", fixed = TRUE)
expect_match(msg, "not on CRAN", fixed = TRUE)
expect_match(msg, "--as-cran", fixed = TRUE)
})
test_that("a released version gets a plain version bound, with no Remotes or Remotes note", {
pkg <- toy_pkg(c("Suggests:", " testthat"))
withr::local_dir(pkg)
msg <- paste(testthat::capture_messages(.ensure_vignette_deps(version = "2.1.0")), collapse = "")
desc <- readLines("DESCRIPTION")
expect_true(" albersdown (>= 2.1.0)," %in% desc)
d <- read.dcf("DESCRIPTION")
expect_false("Remotes" %in% colnames(d))
expect_identical(d[, "VignetteBuilder"], c(VignetteBuilder = "knitr"))
expect_no_match(msg, "Remotes: bbuchsbaum/albersdown", fixed = TRUE)
expect_no_match(msg, "not on CRAN", fixed = TRUE)
# idempotent
expect_false(suppressMessages(.ensure_vignette_deps(version = "2.1.0")))
expect_identical(readLines("DESCRIPTION"), desc)
})
test_that("existing bounds and Remotes are respected; a release adds no Remotes", {
pkg <- toy_pkg(c("Suggests: knitr, albersdown (>= 1.0), rmarkdown",
"Remotes:", " r-lib/foo,", " github::bbuchsbaum/albersdown@main"))
withr::local_dir(pkg)
suppressMessages(.ensure_vignette_deps(version = "2.0.0.9000"))
d <- read.dcf("DESCRIPTION")
expect_identical(d[, "Suggests"], c(Suggests = "knitr, albersdown (>= 2.0.0.9000), rmarkdown"))
expect_identical(trimws(strsplit(d[, "Remotes"], ",")[[1]]), c("r-lib/foo", "github::bbuchsbaum/albersdown@main"))
# a higher bound stays; a CRAN release needs no Remotes
pkg2 <- toy_pkg(c("Suggests: albersdown (>= 3.0)"))
withr::local_dir(pkg2)
suppressMessages(.ensure_vignette_deps(version = "2.1.0"))
d <- read.dcf("DESCRIPTION")
expect_match(d[, "Suggests"], "albersdown (>= 3.0)", fixed = TRUE)
expect_false("Remotes" %in% colnames(d))
# an existing Remotes field is appended to, without reflowing
pkg3 <- toy_pkg(c("Remotes:", " r-lib/foo"))
withr::local_dir(pkg3)
suppressMessages(.ensure_vignette_deps(version = "2.0.0.9000"))
desc <- readLines("DESCRIPTION")
expect_true(all(c("Remotes:", " r-lib/foo,", " bbuchsbaum/albersdown") %in% desc))
expect_identical(sum(grepl("^Remotes:", desc)), 1L)
})
test_that("use_albersdown() writes the bound for the installed version", {
pkg <- toy_pkg()
writeLines(html_vig(), file.path(pkg, "vignettes", "a.Rmd"))
suppressMessages(use_albersdown(pkg))
d <- read.dcf(file.path(pkg, "DESCRIPTION"))
v <- utils::packageVersion("albersdown")
expect_match(d[, "Suggests"], sprintf("albersdown (>= %s)", v), fixed = TRUE)
expect_identical("Remotes" %in% colnames(d), .albers_is_dev_version(v))
expect_true(.albers_is_dev_version("2.0.0.9000"))
expect_false(.albers_is_dev_version("2.1.0"))
})
test_that("a created _pkgdown.yml is kept out of the tarball", {
pkg <- toy_pkg()
suppressMessages(use_albersdown(pkg, apply_to = "new"))
expect_true(file.exists(file.path(pkg, "_pkgdown.yml")))
ign <- readLines(file.path(pkg, ".Rbuildignore"))
expect_true(all(c("^_pkgdown\\.yml$", "^docs$") %in% ign))
withr::with_dir(pkg, {
expect_true(.albers_build_ignored("_pkgdown.yml"))
expect_true(.albers_build_ignored("docs"))
})
# an existing, unignored _pkgdown.yml is added; an equivalent pattern is respected
pkg2 <- toy_pkg()
writeLines(c("template:", " package: albersdown"), file.path(pkg2, "_pkgdown.yml"))
suppressMessages(use_albersdown(pkg2, apply_to = "new"))
expect_true("^_pkgdown\\.yml$" %in% readLines(file.path(pkg2, ".Rbuildignore")))
expect_false("^docs$" %in% readLines(file.path(pkg2, ".Rbuildignore")))
pkg3 <- toy_pkg()
writeLines("^_pkgdown\\.ya?ml$", file.path(pkg3, ".Rbuildignore"))
suppressMessages(use_albersdown(pkg3, apply_to = "new"))
ign <- readLines(file.path(pkg3, ".Rbuildignore"))
expect_false("^_pkgdown\\.yml$" %in% ign)
expect_true("^docs$" %in% ign)
})
legacy_20_vignette <- function(title = "P", body_extra = character()) {
c(
"---", paste0("title: ", title), "output:", " rmarkdown::html_vignette:", " toc: yes",
" toc_depth: 2.0", " css: albers.css", " includes:", " in_header: albers-header.html",
"params:", " family: lapis", " preset: homage",
"resource_files:", "- albers.css", "- albers.js", "- albers-header.html", "- fonts", "",
"vignette: |", paste0(" %\\VignetteIndexEntry{", title, "}"), " %\\VignetteEngine{knitr::rmarkdown}",
" %\\VignetteEncoding{UTF-8}", "---", "",
"```{r setup, include = FALSE}",
"if (requireNamespace(\"ragg\", quietly = TRUE)) knitr::opts_chunk$set(dev = \"ragg_png\")",
"if (",
" requireNamespace(\"systemfonts\", quietly = TRUE) &&",
" requireNamespace(\"albersdown\", quietly = TRUE) &&",
" \"albers_register_fonts\" %in% getNamespaceExports(\"albersdown\")",
") {",
" albersdown::albers_register_fonts()",
"}",
"if (requireNamespace(\"ggplot2\", quietly = TRUE) && requireNamespace(\"albersdown\", quietly = TRUE)) ggplot2::theme_set(albersdown::theme_albers(family = params$family, preset = params$preset))",
"library(ggplot2)",
"```", "",
"```{r albers-classes, echo=FALSE, results='asis'}",
"cat(sprintf('', params$family, params$preset))",
"```", "",
body_extra,
"## Plots", "", "```{r}", "plot(1)", "```"
)
}
legacy_20_pkg <- function(env = parent.frame()) {
pkg <- toy_pkg(c("Suggests:", " ggplot2,", " knitr,", " rmarkdown",
"VignetteBuilder: knitr", "Config/Needs/website: albersdown"), env = env)
writeLines(legacy_20_vignette("P"), file.path(pkg, "vignettes", "plots.Rmd"))
writeLines(legacy_20_vignette("Q", c("Family: `r params$family`.", "")), file.path(pkg, "vignettes", "uses.Rmd"))
for (f in c("albers.css", "albers.js", "albers-header.html")) writeLines("/* vendored */", file.path(pkg, "vignettes", f))
dir.create(file.path(pkg, "vignettes", "fonts"))
for (f in c("newsreader.woff2", "familjen-grotesk.woff2")) writeLines("x", file.path(pkg, "vignettes", "fonts", f))
dir.create(file.path(pkg, "pkgdown"))
writeLines(c("@import url(\"albers.css\");", ""), file.path(pkg, "pkgdown", "extra.css"))
writeLines(c("/* albersdown pkgdown/extra.js: site default classes + full albers.js. */", "(function () {", "})();"),
file.path(pkg, "pkgdown", "extra.js"))
writeLines(c("template:", " package: albersdown", " bootstrap: 5.0"), file.path(pkg, "_pkgdown.yml"))
writeLines(c(
"# toy", "", "Toy package.", "",
"", "## Albers theme",
"This package uses the albersdown theme. ... configured via `params$family` and `params$preset` ...",
""
), file.path(pkg, "README.md"))
# albersdown 2.0 left its own backups
dir.create(file.path(pkg, ".albersdown.bak"))
writeLines("2.0's backup", file.path(pkg, ".albersdown.bak", "plots.Rmd"))
pkg
}
test_that("a package set up by albersdown 2.0 is migrated to the format", {
pkg <- legacy_20_pkg()
suppressMessages(use_albersdown(pkg, family = "teal", preset = "interaction"))
p <- readLines(file.path(pkg, "vignettes", "plots.Rmd"))
expect_true(all(c(" albersdown::albers_vignette:", " family: teal", " preset: interaction",
" toc: yes", "library(ggplot2)", "```{r setup, include = FALSE}") %in% p))
expect_false(any(grepl("theme_set|ragg|systemfonts|albers_register_fonts|albers-classes|params|resource_files|albers\\.css", p)))
# the vignette index entry follows directly
expect_true("vignette: |" %in% p)
# a vignette that reads params$family keeps its params
u <- readLines(file.path(pkg, "vignettes", "uses.Rmd"))
expect_true(all(c("params:", " family: lapis") %in% u))
expect_false(any(grepl("theme_set", u)))
# vendored assets are moved to the backup store; 2.0's backup is not overwritten
expect_false(any(file.exists(file.path(pkg, "vignettes", c("albers.css", "albers.js", "albers-header.html", "fonts")))))
bak <- file.path(pkg, ".albersdown.bak")
expect_true(all(file.exists(file.path(bak, c("albers.css", "albers.js", "albers-header.html",
"fonts/newsreader.woff2", "fonts/familjen-grotesk.woff2")))))
expect_identical(readLines(file.path(bak, "plots.Rmd")), "2.0's backup")
expect_length(list.files(bak, pattern = "^plots\\.Rmd\\."), 1L)
# 2.0's generated pkgdown files are replaced
expect_false(file.exists(file.path(pkg, "pkgdown", "extra.css")))
expect_identical(readLines(file.path(pkg, "pkgdown", "extra.js")),
'window.albersdownDefaults = { family: "teal", preset: "interaction", style: "minimal" };')
# README note describes the format, not 2.0's setup
readme <- paste(readLines(file.path(pkg, "README.md")), collapse = "\n")
expect_match(readme, "albersdown::albers_vignette()", fixed = TRUE)
expect_false(grepl("params$family", readme, fixed = TRUE))
expect_identical(lengths(regmatches(readme, gregexpr("theme-note:start", readme))), 1L)
d <- read.dcf(file.path(pkg, "DESCRIPTION"))
expect_identical(unname(trimws(d[, "Config/Needs/website"])), "bbuchsbaum/albersdown")
expect_true("^_pkgdown\\.yml$" %in% readLines(file.path(pkg, ".Rbuildignore")))
# a second run changes nothing
before <- lapply(list.files(pkg, recursive = TRUE, full.names = TRUE), readLines)
suppressMessages(use_albersdown(pkg, family = "teal", preset = "interaction"))
expect_identical(lapply(list.files(pkg, recursive = TRUE, full.names = TRUE), readLines), before)
})
test_that("a vignette already on the format loses 2.0's leftover setup lines", {
pkg <- toy_pkg()
v <- legacy_20_vignette("P")
v <- c(v[1:2], "output:", " albersdown::albers_vignette:", " family: teal", v[10:length(v)])
v <- v[!grepl("css: albers.css|in_header|includes:", v)]
writeLines(v, file.path(pkg, "vignettes", "p.Rmd"))
msg <- paste(testthat::capture_messages(use_albersdown(pkg, family = "teal")), collapse = "")
expect_match(msg, "removed albersdown 2.0's setup lines", fixed = TRUE)
p <- readLines(file.path(pkg, "vignettes", "p.Rmd"))
expect_false(any(grepl("theme_set|params", p)))
expect_true(" family: teal" %in% p)
})
test_that("vendored assets still used by an unconverted vignette stay, and user extra.css stays", {
pkg <- legacy_20_pkg()
writeLines(c("a { color: hotpink; }", "@import url(\"albers.css\");"), file.path(pkg, "pkgdown", "extra.css"))
q <- c("---", "title: Q", "output:", " html_document: default", " rmarkdown::html_vignette:",
" css: albers.css", "vignette: >", " %\\VignetteIndexEntry{Q}", "---")
writeLines(q, file.path(pkg, "vignettes", "q.Rmd"))
msg <- paste(testthat::capture_messages(use_albersdown(pkg, family = "teal")), collapse = "")
expect_match(msg, "still used by q.Rmd", fixed = TRUE)
expect_true(all(file.exists(file.path(pkg, "vignettes", c("albers.css", "fonts/newsreader.woff2")))))
expect_identical(readLines(file.path(pkg, "pkgdown", "extra.css")), c("a { color: hotpink; }", "@import url(\"albers.css\");"))
})
test_that("YAML fences follow rmarkdown: trailing blanks and a closing ...", {
pkg <- toy_pkg()
mu <- c("---", "title: Mu", "output: rmarkdown::html_vignette",
"vignette: >", " %\\VignetteIndexEntry{Mu}", "...", "", "Text.")
xi <- c("", "--- ", "title: Xi", "output: rmarkdown::html_vignette ",
"vignette: >", " %\\VignetteIndexEntry{Xi}", "--- ", "", "Text.")
bad <- c("---", "title: Bad", "Text without a closing fence.")
writeLines(mu, file.path(pkg, "vignettes", "mu.Rmd"))
writeLines(xi, file.path(pkg, "vignettes", "xi.Rmd"))
writeLines(bad, file.path(pkg, "vignettes", "bad.Rmd"))
msg <- paste(testthat::capture_messages(use_albersdown(pkg, family = "teal")), collapse = "")
expect_match(msg, "Could not find the YAML header delimiters (--- ... --- or ...) in bad.Rmd", fixed = TRUE)
expect_false(grepl("No YAML header", msg, fixed = TRUE))
m <- readLines(file.path(pkg, "vignettes", "mu.Rmd"))
expect_identical(m[1:5], c("---", "title: Mu", "output:", " albersdown::albers_vignette:", " family: teal"))
expect_identical(m[length(m) - 2L], "...")
x <- readLines(file.path(pkg, "vignettes", "xi.Rmd"))
expect_identical(x[1:2], c("", "--- "))
expect_true(all(c(" albersdown::albers_vignette:", "--- ") %in% x))
expect_identical(readLines(file.path(pkg, "vignettes", "bad.Rmd")), bad)
# the re-run path (already on the format) reads the same fences
suppressMessages(use_albersdown(pkg, family = "violet"))
expect_true(" family: violet" %in% readLines(file.path(pkg, "vignettes", "mu.Rmd")))
expect_true(" family: violet" %in% readLines(file.path(pkg, "vignettes", "xi.Rmd")))
expect_identical(.albers_fences(c("---", "a: 1", "...")), c(1L, 3L))
expect_null(.albers_fences(c("text", "---", "a: 1", "---")))
expect_null(.albers_fences(c("...", "a: 1", "---")))
})
test_that("a scalar albers_vignette output takes arguments as a map", {
pkg <- toy_pkg()
writeLines(c("---", "title: S", "output: albersdown::albers_vignette", "---", "", "Text."),
file.path(pkg, "vignettes", "s.Rmd"))
suppressMessages(use_albersdown(pkg))
expect_identical(readLines(file.path(pkg, "vignettes", "s.Rmd"))[3], "output: albersdown::albers_vignette")
suppressMessages(use_albersdown(pkg, family = "teal"))
s <- readLines(file.path(pkg, "vignettes", "s.Rmd"))
expect_identical(s[3:5], c("output:", " albersdown::albers_vignette:", " family: teal"))
skip_if_not_installed("yaml")
expect_identical(yaml::yaml.load(paste(s[2:(length(s) - 3)], collapse = "\n"))$output,
list(`albersdown::albers_vignette` = list(family = "teal")))
})
test_that("readme = TRUE describes the format for the format method", {
pkg <- toy_pkg()
# the format note needs a vignette on the format (else the site-only note)
writeLines(html_vig(), file.path(pkg, "vignettes", "a.Rmd"))
writeLines(c("# toy", "", "Toy."), file.path(pkg, "README.md"))
suppressMessages(use_albersdown(pkg, family = "teal", preset = "interaction", readme = TRUE))
readme <- paste(readLines(file.path(pkg, "README.md")), collapse = "\n")
expect_match(readme, "`albersdown::albers_vignette()` output format (family = 'teal', preset = 'interaction'", fixed = TRUE)
expect_match(readme, "`template: package: albersdown`", fixed = TRUE)
expect_false(grepl("params$family|extra.css|albers.css", readme))
# without readme = TRUE, a user's README is left alone
pkg2 <- toy_pkg()
writeLines(c("# toy"), file.path(pkg2, "README.md"))
suppressMessages(use_albersdown(pkg2, family = "teal"))
expect_identical(readLines(file.path(pkg2, "README.md")), "# toy")
})
test_that("CRLF line endings and a byte-order mark are kept", {
pkg <- toy_pkg()
path <- file.path(pkg, "vignettes", "l.Rmd")
crlf <- function(lines, bom = FALSE) {
con <- file(path, "wb")
if (bom) writeBin(as.raw(c(0xef, 0xbb, 0xbf)), con)
writeLines(lines, con, sep = "\r\n")
close(con)
}
crlf(html_vig("L"), bom = TRUE)
desc <- file.path(pkg, "DESCRIPTION")
d <- readLines(desc)
con <- file(desc, "wb"); writeLines(d, con, sep = "\r\n"); close(con)
suppressMessages(use_albersdown(pkg, family = "teal"))
bytes <- readBin(path, "raw", file.size(path))
expect_identical(bytes[1:3], as.raw(c(0xef, 0xbb, 0xbf)))
text <- rawToChar(bytes[-(1:3)])
expect_false(grepl("[^\r]\n", text))
expect_match(text, " albersdown::albers_vignette:\r\n family: teal\r\n", fixed = TRUE)
dtext <- rawToChar(readBin(desc, "raw", file.size(desc)))
expect_false(grepl("[^\r]\n", dtext))
expect_match(dtext, "albersdown (>= ", fixed = TRUE)
})
test_that("the dry run lists ignore-file edits and changes nothing", {
pkg <- legacy_20_pkg()
files <- list.files(pkg, recursive = TRUE, all.files = TRUE)
sums <- tools::md5sum(file.path(pkg, files))
msg <- paste(testthat::capture_messages(use_albersdown(pkg, family = "teal", dry_run = TRUE)), collapse = "")
expect_match(msg, "Would add ^_pkgdown\\.yml$ to .Rbuildignore", fixed = TRUE)
expect_match(msg, "Would add ^\\.albersdown\\.bak$ to .Rbuildignore", fixed = TRUE)
expect_match(msg, "Would add .albersdown.bak/ to .gitignore", fixed = TRUE)
expect_match(msg, "Would update DESCRIPTION: ", fixed = TRUE)
expect_match(msg, "Would move vignettes/albers.css", fixed = TRUE)
expect_match(msg, "Would remove pkgdown/extra.css", fixed = TRUE)
expect_match(msg, "and remove albersdown 2.0's setup lines", fixed = TRUE)
expect_identical(list.files(pkg, recursive = TRUE, all.files = TRUE), files)
expect_identical(tools::md5sum(file.path(pkg, files)), sums)
})
test_that("Quarto vignettes and articles are reported with the reason", {
pkg <- toy_pkg()
dir.create(file.path(pkg, "vignettes", "articles"))
writeLines(html_vig("K"), file.path(pkg, "vignettes", "articles", "kappa.Rmd"))
writeLines(c("---", "title: Q", "---"), file.path(pkg, "vignettes", "q.qmd"))
msg <- paste(testthat::capture_messages(use_albersdown(pkg, family = "teal")), collapse = "")
expect_match(msg, "Not converted: q.qmd (Quarto", fixed = TRUE)
expect_match(msg, "Not converted: kappa.Rmd in vignettes/articles/ (pkgdown-only articles take the site default", fixed = TRUE)
expect_match(msg, "`output: albersdown::albers_vignette`", fixed = TRUE)
expect_identical(readLines(file.path(pkg, "vignettes", "articles", "kappa.Rmd")), html_vig("K"))
})
test_that("a site-only adoption leaves every field R CMD check reads alone", {
check_fields <- function(pkg) {
d <- read.dcf(file.path(pkg, "DESCRIPTION"))
d[, setdiff(colnames(d), "Config/Needs/website"), drop = FALSE]
}
# no vignettes at all
pkg <- toy_pkg()
unlink(file.path(pkg, "vignettes"), recursive = TRUE)
before <- check_fields(pkg)
msg <- paste(testthat::capture_messages(use_albersdown(pkg, family = "green")), collapse = "")
expect_identical(check_fields(pkg), before)
expect_identical(unname(read.dcf(file.path(pkg, "DESCRIPTION"))[, "Config/Needs/website"]), "bbuchsbaum/albersdown")
expect_match(msg, "No vignettes on albersdown::albers_vignette(): DESCRIPTION gets only Config/Needs/website", fixed = TRUE)
expect_true("^_pkgdown\\.yml$" %in% readLines(file.path(pkg, ".Rbuildignore")))
# vignettes that all stay on other formats
pkg2 <- toy_pkg(c("Suggests: bookdown"))
writeLines(c("---", "title: B", "output: bookdown::html_vignette2", "---"), file.path(pkg2, "vignettes", "b.Rmd"))
before <- check_fields(pkg2)
suppressMessages(use_albersdown(pkg2, family = "green"))
expect_identical(check_fields(pkg2), before)
# apply_to = "new" converts nothing, so it adds no vignette dependencies either
pkg3 <- toy_pkg()
writeLines(html_vig(), file.path(pkg3, "vignettes", "a.Rmd"))
before <- check_fields(pkg3)
suppressMessages(use_albersdown(pkg3, family = "green", apply_to = "new"))
expect_identical(check_fields(pkg3), before)
expect_identical(readLines(file.path(pkg3, "vignettes", "a.Rmd")), html_vig())
# ... unless a vignette is already on the format
writeLines(c("---", "title: F", "output: albersdown::albers_vignette", "---"), file.path(pkg3, "vignettes", "f.Rmd"))
suppressMessages(use_albersdown(pkg3, family = "green", apply_to = "new"))
d <- read.dcf(file.path(pkg3, "DESCRIPTION"))
expect_match(d[, "Suggests"], "albersdown (>= ", fixed = TRUE)
expect_identical(unname(d[, "VignetteBuilder"]), "knitr")
})
test_that("albersdown in Imports gets the bound there, not a second listing", {
pkg <- toy_pkg(c("Imports:", " albersdown (>= 2.0.0)", "Suggests:", " knitr"))
withr::local_dir(pkg)
suppressMessages(.ensure_vignette_deps(version = "2.0.0.9000"))
d <- read.dcf("DESCRIPTION")
expect_identical(unname(trimws(d[, "Imports"])), "albersdown (>= 2.0.0.9000)")
expect_false(grepl("albersdown", d[, "Suggests"]))
expect_match(d[, "Suggests"], "rmarkdown", fixed = TRUE)
expect_identical(unname(trimws(d[, "Remotes"])), "bbuchsbaum/albersdown")
pkg2 <- toy_pkg(c("Depends: R (>= 4.1), albersdown"))
withr::local_dir(pkg2)
suppressMessages(.ensure_vignette_deps(version = "2.0.0.9000"))
d <- read.dcf("DESCRIPTION")
expect_identical(unname(d[, "Depends"]), "R (>= 4.1), albersdown (>= 2.0.0.9000)")
expect_identical(unname(trimws(d[, "Suggests"])), "knitr,\nrmarkdown")
})
test_that("a pinned or qualified website reference is not duplicated", {
for (ref in c("bbuchsbaum/albersdown@main", "github::bbuchsbaum/albersdown", "bbuchsbaum/albersdown#12")) {
pkg <- toy_pkg(sprintf("Config/Needs/website: %s", ref))
withr::local_dir(pkg)
suppressMessages(.ensure_vignette_deps(version = "2.1.0", vignettes = FALSE))
expect_identical(unname(read.dcf("DESCRIPTION")[, "Config/Needs/website"]), ref)
}
expect_identical(.albers_ref_name(c("github::a/b@v1 (>= 1)", "albersdown (>= 2)", "a/b#3")), c("a/b", "albersdown", "a/b"))
})
test_that("the README note goes in README.Rmd when that is the source", {
pkg <- toy_pkg()
writeLines(html_vig(), file.path(pkg, "vignettes", "a.Rmd"))
rmd <- c("---", "output: github_document", "---", "", "# toy")
writeLines(rmd, file.path(pkg, "README.Rmd"))
writeLines("# toy", file.path(pkg, "README.md"))
msg <- paste(testthat::capture_messages(use_albersdown(pkg, family = "teal", readme = TRUE)), collapse = "")
expect_match(msg, "README.Rmd; re-knit it", fixed = TRUE)
r <- readLines(file.path(pkg, "README.Rmd"))
expect_identical(r[1:5], rmd)
expect_true("" %in% r)
expect_identical(readLines(file.path(pkg, "README.md")), "# toy")
})
test_that("a flow-style output map is reported as such, and braces in messages are safe", {
pkg <- toy_pkg()
flow <- c("---", "title: F", "output: {rmarkdown::html_vignette: {toc: true}}", "---")
other <- c("---", "title: O", "output: {bookdown::html_vignette2: default}", "---")
writeLines(flow, file.path(pkg, "vignettes", "flow.Rmd"))
writeLines(other, file.path(pkg, "vignettes", "{odd}.Rmd"))
msg <- paste(testthat::capture_messages(use_albersdown(pkg, family = "teal")), collapse = "")
expect_match(msg, "flow.Rmd has a flow-style `output: {...}` map; not converted", fixed = TRUE)
expect_match(msg, "{odd}.Rmd uses an output format other than html_vignette", fixed = TRUE)
expect_identical(readLines(file.path(pkg, "vignettes", "flow.Rmd")), flow)
expect_identical(.albers_output_to_format(c("output: {html_vignette: default}"), "red", "homage"), "flow")
expect_null(.albers_output_to_format(c("output: {pdf_document: default}"), "red", "homage"))
})
test_that("a user's own family/preset params survive without albersdown 2.0's fingerprint", {
pkg <- toy_pkg()
fam <- c("---", "title: FamParam", "output: rmarkdown::html_vignette", "params:", " family: red", " preset: homage", " n: 3",
"---", "", "```{r}", "params$n", "```")
writeLines(fam, file.path(pkg, "vignettes", "fam.Rmd"))
msg <- paste(testthat::capture_messages(use_albersdown(pkg, family = "teal")), collapse = "")
f <- readLines(file.path(pkg, "vignettes", "fam.Rmd"))
expect_true(all(c("params:", " family: red", " preset: homage", " n: 3") %in% f))
expect_false(grepl("2.0's setup", msg, fixed = TRUE))
expect_false(.albers_legacy_fingerprint(fam[2:7], fam[9:12]))
expect_true(.albers_legacy_fingerprint(" css: albers.css", character()))
})
test_that("removing 2.0's class chunk leaves no double blank line", {
body <- c("```{r setup}", "library(x)", "```", "", "```{r albers-classes, echo=FALSE}", "cat(1)", "```", "", "## Next")
expect_identical(.albers_drop_legacy_setup(body), c("```{r setup}", "library(x)", "```", "", "## Next"))
})
test_that("an if block left empty by removing 2.0's theme_set() line goes too", {
theme <- "ggplot2::theme_set(albersdown::theme_albers(family = params$family, preset = params$preset))"
guard <- 'if (requireNamespace("ggplot2", quietly = TRUE) && requireNamespace("albersdown", quietly = TRUE))'
body <- c(
"```{r setup, include = FALSE}",
"oldopt <- options(digits = 3)",
'if (requireNamespace("systemfonts", quietly = TRUE)) albersdown::albers_register_fonts()',
# the forms in albersdown's own 2.0 vignettes (9854bc1, aab27a1)
paste0(guard, " {"), paste0(" ", theme), "}",
'if (requireNamespace("albersdown", quietly = TRUE)) {', paste0(" ", guard, " ", theme), "}",
"if (TRUE) {", " if (TRUE) {", paste0(" ", theme), " }", "}",
# a block with the user's own code stays, minus the 2.0 line
"if (interactive()) {", paste0(" ", theme), " message('hi')", "}",
"```"
)
out <- .albers_drop_legacy_setup(body)
expect_identical(out, c(
"```{r setup, include = FALSE}",
"oldopt <- options(digits = 3)",
"if (interactive()) {", " message('hi')", "}",
"```"
))
# a user's own empty block (no 2.0 line in it) is left alone
own <- c("```{r}", "if (FALSE) {", "}", "```")
expect_identical(.albers_drop_legacy_setup(own), own)
})
test_that("the README note on the site-only route describes only the site", {
pkg <- toy_pkg()
writeLines(html_vig(), file.path(pkg, "vignettes", "a.Rmd"))
writeLines("# toy", file.path(pkg, "README.md"))
suppressMessages(use_albersdown(pkg, family = "teal", preset = "interaction", apply_to = "new", readme = TRUE))
readme <- paste(readLines(file.path(pkg, "README.md")), collapse = "\n")
expect_match(readme, "This package's pkgdown site uses the albersdown theme (`template: package: albersdown`, site default family = 'teal', preset = 'interaction'). Its vignettes keep their own output format.", fixed = TRUE)
expect_false(grepl("albers_vignette", readme, fixed = TRUE))
})
test_that("albersdown 2.0's README note stays while its vignettes are not on the format", {
pkg <- legacy_20_pkg()
note <- readLines(file.path(pkg, "README.md"))
msg <- paste(testthat::capture_messages(use_albersdown(pkg, family = "teal", apply_to = "new")), collapse = "")
expect_identical(readLines(file.path(pkg, "README.md")), note)
expect_match(msg, "README note from albersdown 2.0 left as is", fixed = TRUE)
# converting the vignettes then replaces it
suppressMessages(use_albersdown(pkg, family = "teal"))
expect_match(paste(readLines(file.path(pkg, "README.md")), collapse = "\n"), "albersdown::albers_vignette()", fixed = TRUE)
})
test_that("albersdown's own vignettes carry no albersdown 2.0 leftovers", {
vig <- test_path("..", "..", "vignettes")
skip_if_not(dir.exists(vig))
for (f in list.files(vig, pattern = "\\.Rmd$", full.names = TRUE)) {
x <- readLines(f, warn = FALSE)
fence <- .albers_fences(x)
head <- x[fence[1]:fence[2]]
expect_true(any(grepl("albersdown::albers_vignette", head, fixed = TRUE)), info = f)
expect_false(any(grepl("^params\\s*:", head)), info = f)
expect_false(any(grepl("params\\$(family|preset|content_width|base_size|style)", x)), info = f)
expect_false(any(grepl("--content\\s*:", x)), info = f)
expect_false(any(grepl("style: balanced", x, fixed = TRUE)), info = f)
}
})
test_that("family and preset are validated by name and case-insensitively", {
expect_identical(.albers_choice("Teal", .albers_families, "family", "f"), "teal")
expect_identical(.albers_choice(" LAPIS ", .albers_families, "family", "f"), "lapis")
expect_identical(.albers_choice("inter", .albers_all_presets, "preset", "f"), "interaction")
expect_identical(.albers_choice(.albers_all_presets, .albers_all_presets, "preset", "f"), "homage")
expect_error(.albers_choice(c("red", "teal"), .albers_families, "family", "f"), "got c(\"red\", \"teal\")", fixed = TRUE)
expect_error(.albers_choice(NA_character_, .albers_families, "family", "f"), "`family` must be one of", fixed = TRUE)
fmt <- albers_vignette(family = "Teal", preset = "INTERACTION")
expect_s3_class(fmt, "rmarkdown_output_format")
expect_error(albers_vignette(style = "loud"), "albers_vignette(): `style` must be one of \"minimal\", \"balanced\", \"assertive\"; got 'loud'.", fixed = TRUE)
pkg <- toy_pkg()
writeLines(html_vig(), file.path(pkg, "vignettes", "a.Rmd"))
suppressMessages(use_albersdown(pkg, family = "Teal", preset = "Interaction"))
a <- readLines(file.path(pkg, "vignettes", "a.Rmd"))
expect_true(all(c(" family: teal", " preset: interaction") %in% a))
expect_error(use_albersdown(pkg, preset = "baroque"), "use_albersdown(): `preset` must be one of", fixed = TRUE)
})
test_that("without family/preset, a 2.0 package keeps its own (from its params)", {
pkg <- legacy_20_pkg() # vignettes: params family lapis, preset homage
msg <- paste(testthat::capture_messages(use_albersdown(pkg)), collapse = "")
expect_match(msg, "Kept the package's family: lapis (from vignettes (plots.Rmd, uses.Rmd)); pass `family` to change it", fixed = TRUE)
expect_match(msg, "Kept the package's preset: homage", fixed = TRUE)
p <- readLines(file.path(pkg, "vignettes", "plots.Rmd"))
expect_true(all(c(" family: lapis", " preset: homage") %in% p))
expect_true(any(grepl('family: "lapis", preset: "homage"', readLines(file.path(pkg, "pkgdown", "extra.js")), fixed = TRUE)))
# a re-run without arguments keeps it (the vignettes are now on the format)
suppressMessages(use_albersdown(pkg))
expect_identical(readLines(file.path(pkg, "vignettes", "plots.Rmd")), p)
# site-only route on a 2.0 package: the site default follows 2.0's family too
pkg2 <- legacy_20_pkg()
suppressMessages(use_albersdown(pkg2, apply_to = "new"))
expect_true(any(grepl('family: "lapis", preset: "homage"', readLines(file.path(pkg2, "pkgdown", "extra.js")), fixed = TRUE)))
})
test_that("without family/preset, site defaults are used when vignettes say nothing", {
pkg <- toy_pkg()
writeLines(html_vig(), file.path(pkg, "vignettes", "a.Rmd"))
dir.create(file.path(pkg, "pkgdown"))
writeLines('window.albersdownDefaults = { family: "teal", preset: "interaction", style: "minimal" };',
file.path(pkg, "pkgdown", "extra.js"))
msg <- paste(testthat::capture_messages(use_albersdown(pkg)), collapse = "")
expect_match(msg, "Kept the package's family: teal (from pkgdown/extra.js)", fixed = TRUE)
a <- readLines(file.path(pkg, "vignettes", "a.Rmd"))
expect_true(all(c(" family: teal", " preset: interaction") %in% a))
# the 2.0 extra.js (class adds) and a _pkgdown.yml defaults script are read too
pkg2 <- toy_pkg()
writeLines(c("template:", " includes:", " in_header: |",
' '),
file.path(pkg2, "_pkgdown.yml"))
withr::with_dir(pkg2, {
got <- .albers_infer_choice()
expect_identical(got$family$value, "violet")
expect_identical(got$family$from, "_pkgdown.yml")
})
pkg3 <- toy_pkg()
dir.create(file.path(pkg3, "pkgdown"))
writeLines(c("(function () {", ' if (!hasAny("palette-", FAMILY_CLASSES)) document.body.classList.add("palette-ochre");',
' if (!hasAny("preset-", PRESET_CLASSES)) document.body.classList.add("preset-interaction");', "})();"),
file.path(pkg3, "pkgdown", "extra.js"))
withr::with_dir(pkg3, {
got <- .albers_infer_choice()
expect_identical(c(got$family$value, got$preset$value), c("ochre", "interaction"))
})
# nothing found: red/homage, silently
pkg4 <- toy_pkg()
writeLines(html_vig(), file.path(pkg4, "vignettes", "a.Rmd"))
msg <- paste(testthat::capture_messages(use_albersdown(pkg4)), collapse = "")
expect_false(grepl("Kept the package's", msg, fixed = TRUE))
expect_true(" family: red" %in% readLines(file.path(pkg4, "vignettes", "a.Rmd")))
})
test_that("disagreeing vignettes give the most common choice, with a warning; explicit arguments win", {
pkg <- toy_pkg()
fmt <- function(t, fam) c("---", paste0("title: ", t), "output:", " albersdown::albers_vignette:",
paste0(" family: ", fam), "---")
writeLines(fmt("A", "lapis"), file.path(pkg, "vignettes", "a.Rmd"))
writeLines(fmt("B", "lapis"), file.path(pkg, "vignettes", "b.Rmd"))
writeLines(fmt("C", "teal"), file.path(pkg, "vignettes", "c.Rmd"))
msg <- paste(testthat::capture_messages(use_albersdown(pkg, dry_run = TRUE)), collapse = "")
expect_match(msg, "Kept the package's family: lapis (from vignettes (a.Rmd, b.Rmd, c.Rmd); vignettes disagree (lapis: 2, teal: 1); using the most common)", fixed = TRUE)
# explicit family wins; preset is still inferred (all default homage here)
suppressMessages(use_albersdown(pkg, family = "green"))
for (f in c("a", "b", "c")) expect_true(" family: green" %in% readLines(file.path(pkg, "vignettes", paste0(f, ".Rmd"))))
pkg2 <- legacy_20_pkg()
msg <- paste(testthat::capture_messages(use_albersdown(pkg2, family = "teal", preset = "interaction")), collapse = "")
expect_false(grepl("Kept the package's", msg, fixed = TRUE))
expect_true(" family: teal" %in% readLines(file.path(pkg2, "vignettes", "plots.Rmd")))
})
test_that("a site-only re-run without family keeps the site default (bare vignettes are not evidence)", {
# e10_bare_site: a vignette on the format with no family:, site set to lapis
pkg <- toy_pkg()
writeLines(c("---", "title: A", "output: albersdown::albers_vignette",
"vignette: >", " %\\VignetteIndexEntry{A}", " %\\VignetteEngine{knitr::rmarkdown}", "---", "", "Text."),
file.path(pkg, "vignettes", "a.Rmd"))
suppressMessages(use_albersdown(pkg, family = "lapis", apply_to = "new"))
js <- file.path(pkg, "pkgdown", "extra.js")
expect_true(any(grepl('family: "lapis"', readLines(js), fixed = TRUE)))
files <- list.files(pkg, recursive = TRUE, all.files = TRUE)
sums <- tools::md5sum(file.path(pkg, files))
msg <- paste(testthat::capture_messages(use_albersdown(pkg, apply_to = "new")), collapse = "")
expect_match(msg, "Kept the package's family: lapis (from pkgdown/extra.js)", fixed = TRUE)
expect_identical(list.files(pkg, recursive = TRUE, all.files = TRUE), files)
expect_identical(tools::md5sum(file.path(pkg, files)), sums)
# the full route too: the bare vignette states no family, so the site's lapis is kept
suppressMessages(use_albersdown(pkg))
expect_true(" family: lapis" %in% readLines(file.path(pkg, "vignettes", "a.Rmd")))
withr::with_dir(pkg, expect_identical(.albers_vignette_choice("vignettes/a.Rmd")$family, "lapis"))
})
test_that("site and vignettes disagreeing: apply_to = 'new' keeps the site, the full route the vignettes", {
pkg <- toy_pkg()
writeLines(c("---", "title: A", "output:", " albersdown::albers_vignette:", " family: ochre", "---"),
file.path(pkg, "vignettes", "a.Rmd"))
dir.create(file.path(pkg, "pkgdown"))
writeLines('window.albersdownDefaults = { family: "lapis", preset: "homage", style: "minimal" };',
file.path(pkg, "pkgdown", "extra.js"))
msg <- paste(testthat::capture_messages(use_albersdown(pkg, apply_to = "new", dry_run = TRUE)), collapse = "")
expect_match(msg, "Kept the package's family: lapis (from pkgdown/extra.js; vignettes (a.Rmd) says ochre)", fixed = TRUE)
msg <- paste(testthat::capture_messages(use_albersdown(pkg, dry_run = TRUE)), collapse = "")
expect_match(msg, "Kept the package's family: ochre (from vignettes (a.Rmd); pkgdown/extra.js says lapis)", fixed = TRUE)
})