diff --git a/R/args.R b/R/args.R index c322629f6..254993403 100644 --- a/R/args.R +++ b/R/args.R @@ -681,7 +681,6 @@ DiagnoseArgs <- R6::R6Class( #' @param self A `CmdStanArgs` object. #' @return `TRUE` invisibly unless an error is thrown. validate_cmdstan_args <- function(self) { - validate_exe_file(self$exe_file) assert_dir_exists(self$output_dir, access = "rw") # at least 1 run id (chain id) @@ -1073,22 +1072,12 @@ process_init.default <- function(init, ...) { return(init) } -#' Remove the leftmost dimension if equal to 1 +#' Drop the draw dimension from `draws_of()` of a single draw #' @noRd -#' @param x An array like object +#' @param x The array `posterior::draws_of()` returns for one draw, whose +#' first dimension has length 1. .remove_leftmost_dim <- function(x) { - dims <- dim(x) - if (length(dims) == 1) { - return(drop(x)) - } else if (dims[1] == 1) { - new_dims <- dims[-1] - # Create a call to subset the array, maintaining all remaining dimensions - subset_expr <- as.call(c(as.name("["), list(x), 1, rep(TRUE, length(new_dims)), drop = FALSE)) - new_x <- eval(subset_expr) - return(array(new_x, dim = new_dims)) - } else { - return(x) - } + array(x, dim = dim(x)[-1]) } #' Write initial values to files if provided as posterior `draws` object @@ -1344,21 +1333,19 @@ process_init_approx <- function(init, num_procs, model_variables = NULL, # resample_draws() needs num_procs distinct candidates if (num_procs > num_candidates) { - if (inherits(init, "CmdStanPathfinder")) { - algo_name <- " Pathfinder " - extra_msg <- " Try running Pathfinder with psis_resample=FALSE." - } else if (inherits(init, "CmdStanVB")) { - algo_name <- " VB " - extra_msg <- "" - } else if (inherits(init, "CmdStanLaplace")) { - algo_name <- " Laplace " - extra_msg <- "" + algo_name <- switch( + class(init)[1], + CmdStanPathfinder = "Pathfinder", + CmdStanVB = "VB", + CmdStanLaplace = "Laplace" + ) + extra_msg <- if (inherits(init, "CmdStanPathfinder")) { + " Try running Pathfinder with psis_resample=FALSE." } else { - algo_name <- "" - extra_msg <- "" + "" } - stop(paste0("Not enough distinct draws (", num_procs, ") in", algo_name , - "fit to create inits.", extra_msg)) + stop(paste0("Not enough distinct draws (", num_procs, ") in ", + algo_name, " fit to create inits.", extra_msg)) } # CmdStan PSIS-resamples Pathfinder draws only with multiple paths and lp weights @@ -1493,20 +1480,6 @@ process_init.CmdStanMLE <- function(init, num_procs, model_variables = NULL, # Validation helpers ------------------------------------------------------ -#' Validate exe file exists -#' @noRd -#' @param exe_file Path to executable. -#' @return Either throws an error or returns `invisible(TRUE)` -validate_exe_file <- function(exe_file) { - if (!length(exe_file) || - !nzchar(exe_file) || - !file.exists(exe_file)) { - stop("There is no executable at '", exe_file, "'.", call. = FALSE) - } - invisible(TRUE) -} - - #' Validate initial values #' #' For CmdStan `init` must be `NULL`, a single real number >= 0, or paths to diff --git a/R/build_record.R b/R/build_record.R index 15f5b6caa..847c535ac 100644 --- a/R/build_record.R +++ b/R/build_record.R @@ -127,7 +127,8 @@ assert_record_dependency_entry <- function(value, field) { #' Check a build record against the format version 1 schema #' -#' Every check of a record's fields is here. `new_build_record()` runs it +#' Every check of a record's fields except `format_version` is here, +#' `read_build_record()` checks that first. `new_build_record()` runs it #' before a record is written and `read_build_record()` after one is read, so #' a record that passes when written passes when read. Fields the schema does #' not name are ignored. No feature in `reported_features` is required, since @@ -141,14 +142,6 @@ assert_record_dependency_entry <- function(value, field) { validate_build_record <- function(record) { assert_record_shape(record, "object", "record") - format_version <- record[["format_version"]] - if (!checkmate::test_int(format_version, tol = 0) || - format_version != build_record_format_version) { - stop_build_record_field( - "format_version", paste0("must be ", build_record_format_version) - ) - } - configuration <- assert_record_member(record, "configuration", "object") cpp_options <- assert_record_member( configuration, "cpp_options", "object", "configuration.cpp_options" diff --git a/R/fit.R b/R/fit.R index 00a44dac7..98603464b 100644 --- a/R/fit.R +++ b/R/fit.R @@ -41,11 +41,6 @@ CmdStanFit <- R6::R6Class( self$runset$num_procs() }, print = function(variables = NULL, ..., digits = 2, max_rows = getOption("cmdstanr_max_rows", 10)) { - if (is.null(private$draws_) && - !length(self$output_files(include_failed = FALSE))) { - stop("Fitting failed. Unable to print.", call. = FALSE) - } - # filter variables before passing to summary to avoid computing anything # that won't be printed because of max_rows all_variables <- self$metadata()$variables @@ -302,9 +297,6 @@ draws <- function(variables = NULL, inc_warmup = FALSE, format = getOption("cmds } else { format <- assert_valid_draws_format(format) } - if (!length(self$output_files(include_failed = FALSE))) { - stop("Fitting failed. Unable to retrieve the draws.", call. = FALSE) - } if (inc_warmup) { warning("`inc_warmup` is ignored except when used with CmdStanMCMC objects.", call. = FALSE) @@ -609,9 +601,7 @@ unconstrain_draws <- function(files = NULL, draws = NULL, format = getOption("cmdstanr_draws_format", "draws_array"), inc_warmup = FALSE) { self$init_model_methods() - if (!(format %in% valid_draws_formats())) { - stop("Invalid draws format requested!", call. = FALSE) - } + format <- assert_valid_draws_format(format) if (!is.null(files) || !is.null(draws)) { if (!is.null(files) && !is.null(draws)) { stop("Either a list of CSV files or a draws object can be passed, not both", @@ -1260,9 +1250,6 @@ CmdStanFit$set("public", name = "output", value = output) #' metadata <- function() { if (is.null(private$metadata_)) { - if (!length(self$output_files(include_failed = FALSE))) { - stop("Fitting failed. Unable to retrieve the metadata.", call. = FALSE) - } private$read_csv_() } private$metadata_ @@ -1538,7 +1525,8 @@ CmdStanMCMC <- R6::R6Class( inv_metric_ = NULL, read_csv_ = function(variables = NULL, sampler_diagnostics = NULL, format = getOption("cmdstanr_draws_format", "draws_array")) { if (!length(self$output_files(include_failed = FALSE))) { - stop("No chains finished successfully. Unable to retrieve the draws.", call. = FALSE) + stop("No chains finished successfully. There is no output to read.", + call. = FALSE) } csv_contents <- read_cmdstan_csv( files = self$output_files(include_failed = FALSE), @@ -1762,10 +1750,6 @@ sampler_diagnostics <- function(inc_warmup = FALSE, format = getOption("cmdstanr if (isTRUE(private$metadata_$algorithm == "fixed_param")) { stop("There are no sampler diagnostics when fixed_param = TRUE.", call. = FALSE) } - if (is.null(private$sampler_diagnostics_) && - !length(self$output_files(include_failed = FALSE))) { - stop("No chains finished successfully. Unable to retrieve the sampler diagnostics.", call. = FALSE) - } to_read <- remaining_columns_to_read( requested = NULL, currently_read = posterior::variables(private$sampler_diagnostics_), @@ -1928,9 +1912,6 @@ CmdStanMCMC$set("public", name = "diagnostic_summary", value = diagnostic_summar #' } #' inv_metric <- function(matrix = TRUE) { - if (!length(self$output_files(include_failed = FALSE))) { - stop("No chains finished successfully. Unable to retrieve the inverse metrics.", call. = FALSE) - } if (is.null(private$inv_metric_)) { private$read_csv_(variables = "", sampler_diagnostics = "") } @@ -2058,7 +2039,7 @@ CmdStanMLE <- R6::R6Class( # inherits draws_ and metadata_ slots from CmdStanFit read_csv_ = function(format = getOption("cmdstanr_draws_format", "draws_matrix")) { if (!length(self$output_files(include_failed = FALSE))) { - stop("Optimization failed. Unable to retrieve the draws.", call. = FALSE) + stop("Optimization failed. There is no output to read.", call. = FALSE) } csv_contents <- read_cmdstan_csv(self$output_files(), format = format) private$draws_ <- csv_contents$point_estimates @@ -2192,7 +2173,8 @@ CmdStanLaplace <- R6::R6Class( # inherits draws_ and metadata_ slots from CmdStanFit read_csv_ = function(format = getOption("cmdstanr_draws_format", "draws_matrix")) { if (!length(self$output_files(include_failed = FALSE))) { - stop("Laplace inference failed. Unable to retrieve the draws.", call. = FALSE) + stop("Laplace inference failed. There is no output to read.", + call. = FALSE) } csv_contents <- read_cmdstan_csv(self$output_files(), format = format) private$draws_ <- csv_contents$draws @@ -2309,7 +2291,8 @@ CmdStanVB <- R6::R6Class( # inherits draws_ and metadata_ slots from CmdStanFit read_csv_ = function(format = getOption("cmdstanr_draws_format", "draws_matrix")) { if (!length(self$output_files(include_failed = FALSE))) { - stop("Variational inference failed. Unable to retrieve the draws.", call. = FALSE) + stop("Variational inference failed. There is no output to read.", + call. = FALSE) } csv_contents <- read_cmdstan_csv(self$output_files(), format = format) private$draws_ <- csv_contents$draws @@ -2404,7 +2387,7 @@ CmdStanPathfinder <- R6::R6Class( # inherits draws_ and metadata_ slots from CmdStanFit read_csv_ = function(format = getOption("cmdstanr_draws_format", "draws_matrix")) { if (!length(self$output_files(include_failed = FALSE))) { - stop("Pathfinder failed. Unable to retrieve the draws.", call. = FALSE) + stop("Pathfinder failed. There is no output to read.", call. = FALSE) } csv_contents <- read_cmdstan_csv(self$output_files(), format = format) private$draws_ <- csv_contents$draws @@ -2496,9 +2479,6 @@ CmdStanGQ <- R6::R6Class( }, # override CmdStanFit draws method draws = function(variables = NULL, inc_warmup = FALSE, format = getOption("cmdstanr_draws_format", "draws_array")) { - if (!length(self$output_files(include_failed = FALSE))) { - stop("Generating quantities for all MCMC chains failed. Unable to retrieve the generated quantities.", call. = FALSE) - } if (inc_warmup) { warning("`inc_warmup` is ignored except when used with CmdStanMCMC objects.", call. = FALSE) @@ -2538,7 +2518,8 @@ CmdStanGQ <- R6::R6Class( # inherits draws_ and metadata_ slots from CmdStanFit read_csv_ = function(variables = NULL, format = getOption("cmdstanr_draws_format", "draws_array")) { if (!length(self$output_files(include_failed = FALSE))) { - stop("Generating quantities for all MCMC chains failed. Unable to retrieve the generated quantities.", call. = FALSE) + stop("Generating quantities for all MCMC chains failed. ", + "There is no output to read.", call. = FALSE) } csv_contents <- read_cmdstan_csv( files = self$output_files(include_failed = FALSE), diff --git a/R/run.R b/R/run.R index a6b42c2ed..069cff1e8 100644 --- a/R/run.R +++ b/R/run.R @@ -807,9 +807,6 @@ CmdStanProcs <- R6::R6Class( show_stdout_messages = function () { private$show_stdout_messages_ }, - show_stderr_messages = function () { - private$show_stderr_messages_ - }, num_procs = function() { private$num_procs_ }, diff --git a/R/utils.R b/R/utils.R index 0add1353f..f27f591c9 100644 --- a/R/utils.R +++ b/R/utils.R @@ -406,8 +406,6 @@ as_draws_format_fun <- function(draws_format) { f <- posterior::as_draws_matrix } else if (draws_format %in% c("draws_list", "list")) { f <- posterior::as_draws_list - } else if (draws_format %in% c("draws_rvars", "rvars")) { - f <- posterior::as_draws_rvars } f } @@ -448,9 +446,7 @@ maybe_convert_draws_format <- function(draws, format, ...) { "df" = posterior::as_draws_df(draws, ...), "data.frame" = posterior::as_draws_df(draws, ...), "list" = posterior::as_draws_list(draws, ...), - "matrix" = posterior::as_draws_matrix(draws, ...), - "rvars" = posterior::as_draws_rvars(draws, ...), - stop("Invalid draws format.", call. = FALSE) + "matrix" = posterior::as_draws_matrix(draws, ...) ) } @@ -462,9 +458,7 @@ create_draws_format <- function(format, ...) { "df" = posterior::draws_df(...), "data.frame" = posterior::draws_df(...), "list" = posterior::draws_list(...), - "matrix" = posterior::draws_matrix(...), - "rvars" = posterior::draws_rvars(...), - stop("Invalid draws format.", call. = FALSE) + "matrix" = posterior::draws_matrix(...) ) } diff --git a/tests/testthat/test-build-record.R b/tests/testthat/test-build-record.R index 67667c156..92b3c35aa 100644 --- a/tests/testthat/test-build-record.R +++ b/tests/testthat/test-build-record.R @@ -233,6 +233,12 @@ test_that("the validator names the field that fails", { rebuild(repeated_option), "`configuration.cpp_options`", fixed = TRUE ) + odd_name <- base + odd_name$configuration$cpp_options <- list(`1THREADS` = "true") + expect_error( + rebuild(odd_name), "`configuration.cpp_options.1THREADS`", fixed = TRUE + ) + unknown_kind <- base unknown_kind$untracked_dependencies <- list( list(kind = "mystery", detected_in = "make/local") diff --git a/tests/testthat/test-csv.R b/tests/testthat/test-csv.R index 1a49bf4d0..f2a254645 100644 --- a/tests/testthat/test-csv.R +++ b/tests/testthat/test-csv.R @@ -976,6 +976,8 @@ test_that("as_cmdstan_fit creates fitted model objects from csv", { error = TRUE, fits$laplace$mode() ) + + expect_length(fits$mcmc$inv_metric(), fit_logistic_thin_1$num_chains()) }) test_that("as_cmdstan_fit can check MCMC diagnostics", { diff --git a/tests/testthat/test-data.R b/tests/testthat/test-data.R index 6daacdff1..bae6fa052 100644 --- a/tests/testthat/test-data.R +++ b/tests/testthat/test-data.R @@ -223,7 +223,9 @@ test_that("process_fitted_params() works with draws_array", { test_that("process_fitted_params() works with draws_array without lp__", { fit <- testing_fit("logistic", method = "sample", seed = 123) - fit_params_files <- process_fitted_params(posterior::subset_draws(fit$draws(), variables = c("alpha", "beta[1]", "beta[2]", "beta[3]"))) + fit_params_files <- process_fitted_params(posterior::subset_draws( + fit$draws(), variable = c("alpha", "beta[1]", "beta[2]", "beta[3]") + )) expect_true(all(file.exists(fit_params_files))) chain <- 1 for(file in fit_params_files) { diff --git a/tests/testthat/test-failed-chains.R b/tests/testthat/test-failed-chains.R index 08b8ef0fc..cd31e7ce3 100644 --- a/tests/testthat/test-failed-chains.R +++ b/tests/testthat/test-failed-chains.R @@ -121,15 +121,23 @@ test_that("$save_* methods save all files regardless of chain failure", { }) test_that("errors when using draws after all chains fail", { - expect_error(fit_all_fail$summary(), "No chains finished successfully") - expect_error(fit_all_fail$draws(), "No chains finished successfully") - expect_error(fit_all_fail$sampler_diagnostics(), "No chains finished successfully") + no_output <- "No chains finished successfully" + expect_error(fit_all_fail$summary(), no_output) + expect_error(fit_all_fail$draws(), no_output) + expect_error(fit_all_fail$sampler_diagnostics(), no_output) expect_error(fit_all_fail$cmdstan_summary(), "Unable to run bin/stansummary") expect_error(fit_all_fail$cmdstan_diagnose(), "Unable to run bin/diagnose") - expect_error(fit_all_fail$print(), "Fitting failed. Unable to print") - expect_error(fit_all_fail$inv_metric(), "No chains finished successfully") - expect_error(fit_all_fail$metadata(), "Fitting failed. Unable to retrieve the metadata") - expect_error(fit_all_fail$inv_metric(), "No chains finished successfully") + expect_error(fit_all_fail$print(), no_output) + expect_error(fit_all_fail$inv_metric(), no_output) + expect_error(fit_all_fail$metadata(), no_output) +}) + +test_that("a fit whose chains all failed cannot be used as init", { + expect_error( + mod$sample(data = list(pr_fail = 0), chains = 1, refresh = 0, + init = fit_all_fail), + "unable to create initial values from a model with no samples" + ) }) test_that("can use draws after some chains fail", { @@ -166,12 +174,12 @@ test_that("errors when using draws after variational fais", { ), "Fitting finished unexpectedly!" ) - expect_error(fit$print(), "Fitting failed. Unable to print.") - expect_error(fit$summary(), "Fitting failed. Unable to retrieve the draws.") - expect_error(fit$draws(), "Fitting failed. Unable to retrieve the draws.") + expect_error(fit$print(), "Variational inference failed") + expect_error(fit$summary(), "Variational inference failed") + expect_error(fit$draws(), "Variational inference failed") expect_error(fit$cmdstan_summary(), "Unable to run bin/stansummary") expect_error(fit$cmdstan_diagnose(), "Unable to run bin/diagnose") - expect_error(fit$metadata(), "Fitting failed. Unable to retrieve the metadata.") + expect_error(fit$metadata(), "Variational inference failed") }) test_that("gq chains error on wrong input CSV", { @@ -197,15 +205,15 @@ test_that("gq chains error on wrong input CSV", { expect_error( fit$draws(), - "Generating quantities for all MCMC chains failed. Unable to retrieve the generated quantities." + "Generating quantities for all MCMC chains failed" ) expect_error( fit$metadata(), - "Fitting failed. Unable to retrieve the metadata." + "Generating quantities for all MCMC chains failed" ) expect_error( fit$print(), - "Fitting failed. Unable to print." + "Generating quantities for all MCMC chains failed" ) expect_warning( utils::capture.output( diff --git a/tests/testthat/test-fit-init.R b/tests/testthat/test-fit-init.R index 57f915a3d..45879d1a8 100644 --- a/tests/testthat/test-fit-init.R +++ b/tests/testthat/test-fit-init.R @@ -282,4 +282,25 @@ test_that("Draws Object with NA or Inf throws error", { draws_df[1, 4] = NA expect_error(mod_logistic$sample( data = data_list_logistic, seed = 1234, refresh=0, init = draws_df[1:4, ]), "alpha, beta contains NA or Inf values!") + + mod_bern <- testing_model("bernoulli") + fit_bern <- testing_fit("bernoulli", method = "laplace", refresh = 0) + draws_bern <- fit_bern$draws() + draws_bern[1, "theta"] <- NA + expect_error( + mod_bern$sample(data = testing_data("bernoulli"), chains = 1, + refresh = 0, init = draws_bern[1, ]), + "Variable: theta contains NA or Inf values!" + ) +}) + +test_that("a fit used as init must share parameters with the model", { + fit_logistic <- testing_fit("logistic", method = "sample", refresh = 0) + expect_error( + testing_model("bernoulli")$sample( + data = testing_data("bernoulli"), chains = 1, refresh = 0, + init = fit_logistic + ), + "None of the names of the parameters" + ) }) diff --git a/tests/testthat/test-fit-mcmc.R b/tests/testthat/test-fit-mcmc.R index b78009bfc..e868f6a55 100644 --- a/tests/testthat/test-fit-mcmc.R +++ b/tests/testthat/test-fit-mcmc.R @@ -299,6 +299,7 @@ test_that("loo method works if log_lik is available", { fit_bernoulli <- testing_fit("bernoulli_log_lik") expect_s3_class(suppressWarnings(fit_bernoulli$loo(cores = 1, save_psis = TRUE)), "loo") expect_s3_class(suppressWarnings(fit_bernoulli$loo(r_eff = FALSE)), "loo") + expect_s3_class(suppressWarnings(fit_bernoulli$loo(r_eff = TRUE)), "loo") expect_error( fit_bernoulli$loo(variables = c("log_lik", "beta")), @@ -379,6 +380,7 @@ test_that("draws() works for different formats", { expect_true(posterior::is_draws_array(a)) a <- fit_mcmc$draws(format = "df") expect_true(posterior::is_draws_df(a)) + expect_true(posterior::is_draws_df(fit_mcmc$draws(format = "data.frame"))) }) test_that("draws() errors if invalid format", { @@ -386,6 +388,10 @@ test_that("draws() errors if invalid format", { fit_mcmc$draws(format = "bad_format"), "The supplied draws format is not valid" ) + expect_error( + fit_mcmc$draws(format = "rvars"), + "convert after extracting the draws" + ) }) test_that("diagnostic_summary() works", { @@ -421,6 +427,9 @@ test_that("diagnostic_summary() works", { ) expect_equal(diagnostics$ebfmi, NA) + expect_no_message(quiet <- fit$diagnostic_summary(quiet = TRUE)) + expect_equal(quiet, diagnostics) + expect_equal(fit$diagnostic_summary(""), list()) expect_equal(fit$diagnostic_summary(NULL), list()) }) diff --git a/tests/testthat/test-fit-mle.R b/tests/testthat/test-fit-mle.R index 40ee475df..04806010a 100644 --- a/tests/testthat/test-fit-mle.R +++ b/tests/testthat/test-fit-mle.R @@ -76,7 +76,7 @@ test_that("no error when checking estimates after failure", { fit <- cmdstanr_example("schools", method = "optimize", seed = 123), # optim ålways fails for this "Fitting finished unexpectedly" ) - expect_error(fit$summary(), "Fitting failed. Unable to retrieve the draws.") + expect_error(fit$summary(), "Optimization failed") }) test_that("draws() works for different formats", { diff --git a/tests/testthat/test-fit-shared.R b/tests/testthat/test-fit-shared.R index 304cf87a7..90ead56f5 100644 --- a/tests/testthat/test-fit-shared.R +++ b/tests/testthat/test-fit-shared.R @@ -8,9 +8,15 @@ fits[["variational"]] <- testing_fit("logistic", method = "variational", seed = 123, save_latent_dynamics = TRUE) fits[["optimize"]] <- testing_fit("logistic", method = "optimize", seed = 123) fits[["laplace"]] <- testing_fit("logistic", method = "laplace", seed = 123) +fits[["pathfinder"]] <- testing_fit("logistic", method = "pathfinder", + seed = 123) fit_bern <- testing_fit("bernoulli", method = "sample", seed = 123) -fits[["generate_quantities"]] <- testing_fit("bernoulli_ppc", method = "generate_quantities", fitted_params = fit_bern, seed = 123) -all_methods <- c("sample", "optimize", "laplace", "variational", "generate_quantities") +fits[["generate_quantities"]] <- testing_fit( + "bernoulli_ppc", method = "generate_quantities", fitted_params = fit_bern, + seed = 123 +) +all_methods <- c("sample", "optimize", "laplace", "variational", "pathfinder", + "generate_quantities") test_that("*_files() methods return the right number of paths", { @@ -216,6 +222,16 @@ test_that("save_object() method works with qs2 format", { expect_identical(fit2$return_codes(), fit$return_codes()) }) +test_that("save_object() says when qs2 is not installed", { + local_mocked_bindings( + requireNamespace = function(...) FALSE, .package = "base" + ) + expect_error( + fits[["sample"]]$save_object(tempfile(fileext = ".qs2"), format = "qs2"), + "qs2 package is required" + ) +}) + test_that("save_object() method works with profiles", { mod <- testing_model("logistic_profiling") utils::capture.output( diff --git a/tests/testthat/test-install.R b/tests/testthat/test-install.R index 7c597f47b..51520d8c1 100644 --- a/tests/testthat/test-install.R +++ b/tests/testthat/test-install.R @@ -242,15 +242,19 @@ test_that("Install from release file works", { "https://github.com/stan-dev/cmdstan/releases/download/v2.37.0/cmdstan-2.37.0.tar.gz", destfile) - expect_message( - expect_output( - install_cmdstan(dir = dir, cores = CORES, quiet = FALSE, overwrite = TRUE, - release_file = destfile, - wsl = os_is_wsl()), - "Compiling C++ code", + expect_warning( + expect_message( + expect_output( + install_cmdstan(dir = dir, cores = CORES, quiet = FALSE, + overwrite = TRUE, release_file = destfile, + version = "2.37.0", wsl = os_is_wsl()), + "Compiling C++ code", + fixed = TRUE + ), + "CmdStan path set", fixed = TRUE ), - "CmdStan path set", + "release_file and release_url/version shouldn't both be specified", fixed = TRUE ) }) diff --git a/tests/testthat/test-knitr.R b/tests/testthat/test-knitr.R index 06a0b8686..588f19c23 100644 --- a/tests/testthat/test-knitr.R +++ b/tests/testthat/test-knitr.R @@ -24,6 +24,15 @@ test_that("eng_cmdstan works", { expect_interactive_message(eng_cmdstan(opts), "Compiling Stan program") opts$eval <- FALSE expect_noninteractive_silent(eng_cmdstan(opts)) + + opts$eval <- TRUE + opts$cache <- FALSE + expect_interactive_message(eng_cmdstan(opts), "Compiling Stan program") + opts$cache <- TRUE + opts$cache.path <- NA + opts$label <- "cmdstanr-knitr" + withr::local_dir(withr::local_tempdir()) + expect_interactive_message(eng_cmdstan(opts), "Compiling Stan program") }) test_that("register_knitr_engine works with and without override", { diff --git a/tests/testthat/test-model-code-print.R b/tests/testthat/test-model-code-print.R index d9740d944..d5565f40f 100644 --- a/tests/testthat/test-model-code-print.R +++ b/tests/testthat/test-model-code-print.R @@ -84,3 +84,11 @@ test_that("check_syntax() errors if only exe and no Stan file", { fixed = TRUE ) }) + +test_that("print(line_numbers = TRUE) numbers the lines", { + lines <- mod$code() + expect_equal( + capture.output(mod$print(line_numbers = TRUE)), + paste(base::format(seq_along(lines)), lines, sep = ": ") + ) +}) diff --git a/tests/testthat/test-model-methods.R b/tests/testthat/test-model-methods.R index 08a8c8164..167dffb63 100644 --- a/tests/testthat/test-model-methods.R +++ b/tests/testthat/test-model-methods.R @@ -297,6 +297,20 @@ test_that("unconstrain_draws returns correct values", { expect_message(fit$unconstrain_draws(draws = fit$draws(), inc_warmup = TRUE), "`inc_warmup` cannot be used with a draws object. Ignoring.") + expect_error( + fit$unconstrain_draws(files = fit$output_files(), draws = fit$draws()), + "not both" + ) + expect_true(posterior::is_draws_df(fit$unconstrain_draws(format = "df"))) + expect_true( + posterior::is_draws_df(fit$unconstrain_draws(format = "data.frame")) + ) + expect_true(posterior::is_draws_list(fit$unconstrain_draws(format = "list"))) + expect_error( + fit$unconstrain_draws(format = "rvars"), + "convert after extracting the draws" + ) + # With a lower-bounded constraint, the parameter draws should be the # exponentiation of the unconstrained draws model_code <- " diff --git a/tests/testthat/test-path.R b/tests/testthat/test-path.R index c71c240b0..a8dbfce7a 100644 --- a/tests/testthat/test-path.R +++ b/tests/testthat/test-path.R @@ -226,6 +226,25 @@ test_that("cmdstan_default_path() orders install directories by CmdStan version" ) }) +test_that("cmdstan_default_path() prefers a release over its rc", { + installs <- withr::local_tempdir(pattern = "cmdstan-rc-installs") + dir.create(file.path(installs, "cmdstan-2.36.0-rc1")) + expect_equal( + cmdstan_default_path(dir = installs), + file.path(installs, "cmdstan-2.36.0-rc1") + ) + dir.create(file.path(installs, "cmdstan-2.36.0")) + expect_equal( + cmdstan_default_path(dir = installs), file.path(installs, "cmdstan-2.36.0") + ) +}) + +test_that("set_cmdstan_path() errors when the makefile has no version line", { + path <- withr::local_tempdir(pattern = "cmdstan-no-version") + writeLines("STAN ?= stan/", file.path(path, "makefile")) + expect_error(set_cmdstan_path(path), "missing a version number") +}) + test_that("cmdstan_default_path() returns NULL for empty custom install directories", { installs <- withr::local_tempdir(pattern = "cmdstan-empty-installs") diff --git a/tests/testthat/test-stan-file-functions.R b/tests/testthat/test-stan-file-functions.R index 4384ea88c..4fc3594ec 100644 --- a/tests/testthat/test-stan-file-functions.R +++ b/tests/testthat/test-stan-file-functions.R @@ -60,6 +60,22 @@ test_that("format_stan_file() formats a program", { format_stan_file(include_model$stan_file, canonicalize = list("includes")), "real divide_real_by_two", fixed = TRUE ) + + expect_output( + format_stan_file(stan_file, canonicalize = TRUE), " real y;", fixed = TRUE + ) + long_line <- withr::local_tempfile( + lines = paste0( + "parameters {real y;} model {y ~ normal(0, ", + paste(rep("1", 20), collapse = " + "), ");}" + ), + fileext = ".stan" + ) + expect_gt(max(nchar(capture.output(format_stan_file(long_line)))), 30) + format_stan_file( + long_line, max_line_length = 30, overwrite_file = TRUE, backup = FALSE + ) + expect_true(all(nchar(readLines(long_line)) <= 30)) }) test_that("variables_stan_file() reports a program's variables", {