R-CMD-check / R CMD check (push) Successful in 3m37s
Supports "bottom-right" (default), "bottom-left", "top-right", and "top-left". The position controls both horizontal alignment of the logo grob and whether it is placed above or below the plot. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
334 lines
11 KiB
R
334 lines
11 KiB
R
library(ggplot2)
|
|
|
|
# --- civilytics_colors -------------------------------------------------------
|
|
|
|
test_that("civilytics_colors is a named character vector of hex codes", {
|
|
expect_type(civilytics_colors, "character")
|
|
expect_named(civilytics_colors)
|
|
expect_true(all(grepl("^#[0-9A-Fa-f]{6}$", civilytics_colors)))
|
|
})
|
|
|
|
test_that("civilytics_colors contains expected brand keys", {
|
|
expected <- c("paper", "ink", "navy_600", "ember_600", "teal_600",
|
|
"plum_600", "moss_600", "paper_2", "rule")
|
|
expect_true(all(expected %in% names(civilytics_colors)))
|
|
})
|
|
|
|
test_that("civilytics_colors values match brand specification", {
|
|
expect_equal(unname(civilytics_colors["paper"]), "#FAF7F2")
|
|
expect_equal(unname(civilytics_colors["ink"]), "#0E1A2B")
|
|
expect_equal(unname(civilytics_colors["ember_600"]), "#C25311")
|
|
expect_equal(unname(civilytics_colors["navy_700"]), "#1A2E4A")
|
|
expect_equal(unname(civilytics_colors["ember_400"]), "#EA8A49")
|
|
})
|
|
|
|
# --- civilytics_palettes / civilytics_palette --------------------------------
|
|
|
|
test_that("civilytics_palettes contains all expected palettes", {
|
|
expected <- c("qual", "qual_warm", "qual_cool",
|
|
"seq_ember", "seq_navy", "seq_violet", "seq_paper_ink",
|
|
"div_navy_ember", "div_violet_ember")
|
|
expect_true(all(expected %in% names(civilytics_palettes)))
|
|
})
|
|
|
|
test_that("civilytics_palette returns character vector of hex codes", {
|
|
result <- civilytics_palette()
|
|
expect_type(result, "character")
|
|
expect_true(all(grepl("^#[0-9A-Fa-f]{6}$", result)))
|
|
})
|
|
|
|
test_that("civilytics_palette respects n argument", {
|
|
expect_length(civilytics_palette("qual", n = 3), 3)
|
|
expect_length(civilytics_palette("seq_navy", n = 5), 5)
|
|
})
|
|
|
|
test_that("civilytics_palette interpolates sequential palettes", {
|
|
result <- civilytics_palette("seq_ember", n = 20)
|
|
expect_length(result, 20)
|
|
expect_true(all(grepl("^#[0-9A-Fa-f]{6}$", result)))
|
|
})
|
|
|
|
test_that("civilytics_palette warns when recycling qualitative", {
|
|
expect_warning(civilytics_palette("qual", n = 10), "recycling")
|
|
})
|
|
|
|
test_that("civilytics_palette reverse works", {
|
|
fwd <- civilytics_palette("seq_navy")
|
|
rev <- civilytics_palette("seq_navy", reverse = TRUE)
|
|
expect_equal(fwd, rev(rev))
|
|
})
|
|
|
|
test_that("civilytics_palette errors on unknown palette name", {
|
|
expect_error(civilytics_palette("nope"), "'nope' is not a valid palette")
|
|
})
|
|
|
|
# --- civilytics_pal (closure) ------------------------------------------------
|
|
|
|
test_that("civilytics_pal returns a function", {
|
|
f <- civilytics_pal()
|
|
expect_type(f, "closure")
|
|
result <- f(4)
|
|
expect_length(result, 4)
|
|
expect_true(all(grepl("^#[0-9A-Fa-f]{6}$", result)))
|
|
})
|
|
|
|
# --- scale_color/fill_civilytics ---------------------------------------------
|
|
|
|
test_that("scale_color_civilytics returns a Scale object (discrete)", {
|
|
sc <- scale_color_civilytics()
|
|
expect_s3_class(sc, "Scale")
|
|
})
|
|
|
|
test_that("scale_color_civilytics returns a Scale object (continuous)", {
|
|
sc <- scale_color_civilytics("seq_navy", discrete = FALSE)
|
|
expect_s3_class(sc, "Scale")
|
|
})
|
|
|
|
test_that("scale_fill_civilytics returns a Scale object (discrete)", {
|
|
sc <- scale_fill_civilytics()
|
|
expect_s3_class(sc, "Scale")
|
|
})
|
|
|
|
test_that("scale_fill_civilytics returns a Scale object (continuous)", {
|
|
sc <- scale_fill_civilytics("seq_ember", discrete = FALSE)
|
|
expect_s3_class(sc, "Scale")
|
|
})
|
|
|
|
test_that("scale_color_civilytics reverse parameter works", {
|
|
sc <- scale_color_civilytics("qual", reverse = TRUE)
|
|
expect_s3_class(sc, "Scale")
|
|
})
|
|
|
|
test_that("scale_color_civilytics works in a ggplot", {
|
|
p <- ggplot(mpg, aes(displ, hwy, colour = class)) +
|
|
geom_point() +
|
|
scale_color_civilytics()
|
|
expect_no_error(ggplot_build(p))
|
|
})
|
|
|
|
test_that("scale_fill_civilytics works in a ggplot", {
|
|
p <- ggplot(mpg, aes(class, fill = class)) +
|
|
geom_bar() +
|
|
scale_fill_civilytics()
|
|
expect_no_error(ggplot_build(p))
|
|
})
|
|
|
|
# --- theme_civilytics --------------------------------------------------------
|
|
|
|
test_that("theme_civilytics returns a complete ggplot2 theme", {
|
|
th <- theme_civilytics()
|
|
expect_s3_class(th, "theme")
|
|
expect_true(attr(th, "complete"))
|
|
})
|
|
|
|
test_that("theme_civilytics applies to a ggplot without error", {
|
|
p <- ggplot(mpg, aes(displ, hwy)) +
|
|
geom_point() +
|
|
theme_civilytics()
|
|
expect_no_error(ggplot_build(p))
|
|
})
|
|
|
|
test_that("theme_civilytics uses brand ink color for text", {
|
|
th <- theme_civilytics()
|
|
expect_equal(th$text$colour, unname(civilytics_colors["ink"]))
|
|
})
|
|
|
|
test_that("theme_civilytics uses brand paper color for plot background", {
|
|
th <- theme_civilytics()
|
|
expect_equal(th$plot.background$fill, unname(civilytics_colors["paper"]))
|
|
})
|
|
|
|
test_that("theme_civilytics uses paper_2 for strip background by default", {
|
|
th <- theme_civilytics()
|
|
expect_equal(th$strip.background$fill, unname(civilytics_colors["paper_2"]))
|
|
})
|
|
|
|
test_that("theme_civilytics strip_color parameter is respected", {
|
|
th <- theme_civilytics(strip_color = "#FF0000")
|
|
expect_equal(th$strip.background$fill, "#FF0000")
|
|
})
|
|
|
|
test_that("theme_civilytics font_size parameter scales text elements", {
|
|
th_big <- theme_civilytics(font_size = 20)
|
|
th_sml <- theme_civilytics(font_size = 10)
|
|
expect_gt(th_big$text$size, th_sml$text$size)
|
|
})
|
|
|
|
test_that("theme_civilytics grid parameter controls gridlines", {
|
|
th_y <- theme_civilytics(grid = "y")
|
|
th_x <- theme_civilytics(grid = "x")
|
|
th_both <- theme_civilytics(grid = "both")
|
|
th_none <- theme_civilytics(grid = "none")
|
|
|
|
# grid="y" shows y gridlines, blanks x
|
|
expect_s3_class(th_y$panel.grid.major.y, "element_line")
|
|
expect_s3_class(th_y$panel.grid.major.x, "element_blank")
|
|
|
|
# grid="x" shows x gridlines, blanks y
|
|
expect_s3_class(th_x$panel.grid.major.x, "element_line")
|
|
expect_s3_class(th_x$panel.grid.major.y, "element_blank")
|
|
|
|
# grid="both" shows both
|
|
|
|
expect_s3_class(th_both$panel.grid.major.x, "element_line")
|
|
expect_s3_class(th_both$panel.grid.major.y, "element_line")
|
|
|
|
# grid="none" blanks both
|
|
expect_s3_class(th_none$panel.grid.major.x, "element_blank")
|
|
expect_s3_class(th_none$panel.grid.major.y, "element_blank")
|
|
})
|
|
|
|
test_that("theme_civilytics paper_bg=FALSE gives transparent background", {
|
|
th <- theme_civilytics(paper_bg = FALSE)
|
|
expect_true(is.na(th$plot.background$fill))
|
|
expect_true(is.na(th$panel.background$fill))
|
|
})
|
|
|
|
test_that("theme_civilytics has plot-aligned title and caption", {
|
|
th <- theme_civilytics()
|
|
expect_equal(th$plot.title.position, "plot")
|
|
expect_equal(th$plot.caption.position, "plot")
|
|
})
|
|
|
|
# --- theme_civilytics_dark ---------------------------------------------------
|
|
|
|
test_that("theme_civilytics_dark returns a complete ggplot2 theme", {
|
|
th <- theme_civilytics_dark()
|
|
expect_s3_class(th, "theme")
|
|
expect_true(attr(th, "complete"))
|
|
})
|
|
|
|
test_that("theme_civilytics_dark applies to a ggplot without error", {
|
|
p <- ggplot(mpg, aes(displ, hwy)) +
|
|
geom_point() +
|
|
theme_civilytics_dark()
|
|
expect_no_error(ggplot_build(p))
|
|
})
|
|
|
|
test_that("theme_civilytics_dark uses paper color as ink (light text on dark bg)", {
|
|
th <- theme_civilytics_dark()
|
|
expect_equal(th$text$colour, unname(civilytics_colors["paper"]))
|
|
})
|
|
|
|
test_that("theme_civilytics_dark uses navy_700 as background", {
|
|
th <- theme_civilytics_dark()
|
|
expect_equal(th$plot.background$fill, unname(civilytics_colors["navy_700"]))
|
|
})
|
|
|
|
test_that("theme_civilytics_dark uses navy_600 for strip background", {
|
|
th <- theme_civilytics_dark()
|
|
expect_equal(th$strip.background$fill, unname(civilytics_colors["navy_600"]))
|
|
})
|
|
|
|
test_that("theme_civilytics_dark inherits grid parameter", {
|
|
th <- theme_civilytics_dark(grid = "both")
|
|
expect_s3_class(th$panel.grid.major.x, "element_line")
|
|
expect_s3_class(th$panel.grid.major.y, "element_line")
|
|
})
|
|
|
|
# --- theme_civilytics_slide --------------------------------------------------
|
|
|
|
test_that("theme_civilytics_slide returns a complete ggplot2 theme", {
|
|
th <- theme_civilytics_slide()
|
|
expect_s3_class(th, "theme")
|
|
expect_true(attr(th, "complete"))
|
|
})
|
|
|
|
test_that("theme_civilytics_slide has transparent background by default", {
|
|
th <- theme_civilytics_slide()
|
|
expect_true(is.na(th$plot.background$fill))
|
|
})
|
|
|
|
test_that("theme_civilytics_slide uses larger base font", {
|
|
th_slide <- theme_civilytics_slide()
|
|
th_base <- theme_civilytics()
|
|
expect_gt(th_slide$text$size, th_base$text$size)
|
|
})
|
|
|
|
test_that("theme_civilytics_slide applies to a ggplot without error", {
|
|
p <- ggplot(mpg, aes(displ, hwy, colour = class)) +
|
|
geom_point() +
|
|
scale_color_civilytics() +
|
|
theme_civilytics_slide()
|
|
expect_no_error(ggplot_build(p))
|
|
})
|
|
|
|
# --- make_logo_grob ----------------------------------------------------------
|
|
|
|
test_that("make_logo_grob returns a gg object for all type/variant combos", {
|
|
for (type in c("wordmark", "mark")) {
|
|
for (variant in c("light", "dark")) {
|
|
logo <- make_logo_grob(type = type, variant = variant)
|
|
expect_s3_class(logo, "gg")
|
|
}
|
|
}
|
|
})
|
|
|
|
test_that("make_logo_grob defaults to wordmark light", {
|
|
expect_no_error(make_logo_grob())
|
|
})
|
|
|
|
test_that("make_logo_grob errors on invalid type", {
|
|
expect_error(make_logo_grob(type = "banner"))
|
|
})
|
|
|
|
test_that("make_logo_grob errors on invalid variant", {
|
|
expect_error(make_logo_grob(variant = "purple"))
|
|
})
|
|
|
|
# --- civilytics_logo (pipe-friendly) -----------------------------------------
|
|
|
|
test_that("civilytics_logo returns a grob", {
|
|
p <- ggplot(mpg, aes(displ, hwy)) + geom_point() + theme_civilytics()
|
|
result <- suppressWarnings(civilytics_logo(p))
|
|
expect_s3_class(result, "grob")
|
|
})
|
|
|
|
test_that("civilytics_logo works with pipe operator", {
|
|
# |> has higher precedence than +, so parens are required
|
|
result <- suppressWarnings(
|
|
(ggplot(mpg, aes(displ, hwy)) + geom_point() + theme_civilytics()) |>
|
|
civilytics_logo()
|
|
)
|
|
expect_s3_class(result, "grob")
|
|
})
|
|
|
|
test_that("civilytics_logo accepts type and variant params", {
|
|
p <- ggplot(mpg, aes(displ, hwy)) + geom_point() + theme_civilytics_dark()
|
|
result <- suppressWarnings(civilytics_logo(p, type = "mark", variant = "dark"))
|
|
expect_s3_class(result, "grob")
|
|
})
|
|
|
|
# --- position argument -------------------------------------------------------
|
|
|
|
test_that("civilytics_logo accepts all four position values", {
|
|
p <- ggplot(mpg, aes(displ, hwy)) + geom_point() + theme_civilytics()
|
|
for (pos in c("bottom-right", "bottom-left", "top-right", "top-left")) {
|
|
result <- suppressWarnings(civilytics_logo(p, position = pos))
|
|
expect_s3_class(result, "grob")
|
|
}
|
|
})
|
|
|
|
test_that("civilytics_logo errors on invalid position", {
|
|
p <- ggplot(mpg, aes(displ, hwy)) + geom_point() + theme_civilytics()
|
|
expect_error(civilytics_logo(p, position = "center"))
|
|
})
|
|
|
|
test_that("make_logo_grob accepts position argument", {
|
|
for (pos in c("bottom-right", "bottom-left", "top-right", "top-left")) {
|
|
logo <- make_logo_grob(position = pos)
|
|
expect_s3_class(logo, "gg")
|
|
}
|
|
})
|
|
|
|
test_that("top positions place logo before plot in arrangeGrob", {
|
|
p <- ggplot(mpg, aes(displ, hwy)) + geom_point() + theme_civilytics()
|
|
result_top <- suppressWarnings(civilytics_logo(p, position = "top-right"))
|
|
result_bot <- suppressWarnings(civilytics_logo(p, position = "bottom-right"))
|
|
# Top: logo is first grob; bottom: plot is first grob.
|
|
|
|
# The arrangeGrob heights differ in order
|
|
expect_s3_class(result_top, "grob")
|
|
expect_s3_class(result_bot, "grob")
|
|
})
|