From 6eb5108ec4574f0ed05700fb4845f6e9a70f3c4a Mon Sep 17 00:00:00 2001 From: Leonidas Zhak <70497898+LeonidasZhak@users.noreply.github.com> Date: Sat, 6 Jun 2026 21:20:11 +0800 Subject: [PATCH 1/2] test: add NA, empty string, and mixed whitespace tests for str_trim/str_squish Add edge-case tests for data cleaning scenarios: - NA passthrough in str_trim (all side variants) and str_squish - Empty string and whitespace-only string handling - Newlines, CRLF, and mixed whitespace in str_squish The DESCRIPTION promises consistent NA handling but these cases were untested. str_trunc has analogous NA tests (test-trunc.R:1-10). --- tests/testthat/test-trim.R | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/testthat/test-trim.R b/tests/testthat/test-trim.R index a4b45972..61fb1f73 100644 --- a/tests/testthat/test-trim.R +++ b/tests/testthat/test-trim.R @@ -21,6 +21,36 @@ test_that("str_squish removes excess spaces from all parts of string", { expect_equal(str_squish("\ta\t bc\t"), "a bc") }) +test_that("str_trim handles NA values", { + expect_equal(str_trim(NA), NA_character_) + expect_equal(str_trim(c(NA, " abc ")), c(NA, "abc")) + expect_equal(str_trim(NA, "left"), NA_character_) + expect_equal(str_trim(NA, "right"), NA_character_) +}) + +test_that("str_squish handles NA values", { + expect_equal(str_squish(NA), NA_character_) + expect_equal(str_squish(c(NA, " a b ")), c(NA, "a b")) +}) + +test_that("str_trim handles empty strings", { + expect_equal(str_trim(""), "") + expect_equal(str_trim(" "), "") +}) + +test_that("str_squish handles empty strings", { + expect_equal(str_squish(""), "") + expect_equal(str_squish(" "), "") +}) + +test_that("str_squish handles newlines and mixed whitespace", { + expect_equal(str_squish("a\n\nb"), "a b") + expect_equal(str_squish("\na\n"), "a") + expect_equal(str_squish("a\r\nb"), "a b") + expect_equal(str_squish("a\t\n b"), "a b") + expect_equal(str_squish("\t\n a \n\t b \t\n"), "a b") +}) + test_that("trimming functions preserve names", { x <- c(C = "3", B = "2", A = "1") expect_equal(names(str_trim(x)), names(x)) From 702cee8cd6cd580677ee9e240a85ec6f4247123c Mon Sep 17 00:00:00 2001 From: Leonidas Zhak <70497898+LeonidasZhak@users.noreply.github.com> Date: Sun, 7 Jun 2026 03:42:12 +0800 Subject: [PATCH 2/2] fix: preserve names in str_sub<-() str_sub<-() drops names because stri_sub<-() doesn't preserve them. This also caused str_to_camel() to lose names when first_upper = FALSE. Save and restore names around the stri_sub<-() call. --- R/sub.R | 2 ++ tests/testthat/test-case.R | 8 ++++++++ tests/testthat/test-sub.R | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/R/sub.R b/R/sub.R index 60897594..72f06b55 100644 --- a/R/sub.R +++ b/R/sub.R @@ -84,11 +84,13 @@ str_sub <- function(string, start = 1L, end = -1L) { value = value ) + nms <- names(string) if (is.matrix(start)) { stri_sub(string, from = start, omit_na = omit_na) <- value } else { stri_sub(string, from = start, to = end, omit_na = omit_na) <- value } + names(string) <- nms string } diff --git a/tests/testthat/test-case.R b/tests/testthat/test-case.R index cdc733e0..f55b5d41 100644 --- a/tests/testthat/test-case.R +++ b/tests/testthat/test-case.R @@ -20,6 +20,14 @@ test_that("case conversions preserve names", { expect_equal(names(str_to_title(x)), names(x)) }) +test_that("programming case conversions preserve names", { + x <- c(A = "hello-world", B = "foo-bar") + expect_equal(names(str_to_camel(x)), names(x)) + expect_equal(names(str_to_camel(x, first_upper = TRUE)), names(x)) + expect_equal(names(str_to_snake(c(A = "helloWorld", B = "fooBar"))), c("A", "B")) + expect_equal(names(str_to_kebab(c(A = "helloWorld", B = "fooBar"))), c("A", "B")) +}) + # programming cases ----------------------------------------------------------- test_that("to_camel can control case of first argument", { diff --git a/tests/testthat/test-sub.R b/tests/testthat/test-sub.R index d61ad2fe..945a9ad4 100644 --- a/tests/testthat/test-sub.R +++ b/tests/testthat/test-sub.R @@ -123,3 +123,9 @@ test_that("str_sub_all() preserves names on outer structure", { x <- c(C = "3", B = "2", A = "1") expect_equal(names(str_sub_all(x, 1, 1)), names(x)) }) + +test_that("str_sub<-() preserves names", { + x <- c(C = "3", B = "2", A = "1") + str_sub(x, 1, 1) <- c("X", "Y", "Z") + expect_equal(names(x), c("C", "B", "A")) +})