context("s2dv::NAO tests")

##############################################
  # dat1
  set.seed(1)
  exp1 <- array(rnorm(144), dim = c(member = 2, sdate = 3, ftime = 4, lat = 2, lon = 3))
  set.seed(2)
  obs1 <- array(rnorm(72), dim = c(member = 1, sdate = 3, ftime = 4, lat = 2, lon = 3))
  lat1 <- c(20, 80)
  lon1 <- c(40, 280, 350)

  # dat2
  set.seed(1)
  exp2 <- array(rnorm(144), dim = c(sdate = 3, ftime = 4, member = 2, lat = 2, lon = 3))
  set.seed(2)
  obs2 <- array(rnorm(144), dim = c(member = 2, sdate = 3, ftime = 4, lat = 2, lon = 3))
  lat2 <- c(20, 80)
  lon2 <- c(-80, 0, 40)
 
##############################################
test_that("1. Input checks", {

  # exp and obs (1)
  expect_error(
  NAO(c(), c()),
  "Parameter 'exp' and 'obs' cannot both be NULL."
  )
  expect_error(
  NAO(exp = c(NA, NA)),
  "Parameter 'exp' must be a numeric array."
  )
  expect_error(
  NAO(exp = c(1:10)),
  paste0("Parameter 'exp' and must have at least dimensions ",
                  "time_dim, memb_dim, space_dim, and ftime_dim.")
  )
  expect_error(
    NAO(array(1:10, dim = c(2, 5))),
    "Parameter 'exp' must have dimension names."
  )
  expect_error(
  NAO(exp = exp1, obs = c(NA, NA)),
  "Parameter 'obs' must be a numeric array."
  )
  expect_error(
  NAO(exp = exp1, obs = c(1:10)),
  paste0("Parameter 'obs' and must have at least dimensions ",
                  "time_dim, memb_dim, space_dim, and ftime_dim.")
  )
  expect_error(
    NAO(exp = exp1, obs = array(1:10, dim = c(2, 5))),
    "Parameter 'obs' must have dimension names."
  )
  # time_dim
  expect_error(
    NAO(exp1, obs1, time_dim = 2),
    "Parameter 'time_dim' must be a character string."
  )
  expect_error(
    NAO(exp1, obs1, time_dim = 'a'),
    "Parameter 'time_dim' is not found in 'exp' or 'obs' dimension."
  )
  # memb_dim
  expect_error(
    NAO(exp1, obs1, memb_dim = 2),
    "Parameter 'memb_dim' must be a character string."
  )
  expect_error(
    NAO(exp1, obs1, memb_dim = 'a'),
    "Parameter 'memb_dim' is not found in 'exp' or 'obs' dimension."
  )
  # space_dim
  expect_error(
    NAO(exp1, obs1, space_dim = 'lat'),
    "Parameter 'space_dim' must be a character vector of 2."
  )
  expect_error(
    NAO(exp1, obs1, space_dim = c('latitude', 'longitude')),
    "Parameter 'space_dim' is not found in 'exp' or 'obs' dimension."
  )
  # ftime_dim
  expect_error(
    NAO(exp1, obs1, ftime_dim = 2),
    "Parameter 'ftime_dim' must be a character string."
  )
  expect_error(
    NAO(exp1, obs1, ftime_dim = 'a'),
    "Parameter 'ftime_dim' is not found in 'exp' or 'obs' dimension."
  )
  # exp and obs (2)
  expect_error(
  NAO(exp1, array(rnorm(10), dim = c(member = 10, sdate = 3, ftime = 4, lat = 2, lon = 2))),
  paste0("Parameter 'exp' and 'obs' must have the same length of ",
         "all dimensions except 'memb_dim'.")
  )
  # ftime_avg
  expect_error(
    NAO(exp1, obs1, ftime_avg = T),
  "Parameter 'ftime_avg' must be an integer vector."
  )
  expect_error(
  NAO(exp1, obs1, ftime_avg = 1:10),
"Parameter 'ftime_avg' must be within the range of ftime_dim length."
  )
  # sdate >= 2
  expect_error(
  NAO(exp = array(rnorm(10), dim = c(member = 10, sdate = 1, ftime = 4, lat = 2, lon = 2)),
      obs = array(rnorm(10), dim = c(member = 10, sdate = 1, ftime = 4, lat = 2, lon = 2))),
  "The length of time_dim must be at least 2."
  )
  # lat and lon
  expect_error(
  NAO(exp1, obs1, lat = 1:10),
    paste0("Parameter 'lat' must be a numeric vector with the same ",
           "length as the latitude dimension of 'exp' and 'obs'.")
  )
  expect_error(
  NAO(exp1, obs1, lat = lat1, lon = c('a', 'b')),
  paste0("Parameter 'lon' must be a numeric vector with the same ",
         "length as the longitude dimension of 'exp' and 'obs'.")
  )
  expect_error(
  NAO(exp1, obs1, lat = c(1, 2), lon = lon1),
  paste0("The typical domain used to compute the NAO is 20N-80N, ",
                "80W-40E. 'lat' or 'lon' is out of range.")
  )
  expect_error(
  NAO(exp1, obs1, lat = c(-10, -5), lon = lon1),
  paste0("The typical domain used to compute the NAO is 20N-80N, ",
                "80W-40E. 'lat' or 'lon' is out of range.")
  )
  expect_error(
  NAO(exp1, obs1, lat = lat1, lon = c(40, 50, 60)),
  paste0("The typical domain used to compute the NAO is 20N-80N, ",
                "80W-40E. 'lat' or 'lon' is out of range.")
  )
  # obsproj
  expect_error(
  NAO(exp1, obs1, lat = lat1, lon = lon1, obsproj = 1),
  "Parameter 'obsproj' must be either TRUE or FALSE."
  )
  expect_error(
  NAO(exp = exp1, lat = lat1, lon = lon1),
  "Parameter 'obsproj' set to TRUE but no 'obs' provided."
  )
  # ncores
  expect_error(
    NAO(exp1, obs1, lat1, lon1, ncore = 3.5),
    "Parameter 'ncores' must be a positive integer."
  )

})
##############################################
test_that("2. dat1", {

  expect_equal(
  names(NAO(exp1, obs1, lat = lat1, lon = lon1)),
  c("exp", "obs")
  )
  expect_equal(
  dim(NAO(exp1, obs1, lat = lat1, lon = lon1)$exp),
  c(sdate = 3, member = 2)
  )
  expect_equal(
  dim(NAO(exp1, obs1, lat = lat1, lon = lon1)$obs),
  c(sdate = 3, member = 1)
  )
  expect_equal(
  NAO(exp1, obs1, lat = lat1, lon = lon1)$exp[1:5],
  c(-0.1995564, -0.2996030, 0.7340010, -0.2747980, -0.3606155),
  tolerance = 0.0001
  )
  expect_equal(
  NAO(exp1, obs1, lat = lat1, lon = lon1)$obs[1:3],
  c(-0.1139683, 0.1056687, 0.1889449),
  tolerance = 0.0001
  )
  expect_equal(
  mean(NAO(exp1, obs1, lat = lat1, lon = lon1, obsproj = FALSE)$exp),
  -0.1362706,
  tolerance = 0.0001
  )
  expect_equal(
  names(NAO(exp = exp1, lat = lat1, lon = lon1, obsproj = FALSE)),
  c("exp")
  )
 suppressWarnings( 
  expect_equal(
  names(NAO(obs = obs1, lat = lat1, lon = lon1)),
  c("obs")
  )
 )

})
##############################################
test_that("3. dat2", {
  expect_equal(
  dim(NAO(exp2, obs2, lat = lat2, lon = lon2)$exp),
  c(sdate = 3, member = 2)
  )
  expect_equal(
  dim(NAO(exp2, obs2, lat = lat2, lon = lon2)$obs),
  c(sdate = 3, member = 2)
  )
  expect_equal(
  mean(NAO(exp2, obs2, lat = lat2, lon = lon2)$exp),
  -0.01566486,
  tolerance = 0.00001
  )
  expect_equal(
  NAO(exp2, obs2, lat = lat2, lon = lon2)$exp[2:4],
  c(0.16231137, -0.10984650, -0.01871716),
  tolerance = 0.00001
  )
  expect_equal(
  NAO(exp2, obs2, lat = lat2, lon = lon2, ftime_avg = 1:3)$exp[2:4],
  c(-0.30102528, -0.06366782, 0.01639220),
  tolerance = 0.00001
  )
})

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