context("s2dv::ACC tests")

##############################################
##NOTE: bootstrap is not tested because sample() is used inside.

  # dat1
  set.seed(1)
  exp1 <- array(rnorm(60), dim = c(dataset = 1, member = 2, sdate = 5,
                                   ftime = 1, lat = 2, lon = 3))

  set.seed(2)
  obs1 <- array(rnorm(30), dim = c(dataset = 1, member = 1, sdate = 5,
                                   ftime = 1, lat = 2, lon = 3))
  lat1 <- c(30, 35)
  lon1 <- c(0, 5, 10)
  # dat2
  set.seed(1)
  exp2 <- array(rnorm(60), dim = c(dataset = 2, sdate = 5,
                                   ftime = 1, lat = 2, lon = 3))
  set.seed(2)
  obs2 <- array(rnorm(30), dim = c(dataset = 1, sdate = 5,
                                   ftime = 1, lat = 2, lon = 3))
  set.seed(2)
  na <- floor(runif(2, min = 1, max = 30))
  obs2[na] <- NA
  lat2 <- c(30, 35)
  lon2 <- c(0, 5, 10)

##############################################
test_that("1. Input checks", {
  # exp and obs (1)
  expect_error(
  ACC(c(), c()),
  "Parameter 'exp' and 'obs' cannot be NULL."
  )
  expect_error(
  ACC(c('b'), c('a')),
  "Parameter 'exp' and 'obs' must be a numeric array."
  )
  expect_error(
  ACC(c(1:10), c(2:4)),
  paste0("Parameter 'exp' and 'obs' must have at least dimensions ",
         "lat_dim and lon_dim.")
  )
  expect_error(
  ACC(array(1:10, dim = c(2, 5)), array(1:4, dim = c(2, 2))),
  "Parameter 'exp' and 'obs' must have dimension names."
  )
  expect_error(
  ACC(array(1:10, dim = c(a = 2, c = 5)), array(1:4, dim = c(a = 2, b = 2))),
  "Parameter 'exp' and 'obs' must have same dimension name"
  )
  # dat_dim
  expect_error(
  ACC(exp1, obs1, dat_dim = 1),
  "Parameter 'dat_dim' must be a character string."
  )
  expect_error(
  ACC(exp1, obs1, dat_dim = 'a'),
  "Parameter 'dat_dim' is not found in 'exp' or 'obs' dimension."
  )
  # space_dim (deprecated)
  expect_warning(
  ACC(exp1, obs1, space_dim = c('lat', 'lon'), lat = c(1, 2)),
  "! Warning: Parameter 'space_dim' is deprecated. Use 'lat_dim' and 'lon_dim'\n!   instead."
  )
  # lat_dim
  expect_error(
  ACC(exp1, obs1, lat_dim = 1),
  "Parameter 'lat_dim' must be a character string."
  )
  expect_error(
  ACC(exp1, obs1, lat_dim = 'latitude'),
  "Parameter 'lat_dim' is not found in 'exp' or 'obs' dimension."
  )
  # lon_dim
  expect_error(
  ACC(exp1, obs1, lon_dim = 2),
  "Parameter 'lon_dim' must be a character string."
  )
  expect_error(
  ACC(exp1, obs1, lon_dim = 'lonn'),
  "Parameter 'lon_dim' is not found in 'exp' or 'obs' dimension."
  )
  # avg_dim
  expect_error(
  ACC(exp1, obs1, avg_dim = 1),
  "Parameter 'avg_dim' must be a character string."
  )
  expect_error(
  ACC(exp1, obs1, avg_dim = c('lev')),
  "Parameter 'avg_dim' is not found in 'exp' or 'obs' dimension."
  )
  # memb_dim
  expect_error(
  ACC(exp1, obs1, memb_dim = TRUE),
  "Parameter 'memb_dim' must be a character string."
  )
  expect_error(
  ACC(exp1, obs1, memb_dim = 'memb'),
  "Parameter 'memb_dim' is not found in 'exp' or 'obs' dimension."
  )
  # lat
  expect_error(
  ACC(exp1, obs1, lat = c(1, 2, 3)),
  paste0("Parameter \'lat\' must be a numeric vector with the same ",
         "length as the latitude dimension of \'exp\' and \'obs\'.")
  )
  # lon
  expect_error(
  ACC(exp1, obs1, lat = c(1, 2), lon = c(1, 3)),
  paste0("Parameter \'lon\' must be a numeric vector with the same ",
         "length as the longitude dimension of \'exp\' and \'obs\'.")
  )
  # lonlatbox
  expect_error(
  ACC(exp1, obs1, lat = c(1, 2), lon = c(1, 2, 3), lonlatbox = c(-90, 90)),
  "Parameter 'lonlatbox' must be a numeric vector of 4."
  )
  # conf
  expect_error(
  ACC(exp1, obs1, lat = c(1, 2), lon = c(1, 2, 3), conf = 1),
  "Parameter 'conf' must be one logical value."
  )
  # conftype
  expect_error(
  ACC(exp1, obs1, lat = c(1, 2), lon = c(1, 2, 3), conftype = 'a'),
  "Parameter \'conftype\' must be either \'parametric\' or \'bootstrap\'."
  )
  expect_error(
  ACC(exp1, obs1, lat = c(1, 2), lon = c(1, 2, 3), memb_dim = NULL, conftype = 'bootstrap'),
  "Parameter 'memb_dim' cannot be NULL when parameter 'conftype' is 'bootstrap'."
  )
  # alpha
  expect_error(
  ACC(exp1, obs1, lat = c(1, 2), lon = c(1, 2, 3), alpha = -1),
  "Parameter 'alpha' must be a numeric number between 0 and 1."
  )
  # pval
  expect_error(
  ACC(exp1, obs1, lat = c(1, 2), lon = c(1, 2, 3), pval = 'TRUE'),
  "Parameter 'pval' must be one logical value."
  )
  # ncores
  expect_error(
  ACC(exp1, obs1, lat = c(1, 2), lon = c(1, 2, 3), ncores = 1.5),
  "Parameter 'ncores' must be a positive integer."
  )
  # exp and obs (2)
  expect_error(
  ACC(exp = array(1:10, dim = c(dataset = 5, member = 1, lat = 2, lon = 1)),
      obs = array(1:4, dim = c(dataset = 2, member = 2, lat = 1, lon = 1)),
      lat = c(1, 2), lon = c(1),
      avg_dim = NULL),
  "Parameter 'exp' and 'obs' must have same length of all the dimensions except 'dat_dim' and 'memb_dim'."
  )

})

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

  expect_equal(
    dim(ACC(exp1, obs1, lat = lat1, lon = lon1)$acc),
    c(nexp = 1, nobs = 1, sdate = 5, ftime = 1)
  )
  expect_equal(
    names(ACC(exp1, obs1, lat = lat1)),
    c("acc", "macc", "conf.lower", "conf.upper", "p.val")
  )
  expect_equal(
    as.vector(ACC(exp1, obs1, lat = lat1)$acc),
    c(-0.006384684, -0.664580451, -0.637292180, 0.320974249, -0.453246995),
    tolerance = 0.00001
  )
  expect_equal(
    as.vector(ACC(exp1, obs1, lat = lat1)$p.val),   
    c(0.7292993, 0.7292993, 0.7292993, 0.7292993, 0.7292993),
    tolerance = 0.00001    
  )
  expect_equal(
    as.vector(ACC(exp1, obs1, lat = lat1)$conf.lower),
    c(-0.8137296, -0.9589397, -0.9549511, -0.6633950, -0.9246771),
    tolerance = 0.00001
  )
  expect_equal(
    as.vector(ACC(exp1, obs1, lat = lat1)$conf.upper),
    c(0.8093704, 0.3190711, 0.3609563, 0.8984881, 0.5668074),
    tolerance = 0.00001
  )
  expect_equal(
    names(ACC(exp1, obs1, lat = lat1, avg_dim = NULL)),
    c("acc", "conf.lower", "conf.upper", "p.val")
  )
  expect_equal(
    dim(ACC(exp1, obs1, lat = lat1, dat_dim = 'member', memb_dim = NULL)$acc),
    c(nexp = 2, nobs = 1, sdate = 5, dataset = 1, ftime = 1)
  )
  expect_equal(
    names(ACC(exp1, obs1, lat = lat1, conf = FALSE)),
    c("acc", "macc", "p.val")
  )
  expect_equal(
    names(ACC(exp1, obs1, lat = lat1, pval = FALSE)),
    c("acc", "macc", "conf.lower", "conf.upper")
  )
  expect_equal(
    names(ACC(exp1, obs1, lat = lat1, conf = FALSE, pval = FALSE)),
    c("acc", "macc")
  )
  expect_equal(
    as.vector(ACC(exp1, obs1, lat = lat1, conf = FALSE, avg_dim = NULL, alpha = 0.1)$p.val),
    c(0.6083998, 0.6083998, 0.6083998, 0.6083998, 0.6083998),
    tolerance = 0.00001
  )
  expect_equal(
    as.vector(ACC(exp1, obs1, lat = c(10, 20), lon = c(20, 30, 40), lonlatbox = c(20, 30, 10, 20))$acc),
    c(0.3555372, -0.5205672, -0.3403301, 0.2690648, -0.5146910),
    tolerance = 0.00001
  )

})


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

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

expect_equal(
  dim(ACC(exp2, obs2, lat = lat2, lon = lon2, memb_dim = NULL)$acc),
  c(nexp = 2, nobs = 1, sdate = 5, ftime = 1)
)
expect_equal(
  as.vector(ACC(exp2, obs2, lat = lat2, memb_dim = NULL)$acc)[3:7],
  c(-0.3601880, -0.5624773, -0.4603762, -0.6997169, -0.1336961),
  tolerance = 0.00001
)
expect_equal(
  mean(ACC(exp2, obs2, lat = lat2, memb_dim = NULL)$acc),
  -0.1484762,
  tolerance = 0.00001
)

})
