
test_that("very long strings", {
  withr::local_options(cli.num_colors = 256)
  str <- strrep("1234 ", 1000)
  expect_equal(
    ansi_simplify(col_red(col_red(str))),
    col_red(str)
  )

  str2 <- paste0(col_green(str), col_red(str))
  expect_equal(
    ansi_simplify(col_green(str2)),
    ansi_string(str2)
  )
})

test_that("RGB colors", {
  cases <- list(
    list("\033[38;5;123mfoo\033[39m", "\033[38;5;123mfoo\033[39m"),
    list("\033[38;2;1;2;3mfoo\033[39m", "\033[38;2;1;2;3mfoo\033[39m"),
    list("\033[38;2;mfoo\033[39m", "\033[38;2;0;0;0mfoo\033[39m"),
    list("\033[48;5;123mfoo\033[49m", "\033[48;5;123mfoo\033[49m"),
    list("\033[48;2;1;2;3mfoo\033[49m", "\033[48;2;1;2;3mfoo\033[49m"),
    list("\033[48;2;mfoo\033[49m", "\033[48;2;0;0;0mfoo\033[49m"),
    ## bad tags are skipped completely
    list("\033[48;4;12mfoo\033[49m", "foo")
  )

  for (c in cases) {
    expect_equal(ansi_simplify(c[[1]]), ansi_string(c[[2]]))
  }
})

test_that("0m closing tag", {
  cases <- list(
    list("\033[1mfoo\033[0m", "\033[1mfoo\033[22m"),
    list("\033[1mfoo\033[m", "\033[1mfoo\033[22m")
  )

  for (c in cases) {
    expect_equal(ansi_simplify(c[[1]]), ansi_string(c[[2]]))
  }
})

test_that("various tags", {
  cases <- list(
    list("\033[1m\033[22m\033[1mfoo",   "\033[1mfoo\033[22m"),
    list("\033[2m\033[22m\033[2mfoo",   "\033[2mfoo\033[22m"),
    list("\033[3m\033[23m\033[3mfoo",   "\033[3mfoo\033[23m"),
    list("\033[4m\033[24m\033[4mfoo",   "\033[4mfoo\033[24m"),
    list("\033[5m\033[25m\033[5mfoo",   "\033[5mfoo\033[25m"),
    list("\033[7m\033[27m\033[7mfoo",   "\033[7mfoo\033[27m"),
    list("\033[8m\033[28m\033[8mfoo",   "\033[8mfoo\033[28m"),
    list("\033[9m\033[29m\033[9mfoo",   "\033[9mfoo\033[29m"),
    list("\033[30m\033[39m\033[30mfoo", "\033[30mfoo\033[39m"),
    list("\033[31m\033[39m\033[31mfoo", "\033[31mfoo\033[39m"),
    list("\033[32m\033[39m\033[32mfoo", "\033[32mfoo\033[39m"),
    list("\033[33m\033[39m\033[33mfoo", "\033[33mfoo\033[39m"),
    list("\033[34m\033[39m\033[34mfoo", "\033[34mfoo\033[39m"),
    list("\033[35m\033[39m\033[35mfoo", "\033[35mfoo\033[39m"),
    list("\033[36m\033[39m\033[36mfoo", "\033[36mfoo\033[39m"),
    list("\033[37m\033[39m\033[37mfoo", "\033[37mfoo\033[39m"),
    list("\033[90m\033[39m\033[90mfoo", "\033[90mfoo\033[39m"),
    list("\033[91m\033[39m\033[91mfoo", "\033[91mfoo\033[39m"),
    list("\033[92m\033[39m\033[92mfoo", "\033[92mfoo\033[39m"),
    list("\033[93m\033[39m\033[93mfoo", "\033[93mfoo\033[39m"),
    list("\033[94m\033[39m\033[94mfoo", "\033[94mfoo\033[39m"),
    list("\033[95m\033[39m\033[95mfoo", "\033[95mfoo\033[39m"),
    list("\033[96m\033[39m\033[96mfoo", "\033[96mfoo\033[39m"),
    list("\033[97m\033[39m\033[97mfoo", "\033[97mfoo\033[39m"),
    list("\033[40m\033[49m\033[40mfoo", "\033[40mfoo\033[49m"),
    list("\033[41m\033[49m\033[41mfoo", "\033[41mfoo\033[49m"),
    list("\033[42m\033[49m\033[42mfoo", "\033[42mfoo\033[49m"),
    list("\033[43m\033[49m\033[43mfoo", "\033[43mfoo\033[49m"),
    list("\033[44m\033[49m\033[44mfoo", "\033[44mfoo\033[49m"),
    list("\033[45m\033[49m\033[45mfoo", "\033[45mfoo\033[49m"),
    list("\033[46m\033[49m\033[46mfoo", "\033[46mfoo\033[49m"),
    list("\033[47m\033[49m\033[47mfoo", "\033[47mfoo\033[49m"),
    list("\033[100m\033[49m\033[100mfoo", "\033[100mfoo\033[49m"),
    list("\033[101m\033[49m\033[101mfoo", "\033[101mfoo\033[49m"),
    list("\033[102m\033[49m\033[102mfoo", "\033[102mfoo\033[49m"),
    list("\033[103m\033[49m\033[103mfoo", "\033[103mfoo\033[49m"),
    list("\033[104m\033[49m\033[104mfoo", "\033[104mfoo\033[49m"),
    list("\033[105m\033[49m\033[105mfoo", "\033[105mfoo\033[49m"),
    list("\033[106m\033[49m\033[106mfoo", "\033[106mfoo\033[49m"),
    list("\033[107m\033[49m\033[107mfoo", "\033[107mfoo\033[49m")
  )

  for (c in cases) {
    expect_equal(ansi_simplify(c[[1]]), ansi_string(c[[2]]))
  }
})

test_that("unknown tags are kept as is, and [0m is also kept for then", {
  cases <- list(
    list("\033[11mfoo\033[0m", "\033[11mfoo\033[0m")
  )
  for (c in cases) {
    expect_equal(ansi_simplify(c[[1]]), ansi_string(c[[2]]))
  }
})

test_that("simplify w/o tags", {
  cases <- list(
    list(c("", "foo", "\033[1mbold"), c("", "foo", "\033[1mbold\033[22m"))
  )
  for (c in cases) {
    expect_equal(ansi_simplify(c[[1]]), ansi_string(c[[2]]))
  }
})

test_that("CSI sequences", {
  expect_equal(
    ansi_simplify("foo\033[10Abar", csi = "drop"),
    ansi_string("foobar")
  )
  expect_equal(
    ansi_simplify("\033[1mfoo\033[0m\033[10Abar", csi = "drop"),
    ansi_string("\033[1mfoo\033[22mbar")
  )
  expect_equal(
    ansi_simplify("foo\033[10Abar", csi = "keep"),
    ansi_string("foo\033[10Abar")
  )
  expect_equal(
    ansi_simplify("\033[1mfoo\033[0m\033[10Abar", csi = "keep"),
    ansi_string("\033[1mfoo\033[10A\033[22mbar")
  )
  expect_equal(
    ansi_strip("\033[1mfoo\033[10Abar\033[0m", csi = TRUE, sgr = FALSE),
    "\033[1mfoobar\033[0m"
  )
  expect_equal(
    ansi_strip("\033[1mfoo\033[10Abar\033[0m", csi = FALSE, sgr = TRUE),
    "foo\033[10Abar"
  )
})

test_that("ansi_has_any", {
  T <- TRUE
  F <- FALSE
  expect_false(ansi_has_any("foobar",                sgr = T, csi = T))
  expect_true (ansi_has_any("\033[1mfoobar",         sgr = T, csi = T))
  expect_true (ansi_has_any("\033[10Afoobar",        sgr = T, csi = T))
  expect_true (ansi_has_any("\033[10A\033[1mfoobar", sgr = T, csi = T))
  expect_false(ansi_has_any("foobar",                sgr = T, csi = F))
  expect_true (ansi_has_any("\033[1mfoobar",         sgr = T, csi = F))
  expect_false(ansi_has_any("\033[10Afoobar",        sgr = T, csi = F))
  expect_true (ansi_has_any("\033[10A\033[1mfoobar", sgr = T, csi = F))
  expect_false(ansi_has_any("foobar",                sgr = F, csi = T))
  expect_false(ansi_has_any("\033[1mfoobar",         sgr = F, csi = T))
  expect_true (ansi_has_any("\033[10Afoobar",        sgr = F, csi = T))
  expect_true (ansi_has_any("\033[10A\033[1mfoobar", sgr = F, csi = T))
  expect_false(ansi_has_any("foobar",                sgr = F, csi = F))
  expect_false(ansi_has_any("\033[1mfoobar",         sgr = F, csi = F))
  expect_false(ansi_has_any("\033[10Afoobar",        sgr = F, csi = F))
  expect_false(ansi_has_any("\033[10A\033[1mfoobar", sgr = F, csi = F))
})

test_that("NA", {
  T <- TRUE
  F <- FALSE
  s <- c("foo", NA, "bar", "\033[1mfoobar")

  expect_equal(
    ansi_simplify(s),
    ansi_string(c("foo", NA, "bar", "\033[1mfoobar\033[22m"))
  )
  expect_equal(is.na(ansi_simplify(s)), c(F, T, F, F))

  expect_equal(
    ansi_substr(s, 1, 2),
    ansi_string(c("fo", NA, "ba", "\033[1mfo\033[22m"))
  )
  expect_equal(is.na(ansi_substr(s, 1, 2)), c(F, T, F, F))

  expect_snapshot(ansi_html(s))
  expect_equal(is.na(ansi_html(s)), c(F, T, F, F))

  expect_equal(ansi_has_any(s), c(F, NA, F, T))

  expect_equal(ansi_strip(s), c("foo", NA, "bar", "foobar"))
  expect_equal(is.na(ansi_strip(s)), c(F, T, F, F))
})

test_that("strrep", {
  expect_equal(strrep(character(), 5), character())
  expect_equal(strrep("a", 5), "aaaaa")
})

test_that("convert to character", {
  expect_false(ansi_has_any(123))
  expect_equal(ansi_strip(123), "123")
  expect_equal(ansi_substr(1234, 2, 3), ansi_string("23"))
  expect_equal(ansi_substring(1234, 2, 3), ansi_string("23"))
  expect_equal(ansi_strsplit(1234, 2), list(ansi_string(c("1", "34"))))
  expect_equal(ansi_trimws(123), ansi_string("123"))
  expect_equal(ansi_strwrap(123), ansi_string("123"))
  expect_equal(ansi_simplify(123), ansi_string("123"))
  expect_equal(ansi_html(123), "123")
  expect_equal(ansi_nchar(123), 3)
})

test_that("ansi_nchar", {
  b <- col_red(c(
    "\U0001f477\U0001f3fb",
    "\U0001f477\U0001f3fc\u200d\u2642\ufe0f",
    "\U0001f477\U0001f3fd\u200d\u2640\ufe0f",
    "\U0001f477",
    "\U0001f477\U0001f3fe\u200d\u2640\ufe0f"
  ))
  expect_equal(ansi_nchar(b), rep(1L, 5))
  expect_equal(ansi_nchar(b, "chars"), rep(1L, 5))
  expect_equal(ansi_nchar(b, "bytes"), c(8L, 17L, 17L, 4L, 17L))
  expect_equal(ansi_nchar(b, "width"), rep(2L, 5))
  expect_equal(ansi_nchar(b, "graphemes"), rep(1L, 5))
  expect_equal(ansi_nchar(b, "codepoints"), c(2L, 5L, 5L, 1L, 5L))

  bb <- paste0(b, collapse = "")
  expect_equal(ansi_nchar(bb), sum(rep(1L, 5)))
  expect_equal(ansi_nchar(bb, "chars"), sum(rep(1L, 5)))
  expect_equal(ansi_nchar(bb, "bytes"), sum(c(8L, 17L, 17L, 4L, 17L)))
  expect_equal(ansi_nchar(bb, "width"), sum(rep(2L, 5)))
  expect_equal(ansi_nchar(bb, "graphemes"), sum(rep(1L, 5)))
  expect_equal(ansi_nchar(bb, "codepoints"), sum(c(2L, 5L, 5L, 1L, 5L)))

  expect_equal(ansi_nchar(character(), "chars"), integer())
  expect_equal(ansi_nchar(character(), "bytes"), integer())
  expect_equal(ansi_nchar(character(), "width"), integer())
  expect_equal(ansi_nchar(character(), "graphemes"), integer())
  expect_equal(ansi_nchar(character(), "codepoints"), integer())

  expect_equal(ansi_nchar("", "chars"), 0L)
  expect_equal(ansi_nchar("", "bytes"), 0L)
  expect_equal(ansi_nchar("", "width"), 0L)
  expect_equal(ansi_nchar("", "graphemes"), 0L)
  expect_equal(ansi_nchar("", "codepoints"), 0L)
})

test_that("ansi_align with graphemes", {
  withr::local_options(cli.num_colors = 256)

  b <- col_red(c(
    "\U0001f477\U0001f3fb",
    "\U0001f477\U0001f3fc\u200d\u2642\ufe0f",
    "\U0001f477\U0001f3fd\u200d\u2640\ufe0f",
    "\U0001f477",
    "\U0001f477\U0001f3fe\u200d\u2640\ufe0f"
  ))

  expect_equal(
    ansi_align(b, width = 10, align = "left"),
    ansi_string(paste0(b, strrep(" ", 8)))
  )
  expect_equal(
    ansi_align(b, width = 10, align = "center"),
    ansi_string(paste0(strrep(" ", 4), b, strrep(" ", 4)))
  )
  expect_equal(
    ansi_align(b, width = 10, align = "right"),
    ansi_string(paste0(strrep(" ", 8), b))
  )
})

test_that("ansi_columns with graphemes", {
  withr::local_options(cli.num_colors = 256)

  b <- col_red(c(
    "\U0001f477\U0001f3fb",
    "\U0001f477\U0001f3fc\u200d\u2642\ufe0f",
    "\U0001f477\U0001f3fd\u200d\u2640\ufe0f",
    "\U0001f477",
    "\U0001f477\U0001f3fe\u200d\u2640\ufe0f"
  ))

  expect_equal(
    ansi_columns(b, width = 6),
    ansi_string(c(
      paste0(b[1], " ", b[2], " "),
      paste0(b[3], " ", b[4], " "),
      paste0(b[5], "    ")
    ))
  )
})

test_that("ansi_substr with graphemes", {
  withr::local_options(cli.num_colors = 256)

  b <- col_red(c(
    "\U0001f477\U0001f3fb",
    "\U0001f477\U0001f3fc\u200d\u2642\ufe0f",
    "\U0001f477\U0001f3fd\u200d\u2640\ufe0f",
    "\U0001f477",
    "\U0001f477\U0001f3fe\u200d\u2640\ufe0f"
  ))
  bb <- paste0(b, collapse = "")

  expect_equal(
    ansi_substr(bb, 2, 4),
    col_red(paste0(
      "\U0001f477\U0001f3fc\u200d\u2642\ufe0f",
      "\U0001f477\U0001f3fd\u200d\u2640\ufe0f",
      "\U0001f477"
    ))
  )
})

test_that("ansi_grep", {
  withr::local_options(cli.num_colors = 256, cli.hyperlink = TRUE)
  red_needle <- col_red("needle")
  haystack <- c("foo", "needle", "foo")
  green_haystack <- col_green(haystack)
  expect_equal(
    ansi_grep(red_needle, green_haystack),
    2L
  )
  expect_equal(
    ansi_grep(red_needle, haystack),
    2L
  )
  expect_equal(
    ansi_grep(red_needle, green_haystack, value = TRUE),
    ansi_string(green_haystack[2])
  )
  expect_equal(
    ansi_grep("nope", haystack),
    integer()
  )
  expect_equal(
    ansi_grep("nope", haystack, value = TRUE),
    ansi_string(character())
  )
  expect_equal(
    ansi_grep("nope", character()),
    integer()
  )
  expect_equal(
    ansi_grep("nope", character(), value = TRUE),
    ansi_string(character())
  )
})

test_that("ansi_grepl", {
  withr::local_options(cli.num_colors = 256, cli.hyperlink = TRUE)
  red_needle <- col_red("needle")
  haystack <- c("foo", "needle", "foo")
  green_haystack <- col_green(haystack)
  expect_equal(
    ansi_grepl(red_needle, green_haystack),
    c(FALSE, TRUE, FALSE)
  )
  expect_equal(
    ansi_grepl(red_needle, haystack),
    c(FALSE, TRUE, FALSE)
  )
  expect_equal(
    ansi_grepl("nope", haystack),
    c(FALSE, FALSE, FALSE)
  )
  expect_equal(
    ansi_grepl("nope", character()),
    logical()
  )
})

test_that("ansi_nzchar", {
  withr::local_options(cli.num_colors = 256, cli.hyperlink = TRUE)

  expect_equal(ansi_nzchar(""), FALSE)
  expect_equal(ansi_nzchar(c("", "")), c(FALSE, FALSE))
  expect_equal(ansi_nzchar(c("", "yes")), c(FALSE, TRUE))
  expect_equal(ansi_nzchar(c("yes", "")), c(TRUE, FALSE))
  expect_equal(ansi_nzchar(c("yes", "yes")), c(TRUE, TRUE))

  expect_equal(ansi_nzchar(col_red("")), FALSE)
  expect_equal(ansi_nzchar(col_red(c("", ""))), c(FALSE, FALSE))
  expect_equal(ansi_nzchar(col_red(c("", "yes"))), c(FALSE, TRUE))
  expect_equal(ansi_nzchar(col_red(c("yes", ""))), c(TRUE, FALSE))
  expect_equal(ansi_nzchar(col_red(c("yes", "yes"))), c(TRUE, TRUE))

  expect_equal(ansi_nzchar(style_hyperlink("text", "https://x.xom")), TRUE)
  expect_equal(ansi_nzchar(style_hyperlink("", "https://x.xom")), FALSE)

  expect_equal(ansi_nzchar(NA), nzchar(NA))
  expect_equal(ansi_nzchar(NA, keepNA = TRUE), nzchar(NA, keepNA = TRUE))
})
