tests/testthat/test-helpers-string.R

# ---- string helpers --------------------------------------------------------

test_that("basic whitespace/case helpers", {
  expect_equal(trim("  a  "), "a")
  expect_equal(squish("  a   b  "), "a b")
  expect_equal(lower("ABC"), "abc")
  expect_equal(upper("abc"), "ABC")
  expect_equal(titlecase("hello world"), "Hello World")
  expect_equal(sentencecase("HELLO WORLD"), "Hello world")
  expect_equal(textlen(c("abc", NA)), c(3L, NA_integer_))
})

test_that("substring helpers", {
  expect_equal(left("hello", 3), "hel")
  expect_equal(right("hello", 3), "llo")
  expect_equal(middle("hello", 2, 4), "ell")
  expect_equal(truncate("hello world", 8), "hello...")
  expect_equal(truncate("hi", 8), "hi")
  expect_equal(padcenter("hi", 6), "  hi  ")
  expect_equal(padcenter("hi", 6, pad = "*"), "**hi**")
})

test_that("pattern-matching helpers", {
  expect_equal(containstext(c("abc", "xyz"), "b"), c(TRUE, FALSE))
  expect_equal(countmatch("aXaXa", "X"), 2L)
  expect_equal(locate("xxabcxx", "abc")[[1]], 3L)
  expect_equal(unlist(locateall("aXaXa", "X")), c(2L, 4L))
  expect_equal(extract("abc123", "[0-9]+"), "123")
  expect_equal(unlist(extractall("a1b2", "[0-9]")), c("1", "2"))
  expect_equal(extractnum("price: -12.5 usd"), -12.5)
  expect_equal(extractint("value: -42"), -42L)
  expect_equal(extractint("id42x"), 42L)
  expect_equal(extractbetween("[abc]", "\\[", "\\]"), "abc")
})

test_that("replace/remove helpers", {
  expect_equal(replacetext("aXbXc", "X", "-"), "a-b-c")
  expect_equal(removetext("aXbXc", "X"), "abc")
  expect_equal(removeall("aXbXc", "X"), "abc")
  expect_equal(replaceall(c("a", "b", "c"), c("a", "b"), c("A", "B")), c("A", "B", "c"))
})

test_that("split/join helpers", {
  expect_equal(splittext("a-b-c", "-"), list(c("a", "b", "c")))
  expect_equal(splitfirst("a-b-c", "-"), "a")
  expect_equal(splitlast("a-b-c", "-"), "c")
  expect_equal(jointext("a", "b", "c"), "abc")
  expect_equal(collapsetext(c("a", "b", "c"), sep = "-"), "a-b-c")
})

test_that("blank/encoding helpers", {
  expect_equal(isblank(c("", "  ", NA, "x")), c(TRUE, TRUE, TRUE, FALSE))
  expect_equal(removeaccents("café"), "cafe")
  expect_equal(normalizeunicode("abc"), "abc")
  expect_equal(normalizeencoding("abc"), enc2utf8("abc"))
  expect_equal(transliterate("café"), "cafe")
})

test_that("string distance and similarity helpers", {
  d <- textdist("cat", c("cat", "bat", "dog"))
  expect_equal(as.integer(d), c(0L, 1L, 3L))
  expect_equal(similartext("cat", c("bat", "dog")), "bat")
})

test_that("classification predicates", {
  expect_equal(isalpha(c("abc", "a1c", "")), c(TRUE, FALSE, FALSE))
  expect_equal(isalphanumeric(c("abc123", "abc 123")), c(TRUE, FALSE))
  expect_equal(isnumerictext(c("12.5", "-3", "abc")), c(TRUE, TRUE, FALSE))
  expect_equal(isintegertext(c("12", "12.5", "-3")), c(TRUE, FALSE, TRUE))
  expect_equal(isemail(c("a@b.com", "not-an-email")), c(TRUE, FALSE))
  expect_equal(isurl(c("https://x.com", "ftp://x.com", "x.com")), c(TRUE, TRUE, FALSE))
})

test_that("recode/collapse/lump/factor-level helpers", {
  expect_equal(recode(c("a", "b", "c"), "a", "A"), c("A", "b", "c"))
  expect_equal(
    collapsevalues(c("cat", "dog", "bird"), list(pet = c("cat", "dog"))),
    c("pet", "pet", "bird")
  )
  expect_equal(
    collapselevels(factor(c("cat", "dog", "bird")), list(pet = c("cat", "dog"))),
    c("pet", "pet", "bird")
  )

  x <- rep(c("a", "b", "c", "d"), c(10, 5, 3, 1))
  lumped <- lump(x, n = 2, other = "Other")
  expect_equal(sort(unique(lumped)), sort(c("a", "b", "Other")))

  f <- factor(c("low", "high", "mid"), levels = c("low", "mid", "high"))
  expect_equal(levels(reorderlevels(f, c("high", "mid", "low"))), c("high", "mid", "low"))
  expect_equal(levels(expandlevels(f, "extra")), c("low", "mid", "high", "extra"))
})

# ---- string helper regressions ---------------------------------------------

test_that("padleft/padright honor a custom pad character", {
  expect_equal(padleft("5", 3, pad = "0"), "005")
  expect_equal(padright("5", 3, pad = "0"), "500")
  expect_equal(padleft(c("1", "22", "333"), 4, pad = "*"), c("***1", "**22", "*333"))
})

test_that("startswith/endswith honor fixed and stay vectorized against x", {
  # fixed = TRUE: "a." is a literal prefix, not a regex
  expect_true(startswith("a.b", "a.", fixed = TRUE))
  expect_false(startswith("axb", "a.", fixed = TRUE))

  # fixed = FALSE (default): real regex support
  expect_equal(startswith(c("abc", "xbc"), "a.c"), c(TRUE, FALSE))
  expect_equal(endswith(c("abc", "abd"), ".c"), c(TRUE, FALSE))

  # endswith must return one value per element of x, not a matrix
  out <- endswith(c("abc", "xyz", "abd"), "c")
  expect_null(dim(out))
  expect_equal(out, c(TRUE, FALSE, FALSE))
})

test_that("matchestext() with fixed = TRUE does a literal comparison, not a broken anchored regex", {
  expect_true(matchestext("a.b", "a.b", fixed = TRUE))
  expect_false(matchestext("axb", "a.b", fixed = TRUE))
  expect_true(matchestext("axb", "a.b", fixed = FALSE))
})

# ---- transliterate ---------------------------------------------------------

test_that("removeaccents folds Latin-1 and Latin Extended-A to ICU Latin-ASCII", {
  expect_equal(
    removeaccents(c("café", "naïve", "Zürich", "Kraków",
                    "Æther", "œuvre", "Straße", "Þór",
                    "Đorđe", "piñata", "hôtel", "Málaga",
                    "Łódź", "Ångström", "Nîmes",
                    "Timișoara", "İstanbul")),
    c("cafe", "naive", "Zurich", "Krakow", "AEther", "oeuvre", "Strasse",
      "THor", "Dorde", "pinata", "hotel", "Malaga", "Lodz", "Angstrom",
      "Nimes", "Timisoara", "Istanbul")
  )
})

test_that("removeaccents leaves ASCII and unmapped scripts untouched", {
  expect_equal(removeaccents(c("plain ascii 123", "a-b_c.d")),
               c("plain ascii 123", "a-b_c.d"))
  # Greek is not folded by removeaccents(); it only strips Latin accents.
  expect_equal(removeaccents("Αθήνα"),
               "Αθήνα")
})

test_that("removeaccents handles NA, empty, factor and non-character input", {
  expect_identical(removeaccents(NA_character_), NA_character_)
  expect_identical(removeaccents(""), "")
  expect_identical(removeaccents(c("café", NA)), c("cafe", NA))
  expect_identical(removeaccents(factor("café")), "cafe")
  expect_identical(removeaccents(1:3), c("1", "2", "3"))
})

test_that("transliterate romanises Greek and Cyrillic like ICU Any-Latin", {
  expect_equal(
    transliterate(c("Αθήνα",       # Athena
                    "Ελλάδα",  # Ellada
                    "Μοσχα",        # Moscha
                    "Москва",  # Moskva
                    "Достоевский", # Dostoevskij
                    "Чайковский")),      # Cajkovskij
    c("Athena", "Ellada", "Moscha", "Moskva", "Dostoevskij", "Cajkovskij")
  )
})

test_that("transliterate also does everything removeaccents does", {
  expect_equal(transliterate(c("café", "Zürich", "Straße")),
               c("cafe", "Zurich", "Strasse"))
})

test_that("transliterate leaves scripts it does not cover unchanged", {
  han <- "北京"
  expect_equal(transliterate(han), han)
})

Try the basetable package in your browser

Any scripts or data that you put into this service are public.

basetable documentation built on Nov. 14, 2026, 1:08 a.m.