From 56e23e33363498b2f9be02db41d425beec8f4499 Mon Sep 17 00:00:00 2001 From: Rich FitzJohn Date: Fri, 3 May 2024 09:20:11 +0100 Subject: [PATCH] Basic testing --- inst/include/dust2/cpu.hpp | 2 +- inst/include/dust2/r/helpers.hpp | 2 +- tests/testthat/test-walk.R | 98 ++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/inst/include/dust2/cpu.hpp b/inst/include/dust2/cpu.hpp index 1f50d3f2..de222253 100644 --- a/inst/include/dust2/cpu.hpp +++ b/inst/include/dust2/cpu.hpp @@ -31,7 +31,7 @@ class dust_cpu { rng_(n_particles_, seed, deterministic) { // TODO: above, filter states need adding here too. if (dt != 1) { - throw std::runtime_error("Assuming dt = 1 for now"); + throw std::runtime_error("Requiring dt = 1 for now"); } } diff --git a/inst/include/dust2/r/helpers.hpp b/inst/include/dust2/r/helpers.hpp index 1ee418d2..d2228b94 100644 --- a/inst/include/dust2/r/helpers.hpp +++ b/inst/include/dust2/r/helpers.hpp @@ -5,7 +5,7 @@ namespace r { inline void check_scalar(cpp11::sexp x, const char * name) { if (LENGTH(x) != 1) { - cpp11::stop("'%s' must be scalar", name); + cpp11::stop("'%s' must be a scalar", name); } } diff --git a/tests/testthat/test-walk.R b/tests/testthat/test-walk.R index 51042fc8..b0a928b5 100644 --- a/tests/testthat/test-walk.R +++ b/tests/testthat/test-walk.R @@ -18,3 +18,101 @@ test_that("can run simple walk model", { expect_equal(s, colSums(r$normal(3, 0, 1))) expect_equal(dust2_cpu_walk_time(ptr), 3) }) + + +test_that("can set model state from a vector", { + pars <- list(sd = 1, random_initial = TRUE) + obj <- dust2_cpu_walk_alloc(pars, 0, 1, 10, 42, FALSE) + ptr <- obj[[1]] + s <- runif(10) + expect_null(dust2_cpu_walk_set_state(ptr, s)) + expect_equal(dust2_cpu_walk_state(ptr), s) + + expect_null(dust2_cpu_walk_run_steps(ptr, 3)) + + r <- mcstate2::mcstate_rng$new(seed = 42, n_streams = 10) + expect_equal(dust2_cpu_walk_state(ptr), + colSums(r$normal(3, 0, 1)) + s) +}) + + +test_that("can set model state from initial conditions", { + pars <- list(sd = 1, random_initial = TRUE) + obj <- dust2_cpu_walk_alloc(pars, 0, 1, 10, 42, FALSE) + ptr <- obj[[1]] + expect_null(dust2_cpu_walk_set_state_initial(ptr)) + r <- mcstate2::mcstate_rng$new(seed = 42, n_streams = 10) + expect_equal(dust2_cpu_walk_state(ptr), + drop(r$normal(1, 0, 1))) +}) + + +## Not 100% sure we'll keep this, but we will see. This is only a +## feature of the walk model and not dust though. +test_that("can set model state from initial conditions with empty version", { + pars <- list(sd = 1) + obj <- dust2_cpu_walk_alloc(pars, 0, 1, 10, 42, FALSE) + ptr <- obj[[1]] + expect_null(dust2_cpu_walk_set_state_initial(ptr)) + expect_equal(dust2_cpu_walk_state(ptr), + rep(0, 10)) +}) + + +test_that("can run deterministically", { + pars <- list(sd = 1) + obj <- dust2_cpu_walk_alloc(pars, 0, 1, 10, 42, TRUE) + ptr <- obj[[1]] + expect_null(dust2_cpu_walk_run_steps(ptr, 3)) + expect_equal(dust2_cpu_walk_state(ptr), + rep(0, 10)) +}) + + +test_that("require that dt is 1 for now", { + pars <- list(sd = 1, random_initial = TRUE) + expect_error( + dust2_cpu_walk_alloc(pars, 0, 0.5, 10, 42, FALSE), + "Requiring dt = 1 for now", + fixed = TRUE) +}) + + +## Not a test at all of the model, but of the error handling in +## r/helpers.hpp +test_that("validate inputs", { + pars <- list(sd = 1, random_initial = TRUE) + expect_error( + dust2_cpu_walk_alloc(pars, 0:3, 1, 10, 42, FALSE), + "'time' must be a scalar") + + expect_identical( + dust2_cpu_walk_time(dust2_cpu_walk_alloc(pars, 5L, 1, 10, 42, FALSE)[[1]]), + 5.0) + expect_identical( + dust2_cpu_walk_time(dust2_cpu_walk_alloc(pars, 5, 1, 10, 42, FALSE)[[1]]), + 5.0) + expect_error( + dust2_cpu_walk_alloc(pars, "5", 1, 10, 42, FALSE), + "'time' must be scalar numeric") + + expect_identical( + dust2_cpu_walk_state(dust2_cpu_walk_alloc(pars, 5, 1, 10, 42, FALSE)[[1]]), + rep(0, 10)) + expect_identical( + dust2_cpu_walk_state(dust2_cpu_walk_alloc(pars, 5, 1, 10L, 42, FALSE)[[1]]), + rep(0, 10)) + expect_error( + dust2_cpu_walk_alloc(pars, 5, 1, 9.5, 42, FALSE), + "'n_particles' must be integer-like") + expect_error( + dust2_cpu_walk_alloc(pars, 5, 1, "10", 42, FALSE), + "'n_particles' must be scalar integer") + expect_error( + dust2_cpu_walk_alloc(pars, 5, 1, -5, 42, FALSE), + "'n_particles' must be non-negative") + + expect_error( + dust2_cpu_walk_alloc(pars, 5, 1, 10, 42, 1), + "'deterministic' must be scalar logical") +})