test_that("cli_ansi_string", { right <- c("cli_ansi_string", "ansi_string", "character") expect_equal(class(ansi_string("foobar")), right) expect_equal(class(ansi_string(133)), right) expect_equal(class(ansi_string(ansi_string(134))), right) }) test_that("ansi_regex", { # somewhat special sequences cases <- list( list("foo\033[39;49mbar", "foobar"), list("foo\033[1;3;4mbar", "foobar"), list("foo\033[1;;4mbar", "foobar"), list("foo\033[mbar", "foobar") ) for (case in cases) { expect_equal(gsub(ansi_regex(), "", case[[1]], perl = TRUE), case[[2]]) } }) test_that("ansi_has_any works", { withr::local_options(list( cli.num_colors = 256L, cli.hyperlink = TRUE )) expect_false(ansi_has_any("foobar")) funcs <- ls(asNamespace("cli"), pattern = "^col_|^bg_|^style_") for (sym in setdiff(funcs, "style_hyperlink")) { fun <- get(sym, envir = asNamespace("cli")) expect_true(ansi_has_any(fun("foo", "bar")), label = sym) } }) test_that("ansi_strip works", { withr::local_options(list( cli.num_colors = 256L, cli.hyperlink = TRUE )) expect_equal("", ansi_strip("")) expect_equal("foobar", ansi_strip("foobar")) expect_equal( "foobar", ansi_strip(col_red(style_underline(style_bold("foobar")))) ) funcs <- ls(asNamespace("cli"), pattern = "^col_|^bg_|^style_") for (sym in setdiff(funcs, "style_hyperlink")) { fun <- get(sym, envir = asNamespace("cli")) ans <- if (sym == "style_hyperlink") "foo" else "foobar" expect_equal(ans, ansi_strip(fun("foo", "bar"))) } }) str <- c("", "plain", "\033[31m", "\033[39m", "\033[31mred\033[39m", "\033[31mred\033[39m\033[31mred\033[39m", "foo\033[31mred\033[39m", "\033[31mred\033[39mfoo") test_that("ansi_nchar", { withr::local_options(list(cli.num_colors = 256L)) for (s in str) { expect_equal(ansi_nchar(s), nchar(ansi_strip(s)), info = s) } }) test_that("ansi_nchar wide characters", { expect_equal(ansi_nchar("\u231a", "width"), 2L) }) test_that("ansi_substr bad input", { expect_snapshot( error = TRUE, ansi_substr("foobar", NULL, 10) ) expect_snapshot( error = TRUE, ansi_substr("foobar", 10, NULL) ) expect_snapshot( error = TRUE, ansi_substr("foobar", "bad", "bad") ) }) test_that("ansi_substr", { withr::local_options(list(cli.num_colors = 256L)) for (s in str) { for (i in 1 %:% ansi_nchar(s)) { for (j in i %:% ansi_nchar(s)) { expect_equal(ansi_strip(ansi_substr(s, i, j)), substr(ansi_strip(s), i, j), info = paste(s, i, j)) } } } }) test_that("ansi_substr keeps color", { withr::local_options(list(cli.num_colors = 256L)) expect_equal( ansi_substr("\033[31mred\033[39m", 1, 1), ansi_string("\033[31mr\033[39m") ) expect_equal( ansi_substr("foo\033[31mred\033[39m", 4, 4), ansi_string("\033[31mr\033[39m") ) expect_equal( ansi_substr("foo\033[31mred\033[39mbar", 4, 4), ansi_string("\033[31mr\033[39m") ) expect_equal( ansi_substr("\033[31mred\033[39mfoo\033[31mred\033[39mbar", 7, 7), ansi_string("\033[31mr\033[39m") ) }) test_that("ansi_substr, start after string end", { withr::local_options(list(cli.num_colors = 256L)) expect_equal(ansi_substr("red", 4, 4), ansi_string("")) expect_equal(ansi_substr("red", 4, 5), ansi_string("")) expect_equal(ansi_strip(ansi_substr("\033[31mred\033[39m", 4, 4)), "") expect_equal(ansi_strip(ansi_substr("\033[31mred\033[39m", 4, 5)), "") expect_equal(ansi_substr("red", 3, 4), ansi_string("d")) expect_equal(ansi_substr("red", 3, 5), ansi_string("d")) expect_equal(ansi_strip(ansi_substr("\033[31mred\033[39m", 3, 4)), "d") expect_equal(ansi_strip(ansi_substr("\033[31mred\033[39m", 3, 5)), "d") }) test_that("ansi_substr, multiple strings", { withr::local_options(list(cli.num_colors = 256L)) set.seed(42) for (i in 1:100) { strs <- sample(str, 4) num_starts <- sample(1:5, 1) num_stops <- sample(1:5, 1) starts <- sample(1:5, num_starts, replace = TRUE) stops <- sample(1:5, num_stops, replace = TRUE) r1 <- ansi_strip(ansi_substr(strs, starts, stops)) r2 <- substr(ansi_strip(strs), starts, stops) expect_equal(r1, r2) } }) test_that("ansi_substr corner cases", { withr::local_options(list(cli.num_colors = 256L)) # Zero length input c0 <- character(0L) o0 <- structure(list(), class="abc") co0 <- structure(character(0L), class="abc") expect_identical(ansi_substr(c0, 1, 1), ansi_string(substr(c0, 1, 1))) expect_identical(ansi_substr(o0, 1, 1), ansi_string(substr(o0, 1, 1))) expect_identical(ansi_substr(co0, 1, 1), ansi_string(substr(co0, 1, 1))) expect_identical( ansi_substring(c0, 1, 1), ansi_string(substring(c0, 1, 1)) ) expect_identical( ansi_substring(o0, 1, 1), ansi_string(substring(o0, 1, 1)) ) expect_identical( ansi_substring(co0, 1, 1), ansi_string(substring(co0, 1, 1)) ) # Character start/stop expect_identical( ansi_substr("abc", "1", 1), ansi_string(substr("abc", "1", 1)) ) expect_identical( ansi_substr("abc", 1, "1"), ansi_string(substr("abc", 1, "1")) ) # non-numeric arguments cause errors; NOTE: this actually "works" # with 'substr' but not implemented in 'ansi_substr' expect_snapshot( error = TRUE, ansi_substr("abc", "hello", 1) ) }) test_that("ansi_substring", { withr::local_options(list(cli.num_colors = 256L)) for (s in str) { for (i in 1 %:% ansi_nchar(s)) { for (j in i %:% ansi_nchar(s)) { expect_equal(ansi_strip(ansi_substring(s, i, j)), substring(ansi_strip(s), i, j), info = paste(s, i, j)) } } } }) test_that("ansi_substring, multiple strings", { withr::local_options(list(cli.num_colors = 256L)) set.seed(42) for (i in 1:100) { strs <- sample(str, 4) num_starts <- sample(1:5, 1) num_stops <- sample(1:5, 1) starts <- sample(1:5, num_starts, replace = TRUE) stops <- sample(1:5, num_stops, replace = TRUE) r1 <- ansi_strip(ansi_substring(strs, starts, stops)) r2 <- substring(ansi_strip(strs), starts, stops) expect_equal(r1, r2) } }) test_that("ansi_substring corner cases", { withr::local_options(list(cli.num_colors = 256L)) # Zero length input c0 <- character(0L) o0 <- structure(list(), class="abc") co0 <- structure(character(0L), class="abc") expect_identical( ansi_substring(c0, 1, 1), ansi_string(substring(c0, 1, 1)) ) expect_identical( ansi_substring(o0, 1, 1), ansi_string(substring(o0, 1, 1)) ) expect_identical( ansi_substring(co0, 1, 1), ansi_string(substring(co0, 1, 1)) ) }) test_that("ansi_strsplit", { withr::local_options(list(cli.num_colors = 256L)) red <- "\033[31mred\033[39m" str <- "plain-plain" expect_equal( ansi_strsplit(str, "-"), lapply(strsplit(str, "-"), ansi_string) ) str <- paste0(red, "-plain") expect_equal( ansi_strip(ansi_strsplit(str, "-")[[1]]), strsplit(ansi_strip(str), "-")[[1]] ) expect_equal( ansi_strsplit(str, "e"), list(ansi_string(c("\033[31mr\033[39m", "\033[31md\033[39m-plain"))) ) str <- paste0(red, "-", red, "-", red) expect_equal( ansi_strip(ansi_strsplit(str, "-")[[1]]), strsplit(ansi_strip(str), "-")[[1]] ) # with leading and trailing separators str.2 <- paste0("-", red, "-", red, "-", red, "-") expect_equal(ansi_strip(ansi_strsplit(str.2, "-")[[1]]), strsplit(ansi_strip(str.2), "-")[[1]]) # greater than length 1 str.3 <- paste0("-", c(col_green("hello"), col_red("goodbye")), "-world-") expect_equal(ansi_strip(unlist(ansi_strsplit(str.3, "-"))), unlist(strsplit(ansi_strip(str.3), "-"))) }) test_that("ansi_strsplit multiple strings", { withr::local_options(list(cli.num_colors = 256L)) red <- "\033[31mred\033[39m" str <- c( paste0("plain-plain-", red, "-plain-", red), paste0(red, "-", red), red ) r1 <- lapply(ansi_strsplit(str, "-"), ansi_strip) r2 <- strsplit(ansi_strip(str), "-") expect_equal(r1, r2) }) test_that("ansi_strsplit edge cases", { withr::local_options(list(cli.num_colors = 256L)) expect_equal(ansi_strsplit("", "-"), list(ansi_string(character(0L)))) expect_equal( ansi_strip(ansi_strsplit("\033[31m\033[39m", "-")[[1]]), character(0L) ) # special cases expect_equal(ansi_strsplit("", ""), lapply(strsplit("", ""), ansi_string)) expect_equal( ansi_strsplit("a", "a"), lapply(strsplit("a", "a"), ansi_string) ) # this following test isn't working yet expect_equal( ansi_strsplit("a", ""), lapply(strsplit("a", ""), ansi_string) ) expect_equal( ansi_strsplit("", "a"), lapply(strsplit("", "a"), ansi_string) ) # Longer strings expect_identical( ansi_strsplit(c("", "a", "aa"), "a"), lapply(strsplit(c("", "a", "aa"), "a"), ansi_string) ) expect_identical( ansi_strsplit(c("abaa", "ababza"), "b."), lapply(strsplit(c("abaa", "ababza"), "b."), ansi_string) ) }) test_that("Weird length 'split'", { withr::local_options(list(cli.num_colors = 256L)) expect_snapshot( error = TRUE, ansi_strsplit(c("ab", "bd"), c("b", "d")) ) expect_identical( ansi_strsplit("ab", NULL), lapply(strsplit("ab", NULL), ansi_string) ) expect_identical( ansi_strsplit("ab", character(0L)), lapply(strsplit("ab", character(0L)), ansi_string) ) }) test_that("ansi_align", { withr::local_options(list(cli.num_colors = 256L)) expect_equal(ansi_align(character()), ansi_string(character())) expect_equal(ansi_align("", 0), ansi_string("")) expect_equal(ansi_align(" ", 0), ansi_string(" ")) expect_equal(ansi_align(" ", 1), ansi_string(" ")) expect_equal(ansi_align(" ", 2), ansi_string(" ")) expect_equal(ansi_align("a", 1), ansi_string("a")) expect_equal(ansi_align(letters, 1), ansi_string(letters)) expect_equal(ansi_align(letters, 0), ansi_string(letters)) expect_equal(ansi_align(letters, -1), ansi_string(letters)) expect_equal(ansi_align(letters, 2), ansi_string(paste0(letters, " "))) expect_equal( ansi_align(letters, 3, "center"), ansi_string(paste0(" ", letters, " ")) ) expect_equal( ansi_align(letters, 2, "right"), ansi_string(paste0(" ", letters)) ) expect_equal( ansi_align(c("foo", "foobar", "", "a"), 6, "left"), ansi_string(c("foo ", "foobar", " ", "a "))) expect_equal( ansi_align(c("foo", "foobar", "", "a"), 6, "center"), ansi_string(c(" foo ", "foobar", " ", " a "))) expect_equal( ansi_align(c("foo", "foobar", "", "a"), 6, "right"), ansi_string(c(" foo", "foobar", " ", " a"))) # #54: alignment of wide characters expect_equal( ansi_align(c("foo", "\u6210\u4ea4\u65e5", "", "a"), 6, "left"), ansi_string(c("foo ", "\u6210\u4ea4\u65e5", " ", "a "))) expect_equal( ansi_align(c("foo", "\u6210\u4ea4\u65e5", "", "a"), 6, "center"), ansi_string(c(" foo ", "\u6210\u4ea4\u65e5", " ", " a "))) expect_equal( ansi_align(c("foo", "\u6210\u4ea4\u65e5", "", "a"), 6, "right"), ansi_string(c(" foo", "\u6210\u4ea4\u65e5", " ", " a"))) }) test_that("stripping hyperlinks", { withr::local_options(list(cli.hyperlink = TRUE)) x <- unclass(style_hyperlink("foo", "https://r-pkg.org")) expect_equal( ansi_strip(paste0("1111-", x, "-2222-", x, "-333")), "1111-foo-2222-foo-333" ) }) test_that("ansi_trimws", { cases <- list( list(character(), ansi_string(character())), list(1, ansi_string(1)), list("", ansi_string("")), list("foo", ansi_string("foo")), list(" foo ", ansi_string("foo")), list(c("foo", "bar"), ansi_string(c("foo", "bar"))), list(col_red(c(" colored ")), ansi_string(col_red("colored"))), list( paste0(" ", col_red(c(" colored ")), " "), ansi_string(col_red("colored"))) ) for (case in cases) expect_equal(ansi_trimws(case[[1]]), case[[2]]) cases_left <- list( list(character(), ansi_string(character())), list(1, ansi_string(1)), list("", ansi_string("")), list("foo", ansi_string("foo")), list(" foo ", ansi_string("foo ")), list(c("foo", "bar"), ansi_string(c("foo", "bar"))), list(col_red(c(" colored ")), ansi_string(col_red("colored "))), list( paste0(" ", col_red(c(" colored ")), " "), ansi_string(paste0(col_red("colored "), " "))) ) for (case in cases_left) { expect_equal(ansi_trimws(case[[1]], "left"), case[[2]]) } cases_right <- list( list(character(), ansi_string(character())), list(1, ansi_string(1)), list("", ansi_string("")), list("foo", ansi_string("foo")), list(" foo ", ansi_string(" foo")), list(c(" foo ", " bar "), ansi_string(c(" foo", " bar"))), list(c("foo", "bar"), ansi_string(c("foo", "bar"))), list(col_red(c(" colored ")), ansi_string(col_red(" colored"))), list( paste0(" ", col_red(c(" colored ")), " "), ansi_string(paste0(" ", col_red(" colored")))) ) for (case in cases_right) { expect_equal(ansi_trimws(case[[1]], "right"), case[[2]]) } }) test_that("ansi_strwrap simple", { cases = list( list(character(), character()), list("", ""), list("foo", "foo"), list(1, "1"), list(c("foo", "bar"), c("foo", "bar")) ) for (case in cases) { expect_equal(ansi_strwrap(case[[1]], 20), ansi_string(case[[2]])) } }) test_that("ansi_strwrap simple styled", { cases = list( list(col_red("foo"), col_red("foo")), list(col_red(c("foo", "bar")), col_red(c("foo", "bar"))), list( paste0("foo", bg_red(" "), "bar"), paste0("foo", bg_red(" "), "bar") ) ) for (case in cases) { expect_equal(ansi_strwrap(case[[1]], 20), ansi_string(case[[2]])) } }) test_that("ansi_strwrap", { txt0 <- glue::glue_col(" {col_red Velit occaecat} quis culpa occaecat. {col_green Pariatur} \\ ad veniam pariatur {bg_blue consectetur}. Dolore aliquip et \\ {style_underline consequat Lorem consectetur} dolor. Irure id velit \\ proident elit veniam eu exercitation nisi laboris officia. Qui \\ {col_red sunt occaecat} cillum {col_red sit commodo sit. \\ Culpa} aliquip et consectetur ullamco aliqua Lorem laborum dolore. ") txt <- paste0(txt0, "\n\t \n", txt0) expect_equal( ansi_strip(ansi_strwrap(txt0, 40)), strwrap(ansi_strip(txt0), 40) ) expect_equal( ansi_strip(ansi_strwrap(txt, 40)), strwrap(ansi_strip(txt), 40) ) expect_equal( ansi_strip(ansi_strwrap(txt, 40, indent = 2)), strwrap(ansi_strip(txt), 40, indent = 2) ) expect_equal( ansi_strip(ansi_strwrap(txt, 40, exdent = 2)), strwrap(ansi_strip(txt), 40, exdent = 2) ) expect_equal( ansi_strip(ansi_strwrap(txt, 40, indent = 2, exdent = 4)), strwrap(ansi_strip(txt), 40, indent = 2, exdent = 4) ) }) test_that("ansi_strwrap double width", { expect_equal( ansi_strwrap("\U0001F477 1 2 3", 4), ansi_string(c("\U0001f477", "1 2", "3")) ) }) test_that("ansi_strwrap newlines", { expect_equal( ansi_strwrap("\033[32mv\033[39m hello world.\nxxx"), ansi_string("\033[32mv\033[39m hello world. xxx") ) }) test_that("ansi_strwrap and \f edge cases", { expect_equal( ansi_strwrap("\033[32mfoo\fbar\033[39m"), ansi_string(c("\033[32mfoo\033[39m", "\033[32mbar\033[39m")) ) expect_equal( ansi_strwrap("\033[32m\ffoo\f\033[39m"), ansi_string(c("", "\033[32mfoo\033[39m", "")) ) }) test_that_cli(configs = c("plain", "ansi"), "ansi_strtrim", { withr::local_options(c(cli.unicode = FALSE)) setup_unicode_width_fix() cases <- list( list("", ansi_string("")), list("1", ansi_string("1")), list("123456789", ansi_string("123456789")), list("1234567890", ansi_string("1234567890")), list("12345678901", ansi_string("1234567...")), list( strrep("\u231A", 6), ansi_string(paste0(strrep("\u231A", 3), "..."))), list(col_red("1"), col_red("1")), list(c("foo", NA, col_red("bar")), ansi_string(c("foo", NA, col_red("bar")))) ) for (case in cases) expect_equal(ansi_strtrim(case[[1]], 10), case[[2]]) }) test_that("ansi_strtrim with zero-length ellipsis", { expect_snapshot({ ansi_strtrim("12345", 1, ellipsis = "") ansi_strtrim("12345", 3, ellipsis = "") ansi_strtrim("12345", 5, ellipsis = "") }) }) test_that("ansi_strtrim errors", { expect_snapshot( error = TRUE, ansi_strtrim("foobar", -1) ) }) test_that("ansi_strtrim edge cases", { expect_snapshot({ ansi_strtrim("foobar", width = 3, ellipsis = "...") ansi_strtrim("foobar", width = 2, ellipsis = "...") ansi_strtrim("foobar", width = 1, ellipsis = "...") ansi_strtrim("foobar", width = 0, ellipsis = "...") }) }) test_that("ansi_columns", { withr::local_options(c(cli.unicode = FALSE)) local_edition(3) expect_equal(ansi_columns(character()), ansi_string(character())) expect_snapshot_output( cat(ansi_columns(paste("foo", 1:10), width = 40), sep = "\n") ) txt60 <- strrep("1234567890", 6) expect_snapshot_output( cat(ansi_columns(txt60, width = 15), sep = "\n") ) }) test_that_cli(configs = c("plain", "ansi"), "ansi_toupper", { x <- paste0( col_red("Red "), "normal ", style_bold(col_green("green")) ) expect_snapshot(local({ cat_line(x) cat_line(ansi_toupper(x)) })) }) test_that_cli(configs = c("plain", "ansi"), "ansi_tolower", { x <- paste0( col_red("Red "), "NORMAL ", style_bold(col_green("grEeN")) ) expect_snapshot(local({ cat_line(x) cat_line(ansi_tolower(x)) })) }) test_that_cli(configs = c("plain", "ansi"), "ansi_chartr", { x <- paste0( col_red("Red "), "normal ", style_bold(col_green("green")) ) expect_snapshot(local({ cat_line(x) cat_line(ansi_chartr(" R_", "-r*", x)) })) })