skip_if_not_installed("sandwich")
skip_on_cran()

# standard errors -------------------------------------
test_that("robust-se glm warn with profile-CI", {
  mglm <- glm(mpg ~ wt, data = mtcars)
  expect_message(
    ci(mglm, vcov = "HC3"),
    regex = "available"
  )
  expect_message(
    model_parameters(mglm, vcov = "HC3", ci_method = "profile"),
    regex = "modifies"
  )
})


# standard errors -------------------------------------
test_that("robust-se lm", {
  m <- lm(Petal.Length ~ Sepal.Length * Species, data = iris)
  se1 <- standard_error(m, vcov = "HC")
  se2 <- sqrt(diag(sandwich::vcovHC(m)))
  expect_equal(se1$SE, se2, tolerance = 1e-4, ignore_attr = TRUE)
})

test_that("robust-se polr", {
  skip_if_not_installed("MASS")
  data(housing, package = "MASS")
  m <- MASS::polr(Sat ~ Infl + Type + Cont, weights = Freq, data = housing)
  se1 <- standard_error(m, vcov = "vcovCL")
  se2 <- sqrt(diag(sandwich::vcovCL(m)))
  expect_equal(se1$SE, se2, tolerance = 1e-4, ignore_attr = TRUE)

  se1 <- standard_error(m, vcov = "vcovOPG")
  se2 <- sqrt(diag(sandwich::vcovOPG(m)))
  expect_equal(se1$SE, se2, tolerance = 1e-4, ignore_attr = TRUE)
})


test_that("robust-se zeroinfl", {
  skip_if_not_installed("pscl")
  skip_if_not_installed("clubSandwich")
  data("bioChemists", package = "pscl")
  m <- pscl::zeroinfl(art ~ fem + mar + kid5 + ment | kid5 + phd, data = bioChemists)
  se1 <- standard_error(m, vcov = "vcovCL")
  se2 <- sqrt(diag(sandwich::vcovCL(m)))
  expect_equal(se1$SE, se2, tolerance = 1e-4, ignore_attr = TRUE)

  se1 <- standard_error(m, vcov = "vcovOPG")
  se2 <- sqrt(diag(sandwich::vcovOPG(m)))
  expect_equal(se1$SE, se2, tolerance = 1e-4, ignore_attr = TRUE)
})

test_that("robust-se ivreg", {
  skip_if_not_installed("AER")
  skip_if_not_installed("clubSandwich")
  data(CigarettesSW, package = "AER")
  CigarettesSW$rprice <- with(CigarettesSW, price / cpi)
  CigarettesSW$rincome <- with(CigarettesSW, income / population / cpi)
  CigarettesSW$tdiff <- with(CigarettesSW, (taxs - tax) / cpi)

  m <- AER::ivreg(
    log(packs) ~ log(rprice) + log(rincome) | log(rincome) + tdiff + I(tax / cpi),
    data = CigarettesSW,
    subset = year == "1995"
  )

  se1 <- standard_error(m, vcov = "vcovCL")
  se2 <- sqrt(diag(sandwich::vcovCL(m)))
  expect_equal(se1$SE, se2, tolerance = 1e-4, ignore_attr = TRUE)

  se1 <- standard_error(m, vcov = "vcovOPG")
  se2 <- sqrt(diag(sandwich::vcovOPG(m)))
  expect_equal(se1$SE, se2, tolerance = 1e-4, ignore_attr = TRUE)
})


test_that("robust-se survival", {
  skip_if_not_installed("survival")
  set.seed(123)
  m <- survival::survreg(
    formula = survival::Surv(futime, fustat) ~ ecog.ps + rx,
    data = survival::ovarian,
    dist = "logistic"
  )

  se1 <- standard_error(m, vcov = "vcovOPG")
  se2 <- sqrt(diag(sandwich::vcovOPG(m)))
  expect_equal(se1$SE, se2, tolerance = 1e-4, ignore_attr = TRUE)
})




# p-values -------------------------------------

test_that("robust-p lm", {
  m <- lm(Petal.Length ~ Sepal.Length * Species, data = iris)
  p1 <- p_value(m, vcov = "HC")
  # robust p manually
  se <- sqrt(diag(sandwich::vcovHC(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  stat <- coef(m) / se
  p2 <- 2 * pt(abs(stat), df = dof, lower.tail = FALSE)
  expect_equal(p1$p, p2, tolerance = 1e-4, ignore_attr = TRUE)
})

test_that("robust-p polr", {
  skip_if_not_installed("MASS")
  data(housing, package = "MASS")
  m <- MASS::polr(Sat ~ Infl + Type + Cont, weights = Freq, data = housing)
  p1 <- p_value(m, vcov = "vcovCL")
  # robust p manually
  se <- sqrt(diag(sandwich::vcovCL(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  stat <- c(m$coefficients, m$zeta) / se
  p2 <- 2 * pt(abs(stat), df = dof, lower.tail = FALSE)
  expect_equal(p1$p, p2, tolerance = 1e-4, ignore_attr = TRUE)

  p1 <- p_value(m, vcov = "vcovOPG")
  # robust p manually
  se <- sqrt(diag(sandwich::vcovOPG(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  stat <- c(m$coefficients, m$zeta) / se
  p2 <- 2 * pt(abs(stat), df = dof, lower.tail = FALSE)
  expect_equal(p1$p, p2, tolerance = 1e-4, ignore_attr = TRUE)
})


test_that("robust-p ivreg", {
  skip_if_not_installed("AER")
  data(CigarettesSW, package = "AER")
  CigarettesSW$rprice <- with(CigarettesSW, price / cpi)
  CigarettesSW$rincome <- with(CigarettesSW, income / population / cpi)
  CigarettesSW$tdiff <- with(CigarettesSW, (taxs - tax) / cpi)

  m <- AER::ivreg(
    log(packs) ~ log(rprice) + log(rincome) | log(rincome) + tdiff + I(tax / cpi),
    data = CigarettesSW,
    subset = year == "1995"
  )
  p1 <- p_value(m, vcov = "vcovCL")
  # robust p manually
  se <- sqrt(diag(sandwich::vcovCL(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  stat <- coef(m) / se
  p2 <- 2 * pt(abs(stat), df = dof, lower.tail = FALSE)
  expect_equal(p1$p, p2, tolerance = 1e-4, ignore_attr = TRUE)

  p1 <- p_value(m, vcov = "vcovOPG")
  # robust p manually
  se <- sqrt(diag(sandwich::vcovOPG(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  stat <- coef(m) / se
  p2 <- 2 * pt(abs(stat), df = dof, lower.tail = FALSE)
  expect_equal(p1$p, p2, tolerance = 1e-4, ignore_attr = TRUE)
})


test_that("robust-p zeroinfl", {
  skip_if_not_installed("pscl")

  data("bioChemists", package = "pscl")
  m <- pscl::zeroinfl(art ~ fem + mar + kid5 + ment | kid5 + phd, data = bioChemists)

  p1 <- p_value(m, vcov = "vcovCL")
  # robust p manually
  se <- sqrt(diag(sandwich::vcovCL(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  stat <- coef(m) / se
  p2 <- 2 * pt(abs(stat), df = dof, lower.tail = FALSE)
  expect_equal(p1$p, p2, tolerance = 1e-4, ignore_attr = TRUE)

  p1 <- p_value(m, vcov = "vcovOPG")
  # robust p manually
  se <- sqrt(diag(sandwich::vcovOPG(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  stat <- coef(m) / se
  p2 <- 2 * pt(abs(stat), df = dof, lower.tail = FALSE)
  expect_equal(p1$p, p2, tolerance = 1e-4, ignore_attr = TRUE)
})


test_that("robust-p survival", {
  skip_if_not_installed("survival")

  set.seed(123)
  m <- survival::survreg(
    formula = survival::Surv(futime, fustat) ~ ecog.ps + rx,
    data = survival::ovarian,
    dist = "logistic"
  )
  p1 <- p_value(m, vcov = "vcovOPG")
  # robust p manually
  se <- sqrt(diag(sandwich::vcovOPG(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  stat <- insight::get_parameters(m)$Estimate / se
  p2 <- 2 * pt(abs(stat), df = dof, lower.tail = FALSE)
  expect_equal(p1$p, p2, tolerance = 1e-4, ignore_attr = TRUE)
})




# CI -------------------------------------


test_that("robust-ci lm", {
  data(iris)
  m <- lm(Petal.Length ~ Sepal.Length * Species, data = iris)
  ci1 <- ci(m, vcov = "HC")
  # robust CI manually
  params <- insight::get_parameters(m)
  se <- sqrt(diag(sandwich::vcovHC(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  fac <- suppressWarnings(stats::qt(0.975, df = dof))
  ci2 <- as.data.frame(cbind(
    CI_low = params$Estimate - se * fac,
    CI_high = params$Estimate + se * fac
  ))
  expect_equal(ci1$CI_low, ci2$CI_low, tolerance = 1e-4, ignore_attr = TRUE)
  expect_equal(ci1$CI_high, ci2$CI_high, tolerance = 1e-4, ignore_attr = TRUE)
})


test_that("robust-ci polr", {
  skip_if_not_installed("MASS")
  data(housing, package = "MASS")
  m <- MASS::polr(Sat ~ Infl + Type + Cont, weights = Freq, data = housing)
  ci1 <- ci(m, vcov = "vcovCL")
  # robust CI manually
  se <- sqrt(diag(sandwich::vcovCL(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  fac <- suppressWarnings(stats::qt(0.975, df = dof))
  ci2 <- as.data.frame(cbind(
    CI_low = c(m$coefficients, m$zeta) - se * fac,
    CI_high = c(m$coefficients, m$zeta) + se * fac
  ))
  expect_equal(ci1$CI_low, ci2$CI_low, tolerance = 1e-4, ignore_attr = TRUE)
  expect_equal(ci1$CI_high, ci2$CI_high, tolerance = 1e-4, ignore_attr = TRUE)

  ci1 <- ci(m, vcov = "vcovOPG")
  # robust CI manually
  se <- sqrt(diag(sandwich::vcovOPG(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  fac <- suppressWarnings(stats::qt(0.975, df = dof))
  ci2 <- as.data.frame(cbind(
    CI_low = c(m$coefficients, m$zeta) - se * fac,
    CI_high = c(m$coefficients, m$zeta) + se * fac
  ))
  expect_equal(ci1$CI_low, ci2$CI_low, tolerance = 1e-4, ignore_attr = TRUE)
  expect_equal(ci1$CI_high, ci2$CI_high, tolerance = 1e-4, ignore_attr = TRUE)
})


test_that("robust-ci ivreg", {
  skip_if_not_installed("AER")
  data(CigarettesSW, package = "AER")
  CigarettesSW$rprice <- with(CigarettesSW, price / cpi)
  CigarettesSW$rincome <- with(CigarettesSW, income / population / cpi)
  CigarettesSW$tdiff <- with(CigarettesSW, (taxs - tax) / cpi)

  m <- AER::ivreg(
    log(packs) ~ log(rprice) + log(rincome) | log(rincome) + tdiff + I(tax / cpi),
    data = CigarettesSW,
    subset = year == "1995"
  )
  ci1 <- ci(m, vcov = "vcovCL")
  # robust CI manually
  se <- sqrt(diag(sandwich::vcovCL(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  fac <- suppressWarnings(stats::qt(0.975, df = dof))
  ci2 <- as.data.frame(cbind(
    CI_low = coef(m) - se * fac,
    CI_high = coef(m) + se * fac
  ))
  expect_equal(ci1$CI_low, ci2$CI_low, tolerance = 1e-4, ignore_attr = TRUE)
  expect_equal(ci1$CI_high, ci2$CI_high, tolerance = 1e-4, ignore_attr = TRUE)

  ci1 <- ci(m, vcov = "vcovOPG")
  # robust CI manually
  se <- sqrt(diag(sandwich::vcovOPG(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  fac <- suppressWarnings(stats::qt(0.975, df = dof))
  ci2 <- as.data.frame(cbind(
    CI_low = coef(m) - se * fac,
    CI_high = coef(m) + se * fac
  ))
  expect_equal(ci1$CI_low, ci2$CI_low, tolerance = 1e-4, ignore_attr = TRUE)
  expect_equal(ci1$CI_high, ci2$CI_high, tolerance = 1e-4, ignore_attr = TRUE)
})


test_that("robust-ci zeroinfl", {
  skip_if_not_installed("pscl")
  data("bioChemists", package = "pscl")
  m <- pscl::zeroinfl(art ~ fem + mar + kid5 + ment | kid5 + phd, data = bioChemists)
  ci1 <- ci(m, vcov = "vcovCL")
  # robust CI manually
  se <- sqrt(diag(sandwich::vcovCL(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  fac <- suppressWarnings(stats::qt(0.975, df = dof))
  ci2 <- as.data.frame(cbind(
    CI_low = coef(m) - se * fac,
    CI_high = coef(m) + se * fac
  ))
  expect_equal(ci1$CI_low, ci2$CI_low, tolerance = 1e-4, ignore_attr = TRUE)
  expect_equal(ci1$CI_high, ci2$CI_high, tolerance = 1e-4, ignore_attr = TRUE)

  ci1 <- ci(m, vcov = "vcovOPG")
  # robust CI manually
  se <- sqrt(diag(sandwich::vcovOPG(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  fac <- suppressWarnings(stats::qt(0.975, df = dof))
  ci2 <- as.data.frame(cbind(
    CI_low = coef(m) - se * fac,
    CI_high = coef(m) + se * fac
  ))
  expect_equal(ci1$CI_low, ci2$CI_low, tolerance = 1e-4, ignore_attr = TRUE)
  expect_equal(ci1$CI_high, ci2$CI_high, tolerance = 1e-4, ignore_attr = TRUE)
})


test_that("robust-ci survival", {
  skip_if_not_installed("survival")
  set.seed(123)
  m <- survival::survreg(
    formula = survival::Surv(futime, fustat) ~ ecog.ps + rx,
    data = survival::ovarian,
    dist = "logistic"
  )

  ci1 <- ci(m, vcov = "vcovOPG")
  # robust CI manually
  se <- sqrt(diag(sandwich::vcovOPG(m)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  fac <- suppressWarnings(stats::qt(0.975, df = dof))
  ci2 <- as.data.frame(cbind(
    CI_low = insight::get_parameters(m)$Estimate - se * fac,
    CI_high = insight::get_parameters(m)$Estimate + se * fac
  ))
  expect_equal(ci1$CI_low, ci2$CI_low, tolerance = 1e-4, ignore_attr = TRUE)
  expect_equal(ci1$CI_high, ci2$CI_high, tolerance = 1e-4, ignore_attr = TRUE)
})




# mixed models ----------------------

skip_if_not_installed("clubSandwich")
skip_if_not_installed("lme4")

test_that("robust-se lmer", {
  data(iris)
  set.seed(1234)
  iris$grp <- as.factor(sample(1:3, nrow(iris), replace = TRUE))

  m <- lme4::lmer(
    Sepal.Length ~ Species * Sepal.Width + Petal.Length + (1 | grp),
    data = iris
  )
  se1 <- standard_error(m, vcov = "vcovCR", vcov_args = list(type = "CR1", cluster = iris$grp))
  se2 <- sqrt(diag(clubSandwich::vcovCR(m, type = "CR1", cluster = iris$grp)))
  expect_equal(se1$SE, se2, tolerance = 1e-4, ignore_attr = TRUE)
})

test_that("robust-p lmer", {
  data(iris)
  set.seed(1234)
  iris$grp <- as.factor(sample(1:3, nrow(iris), replace = TRUE))

  m <- lme4::lmer(
    Sepal.Length ~ Species * Sepal.Width + Petal.Length + (1 | grp),
    data = iris
  )
  p1 <- p_value(m, vcov = "vcovCR", vcov_args = list(type = "CR1", cluster = iris$grp))
  se <- sqrt(diag(clubSandwich::vcovCR(m, type = "CR1", cluster = iris$grp)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  stat <- lme4::fixef(m) / se
  p2 <- 2 * pt(abs(stat), df = dof, lower.tail = FALSE)
  expect_equal(p1$p, p2, tolerance = 1e-4, ignore_attr = TRUE)
})

test_that("robust-ci lmer", {
  data(iris)
  set.seed(1234)
  iris$grp <- as.factor(sample(1:3, nrow(iris), replace = TRUE))

  m <- lme4::lmer(
    Sepal.Length ~ Species * Sepal.Width + Petal.Length + (1 | grp),
    data = iris
  )
  ci1 <- ci(m, vcov = "vcovCR", vcov_args = list(type = "CR1", cluster = iris$grp))
  # robust CI manually
  params <- insight::get_parameters(m)
  se <- sqrt(diag(clubSandwich::vcovCR(m, type = "CR1", cluster = iris$grp)))
  dof <- degrees_of_freedom(m, method = "wald", verbose = FALSE)
  fac <- suppressWarnings(stats::qt(0.975, df = dof))
  ci2 <- as.data.frame(cbind(
    CI_low = params$Estimate - se * fac,
    CI_high = params$Estimate + se * fac
  ))
  expect_equal(ci1$CI_low, ci2$CI_low, tolerance = 1e-4, ignore_attr = TRUE)
  expect_equal(ci1$CI_high, ci2$CI_high, tolerance = 1e-4, ignore_attr = TRUE)
})
