library(testthat)
library(DataAudit)

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

test_that("infinite_check returns InfiniteCheck object", {

  result <- infinite_check(iris)

  expect_s3_class(
    result,
    "InfiniteCheck"
  )

})

test_that("infinite_check returns data.frame", {

  result <- infinite_check(iris)

  expect_s3_class(
    result,
    "data.frame"
  )

})

test_that("infinite_check contains expected columns", {

  result <- infinite_check(iris)

  expect_equal(
    names(result),
    c(
      "Variable",
      "Numeric",
      "PositiveInf",
      "NegativeInf",
      "Infinite",
      "HasInfinite"
    )
  )

})

test_that("infinite_check returns one row per variable", {

  result <- infinite_check(iris)

  expect_equal(
    nrow(result),
    ncol(iris)
  )

})


#==========================================================
# Data without infinite values
#==========================================================

test_that("infinite_check reports no infinity for iris", {

  result <- infinite_check(iris)

  expect_true(
    all(result$Infinite == 0L)
  )

  expect_false(
    any(result$HasInfinite)
  )

})


#==========================================================
# Positive infinity
#==========================================================

test_that("infinite_check detects positive infinity", {

  dat <- data.frame(
    x = c(
      1,
      2,
      Inf,
      4
    )
  )

  result <- infinite_check(dat)

  expect_equal(
    result$PositiveInf,
    1L
  )

  expect_equal(
    result$NegativeInf,
    0L
  )

  expect_equal(
    result$Infinite,
    1L
  )

  expect_true(
    result$HasInfinite
  )

})


#==========================================================
# Negative infinity
#==========================================================

test_that("infinite_check detects negative infinity", {

  dat <- data.frame(
    x = c(
      1,
      -Inf,
      3,
      4
    )
  )

  result <- infinite_check(dat)

  expect_equal(
    result$PositiveInf,
    0L
  )

  expect_equal(
    result$NegativeInf,
    1L
  )

  expect_equal(
    result$Infinite,
    1L
  )

  expect_true(
    result$HasInfinite
  )

})


#==========================================================
# Positive and negative infinity
#==========================================================

test_that("infinite_check detects both infinity types", {

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

  result <- infinite_check(dat)

  expect_equal(
    result$PositiveInf,
    2L
  )

  expect_equal(
    result$NegativeInf,
    2L
  )

  expect_equal(
    result$Infinite,
    4L
  )

  expect_true(
    result$HasInfinite
  )

})


#==========================================================
# Multiple variables
#==========================================================

test_that("infinite_check handles multiple numeric variables", {

  dat <- data.frame(
    x = c(1, Inf, 3),
    y = c(-Inf, 2, 3),
    z = c(1, 2, 3)
  )

  result <- infinite_check(dat)

  expect_equal(
    result$PositiveInf,
    c(
      1L,
      0L,
      0L
    )
  )

  expect_equal(
    result$NegativeInf,
    c(
      0L,
      1L,
      0L
    )
  )

  expect_equal(
    result$Infinite,
    c(
      1L,
      1L,
      0L
    )
  )

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

})


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

test_that("infinite_check does not classify NA as infinite", {

  dat <- data.frame(
    x = c(
      1,
      NA,
      3,
      4
    )
  )

  result <- infinite_check(dat)

  expect_equal(
    result$Infinite,
    0L
  )

  expect_false(
    result$HasInfinite
  )

})

test_that("infinite_check handles NA and infinity together", {

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

  result <- infinite_check(dat)

  expect_equal(
    result$PositiveInf,
    1L
  )

  expect_equal(
    result$NegativeInf,
    1L
  )

  expect_equal(
    result$Infinite,
    2L
  )

})


#==========================================================
# Numeric classification
#==========================================================

test_that("infinite_check identifies numeric variables", {

  dat <- data.frame(
    x = 1:5,
    y = letters[1:5],
    stringsAsFactors = FALSE
  )

  result <- infinite_check(dat)

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

})


#==========================================================
# Character variables
#==========================================================

test_that("infinite_check handles character variables", {

  dat <- data.frame(
    x = c(
      "Inf",
      "-Inf",
      "A"
    ),
    stringsAsFactors = FALSE
  )

  result <- infinite_check(dat)

  expect_false(
    result$Numeric
  )

  expect_equal(
    result$PositiveInf,
    0L
  )

  expect_equal(
    result$NegativeInf,
    0L
  )

  expect_equal(
    result$Infinite,
    0L
  )

  expect_false(
    result$HasInfinite
  )

})


#==========================================================
# Factor variables
#==========================================================

test_that("infinite_check handles factors", {

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

  result <- infinite_check(dat)

  expect_false(
    result$Numeric
  )

  expect_equal(
    result$Infinite,
    0L
  )

})


#==========================================================
# Logical variables
#==========================================================

test_that("infinite_check handles logical variables", {

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

  result <- infinite_check(dat)

  expect_false(
    result$Numeric
  )

  expect_equal(
    result$Infinite,
    0L
  )

})


#==========================================================
# Date variables
#==========================================================

test_that("infinite_check handles Date variables", {

  dat <- data.frame(
    x = as.Date("2026-01-01") + 0:4
  )

  result <- infinite_check(dat)

  expect_false(
    result$Numeric
  )

  expect_equal(
    result$Infinite,
    0L
  )

})


#==========================================================
# POSIXct variables
#==========================================================

test_that("infinite_check handles POSIXct variables", {

  dat <- data.frame(
    x = as.POSIXct(
      "2026-01-01 10:00:00",
      tz = "UTC"
    ) + 0:4
  )

  result <- infinite_check(dat)

  expect_false(
    result$Numeric
  )

  expect_equal(
    result$Infinite,
    0L
  )

})


#==========================================================
# Mixed data
#==========================================================

test_that("infinite_check handles mixed data", {

  dat <- data.frame(
    numeric = c(
      1,
      Inf,
      -Inf
    ),
    character = c(
      "A",
      "Inf",
      "B"
    ),
    factor = factor(
      c(
        "A",
        "B",
        "C"
      )
    ),
    logical = c(
      TRUE,
      FALSE,
      TRUE
    ),
    stringsAsFactors = FALSE
  )

  result <- infinite_check(dat)

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

  expect_equal(
    result$Infinite,
    c(
      2L,
      0L,
      0L,
      0L
    )
  )

})


#==========================================================
# All infinite
#==========================================================

test_that("infinite_check handles all-infinite variable", {

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

  result <- infinite_check(dat)

  expect_equal(
    result$PositiveInf,
    2L
  )

  expect_equal(
    result$NegativeInf,
    2L
  )

  expect_equal(
    result$Infinite,
    4L
  )

  expect_true(
    result$HasInfinite
  )

})


#==========================================================
# One-column data
#==========================================================

test_that("infinite_check works with one-column data", {

  dat <- data.frame(
    x = c(
      1,
      Inf,
      3
    )
  )

  result <- infinite_check(dat)

  expect_equal(
    nrow(result),
    1L
  )

  expect_equal(
    result$Variable,
    "x"
  )

  expect_equal(
    result$Infinite,
    1L
  )

})


#==========================================================
# Zero-row data
#==========================================================

test_that("infinite_check handles zero-row data", {

  dat <- data.frame(
    x = numeric(0),
    y = character(0)
  )

  result <- infinite_check(dat)

  expect_s3_class(
    result,
    "InfiniteCheck"
  )

  expect_equal(
    nrow(result),
    2L
  )

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

  expect_equal(
    result$Infinite,
    c(
      0L,
      0L
    )
  )

  expect_false(
    any(result$HasInfinite)
  )

})


#==========================================================
# Tibble
#==========================================================

test_that("infinite_check handles tibble", {

  skip_if_not_installed("tibble")

  dat <- tibble::tibble(
    x = c(
      1,
      Inf,
      -Inf
    ),
    y = c(
      "A",
      "B",
      "C"
    )
  )

  result <- infinite_check(dat)

  expect_s3_class(
    result,
    "InfiniteCheck"
  )

  expect_equal(
    result$Infinite,
    c(
      2L,
      0L
    )
  )

})


#==========================================================
# Variable names
#==========================================================

test_that("infinite_check preserves variable names", {

  dat <- data.frame(
    Weight = c(10, Inf, 20),
    Temperature = c(38, 39, 40)
  )

  result <- infinite_check(dat)

  expect_equal(
    result$Variable,
    c(
      "Weight",
      "Temperature"
    )
  )

})


#==========================================================
# Invalid input
#==========================================================

test_that("infinite_check rejects NULL", {

  expect_error(
    infinite_check(NULL),
    "'data' cannot be NULL"
  )

})

test_that("infinite_check rejects numeric vector", {

  expect_error(
    infinite_check(1:10),
    "'data' must be a data.frame"
  )

})

test_that("infinite_check rejects character vector", {

  expect_error(
    infinite_check(letters),
    "'data' must be a data.frame"
  )

})

test_that("infinite_check rejects list", {

  expect_error(
    infinite_check(
      list(
        x = 1:5,
        y = 6:10
      )
    ),
    "'data' must be a data.frame"
  )

})

test_that("infinite_check rejects data.frame without variables", {

  expect_error(
    infinite_check(
      data.frame()
    ),
    "at least one variable"
  )

})
