diff --git a/R/central-tendency.R b/R/central-tendency.R index ba4752f..4da09d3 100644 --- a/R/central-tendency.R +++ b/R/central-tendency.R @@ -1,5 +1,4 @@ # TODO: -# - Add tests # - Add description #' Geometric Mean (GM) diff --git a/R/variability.R b/R/variability.R index e1f6608..0bd8e22 100644 --- a/R/variability.R +++ b/R/variability.R @@ -1,5 +1,4 @@ # TODO: -# - Add tests # - Add description #' Coefficient of Variation (Cv) @@ -52,6 +51,9 @@ cv.data.frame <- function( ) } +# TODO: +# Rewrite in C++ + #' @rdname cv #' @export cv_vec <- function( @@ -59,6 +61,7 @@ cv_vec <- function( na_rm = TRUE, ... ) { + # ugly, might not need yardstick::check_numeric_metric(truth, truth, case_weights = NULL) if (na_rm) { diff --git a/tests/testthat.R b/tests/testthat.R index 99bfdc6..883f850 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -7,6 +7,7 @@ # * https://testthat.r-lib.org/articles/special-files.html library(testthat) +library(checkmate) library(tidyhydro) test_check("tidyhydro") diff --git a/tests/testthat/test-kge.R b/tests/testthat/test-kge.R index 43dd9e7..411d1bc 100644 --- a/tests/testthat/test-kge.R +++ b/tests/testthat/test-kge.R @@ -81,3 +81,12 @@ test_that("Internal function works as expected", { kge_cpp(ex_dat$obs, ex_dat$pred, na_rm = TRUE, version = "2012") ) }) + +test_that("Negative values are not allowed in kgelog", { + x <- rnorm(100) + y <- rnorm(100) + + expect_error(kgelog_vec(x, y)) + expect_error(kgelog_hi_vec(x, y)) + expect_error(kgelog_low_vec(x, y)) +}) diff --git a/tests/testthat/test-measures.R b/tests/testthat/test-measures.R new file mode 100644 index 0000000..54ef69a --- /dev/null +++ b/tests/testthat/test-measures.R @@ -0,0 +1,5 @@ +test_that("Negative values are not allowed in GM", { + x <- rnorm(100) + + expect_error(gm_vec(x)) +}) diff --git a/tests/testthat/test-outputs.R b/tests/testthat/test-outputs.R new file mode 100644 index 0000000..4ce0fbe --- /dev/null +++ b/tests/testthat/test-outputs.R @@ -0,0 +1,424 @@ +# Property-based testing +# https://www.etiennebacher.com/posts/2024-10-01-using-property-testing-in-r + +# Tests to check that no matter the all sorts of numeric values +# are allowed in functions. + +options( + quickcheck.tests = 20L, + quickcheck.shrinks = 10L, + quickcheck.discards = 10L +) + +test_that("GM", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::double_left_bounded( + left = 1L, + len = 100L, + any_na = TRUE + ), + na_flag = quickcheck::logical_(len = 1L, any_na = FALSE), + property = function(obs, na_flag) { + x <- gm_vec(truth = obs, na_rm = na_flag) + df <- gm(data = data.frame(obs), truth = obs, na_rm = na_flag) + + checkmate::expect_number(x, na.ok = TRUE) + checkmate::expect_data_frame( + df, + types = c("numeric", "character"), + min.rows = 1L + ) + } + ) +}) + +test_that("CV", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::double_( + len = 100L, + any_na = TRUE + ), + na_flag = quickcheck::logical_(len = 1L, any_na = FALSE), + property = function(obs, na_flag) { + x <- cv_vec(truth = obs, na_rm = na_flag) + df <- cv( + data = data.frame(obs), + truth = obs, + na_rm = na_flag + ) + + checkmate::expect_number(x, na.ok = TRUE) + checkmate::expect_data_frame( + df, + types = c("numeric", "character"), + min.rows = 1L + ) + } + ) +}) + +test_that("NSE", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + sim = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + na_flag = quickcheck::logical_(len = 1L, any_na = FALSE), + property = function(obs, sim, na_flag) { + x <- nse_vec( + truth = obs, + estimate = sim, + na_rm = na_flag + ) + df <- nse( + data = data.frame(obs, sim), + truth = obs, + estimate = sim, + na_rm = na_flag + ) + + checkmate::expect_number(x, na.ok = TRUE) + checkmate::expect_data_frame( + df, + types = c("numeric", "character"), + min.rows = 1L + ) + } + ) +}) + +test_that("KGE", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + sim = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + na_flag = quickcheck::logical_(len = 1L, any_na = FALSE), + property = function(obs, sim, na_flag) { + x <- kge_vec( + truth = obs, + estimate = sim, + na_rm = na_flag + ) + df <- kge( + data = data.frame(obs, sim), + truth = obs, + estimate = sim, + na_rm = na_flag + ) + + checkmate::expect_number(x, na.ok = TRUE) + checkmate::expect_data_frame( + df, + types = c("numeric", "character"), + min.rows = 1L + ) + } + ) +}) + +test_that("KGE'", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + sim = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + na_flag = quickcheck::logical_(len = 1L, any_na = FALSE), + property = function(obs, sim, na_flag) { + x <- kge2012_vec( + truth = obs, + estimate = sim, + na_rm = na_flag + ) + df <- kge2012( + data = data.frame(obs, sim), + truth = obs, + estimate = sim, + na_rm = na_flag + ) + + checkmate::expect_number(x, na.ok = TRUE) + checkmate::expect_data_frame( + df, + types = c("numeric", "character"), + min.rows = 1L + ) + } + ) +}) + +test_that("KGElog", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::double_left_bounded( + left = 1, + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + sim = quickcheck::double_left_bounded( + left = 1, + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + na_flag = quickcheck::logical_(len = 1L, any_na = FALSE), + property = function(obs, sim, na_flag) { + x <- kgelog_vec( + truth = obs, + estimate = sim, + na_rm = na_flag + ) + df <- kgelog( + data = data.frame(obs, sim), + truth = obs, + estimate = sim, + na_rm = na_flag + ) + + checkmate::expect_number(x, na.ok = TRUE) + checkmate::expect_data_frame( + df, + types = c("numeric", "character"), + min.rows = 1L + ) + } + ) +}) + +test_that("RMSE", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + sim = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + na_flag = quickcheck::logical_(len = 1L, any_na = FALSE), + property = function(obs, sim, na_flag) { + x <- rmse_vec( + truth = obs, + estimate = sim, + na_rm = na_flag + ) + df <- rmse( + data = data.frame(obs, sim), + truth = obs, + estimate = sim, + na_rm = na_flag + ) + + checkmate::expect_number(x, na.ok = TRUE) + checkmate::expect_data_frame( + df, + types = c("numeric", "character"), + min.rows = 1L + ) + } + ) +}) + +test_that("MSE", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + sim = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + na_flag = quickcheck::logical_(len = 1L, any_na = FALSE), + property = function(obs, sim, na_flag) { + x <- mse_vec( + truth = obs, + estimate = sim, + na_rm = na_flag + ) + df <- mse( + data = data.frame(obs, sim), + truth = obs, + estimate = sim, + na_rm = na_flag + ) + + checkmate::expect_number(x, na.ok = TRUE) + checkmate::expect_data_frame( + df, + types = c("numeric", "character"), + min.rows = 1L + ) + } + ) +}) + +test_that("pBIAS", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + sim = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + na_flag = quickcheck::logical_(len = 1L, any_na = FALSE), + property = function(obs, sim, na_flag) { + x <- pbias_vec( + truth = obs, + estimate = sim, + na_rm = na_flag + ) + df <- pbias( + data = data.frame(obs, sim), + truth = obs, + estimate = sim, + na_rm = na_flag + ) + + checkmate::expect_number(x, na.ok = TRUE) + checkmate::expect_data_frame( + df, + types = c("numeric", "character"), + min.rows = 1L + ) + } + ) +}) + +test_that("PRESS", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + sim = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + na_flag = quickcheck::logical_(len = 1L, any_na = FALSE), + property = function(obs, sim, na_flag) { + x <- press_vec( + truth = obs, + estimate = sim, + na_rm = na_flag + ) + df <- press( + data = data.frame(obs, sim), + truth = obs, + estimate = sim, + na_rm = na_flag + ) + + checkmate::expect_number(x, na.ok = TRUE) + checkmate::expect_data_frame( + df, + types = c("numeric", "character"), + min.rows = 1L + ) + } + ) +}) + +test_that("SFE", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + sim = quickcheck::double_( + len = 100L, + any_na = TRUE, + any_nan = TRUE, + big_dbl = TRUE + ), + na_flag = quickcheck::logical_(len = 1L, any_na = FALSE), + property = function(obs, sim, na_flag) { + x <- sfe_vec( + truth = obs, + estimate = sim, + na_rm = na_flag + ) + df <- sfe( + data = data.frame(obs, sim), + truth = obs, + estimate = sim, + na_rm = na_flag + ) + + checkmate::expect_number(x, na.ok = TRUE) + checkmate::expect_data_frame( + df, + types = c("numeric", "character"), + min.rows = 1L + ) + } + ) +}) diff --git a/tests/testthat/test-system-crash.R b/tests/testthat/test-system-crash.R index 536690f..644190e 100644 --- a/tests/testthat/test-system-crash.R +++ b/tests/testthat/test-system-crash.R @@ -1,6 +1,8 @@ # Property-based testing # https://www.etiennebacher.com/posts/2024-10-01-using-property-testing-in-r +# Tests to ensure that the C++ code wouldn't crash the system + options( quickcheck.tests = 20L, quickcheck.shrinks = 10L, @@ -215,3 +217,39 @@ test_that("press", { } ) }) + +test_that("CV", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::any_atomic(any_na = TRUE), + na_flag = quickcheck::logical_(any_na = FALSE), + property = function(obs, na_flag) { + suppressWarnings( + try( + cv_vec(truth = obs, na_rm = na_flag), + silent = TRUE + ) + ) + expect_true(TRUE) + } + ) +}) + +test_that("GM", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::any_atomic(any_na = TRUE), + na_flag = quickcheck::logical_(any_na = FALSE), + property = function(obs, na_flag) { + suppressWarnings( + try( + gm_vec(truth = obs, na_rm = na_flag), + silent = TRUE + ) + ) + expect_true(TRUE) + } + ) +})