context("s2dv::RMSSS tests")

##############################################
 # case 1
 set.seed(1)
 exp1 <- array(rnorm(15), dim = c(sdate = 3, dataset = 5))
 set.seed(2)
 obs1 <- array(rnorm(6), dim = c(sdate = 3, dataset = 2))
 set.seed(3)
 ref1_1 <- array(rnorm(15), dim = c(sdate = 3, dataset = 5))
 ref1_2 <- exp1[, 3]
 dim(ref1_2) <- c(sdate = 3)

 # case 2
 set.seed(3)
 exp2 <- array(rnorm(120), dim = c(time = 10, dat = 1, lon = 3, lat = 2, dataset = 2))
 set.seed(4)
 obs2 <- array(rnorm(60), dim = c(dat = 1, time = 10, dataset = 1, lat = 2, lon = 3))

 # case 3: vector
 set.seed(5)
 exp3 <- rnorm(10)
 set.seed(6)
 obs3 <- rnorm(10)

 # case 4
 set.seed(7)
 exp4 <- array(rnorm(60), dim = c(sdate = 10, lon = 3, lat = 2))
 set.seed(8)
 obs4 <- array(exp4 + rnorm(60) / 2, dim = dim(exp4))

 # case 5: memb_dim
 set.seed(1)
 exp5 <- array(rnorm(45), dim = c(sdate = 3, dataset = 5, member = 3))
 set.seed(2)
 obs5 <- array(rnorm(3), dim = c(sdate = 3, dataset = 1, member = 1))
 set.seed(3)
 ref5 <- array(rnorm(6), dim = c(sdate = 3, member = 2))


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

test_that("1. Input checks", {
  ## exp and obs (1)
  expect_error(
  RMSSS(c(), c()),
  "Parameter 'exp' and 'obs' cannot be NULL."
  )
  expect_error(
  RMSSS('exp', 'obs'),
  "Parameter 'exp' and 'obs' must be a numeric array."
  )
  expect_error(
  RMSSS(c(1:10), c(2:4)),
  paste0("Parameter 'exp' and 'obs' must be array with as least two dimensions ",
         "time_dim and dat_dim, or vector of same length.")
  )
  expect_error(
  RMSSS(array(1:10, dim = c(2, 5)), array(1:10, dim = c(2, 5))),
  "Parameter 'exp' and 'obs' must have dimension names."
  )
  expect_error(
  RMSSS(array(1:10, dim = c(a = 3, c = 5)), array(1:4, dim = c(a = 3, b = 5)), time_dim = 'a', dat_dim = NULL),
  "Parameter 'exp' and 'obs' must have same dimension name"
  )
  ## time_dim
  expect_error(
  RMSSS(exp1, obs1, time_dim = 1),
  "Parameter 'time_dim' must be a character string."
  )
  expect_error(
  RMSSS(exp1, obs1, time_dim = 'a'),
  "Parameter 'time_dim' is not found in 'exp' or 'obs' dimension."
  )
  ## dat_dim
  expect_error(
  RMSSS(exp1, obs1, dat_dim = NA),
  "Parameter 'dat_dim' must be a character string."
  )
  expect_error(
  RMSSS(exp1, obs1, dat_dim = 'memb'),
  paste0("Parameter 'dat_dim' is not found in 'exp' or 'obs' dimension.",
           " Set it as NULL if there is no dataset dimension.")
  )
  ## pval
  expect_error(
  RMSSS(exp1, obs1, pval = c(T, T)),
  "Parameter 'pval' must be one logical value."
  )
  ## sign
  expect_error(
  RMSSS(exp1, obs1, sign = 0.05),
  "Parameter 'sign' must be one logical value."
  )
  ## alpha
  expect_error(
  RMSSS(exp1, obs1, alpha = T),
  "Parameter 'alpha' must be one numeric value."
  )
  ## ncores
  expect_error(
  RMSSS(exp1, obs1, ncores = 1.4),
  "Parameter 'ncores' must be a positive integer."
  )
  ## exp and obs (2)
  expect_error(
  RMSSS(exp = array(1:10, dim = c(sdate = 1, dataset = 5, a = 1)),
        obs = array(1:4, dim = c(a = 1, sdate = 2, dataset = 2))),
  "Parameter 'exp' and 'obs' must have same length of all dimension except 'memb_dim' and 'dat_dim'."
  )
  expect_error(
  RMSSS(exp = array(1:10, dim = c(sdate = 1, dataset = 5, a = 1)),
        obs = array(1:4, dim = c(a = 1, sdate = 1, dataset = 2))),
  "The length of time_dim must be more than 2 to compute RMSSS."
  )
})

##############################################
test_that("2. Output checks: case 1", {

  res1_1 <- RMSSS(exp1, obs1, dat_dim = 'dataset')
  expect_equal(
    dim(res1_1$rmsss),
    c(nexp = 5, nobs = 2)
  )
  expect_equal(
    dim(res1_1$p.val),
    c(nexp = 5, nobs = 2)
  )
  expect_equal(
    mean(res1_1$rmsss),
    -0.5449538,
    tolerance = 0.00001
  )
  expect_equal(
  as.vector(res1_1$p.val)[3:7],
  c(0.4914588, 0.5134658, 0.6428701, 0.4919943, 0.8672634),
  tolerance = 0.001
  )

  exp1_2 <- exp1
  exp1_2[2:4] <- NA
  obs1_2 <- obs1
  obs1_2[1:2] <- NA
  res1_2 <- RMSSS(exp1_2, obs1_2, dat_dim = 'dataset', pval = TRUE)

  expect_equal(
    length(res1_2$rmsss[which(is.na(res1_2$rmsss))]),
    7
  )
  expect_equal(
    range(res1_2$p.val, na.rm = T),
    c(0.7159769, 0.8167073),
    tolerance = 0.00001
  )

  #ref
  res1_3 <- RMSSS(exp1, obs1, ref = ref1_1, dat_dim = 'dataset')
  expect_equal(
  dim(res1_3$rmsss),
  c(nexp = 5, nobs = 2)
  )
  expect_equal(
  dim(res1_3$p.val),
  c(nexp = 5, nobs = 2)
  )
  expect_equal(
  as.vector(res1_3$rmsss[2, ]),
  c(-1.197432, -8.879809),
  tolerance = 0.0001
  )
  expect_equal(
  as.vector(res1_3$p.val[2, ]),
  c(0.8284354, 0.9898591),
  tolerance = 0.0001
  )
  res1_4 <- RMSSS(exp1, obs1, ref = ref1_2, dat_dim = 'dataset', sign = T, alpha = 0.3)
  expect_equal(
  dim(res1_4$rmsss),
  c(nexp = 5, nobs = 2)
  )
  expect_equal(
  dim(res1_4$sign),
  c(nexp = 5, nobs = 2)
  )
  expect_equal(
  as.vector(res1_4$rmsss[2, ]),
  c(-0.9249772, -0.5624465),
  tolerance = 0.0001
  )
  expect_equal(
  as.vector(res1_4$p[2, ]),
  c(0.7874844, 0.7094070),
  tolerance = 0.0001
  )
  expect_equal(
  as.vector(res1_4$sign),
  c(rep(F, 5), T, rep(F, 4))
  )

  # Random Walk
  suppressWarnings({
  res1_5 <- RMSSS(exp1, obs1, ref = ref1_1, dat_dim = 'dataset', sig_method = "Random Walk", pval = F, sign = T)
  })
  expect_equal( 
  as.vector(res1_5$sign),
  rep(F, 10)
  )
  suppressWarnings({
  res1_6 <- RMSSS(exp1, obs1, ref = NULL, dat_dim = 'dataset', sig_method = "Random Walk", pval = F, sign = T)
  })
  expect_equal(
  as.vector(res1_6$sign),
  rep(F, 10)
  )

})


##############################################
test_that("3. Output checks: case 2", {

  expect_equal(
    dim(RMSSS(exp2, obs2, time_dim = 'time')$rmsss),
    c(nexp = 2, nobs = 1, dat = 1, lon = 3, lat = 2) 
  )
  expect_equal(
    mean(RMSSS(exp2, obs2, time_dim = 'time')$rmsss),
    -0.3912208,
    tolerance = 0.00001
  )
  expect_equal(
    range(RMSSS(exp2, obs2, time_dim = 'time')$p.val),
    c(0.2627770, 0.9868412),
    tolerance = 0.00001
  )

})

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

test_that("4. Output checks: case 3", {

  expect_equal(
    dim(RMSSS(exp3, obs3)$rmsss),
    c(nexp = 1, nobs = 1)
  )
  expect_equal(
  as.vector(RMSSS(exp3, obs3)$rmsss),
  -0.6289915,
  tolerance = 0.00001
  )

})

##############################################
test_that("5. Output checks: case 4", {

  expect_equal(
    dim(RMSSS(exp4, obs4, dat_dim = NULL)$rmsss),
    c(lon = 3, lat = 2) 
  )
  expect_equal(
    dim(RMSSS(exp4, obs4, dat_dim = NULL)$p.val),
    c(lon = 3, lat = 2)
  )
  expect_equal(
    as.vector(RMSSS(exp4, obs4, dat_dim = NULL)$rmsss),
    c(0.5393823, 0.6818405, 0.4953423, 0.4093817, 0.5972085, 0.5861135),
    tolerance = 0.00001
  )
  expect_equal(
    as.vector(RMSSS(exp4, obs4, dat_dim = NULL)$p.val),
    c(0.015203983, 0.001091360, 0.026987112, 0.066279877, 0.006161059, 0.007437649),
    tolerance = 0.00001
  )
  expect_equal(
    names(RMSSS(exp4, obs4, dat_dim = NULL)),
    c('rmsss', 'p.val')
  )
  expect_equal(
    names(RMSSS(exp4, obs4, dat_dim = NULL, sign = T, pval = F)),
    c('rmsss', 'sign')
  )
  expect_equal(
    names(RMSSS(exp4, obs4, dat_dim = NULL, sign = T, pval = T)),
    c('rmsss', 'p.val', 'sign')
  )
  expect_equal(
    as.vector(RMSSS(exp4, obs4, dat_dim = NULL, sign = T, pval = F)$sign),
    c(T, T, T, F, T, T)
  )
  expect_equal(
    as.vector(RMSSS(exp4, obs4, dat_dim = NULL, sign = T, pval = F, alpha = 0.01)$sign),
    c(F, T, F, F, T, T)
  )
  
})

##############################################
test_that("6. Output checks: case 5", {
  res5_1 <- RMSSS(exp5, obs5, ref = ref5, dat_dim = 'dataset', memb_dim = 'member')
  res5_2 <- RMSSS(s2dv::MeanDims(exp5, 'member'), s2dv::MeanDims(obs5, 'member'),
                  ref = s2dv::MeanDims(ref5, 'member'), dat_dim = 'dataset')
  expect_equal(
  res5_1,
  res5_2
  )


})

