library(testthat)
library(DataAudit)

#==========================================================
# Basic output
#==========================================================

test_that("whitespace_check returns WhitespaceCheck", {

  dat <- data.frame(
    x = c("Dog", "Cat")
  )

  result <- whitespace_check(
    dat,
    "x"
  )

  expect_s3_class(
    result,
    "WhitespaceCheck"
  )

  expect_s3_class(
    result,
    "data.frame"
  )
})

test_that("whitespace_check returns expected columns", {

  dat <- data.frame(
    x = c("Dog", "Cat")
  )

  result <- whitespace_check(
    dat,
    "x"
  )

  expect_equal(
    names(result),
    c(
      "Row",
      "Value",
      "Missing",
      "LeadingWhitespace",
      "TrailingWhitespace",
      "WhitespaceOnly",
      "WhitespaceIssue"
    )
  )
})

#==========================================================
# Detection
#==========================================================

test_that("whitespace_check detects leading whitespace", {

  dat <- data.frame(
    x = c("Dog", " Cat", "  Cattle")
  )

  result <- whitespace_check(
    dat,
    "x"
  )

  expect_equal(
    result$LeadingWhitespace,
    c(FALSE, TRUE, TRUE)
  )
})

test_that("whitespace_check detects trailing whitespace", {

  dat <- data.frame(
    x = c("Dog", "Cat ", "Cattle  ")
  )

  result <- whitespace_check(
    dat,
    "x"
  )

  expect_equal(
    result$TrailingWhitespace,
    c(FALSE, TRUE, TRUE)
  )
})

test_that("whitespace_check detects both leading and trailing whitespace", {

  dat <- data.frame(
    x = c(
      "Dog",
      " Cat ",
      " Cattle"
    )
  )

  result <- whitespace_check(
    dat,
    "x"
  )

  expect_equal(
    result$WhitespaceIssue,
    c(FALSE, TRUE, TRUE)
  )

  expect_true(
    result$LeadingWhitespace[2]
  )

  expect_true(
    result$TrailingWhitespace[2]
  )
})

test_that("whitespace_check detects whitespace-only values", {

  dat <- data.frame(
    x = c(
      "Dog",
      " ",
      "   ",
      ""
    )
  )

  result <- whitespace_check(
    dat,
    "x"
  )

  expect_equal(
    result$WhitespaceOnly,
    c(FALSE, TRUE, TRUE, FALSE)
  )
})

test_that("empty string is not whitespace", {

  dat <- data.frame(
    x = c("", " ")
  )

  result <- whitespace_check(
    dat,
    "x"
  )

  expect_false(
    result$WhitespaceIssue[1]
  )

  expect_true(
    result$WhitespaceIssue[2]
  )
})

#==========================================================
# Missing values
#==========================================================

test_that("whitespace_check handles missing values", {

  dat <- data.frame(
    x = c(
      "Dog",
      NA,
      " Cat "
    )
  )

  result <- whitespace_check(
    dat,
    "x"
  )

  expect_equal(
    result$Missing,
    c(FALSE, TRUE, FALSE)
  )

  expect_false(
    result$WhitespaceIssue[2]
  )

  expect_true(
    result$WhitespaceIssue[3]
  )
})

#==========================================================
# Factors
#==========================================================

test_that("whitespace_check works with factors", {

  dat <- data.frame(
    x = factor(
      c(
        "Dog",
        " Cat",
        "Cattle "
      )
    )
  )

  result <- whitespace_check(
    dat,
    "x"
  )

  expect_equal(
    result$WhitespaceIssue,
    c(FALSE, TRUE, TRUE)
  )
})

#==========================================================
# Tabs and newlines
#==========================================================

test_that("whitespace_check detects tabs", {

  dat <- data.frame(
    x = c(
      "Dog",
      "\tCat",
      "Cattle\t"
    )
  )

  result <- whitespace_check(
    dat,
    "x"
  )

  expect_equal(
    result$WhitespaceIssue,
    c(FALSE, TRUE, TRUE)
  )
})

test_that("whitespace_check detects newline whitespace", {

  dat <- data.frame(
    x = c(
      "Dog",
      "\nCat",
      "Cattle\n"
    )
  )

  result <- whitespace_check(
    dat,
    "x"
  )

  expect_equal(
    result$WhitespaceIssue,
    c(FALSE, TRUE, TRUE)
  )
})

#==========================================================
# Valid data
#==========================================================

test_that("clean values are not flagged", {

  dat <- data.frame(
    x = c(
      "Dog",
      "Domestic Cat",
      "Dairy Cattle"
    )
  )

  result <- whitespace_check(
    dat,
    "x"
  )

  expect_false(
    any(result$WhitespaceIssue)
  )
})

#==========================================================
# Invalid variable argument
#==========================================================

test_that("whitespace_check rejects missing variable", {

  expect_error(
    whitespace_check(iris),
    "'variable' must be a single non-empty character string"
  )
})

test_that("whitespace_check rejects NULL variable", {

  expect_error(
    whitespace_check(
      iris,
      NULL
    ),
    "'variable' must be a single non-empty character string"
  )
})

test_that("whitespace_check rejects empty variable name", {

  expect_error(
    whitespace_check(
      iris,
      ""
    ),
    "'variable' must be a single non-empty character string"
  )
})

test_that("whitespace_check rejects numeric variable argument", {

  expect_error(
    whitespace_check(
      iris,
      1
    ),
    "'variable' must be a single non-empty character string"
  )
})

test_that("whitespace_check rejects multiple variable names", {

  expect_error(
    whitespace_check(
      iris,
      c(
        "Species",
        "Sepal.Length"
      )
    ),
    "'variable' must be a single non-empty character string"
  )
})

test_that("whitespace_check rejects NA variable", {

  expect_error(
    whitespace_check(
      iris,
      NA_character_
    ),
    "'variable' must be a single non-empty character string"
  )
})

#==========================================================
# Unknown variable
#==========================================================

test_that("whitespace_check rejects unknown variable", {

  expect_error(
    whitespace_check(
      iris,
      "Unknown"
    ),
    "Variable 'Unknown' was not found in 'data'"
  )
})

#==========================================================
# Invalid variable types
#==========================================================

test_that("whitespace_check rejects numeric column", {

  expect_error(
    whitespace_check(
      iris,
      "Sepal.Length"
    ),
    "'variable' must refer to a character or factor variable"
  )
})

test_that("whitespace_check rejects logical column", {

  dat <- data.frame(
    x = c(
      TRUE,
      FALSE
    )
  )

  expect_error(
    whitespace_check(
      dat,
      "x"
    ),
    "'variable' must refer to a character or factor variable"
  )
})

test_that("whitespace_check rejects Date column", {

  dat <- data.frame(
    x = as.Date(
      c(
        "2026-01-01",
        "2026-01-02"
      )
    )
  )

  expect_error(
    whitespace_check(
      dat,
      "x"
    ),
    "'variable' must refer to a character or factor variable"
  )
})

#==========================================================
# Invalid data
#==========================================================

test_that("whitespace_check rejects invalid data", {

  expect_error(
    whitespace_check(
      NULL,
      "x"
    )
  )

  expect_error(
    whitespace_check(
      1:5,
      "x"
    )
  )

  expect_error(
    whitespace_check(
      list(x = "Dog"),
      "x"
    )
  )

  expect_error(
    whitespace_check(
      data.frame(),
      "x"
    )
  )
})
