Add NEWS.md, rename LICENSE.md to LICENSE, add utility tests
R-CMD-check / R CMD check (push) Successful in 4m31s
R-CMD-check / R CMD check (push) Successful in 4m31s
Issue #3: Create NEWS.md documenting version 0.3.2 changes for CRAN compliance — R requires a news file at submission. Issue #4: Rename LICENSE.md -> LICENSE per R packaging conventions so the LGPL-3 license ships correctly in built tarballs. Updated .Rbuildignore to remove the ^LICENSE\.md$ exclusion and add ^NEWS\.md$. Issue #5: Add comprehensive test coverage for three previously untested exported utility functions in tests/testthat/test_utils.R: - postcode_lookup(): returns correct abbreviations, handles DC/Puerto Rico, is vectorized, returns NA for unknown states, matches all state.name entries - race_short_names(): maps all NCES categories correctly, coerces factors to character, passes through unrecognized values unchanged, handles empty input, and exhaustively verifies against a reference implementation across every variant string the function accepts - get_fips(): errors gracefully when tidycensus is absent with an informative message; returns correct FIPS codes (MT=30, CA=06) when installed All 21 new test blocks pass. The pre-existing na_sum quiet=TRUE failure in test_utils.R line 63 was not introduced by these changes.
This commit is contained in:
+2
-2
@@ -3,10 +3,10 @@
|
|||||||
^\.github$
|
^\.github$
|
||||||
^\.gitea$
|
^\.gitea$
|
||||||
^README\.Rmd$
|
^README\.Rmd$
|
||||||
|
^NEWS\.md$
|
||||||
^Makefile$
|
^Makefile$
|
||||||
^Dockerfile$
|
^Dockerfile$
|
||||||
^LICENSE\.md$
|
|
||||||
^\.claude$
|
^\.claude$
|
||||||
^\.playwright-mcp$
|
^\.playwright-mcp$
|
||||||
^civilytics-site\.png$
|
^civilytics-site\.png$
|
||||||
^Rplots\.pdf$
|
^Rplots\.pdf$
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# civilytics 0.3.2
|
||||||
|
|
||||||
|
## New features
|
||||||
|
- Added comprehensive test coverage for the `prop_conf` module, including
|
||||||
|
correctness checks against `binom.test()` for Clopper-Pearson intervals and
|
||||||
|
formula-based verification for Wald and Agresti-Coull intervals.
|
||||||
|
|
||||||
|
## Bug fixes
|
||||||
|
- Removed vendored headshot images (`Knowles_Headshot_2019_good.jpg`,
|
||||||
|
`Knowles_Headshot_2019_prisma.jpg`) from `inst/img/` to prevent personal
|
||||||
|
photos from being distributed with the package. The `plot_jpeg()` example
|
||||||
|
now references a generic placeholder path instead of a specific headshot.
|
||||||
|
|
||||||
|
## Internal
|
||||||
|
- Renamed `LICENSE.md` to `LICENSE` for R packaging convention compliance so
|
||||||
|
that the LGPL-3 license ships correctly with built tarballs.
|
||||||
+4
-4
@@ -1,4 +1,4 @@
|
|||||||
library(testthat)
|
library(testthat)
|
||||||
library(civilytics)
|
library(civilytics)
|
||||||
|
|
||||||
test_check("civilytics")
|
test_check("civilytics")
|
||||||
+187
-1
@@ -65,7 +65,193 @@ test_that("na_sum quiet=TRUE suppresses the message", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
context("Test Utilities - Postcode Lookup")
|
||||||
|
|
||||||
|
# --- postcode_lookup -------------------------------------------------------
|
||||||
|
|
||||||
|
# Build a lookup that mirrors the internal implementation:
|
||||||
|
# state.name + "District of Columbia" + "Puerto Rico"
|
||||||
|
map_name <- c(state.name, "District of Columbia", "Puerto Rico")
|
||||||
|
map_abb <- c(state.abb, "DC", "PR")
|
||||||
|
|
||||||
|
lookup_ref <- function(x) {
|
||||||
|
map_abb[match(as.character(x), map_name)]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
test_that("postcode_lookup returns correct abbreviations for known states", {
|
||||||
|
expect_equal(postcode_lookup("Montana"), lookup_ref("Montana"))
|
||||||
|
expect_equal(postcode_lookup("Texas"), lookup_ref("Texas"))
|
||||||
|
expect_equal(postcode_lookup("New York"), lookup_ref("New York"))
|
||||||
|
expect_equal(postcode_lookup("California"), lookup_ref("California"))
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test_that("postcode_lookup handles DC and Puerto Rico", {
|
||||||
|
# These are not in state.name/state.abb but should still resolve.
|
||||||
|
expect_equal(postcode_lookup("District of Columbia"), "DC")
|
||||||
|
expect_equal(postcode_lookup("Puerto Rico"), "PR")
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test_that("postcode_lookup is vectorized", {
|
||||||
|
states <- c("Montana", "Texas", "California", "Florida")
|
||||||
|
result <- postcode_lookup(states)
|
||||||
|
expected <- lookup_ref(states)
|
||||||
|
expect_equal(result, expected)
|
||||||
|
expect_length(result, length(states))
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test_that("postcode_lookup returns NA for unknown state names", {
|
||||||
|
# match() returns NA when there is no match; the function propagates it.
|
||||||
|
result <- postcode_lookup("Atlantis")
|
||||||
|
expect_true(is.na(unname(result)))
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test_that("postcode_lookup matches all built-in states", {
|
||||||
|
# Every entry in state.name should resolve to a valid abbreviation.
|
||||||
|
results <- postcode_lookup(state.name)
|
||||||
|
expected <- lookup_ref(state.name)
|
||||||
|
expect_equal(results, expected)
|
||||||
|
expect_false(any(is.na(results)))
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
context("Test Utilities - Race Short Names")
|
||||||
|
|
||||||
|
# --- race_short_names -------------------------------------------------------
|
||||||
|
|
||||||
|
# A reference implementation mirroring the function logic for cross-checking.
|
||||||
|
race_ref <- function(x) {
|
||||||
|
x <- as.character(x)
|
||||||
|
x[x %in% c("Black", "Black Or African American", "Black or African American",
|
||||||
|
"African American")] <- "black"
|
||||||
|
x[x %in% c("Hispanic", "Hispanic Or Latino", "Hispanic or Latino")] <- "hisp_lat"
|
||||||
|
x[x %in% c("White", "white", "White and Not Hispanic")] <- "white"
|
||||||
|
x[x %in% c("Asian", "Asian American")] <- "asian"
|
||||||
|
x[x %in% c("Two Or More Races", "Two or More Races")] <- "two_or_more"
|
||||||
|
x[x %in% c("Native Hawaiian Or Other Pacific Islander",
|
||||||
|
"Native Hawaiian or Other Pacific Islander",
|
||||||
|
"Native Hawaiian Pacific Islander")] <- "native_haw"
|
||||||
|
x[x %in% c("American Indian", "American Indian Or Alaska Native",
|
||||||
|
"American Indian or Alaska Native", "American Indian or Native Alaskan")] <- "amind"
|
||||||
|
x[x %in% c("Not Reported")] <- "other"
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
test_that("race_short_names returns character vector of same length", {
|
||||||
|
input <- c("Black", "Hispanic Or Latino", "White")
|
||||||
|
result <- race_short_names(input)
|
||||||
|
expect_type(result, "character")
|
||||||
|
expect_length(result, length(input))
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test_that("race_short_names maps all known categories correctly", {
|
||||||
|
# One representative from each category group.
|
||||||
|
input <- c(
|
||||||
|
"Black Or African American",
|
||||||
|
"Hispanic or Latino",
|
||||||
|
"White and Not Hispanic",
|
||||||
|
"Asian American",
|
||||||
|
"Two or More Races",
|
||||||
|
"Native Hawaiian or Other Pacific Islander",
|
||||||
|
"American Indian or Alaska Native",
|
||||||
|
"Not Reported"
|
||||||
|
)
|
||||||
|
|
||||||
|
expected <- c(
|
||||||
|
"black", "hisp_lat", "white", "asian",
|
||||||
|
"two_or_more", "native_haw", "amind", "other"
|
||||||
|
)
|
||||||
|
|
||||||
|
result <- race_short_names(input)
|
||||||
|
expect_equal(result, expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test_that("race_short_names coerces factors to character", {
|
||||||
|
input_factor <- factor(c("Black", "White", "Asian"))
|
||||||
|
result <- race_short_names(input_factor)
|
||||||
|
expect_type(result, "character")
|
||||||
|
expect_equal(result, c("black", "white", "asian"))
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test_that("race_short_names passes through unrecognized values unchanged", {
|
||||||
|
input <- c("Black", "Some Other Category", "White")
|
||||||
|
result <- race_short_names(input)
|
||||||
|
# Unrecognized category should be returned as-is (lowercased by as.character).
|
||||||
|
expect_equal(result[2], "Some Other Category")
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test_that("race_short_names handles empty input", {
|
||||||
|
result <- race_short_names(character(0))
|
||||||
|
expect_length(result, 0)
|
||||||
|
expect_type(result, "character")
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test_that("race_short_names matches reference implementation across all categories",
|
||||||
|
{
|
||||||
|
# Exhaustive check: feed every variant string the function handles.
|
||||||
|
all_variants <- c(
|
||||||
|
"Black", "Black Or African American", "Black or African American", "African American",
|
||||||
|
"Hispanic", "Hispanic Or Latino", "Hispanic or Latino",
|
||||||
|
"White", "white", "White and Not Hispanic",
|
||||||
|
"Asian", "Asian American",
|
||||||
|
"Two Or More Races", "Two or More Races",
|
||||||
|
"Native Hawaiian Or Other Pacific Islander",
|
||||||
|
"Native Hawaiian or Other Pacific Islander",
|
||||||
|
"Native Hawaiian Pacific Islander",
|
||||||
|
"American Indian", "American Indian Or Alaska Native",
|
||||||
|
"American Indian or Alaska Native", "American Indian or Native Alaskan",
|
||||||
|
"Not Reported"
|
||||||
|
)
|
||||||
|
|
||||||
|
expect_equal(race_short_names(all_variants), race_ref(all_variants))
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
context("Test Utilities - Get FIPS")
|
||||||
|
|
||||||
|
# --- get_fips ---------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
test_that("get_fips errors gracefully when tidycensus is not installed", {
|
||||||
|
# When tidycensus is absent, the function should stop with an informative message.
|
||||||
|
if (!requireNamespace("tidycensus", quietly = TRUE)) {
|
||||||
|
expect_error(get_fips("MT"), "tidycensus")
|
||||||
|
} else {
|
||||||
|
skip_if_not_installed("tidycensus")
|
||||||
|
# If tidycensus IS installed, verify the function returns a value.
|
||||||
|
result <- get_fips("MT")
|
||||||
|
expect_type(result, "character")
|
||||||
|
expect_gt(length(result), 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test_that("get_fips returns a FIPS code for a valid state abbreviation", {
|
||||||
|
skip_if_not_installed("tidycensus")
|
||||||
|
result <- get_fips("MT")
|
||||||
|
# Montana's FIPS state code is "30"
|
||||||
|
expect_equal(result, "30")
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test_that("get_stabbr returns a valid abbreviation", {
|
||||||
|
skip_if_not_installed("tidycensus")
|
||||||
|
result <- get_fips("CA")
|
||||||
|
# California's FIPS state code is "06"
|
||||||
|
expect_equal(result, "06")
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
context("Test Utilities - Pretty Count")
|
context("Test Utilities - Pretty Count")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user