context("s2dv::AbsBiasSS tests")

##############################################

# dat1
set.seed(1)
exp1 <- array(rnorm(20), dim = c(sdate = 10, lat = 2))
set.seed(2)
obs1 <- array(rnorm(20), dim = c(sdate = 10, lat = 2))
set.seed(3)
ref1 <- array(rnorm(20), dim = c(sdate = 10, lat = 2))

# dat2
set.seed(1)
exp2 <- array(rnorm(60), dim = c(member = 2, sdate = 10, lat = 3))
set.seed(2)
obs2 <- array(rnorm(30), dim = c(member = 1, sdate = 10, lat = 3))
set.seed(3)
ref2 <- array(rnorm(60), dim = c(member = 2, sdate = 10, lat = 3))

# dat3
set.seed(1)
exp3 <- array(rnorm(80), dim = c(member = 2, sdate = 10, lat = 2, dataset = 2))
set.seed(2)
obs3 <- array(rnorm(60), dim = c(sdate = 10, lat = 2, dataset = 3))
set.seed(3)
ref3 <- array(rnorm(20), dim = c(sdate = 10, lat = 2))

# dat4
set.seed(1)
exp4 <- array(rnorm(80), dim = c(member = 2, sdate = 10, lat = 2, dataset = 2))
set.seed(2)
obs4 <- array(rnorm(60), dim = c(sdate = 10, lat = 2, dataset = 3))
set.seed(3)
ref4 <- array(rnorm(40), dim = c(sdate = 10, lat = 2, dataset = 2))

# dat5
set.seed(1)
exp5 <- array(rnorm(10), dim = c(sdate = 10))
exp5_1 <- array(exp5, dim = c(sdate = 10, dataset = 1))
exp5_2 <- exp5_1
exp5_2[1] <- NA
set.seed(2)
obs5 <- array(rnorm(10), dim = c(sdate = 10))
obs5_1 <- array(obs5, dim = c(sdate = 10, dataset = 1))
obs5_2 <- obs5_1
obs5_2[c(1, 3)] <- NA
set.seed(3)
ref5 <- array(rnorm(10), dim = c(sdate = 10))

##############################################
test_that("1. Input checks", {
  # exp and obs (1)
  expect_error(
    AbsBiasSS(c()),
    "Parameter 'exp' must be a numeric array."
  )
  expect_error(
    AbsBiasSS(exp1, c()),
    "Parameter 'obs' must be a numeric array."
  )
  expect_error(
    AbsBiasSS(exp1, array(rnorm(20), dim = c(10, lat = 2))),
    "Parameter 'exp' and 'obs' must have dimension names."
  )
  expect_error(
    AbsBiasSS(exp1, array(rnorm(20), dim = c(10, lat = 2))),
    "Parameter 'exp' and 'obs' must have dimension names."
  )
  expect_error(
    AbsBiasSS(exp1, obs1, ref = 'ref'),
    "Parameter 'ref' must be a numeric array."
  )
  expect_error(
    AbsBiasSS(exp1, obs1, ref = array(rnorm(20), dim = c(10, lat = 2))),
    "Parameter 'ref' must have dimension names."
  )
  # time_dim
  expect_error(
    AbsBiasSS(exp1, obs1, time_dim = 1),
    "Parameter 'time_dim' must be a character string."
  )
  expect_error(
    AbsBiasSS(exp1, obs1, time_dim = 'time'),
    "Parameter 'time_dim' is not found in 'exp' or 'obs' dimension."
  )
  expect_error(
    AbsBiasSS(exp1, obs1, ref = array(rnorm(20), dim = c(lon = 10, lat = 2)), time_dim = 'time'),
    "Parameter 'time_dim' is not found in 'exp' or 'obs' dimension."
  )
  # memb_dim
  expect_error(
    AbsBiasSS(exp1, obs1, memb_dim = TRUE),
    "Parameter 'memb_dim' must be a character string."
  )
  expect_error(
    AbsBiasSS(exp1, obs1, memb_dim = 'memb'),
    "Parameter 'memb_dim' is not found in 'exp' dimension."
  )
  expect_error(
    AbsBiasSS(exp2, array(rnorm(20), dim = c(member = 3, sdate = 10, lat = 2)), memb_dim = 'member'),
    "Not implemented for observations with members ('obs' can have 'memb_dim', but it should be of length = 1).", fixed = TRUE
  )
  # dat_dim
  expect_error(
    AbsBiasSS(exp1, obs1, dat_dim = TRUE, ),
    "Parameter 'dat_dim' must be a character string."
  )
  expect_error(
    AbsBiasSS(exp1, obs1, dat_dim = 'dat_dim'),
    "Parameter 'dat_dim' is not found in 'exp' or 'obs' dimension. Set it as NULL if there is no dataset dimension."
  )
  # exp, ref, and obs (2)
  expect_error(
    AbsBiasSS(exp1, array(1:9, dim = c(sdate = 9))),
    "Parameter 'exp' and 'obs' must have same length of all dimensions except 'memb_dim' and 'dat_dim'."
  )
  expect_error(
    AbsBiasSS(exp3, obs3, ref = obs3, dat_dim = 'dataset', memb_dim = 'member'),
    "If parameter 'ref' has dataset dimension, it must be equal to dataset dimension of 'exp'."
  )
  expect_error(
    AbsBiasSS(exp1, obs1, ref = ref2),
    "Parameter 'exp' and 'ref' must have the same length of all dimensions except 'memb_dim' and 'dat_dim' if there is only one reference dataset."
  )
  # na.rm
  expect_error(
    AbsBiasSS(exp2, obs2, memb_dim = 'member', na.rm = 1.5),
    "Parameter 'na.rm' must be one logical value."
  )
  # ncores
  expect_error(
    AbsBiasSS(exp2, obs2, memb_dim = 'member', ncores = 1.5),
    "Parameter 'ncores' must be either NULL or a positive integer."
  )

})

##############################################
test_that("2. Output checks: dat1", {

  expect_equal(
    dim(AbsBiasSS(exp1, obs1)$biasSS),
    c(lat = 2)
  )
  expect_equal(
    dim(AbsBiasSS(exp1, obs1)$sign),
    c(lat = 2)
  )
  expect_equal(
    dim(AbsBiasSS(exp1, obs1, ref1)$biasSS),
    c(lat = 2)
  )
  expect_equal(
    dim(AbsBiasSS(exp1, obs1, ref1)$sign),
    c(lat = 2)
  )
  expect_equal(
    as.vector(AbsBiasSS(exp1, obs1)$biasSS),
    c(-0.3103594, 0.0772921),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(AbsBiasSS(exp1, obs1, ref1)$biasSS),
    c(-0.07871642, 0.28868904),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(AbsBiasSS(exp1, obs1)$sign),
    c(FALSE, FALSE),
    tolerance = 0.0001
  )

})

##############################################
test_that("3. Output checks: dat2", {

  expect_equal(
    dim(AbsBiasSS(exp2, obs2, memb_dim = 'member')$biasSS),
    c(lat = 3)
  )
  expect_equal(
    dim(AbsBiasSS(exp2, obs2, ref2, memb_dim = 'member')$biasSS),
    c(lat = 3)
  )
  expect_equal(
    as.vector(AbsBiasSS(exp2, obs2, memb_dim = 'member')$biasSS),
    c(-0.4743706, -0.2884077, -0.4064404),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(AbsBiasSS(exp2, obs2, ref2, memb_dim = 'member')$biasSS),
    c(-0.07319869, 0.06277502, -0.17321998),
    tolerance = 0.0001
  )

})

##############################################
test_that("4. Output checks: dat3", {

  expect_equal(
    dim(AbsBiasSS(exp3, obs3, memb_dim = 'member', dat_dim = 'dataset')$biasSS),
    c(nexp = 2, nobs = 3, lat = 2)
  )
  expect_equal(
    dim(AbsBiasSS(exp3, obs3, ref3, memb_dim = 'member', dat_dim = 'dataset')$biasSS),
    c(nexp = 2, nobs = 3, lat = 2)
  )
  expect_equal(
    as.vector(AbsBiasSS(exp3, obs3, memb_dim = 'member', dat_dim = 'dataset')$biasSS)[5:10],
    c(-0.09794912, -0.11814710, -0.28840768, 0.02117376, -0.31282805, -0.08754112),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(AbsBiasSS(exp3, obs3, ref3, memb_dim = 'member', dat_dim = 'dataset')$biasSS)[5:10],
    c(0.264602089, 0.251073637, 0.006772886, 0.245427687, 0.168998894, 0.311602249),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(AbsBiasSS(exp2, obs2, memb_dim = 'member')$biasSS)[1:2],
    as.vector(AbsBiasSS(exp3, obs3, memb_dim = 'member', dat_dim = 'dataset')$biasSS[1,1,])
  )
  expect_equal(
    as.vector(AbsBiasSS(exp3, obs3, ref3, memb_dim = 'member', dat_dim = 'dataset', na.rm = TRUE)$biasSS)[1:5],
    c(-0.21373395, -0.34444526, 0.11039962, 0.05523797, 0.26460209)
  )

})
##############################################
test_that("5. Output checks: dat4", {

  expect_equal(
    dim(AbsBiasSS(exp4, obs4, memb_dim = 'member', dat_dim = 'dataset')$biasSS),
    c(nexp = 2, nobs = 3, lat = 2)
  )
  expect_equal(
    dim(AbsBiasSS(exp4, obs4, ref4, memb_dim = 'member', dat_dim = 'dataset')$biasSS),
    c(nexp = 2, nobs = 3, lat = 2)
  )
  expect_equal(
    as.vector(AbsBiasSS(exp4, obs4, memb_dim = 'member', dat_dim = 'dataset', na.rm = TRUE)$biasSS)[5:10],
    c(-0.09794912, -0.11814710, -0.28840768, 0.02117376, -0.31282805, -0.08754112),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(AbsBiasSS(exp4, obs4, ref4, memb_dim = 'member', dat_dim = 'dataset')$biasSS)[5:10],
    c(0.264602089, 0.133379718, 0.006772886, 0.242372951, 0.168998894, 0.272767238),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(AbsBiasSS(exp2, obs2, memb_dim = 'member')$biasSS)[1:2],
    as.vector(AbsBiasSS(exp4, obs4, memb_dim = 'member', dat_dim = 'dataset')$biasSS[1,1,])
  )
  expect_equal(
    as.vector(AbsBiasSS(exp4, obs4, ref4, memb_dim = 'member', dat_dim = 'dataset', na.rm = TRUE)$biasSS)[1:5],
    c(-0.213733950, -0.214240924, 0.110399615, -0.009733463, 0.264602089)
  )

})

##############################################
test_that("6. Output checks: dat5", {
  expect_equal(
    dim(AbsBiasSS(exp5, obs5)$biasSS),
    NULL
  )
  expect_equal(
    dim(AbsBiasSS(exp5, obs5)$sign),
    NULL
  )
  expect_equal(
    as.vector(AbsBiasSS(exp5, obs5)$biasSS),
    -0.3103594,
    tolerance = 0.0001
  )
  expect_equal( 
    as.vector(AbsBiasSS(exp5, obs5)$sign),
    FALSE
  )
  expect_equal(
    as.vector(AbsBiasSS(exp5, obs5, ref5)$biasSS),
    -0.07871642,
    tolerance = 0.0001
  )
  #5_1
  expect_equal(
    dim(AbsBiasSS(exp5_1, obs5_1, dat_dim = 'dataset')$biasSS),
    c(nexp = 1, nobs = 1)
  )
  expect_equal(
    dim(AbsBiasSS(exp5_1, obs5_1, dat_dim = 'dataset')$sign),
    c(nexp = 1, nobs = 1)
  )
  expect_equal(
    as.vector(AbsBiasSS(exp5_1, obs5_1, dat_dim = 'dataset')$biasSS),
    as.vector(AbsBiasSS(exp5, obs5)$biasSS)
  )
  expect_equal(
    as.vector(AbsBiasSS(exp5_1, obs5_1, ref = ref5, dat_dim = 'dataset')$biasSS),
    as.vector(AbsBiasSS(exp5, obs5, ref = ref5)$biasSS)
  )
  #5_2: NA test
  expect_equal(
    as.vector(AbsBiasSS(exp5_1, obs5_2, dat_dim = 'dataset')$biasSS),
    as.numeric(NA)
  )
  expect_equal(
    as.vector(AbsBiasSS(exp5_1, obs5_2, dat_dim = 'dataset', na.rm = T)$biasSS),
    c(-0.4636772),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(AbsBiasSS(exp5_2, obs5_2, ref = ref5, dat_dim = 'dataset', na.rm = T)$biasSS),
    c(0.08069355),
    tolerance = 0.0001
  )
})
