tests/testthat/test-clm_stan.R

# Tests for clm_stan main function
#
# These tests verify the core functionality of clm_stan(), including:
# - Basic model fitting and object creation
# - Warmup parameter auto-adjustment (consistent with rstan/brms)
# - Input validation (iter > warmup)
# - Edge cases (odd iteration numbers, etc.)
#
# NOTE: These tests require compiled Stan models.
# - Skipped in devtools::test() (development mode)
# - Run in R CMD check (after package build/install)

# Helper to check if Stan models are compiled
stan_models_compiled <- function() {
  model_path <- system.file("bin", "stan", "clm_base", package = "clmstan")
  nzchar(model_path) && file.exists(model_path)
}

# =============================================================================
# Basic functionality tests
# =============================================================================

test_that("clm_stan returns valid clmstan object", {
  skip_on_cran()
  skip_if_not(instantiate::stan_cmdstan_exists(), "CmdStan not available")
  skip_if_not(stan_models_compiled(), "Stan models not compiled")

  data(wine, package = "ordinal")

  fit <- clm_stan(rating ~ temp, data = wine,
                  chains = 1, iter = 200, refresh = 0)

  # Check class
  expect_s3_class(fit, "clmstan")

  # Check basic methods work
  expect_no_error(print(fit))
  expect_no_error(summary(fit))
  expect_no_error(coef(fit))
})

# =============================================================================
# Warmup parameter auto-adjustment tests
# =============================================================================

test_that("warmup parameter auto-adjustment works", {
  skip_on_cran()
  skip_if_not(instantiate::stan_cmdstan_exists(), "CmdStan not available")
  skip_if_not(stan_models_compiled(), "Stan models not compiled")

  data(wine, package = "ordinal")

  # Test 1: warmup = NULL (default) uses floor(iter/2)
  fit <- clm_stan(rating ~ temp, data = wine,
                  chains = 1, iter = 200,  # warmup未指定
                  refresh = 0)

  # iter_sampling = 200 - floor(200/2) = 200 - 100 = 100
  # Access internal CmdStanMCMC object via fit$fit
  expect_equal(fit$fit$metadata()$iter_sampling, 100)
  expect_equal(fit$fit$metadata()$iter_warmup, 100)

  # Test 2: explicit warmup is respected
  fit2 <- clm_stan(rating ~ temp, data = wine,
                   chains = 1, iter = 200, warmup = 50,
                   refresh = 0)

  # iter_sampling = 200 - 50 = 150
  expect_equal(fit2$fit$metadata()$iter_sampling, 150)
  expect_equal(fit2$fit$metadata()$iter_warmup, 50)
})

test_that("odd iter values work correctly with auto-adjustment", {
  skip_on_cran()
  skip_if_not(instantiate::stan_cmdstan_exists(), "CmdStan not available")
  skip_if_not(stan_models_compiled(), "Stan models not compiled")

  data(wine, package = "ordinal")

  # iter = 201 (odd number) → warmup = floor(201/2) = 100
  fit <- clm_stan(rating ~ temp, data = wine,
                  chains = 1, iter = 201, refresh = 0)

  # Access internal CmdStanMCMC object via fit$fit
  expect_equal(fit$fit$metadata()$iter_warmup, 100)
  expect_equal(fit$fit$metadata()$iter_sampling, 101)
})

# =============================================================================
# Input validation tests
# =============================================================================

test_that("iter <= warmup validation works", {
  data(wine, package = "ordinal")

  # iter < warmup should error
  expect_error(
    clm_stan(rating ~ temp, data = wine,
             chains = 1, iter = 100, warmup = 200),
    regexp = "iter.*must be greater than.*warmup"
  )

  # iter == warmup should error
  expect_error(
    clm_stan(rating ~ temp, data = wine,
             chains = 1, iter = 100, warmup = 100),
    regexp = "iter.*must be greater than.*warmup"
  )
})

Try the clmstan package in your browser

Any scripts or data that you put into this service are public.

clmstan documentation built on June 29, 2026, 5:06 p.m.