test_that("strings mapped to levels", {
  test_vroom(
    "a\nb\n",
    col_names = FALSE,
    col_types = list(X1 = col_factor(levels = c("a", "b"))),
    equals = tibble::tibble(X1 = factor(c("a", "b")))
  )
})

test_that("can generate ordered factor", {
  res <- test_vroom(
    "a\nb\n",
    col_names = FALSE,
    col_types = list(X1 = col_factor(levels = c("a", "b"), ordered = TRUE)),
    equals = tibble::tibble(X1 = ordered(c("a", "b")))
  )

  expect_true(is.ordered(res$X1))
})

test_that("NA if value not in levels", {
  test_vroom(
    "a\nb\nc\n",
    col_names = FALSE,
    col_types = list(X1 = col_factor(levels = c("a", "b"))),
    equals = tibble::tibble(X1 = factor(c("a", "b", NA)))
  )
})

test_that("NAs silently passed along", {
  test_vroom(
    "a\nb\nNA\n",
    col_names = FALSE,
    col_types = list(X1 = col_factor(levels = c("a", "b"), include_na = FALSE)),
    equals = tibble::tibble(X1 = factor(c("a", "b", NA)))
  )
})

test_that("levels = NULL", {
  test_vroom(
    "a\nb\nc\nb\n",
    col_names = FALSE,
    col_types = list(X1 = col_factor(levels = NULL)),
    equals = tibble::tibble(X1 = factor(c("a", "b", "c", "b")))
  )
})

test_that("levels = NULL orders by data", {
  test_vroom(
    "b\na\nc\nb\n",
    col_names = FALSE,
    col_types = list(X1 = col_factor(levels = NULL)),
    equals = tibble::tibble(
      X1 = factor(c("b", "a", "c", "b"), levels = c("b", "a", "c"))
    )
  )
})

test_that("levels = NULL is the default", {
  test_vroom(
    "a\nb\nc\nd\n",
    col_names = FALSE,
    col_types = list(X1 = "f"),
    equals = tibble::tibble(X1 = factor(c("a", "b", "c", "d")))
  )
})

test_that("NAs included in levels if desired", {
  test_vroom(
    "NA\nb\na\n",
    col_names = FALSE,
    col_types = list(X1 = col_factor(levels = c("a", "b", NA))),
    equals = tibble::tibble(
      X1 = factor(c(NA, "b", "a"), levels = c("a", "b", NA), exclude = NULL)
    )
  )

  test_vroom(
    "NA\nb\na\n",
    col_names = FALSE,
    col_types = list(
      X1 = col_factor(levels = c("a", "b", NA), include_na = TRUE)
    ),
    equals = tibble::tibble(
      X1 = factor(c(NA, "b", "a"), levels = c("a", "b", NA), exclude = NULL)
    )
  )

  test_vroom(
    "NA\nb\na\n",
    col_names = FALSE,
    col_types = list(X1 = col_factor(levels = NULL, include_na = FALSE)),
    equals = tibble::tibble(X1 = factor(c(NA, "b", "a"), levels = c("b", "a")))
  )

  test_vroom(
    "NA\nb\na\n",
    col_names = FALSE,
    col_types = list(X1 = col_factor(levels = NULL, include_na = TRUE)),
    equals = tibble::tibble(
      X1 = factor(c(NA, "b", "a"), levels = c(NA, "b", "a"), exclude = NULL)
    )
  )
})

test_that("Factors handle encodings properly (#615)", {
  encoded <- function(x, encoding) {
    Encoding(x) <- encoding
    x
  }
  f <- tempfile()
  on.exit(unlink(f))
  writeBin(charToRaw(encoded("test\nA\n\xC4\n", "latin1")), f)
  x <- test_vroom(
    f,
    delim = ",",
    col_types = cols(col_factor(c("A", "\uC4"))),
    locale = locale(encoding = "latin1"),
    equals = tibble::tibble(
      test = factor(c("A", "\uC4"), levels = c("A", "\uC4"))
    )
  )
})

test_that("factors parse like factor if trim_ws = FALSE", {
  test_vroom(
    "a\na \n",
    col_names = FALSE,
    trim_ws = FALSE,
    col_types = list(X1 = col_factor(levels = "a")),
    equals = tibble::tibble(X1 = factor(c("a", "a "), levels = c("a")))
  )
  test_vroom(
    "a\na \n",
    col_names = FALSE,
    trim_ws = FALSE,
    col_types = list(X1 = col_factor(levels = "a ")),
    equals = tibble::tibble(X1 = factor(c("a", "a "), levels = c("a ")))
  )
  test_vroom(
    "a\na \n",
    col_names = FALSE,
    trim_ws = FALSE,
    col_types = list(X1 = col_factor(levels = c("a ", "a"))),
    equals = tibble::tibble(X1 = factor(c("a", "a "), levels = c("a ", "a")))
  )
})

test_that("Can parse a factor with levels of NA and empty string", {
  x <- c(
    "NC",
    "NC",
    "NC",
    "",
    "",
    "NB",
    "NA",
    "",
    "",
    "NB",
    "NA",
    "NA",
    "NC",
    "NB",
    "NB",
    "NC",
    "NB",
    "NA",
    "NA"
  )

  x_in <- paste0(paste(x, collapse = "\n"), "\n")

  test_vroom(
    x_in,
    col_names = FALSE,
    col_types = list(X1 = col_factor(levels = c("NA", "NB", "NC", ""))),
    na = character(),
    skip_empty_rows = FALSE,
    equals = tibble::tibble(X1 = factor(x, levels = c("NA", "NB", "NC", "")))
  )
})


test_that("encodings are respected", {
  loc <- locale(encoding = "ISO-8859-1")
  expected <- c("fran\u00e7ais", "\u00e9l\u00e8ve")

  x <- vroom(
    test_path("enc-iso-8859-1.txt"),
    delim = "\n",
    locale = loc,
    col_types = c(X1 = "f"),
    col_names = FALSE
  )
  expect_equal(x[[1]], factor(expected, levels = expected))

  y <- vroom(
    test_path("enc-iso-8859-1.txt"),
    delim = "\n",
    locale = loc,
    col_types = list(X1 = col_factor(levels = expected)),
    col_names = FALSE
  )

  expect_equal(y[[1]], factor(expected, levels = expected))
})

test_that("Results are correct with backslash escapes", {
  obj <- vroom(
    I("A,T\nB,F\n"),
    col_names = FALSE,
    col_types = list("f", "f"),
    escape_backslash = TRUE
  )
  exp <- tibble::tibble(
    X1 = factor(c("A", "B")),
    X2 = factor(c("T", "F"), levels = c("T", "F"))
  )
  expect_equal(obj, exp)

  obj2 <- vroom(
    I("A,T\nB,F\n"),
    col_names = FALSE,
    col_types = list("f", "f"),
    escape_backslash = FALSE
  )
  expect_equal(obj2, exp)
})


test_that("subsetting works with both double and integer indexes", {
  x <- vroom(I("X1\nfoo"), delim = ",", col_types = "f")
  expect_equal(x$X1[1L], factor("foo"))
  expect_equal(x$X1[1], factor("foo"))
  expect_equal(x$X1[NA_integer_], factor(NA_character_, levels = "foo"))
  expect_equal(x$X1[NA_real_], factor(NA_character_, levels = "foo"))
})

test_that("results are correct even with quoted values", {
  expect_equal(
    vroom(
      I('day\n"Sun"\n"Sat"\n"Sat"'),
      altrep = FALSE,
      col_types = "f",
      delim = ","
    )$day,
    factor(c("Sun", "Sat", "Sat"), levels = c("Sun", "Sat"))
  )
})

test_that("NAs are correctly encoded and not included in levels unless desired", {
  test_vroom(
    "X\nunknown\nb\na\n",
    col_types = list(X = col_factor(levels = NULL, include_na = FALSE)),
    na = "unknown",
    equals = tibble::tibble(
      X = factor(c(NA, "b", "a"), levels = c("b", "a"), exclude = NULL)
    )
  )
  test_vroom(
    "X\nunknown\nb\na\nmissing\n",
    col_types = list(X = col_factor(levels = NULL, include_na = FALSE)),
    na = c("unknown", "missing"),
    equals = tibble::tibble(
      X = factor(c(NA, "b", "a", NA), levels = c("b", "a"), exclude = NULL)
    )
  )
  test_vroom(
    "X\nunknown\nb\na\n",
    col_types = list(X = col_factor(levels = NULL, include_na = TRUE)),
    na = "unknown",
    equals = tibble::tibble(
      X = factor(c(NA, "b", "a"), levels = c(NA, "b", "a"), exclude = NULL)
    )
  )
  test_vroom(
    "X\nunknown\nb\na\nmissing\n",
    col_types = list(X = col_factor(levels = NULL, include_na = TRUE)),
    na = c("unknown", "missing"),
    equals = tibble::tibble(
      X = factor(c(NA, "b", "a", NA), levels = c(NA, "b", "a"), exclude = NULL)
    )
  )
})
