context("ANOVAs: structural tests")

test_that("dv is numeric", {
  data(obk.long)
  expect_that(
    aov_car(
      treatment ~ gender + Error(id / phase * hour),
      data = obk.long,
      observed = "gender"
    ),
    throws_error("dv needs to be numeric.")
  )
})

## check_contrast argument disabled, see: https://github.com/singmann/afex/issues/109
# test_that("non Type 3 sums give warning", {
#   data(obk.long)
#   expect_that(aov_4(value ~ treatment * gender + (phase*hour|id), data = obk.long, observed = "gender", check.contrasts = FALSE), gives_warning("contrasts"))
# })

test_that("return='aov' works", {
  data(obk.long)
  data(md_12.1)

  # purely within
  expect_that(
    aov_ez("id", "rt", md_12.1, within = c("angle", "noise"), return = "aov"),
    is_a(c("aovlist", "listof"))
  )
  expect_that(
    aov_car(value ~ Error(id / phase * hour), data = obk.long, return = "aov"),
    is_a(c("aovlist", "listof"))
  )
  #purely between
  expect_that(
    suppressWarnings(aov_car(
      value ~ treatment * gender + Error(id),
      data = obk.long,
      return = "aov"
    )),
    is_a(c("aov"))
  )
  expect_that(
    suppressWarnings(aov_car(
      value ~ treatment * gender + Error(id / phase * hour),
      data = obk.long,
      return = "aov"
    )),
    is_a(c("aovlist", "listof"))
  )

  # terms within Error() are within parentheses:
  test <- summary(aov_car(
    value ~ Error(id / phase * hour),
    data = obk.long,
    return = "aov"
  ))
  positive <- summary(aov(
    value ~ phase * hour + Error(id / (phase * hour)),
    data = obk.long
  ))
  negative <- summary(aov(
    value ~ phase * hour + Error(id / phase * hour),
    data = obk.long
  ))
  expect_equal(test, positive)
  expect_false(isTRUE(all.equal(test, negative, check.attributes = FALSE)))

  orig1 <- aov_car(value ~ Error(id / phase * hour), data = obk.long)
  obk.long$id <- as.numeric(obk.long$id)
  obk.long$phase <- as.numeric(obk.long$phase)
  obk.long$hour <- as.numeric(obk.long$hour)
  positive2 <- summary(aov_car(
    value ~ Error(id / phase * hour),
    data = obk.long,
    return = "aov"
  ))
  expect_equal(test, positive2)
  positive3 <- aov_car(value ~ Error(id / phase * hour), data = obk.long)
  expect_equal(summary(orig1), summary(positive3))
  expect_equal(
    summary(orig1$Anova, multivariate = FALSE),
    summary(positive3$Anova, multivariate = FALSE)
  )
  expect_equal(summary(orig1$aov), summary(positive3$aov))
})

test_that("anova_table attributes", {
  data(md_12.1)
  no_attr <- aov_ez(
    "id",
    "rt",
    md_12.1,
    within = c("angle", "noise"),
    anova_table = list(correction = "none")
  )

  expect_that(attr(no_attr$anova_table, "correction"), equals("none"))
  expect_that(attr(no_attr$anova_table, "p_adjust_method"), equals("none"))
  expect_output(
    print(attr(no_attr$anova_table, "observed")),
    "character\\(0\\)"
  )

  all_attr <- suppressWarnings(aov_ez(
    "id",
    "rt",
    md_12.1,
    within = c("angle", "noise"),
    observed = "angle",
    anova_table = list(correction = "HF", p_adjust_method = "bonferroni")
  ))

  expect_that(attr(all_attr$anova_table, "correction"), equals("HF"))
  expect_that(
    attr(all_attr$anova_table, "p_adjust_method"),
    equals("bonferroni")
  )
  expect_that(attr(all_attr$anova_table, "observed"), equals("angle"))
  expect_output(print(all_attr), "bonferroni")
  expect_output(print(all_attr), "HF")

  expect_false(isTRUE(all.equal(
    nice(no_attr),
    suppressWarnings(nice(all_attr)),
    check.attributes = FALSE
  )))

  added_attr <- suppressWarnings(nice(
    no_attr,
    correction = "HF",
    p_adjust_method = "bonferroni",
    observed = "angle"
  ))
  expect_that(suppressWarnings(nice(all_attr)), is_identical_to(added_attr))
  expect_that(nice(all_attr$anova_table), is_identical_to(added_attr))

  reset_attr <- nice(
    no_attr,
    correction = "none",
    p.adjust = "none",
    observed = NULL
  )
  expect_that(nice(no_attr), is_identical_to(reset_attr))
  expect_that(nice(no_attr$anova_table), is_identical_to(reset_attr))

  intercept_test <- aov_ez(
    "id",
    "rt",
    md_12.1,
    within = c("angle", "noise"),
    anova_table = list(intercept = TRUE)
  )
  expect_output(print(intercept_test), "(Intercept)")

  mse_test <- aov_ez(
    "id",
    "rt",
    md_12.1,
    within = c("angle", "noise"),
    anova_table = list(MSE = FALSE)
  )
  expect_null(mse_test$anova_table$MSE)
  expect_output(print(nice(mse_test, MSE = TRUE)), "MSE")

  symbol_test <- aov_ez(
    "id",
    "rt",
    md_12.1,
    within = c("angle", "noise"),
    anova_table = list(sig_symbols = c(" ", " a", " aa", " aaa")),
    return = "nice"
  )
  expect_output(print(symbol_test), "aaa")

  symbol_test <- aov_ez(
    "id",
    "rt",
    md_12.1,
    within = c("angle", "noise"),
    anova_table = list(sig_symbols = c(" ", " a", " aa", " aaa"))
  )
  expect_output(print(symbol_test), "aaa")

  new_symbols <- c(" ", " b", " bb", " bbb")
  symbol_test <- anova(symbol_test, sig_symbols = c(" ", " b", " bb", " bbb"))
  expect_identical(attr(symbol_test, "sig_symbols"), new_symbols)
  expect_output(print(nice(symbol_test)), "bbb")

  # Test support for old afex objects
  old_afex_object <- default_options <- aov_ez(
    "id",
    "rt",
    md_12.1,
    within = c("angle", "noise")
  )
  attr(old_afex_object$anova_table, "observed") <- NULL
  attr(old_afex_object$anova_table, "correction") <- NULL
  attr(old_afex_object$anova_table, "p.adjust.method") <- NULL
  expect_that(nice(old_afex_object), is_identical_to(nice(default_options)))

  # Test if sphericity correction is set to "none" in the absence of within-subject factors or if within-subject factors have only two levels
  data(obk.long)
  between_anova <- suppressWarnings(aov_car(
    value ~ treatment * gender + Error(id),
    data = obk.long
  ))
  expect_that(attr(between_anova$anova_table, "correction"), equals("none"))

  obk.long <- droplevels(obk.long[obk.long$phase %in% c("post", "pre"), ])
  two_level_anova <- suppressWarnings(aov_ez(
    "id",
    "value",
    obk.long,
    between = c("treatment"),
    within = c("phase")
  ))
  expect_that(attr(two_level_anova$anova_table, "correction"), equals("none"))

  more_levels_anova <- aov_ez(
    "id",
    "value",
    obk.long,
    between = c("treatment"),
    within = c("phase", "hour")
  )
  expect_that(attr(more_levels_anova$anova_table, "correction"), equals("GG"))

  obk.long <- droplevels(obk.long[obk.long$hour %in% c("1", "2"), ])
  two_levels_anova <- aov_ez(
    "id",
    "value",
    obk.long,
    between = c("treatment"),
    within = c("phase", "hour")
  )
  expect_that(attr(two_levels_anova$anova_table, "correction"), equals("none"))

  # Test incomplete observation attribute
  incomplete_cases <- suppressWarnings(
    aov_ez("id", "rt", md_12.1[-10, ], within = c("angle", "noise"))
  )

  expect_equal(as.character(attr(incomplete_cases, "incomplete_cases")), "10")
  expect_equal(
    as.character(attr(incomplete_cases$anova_table, "incomplete_cases")),
    "10"
  )
  expect_equal(
    as.character(attr(anova(incomplete_cases), "incomplete_cases")),
    "10"
  )
})

test_that("error messages for common problems", {
  data(md_12.1)
  md_12.2 <- md_12.1[!(md_12.1$noise == "present" & md_12.1$angle == "0"), ]

  expect_error(
    aov_ez("id", "rt", md_12.2, within = c("angle", "noise")),
    "within-subjects design"
  )

  data(obk.long)
  obk2 <- obk.long[
    !(obk.long$treatment == "A" & obk.long$gender == "F"),
  ]

  expect_error(
    aov_car(
      value ~ treatment * gender + Error(id),
      data = obk2,
      fun_aggregate = mean
    ),
    "between-subjects design"
  )
  expect_error(
    aov_car(value ~ treatment * gender + Error(id / phase * hour), data = obk2),
    "between-subjects design"
  )
  expect_error(
    aov_car(value ~ treatment * gender, data = obk2),
    "formula needs an error term"
  )

  expect_error(
    aov_4(formula = value ~ treatment * gender, data = obk2),
    "requires one random-effect term in formula"
  )
})
