From 1d80d9c4e4281059a39f5dd45173c382a5e59073 Mon Sep 17 00:00:00 2001 From: fly1d <309400591+fly1d@users.noreply.github.com> Date: Thu, 20 Aug 2026 18:24:01 +0800 Subject: [PATCH 1/2] hash: validate raw helper size arguments Fixes #834. Assisted-by: OpenAI Codex (GPT-5) --- NEWS.md | 4 ++++ R/hash.R | 12 ++++++++++-- tests/testthat/test-hash.R | 20 ++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index bb4f73768..15d6c60c0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -30,6 +30,10 @@ cli progress bars. It makes cli redraw the progress bar for every progress update. +* `hash_raw_animal()` and `hash_raw_emoji()` now validate `n_adj` and `size`, + respectively, consistently with their character-vector variants. This also + affects `hash_obj_animal()` and `hash_obj_emoji()` (#834, @fly1d). + # cli 3.6.6 * New `{.num}` and `{.bytes}` inline styles to format numbers diff --git a/R/hash.R b/R/hash.R index f2f76d903..671b0d9f4 100644 --- a/R/hash.R +++ b/R/hash.R @@ -348,7 +348,11 @@ hash_emoji1_transform <- function(md5, size) { #' * `names`: names of the emojis, in a character vector. hash_raw_emoji <- function(x, size = 3) { - stopifnot(is.raw(x)) + stopifnot( + is.raw(x), + is_count(size), + size >= 1 && size <= 4 + ) md5 <- hash_raw_md5(x) emo <- hash_emoji1_transform(md5, size) @@ -492,7 +496,11 @@ hash_animal1_transform <- function(md5, n_adj) { #' * `words: the adjectives and the animal name in a character vector. hash_raw_animal <- function(x, n_adj = 2) { - stopifnot(is.raw(x)) + stopifnot( + is.raw(x), + is_count(n_adj), + n_adj >= 0 && n_adj <= 3 + ) md5 <- hash_raw_md5(x) hash <- hash_animal1_transform(md5, n_adj) diff --git a/tests/testthat/test-hash.R b/tests/testthat/test-hash.R index 92d90cf73..c25f16a36 100644 --- a/tests/testthat/test-hash.R +++ b/tests/testthat/test-hash.R @@ -165,6 +165,16 @@ test_that("hash_obj_emoji", { }) }) +test_that("emoji hash size is validated for raw vectors and objects", { + expect_no_error(hash_raw_emoji(raw(), size = 1)) + expect_no_error(hash_raw_emoji(raw(), size = 4)) + expect_error(hash_raw_emoji(raw(), size = 0), class = "simpleError") + expect_error(hash_raw_emoji(raw(), size = 1.5), class = "simpleError") + expect_error(hash_raw_emoji(raw(), size = 5), class = "simpleError") + expect_error(hash_obj_emoji(NULL, size = 0), class = "simpleError") + expect_error(hash_obj_emoji(NULL, size = 5), class = "simpleError") +}) + test_that("hash_animal", { expect_snapshot({ hash_animal(character())$words @@ -193,6 +203,16 @@ test_that("hash_obj_animal", { }) }) +test_that("animal hash adjective count is validated for raw vectors and objects", { + expect_no_error(hash_raw_animal(raw(), n_adj = 0)) + expect_no_error(hash_raw_animal(raw(), n_adj = 3)) + expect_error(hash_raw_animal(raw(), n_adj = -1), class = "simpleError") + expect_error(hash_raw_animal(raw(), n_adj = 1.5), class = "simpleError") + expect_error(hash_raw_animal(raw(), n_adj = 4), class = "simpleError") + expect_error(hash_obj_animal(NULL, n_adj = -1), class = "simpleError") + expect_error(hash_obj_animal(NULL, n_adj = 4), class = "simpleError") +}) + test_that("hash_xxhash", { expect_snapshot({ hash_xxhash(letters[1:5]) From 459ef7800310db90a31092b9d248d701c5b90b4f Mon Sep 17 00:00:00 2001 From: fly1d Date: Sun, 27 Sep 2026 21:48:13 +0800 Subject: [PATCH 2/2] hash: explain raw helper size limits Document that the raw helper ranges match hash_emoji() and hash_animal(), and that the upper bounds keep the shared conversions within exact double-precision integer arithmetic. This is a comment-only follow-up to the review; executable code and regression tests are unchanged. Verified both upper bounds against the table sizes documented by the package and checked the diff for whitespace errors. Prepared with OpenAI Codex assistance. --- R/hash.R | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/R/hash.R b/R/hash.R index 671b0d9f4..b326d8aa1 100644 --- a/R/hash.R +++ b/R/hash.R @@ -351,6 +351,8 @@ hash_raw_emoji <- function(x, size = 3) { stopifnot( is.raw(x), is_count(size), + # Match hash_emoji(): at least one emoji, and at most four to keep + # nrow(emojis)^size within the exact integer range of an R double. size >= 1 && size <= 4 ) md5 <- hash_raw_md5(x) @@ -499,6 +501,9 @@ hash_raw_animal <- function(x, n_adj = 2) { stopifnot( is.raw(x), is_count(n_adj), + # Match hash_animal(): zero adjectives leaves just the animal name; + # at most three keeps length(gfycat_adjectives)^n_adj * + # length(gfycat_animals) within the exact integer range of an R double. n_adj >= 0 && n_adj <= 3 ) md5 <- hash_raw_md5(x)