library(testthat) suppressWarnings(library(data.table)) test_that("ndate works", { d <- as.Date(c("2023-01-01", "2023-01-02")) res <- ndate(d, show_weekday = FALSE) expect_equal(res[1], "Jan 01, 2023") }) test_that("ndate_weekday works", { d <- as.Date("2023-01-01") res <- ndate(d, show_weekday = TRUE) expect_true(grepl("Sun", res[1])) }) test_that("ntimestamp works", { ts <- as.POSIXct("2023-01-01 12:30:45") res <- ntimestamp(ts, show_timezone = FALSE) expect_true(grepl("Jan 01, 2023", res[1])) expect_true(grepl("12H", res[1])) expect_true(grepl("30M", res[1])) expect_true(grepl("45S", res[1])) expect_true(grepl("PM", res[1])) }) test_that("nday_alias works", { d <- as.Date("2023-01-01") res <- nday(d, show_relative_day = FALSE) expect_equal(res[1], "Sun") today <- Sys.Date() res_today <- nday(today, show_relative_day = TRUE) expect_true(grepl("Today", res_today[1])) yesterday <- today - 1 res_yest <- nday(yesterday, show_relative_day = TRUE) expect_true(grepl("Yesterday", res_yest[1])) }) test_that("ndate_scalars works", { d <- as.Date("2023-12-25") res <- ndate(d) expect_true(grepl("Dec 25, 2023", res)) expect_true(grepl("Mon", res)) res_str <- ndate(as.Date("2024-01-01")) expect_true(grepl("Jan 01, 2024", res_str)) }) test_that("ndate_formats works", { d <- as.Date("2023-05-15") res_mon <- ndate(d, show_month_year = TRUE) expect_equal(res_mon[1], "May'23") res_wd <- ndate(d, show_weekday = TRUE) expect_true(grepl("Mon", res_wd[1])) res_no_wd <- ndate(d, show_weekday = FALSE) expect_false(grepl("Mon", res_no_wd[1])) }) test_that("nday_future works", { today <- Sys.Date() tmrw <- today + 1 res_tmrw <- nday(tmrw, show_relative_day = TRUE) expect_true(grepl("Tomorrow", res_tmrw)) coming <- today + 5 res_coming <- nday(coming, show_relative_day = TRUE) expect_true(grepl("Coming", res_coming)) }) test_that("ntimestamp_components works", { ts <- as.POSIXct("2023-01-01 14:30:05") res_no_date <- ntimestamp(ts, show_date = FALSE, show_weekday = FALSE) expect_false(grepl("Jan", res_no_date)) expect_true(grepl("02H", res_no_date)) expect_true(grepl("PM", res_no_date)) res_no_secs <- ntimestamp(ts, show_seconds = FALSE, show_weekday = FALSE) expect_false(grepl("05S", res_no_secs)) expect_true(grepl("30M", res_no_secs)) res_date_only <- ntimestamp(ts, show_hours = FALSE, show_minutes = FALSE, show_seconds = FALSE, show_weekday = FALSE ) expect_true(grepl("Jan 01, 2023", res_date_only)) expect_true(grepl("PM", res_date_only)) expect_false(grepl("H", res_date_only)) }) test_that("data.table_column works", { df <- data.table(vals = c(1000000, 2000000)) res <- nnumber(df$vals, unit = "Mn") expect_equal(res[1], "1.0 Mn") }) test_that("comprehensive_data_table works", { data <- data.table( user_review = c( "Great app!!! Used 5 times in 2 days, cost $12.99 :)", "Terrible!! Crashed 999 times @#$%", "Average service, 3/10, paid $45.67", "Loved it <3 used 100 times, saved $1000!!!", "Worst experience ever!!! -1 stars", "", NA, "Okay-ish… used once, paid $0.99", "Numbers 1234567890 !!! ??? ###", "Good but expensive, $99999.99!!!", "Refunded 50%, not happy :(", "Used on 2024-01-01 @ 12:30:45, works fine", "🔥🔥🔥 10/10 would recommend $$$", "Error code 500, retry count 7", "Cheap!!! only $0.01 unbelievable", "Overcharged by $1000000!!!", NA, "Mixed feelings... paid $12.00 twice", "Special chars only !!!@@@###$$$", "Final test review 42 times" ), mcc_code = c( 5411, 5812, 5732, 5999, 4111, 1234, NA, 7999, 4899, 9999, 5311, 5814, 5651, 0, 1, 8888, NA, 3000, 7000, 5555 ), revenue = c( 12.99, 0.0, 45.67, 1000.00, -5.00, NA, NA, 0.99, 123456.78, 99999.99, 50.00, 10.00, 5.55, 0.01, 0.01, 1000000.00, NA, 24.00, 0.00, 42.42 ), conversion_rate = c( 0.22, 0.00, 0.45, 0.95, -0.10, NA, NA, 0.01, 0.88, 1.50, 0.50, 0.30, 0.99, 0.001, 0.02, 2.00, NA, 0.24, 0.00, 0.42 ), date_str = c( "2024-01-01", "2024-01-02", "2024-01-03", "2024-01-04", "2024-01-05", NA, "2024-01-07", "2024-01-08", "2024-01-09", "2024-01-10", "2024-01-11", "2024-01-12", "2024-01-13", "2024-01-14", "2024-01-15", "2024-01-16", NA, "2024-01-18", "2024-01-19", "2024-01-20" ), timestamp_str = c( "2024-01-01 10:15:30", "2024-01-02 11:00:00", "2024-01-03 09:45:10", "2024-01-04 23:59:59", "2024-01-05 00:00:01", NA, "2024-01-07 14:22:33", "2024-01-08 08:08:08", "2024-01-09 12:12:12", "2024-01-10 16:45:00", "2024-01-11 10:10:10", "2024-01-12 12:30:45", "2024-01-13 01:01:01", "2024-01-14 18:18:18", "2024-01-15 20:20:20", "2024-01-16 22:22:22", NA, "2024-01-18 06:06:06", "2024-01-19 09:09:09", "2024-01-20 23:23:23" ) ) data[, date := as.Date(date_str)] data[, timestamp := as.POSIXct(timestamp_str)] res_rev <- nnumber(data$revenue, unit = "custom") expect_true(grepl("1.0 Mn", res_rev[16])) res_kp <- npercent(data$conversion_rate, is_ratio = TRUE) expect_true(grepl("\\+22.0%", res_kp[1])) res_dt <- ndate(data$date) expect_true(grepl("Jan 01, 2024", res_dt[1])) expect_true(is.na(res_dt[6])) res_ts <- ntimestamp(data$timestamp) expect_true(grepl("10H 15M 30S AM", res_ts[1])) res_str <- nstring(data$user_review, remove_specials = TRUE) expect_true(grepl("Great app", res_str[1])) expect_false(grepl("!!!", res_str[1])) }) test_that("empty_input works", { expect_equal(length(nstring(character(0))), 0) expect_equal(length(ndate(as.Date(character(0)))), 0) }) test_that("nan_handling_numbers works", { x <- c(10.0, NA_real_, 1000.0) res <- nnumber(x, unit = "auto") expect_equal(length(res), 3) }) test_that("inf_handling_numbers works", { x <- c(Inf, -Inf, 1000.0) res <- nnumber(x) expect_equal(length(res), 3) }) test_that("nan_handling_dates works", { d <- as.Date(c("2023-01-01", NA)) res <- ndate(d) expect_equal(length(res), 2) expect_true(grepl("Jan 01, 2023", res[1])) expect_true(is.na(res[2])) # Logical NA check expect_true(is.na(ndate(NA))) expect_true(is.na(nday(NA))) expect_true(is.na(ntimestamp(NA))) expect_true(is.na(nnumber(NA))) expect_true(is.na(npercent(NA))) expect_true(is.na(nstring(NA))) }) test_that("none_input works", { x <- c(10, NA, 100) res <- nnumber(x) expect_equal(length(res), 3) expect_true(is.na(res[2])) }) test_that("mixed_types_strings works", { x <- c("hello", "123", NA) res <- nstring(x) expect_equal(length(res), 3) expect_equal(res[1], "hello") # nstring default case is NULL (no change) expect_true(is.na(res[3])) }) test_that("f_inference_date works", { d <- as.Date("2026-01-01") expect_equal(f(d), "Jan 01, 2026") }) test_that("f_na_handling works", { expect_true(is.na(f(NA))) expect_true(is.na(f(NA_real_))) expect_true(is.na(f(NA_character_))) # Mixed x <- c(1, NA, 2) res <- f(x) expect_equal(res[1], "1.0") expect_true(is.na(res[2])) expect_equal(res[3], "2.0") }) test_that("f_inference_ts works", { ts <- as.POSIXct("2025-11-09 12:07:48") res <- f(ts) expect_true(grepl("Nov 09, 2025", res)) expect_true(grepl("12H 07M 48S PM", res)) expect_true(grepl("Sun", res)) }) test_that("f_inference_number works", { expect_equal(f(1345000000000), "1.3 Tn") expect_equal(f(1234.56, digits = 2, unit = ""), "1,234.56") }) test_that("f_inference_string works", { s <- "all Models are Wrong!!!" # R's toTitleCase keeps 'all' lowercase expect_equal(f(s), "all Models are Wrong") }) test_that("f_day works", { d <- as.Date("2026-01-01") # Thursday expect_equal(f(d, format_type = "day"), "Thu") }) test_that("f_percent works", { res <- f(9.0, format_type = "percent") expect_true(grepl("\\+900.0%", res)) expect_true(grepl("9x growth", res)) expect_true(grepl("90K basis points", res)) }) test_that("f_kwargs works", { expect_equal(f(1234.56, format_type = "number", digits = 2, thousand_separator = "_", unit = "" ), "1_234.56") expect_equal(f("hello world", case = "upper"), "HELLO WORLD") }) test_that("f_vectorized works", { x <- c(1000, 2000) res <- f(x) expect_equal(res[1], "1.0 K") expect_equal(res[2], "2.0 K") d <- as.Date(c("2026-01-01", "2026-01-02")) res_d <- f(d) expect_equal(res_d[1], "Jan 01, 2026") expect_equal(res_d[2], "Jan 02, 2026") }) test_that("f_inference_mixed works", { x <- c(1000, NA, 2000) res <- f(x) expect_equal(res[1], "1.0 K") expect_equal(res[1], "1.0 K") expect_equal(res[3], "2.0 K") }) test_that("f_invalid_type works", { expect_error(f(10, format_type = "invalid")) }) test_that("nnumber_basics works", { x <- c(10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000) expected <- c( "10.0", "100.0", "1.0 K", "10.0 K", "100.0 K", "1.0 Mn", "10.0 Mn", "100.0 Mn", "1.0 Bn" ) res_custom <- nnumber(x, digits = 1, unit = "custom") expect_equal(res_custom, expected) }) test_that("nnumber_fixed_unit works", { x <- c(123456789.123456) res <- nnumber(x, digits = 1, unit = "Mn", prefix = "$") expect_equal(res[1], "$123.5 Mn") }) test_that("nnumber_separators works", { x <- c(10000) res <- nnumber(x, digits = 0, thousand_separator = ".", unit = "") expect_equal(res[1], "10.000") }) test_that("npercent_extended works", { # Scenarios from python test scenarios <- list( list(val = -0.05, pct = "-5.00%", bps = "(-500 bps)"), list(val = 0.01, pct = "+1.00%", bps = "(+100 bps)") ) for (s in scenarios) { res <- npercent(s$val, is_ratio = TRUE, digits = 2, show_bps = TRUE, show_plus_sign = TRUE ) expect_true(grepl(s$pct, res, fixed = TRUE)) expect_true(grepl(s$bps, res, fixed = TRUE)) } }) test_that("nnumber_values works", { x <- c(-1000000, 0, 1000000) res <- nnumber(x, digits = 1) expect_equal(res[1], "-1.0 Mn") expect_equal(res[2], "0.0") expect_equal(res[3], "1.0 Mn") }) test_that("nnumber_units works", { x <- c(1500, 1500000, 1500000000) res_k <- nnumber(x, unit = "K", digits = 1) expect_equal(res_k[1], "1.5 K") expect_equal(res_k[2], "1,500.0 K") expect_equal(res_k[3], "1,500,000.0 K") }) test_that("nstring_case works", { x <- c("hello world", "GOODBYE") res <- nstring(x, case = "title") expect_equal(res[1], "Hello World") expect_equal(res[2], "Goodbye") })