export_bundle_fixture <- local({ old_opt <- options(lifecycle_verbosity = "quiet") on.exit(options(old_opt), add = TRUE) dat <- mfrmr:::sample_mfrm_data(seed = 123) fit <- suppressWarnings(fit_mfrm( dat, "Person", c("Rater", "Criterion"), "Score", method = "JML", maxit = 20 )) diagnostics <- suppressWarnings(diagnose_mfrm(fit, residual_pca = "overall")) run <- suppressWarnings(run_mfrm_facets( dat, person = "Person", facets = c("Rater", "Criterion"), score = "Score", method = "JML", maxit = 20 )) bias_all <- suppressWarnings(estimate_bias( fit, diagnostics = diagnostics, facet_a = "Rater", facet_b = "Criterion", max_iter = 2 )) list( fit = fit, diagnostics = diagnostics, run = run, bias_all = bias_all ) }) prediction_bundle_fixture <- local({ dat <- load_mfrmr_data("example_core") keep_people <- unique(dat$Person)[1:18] dat <- dat[dat$Person %in% keep_people, , drop = FALSE] fit <- suppressWarnings(fit_mfrm( dat, "Person", c("Rater", "Criterion"), "Score", method = "MML", quad_points = 5, maxit = 15 )) diagnostics <- diagnose_mfrm(fit, residual_pca = "none") spec <- build_mfrm_sim_spec( n_person = 20, n_rater = 4, n_criterion = 4, raters_per_person = 2, assignment = "rotating" ) population_prediction <- suppressWarnings( predict_mfrm_population( sim_spec = spec, reps = 2, maxit = 15, seed = 1 ) ) new_units <- data.frame( Person = c("NEW01", "NEW01"), Rater = unique(dat$Rater)[1], Criterion = unique(dat$Criterion)[1:2], Score = c(2, 3) ) unit_prediction <- predict_mfrm_units( fit, new_units, n_draws = 2, seed = 1 ) plausible_values <- sample_mfrm_plausible_values( fit, new_units, n_draws = 2, seed = 1 ) list( fit = fit, diagnostics = diagnostics, population_prediction = population_prediction, unit_prediction = unit_prediction, plausible_values = plausible_values ) }) latent_prediction_bundle_fixture <- local({ fixture <- mfrmr:::with_preserved_rng_seed(20260403, { persons <- paste0("P", sprintf("%02d", 1:60)) items <- paste0("I", 1:6) x <- stats::rnorm(length(persons)) theta <- 0.25 + 0.9 * x + stats::rnorm(length(persons), sd = 0.6) item_beta <- seq(-1.0, 1.0, length.out = length(items)) dat <- expand.grid(Person = persons, Item = items, stringsAsFactors = FALSE) eta <- theta[match(dat$Person, persons)] - item_beta[match(dat$Item, items)] dat$Score <- stats::rbinom(nrow(dat), 1, stats::plogis(eta)) person_tbl <- data.frame( Person = persons, X = x, stringsAsFactors = FALSE ) fit <- suppressWarnings(fit_mfrm( dat, "Person", "Item", "Score", method = "MML", model = "RSM", population_formula = ~ X, person_data = person_tbl, quad_points = 7, maxit = 80 )) new_units <- data.frame( Person = c("NEW_LOW", "NEW_LOW", "NEW_HIGH", "NEW_HIGH"), Item = c(items[1], items[2], items[1], items[2]), Score = c(1, 0, 1, 0), stringsAsFactors = FALSE ) new_person_data <- data.frame( Person = c("NEW_LOW", "NEW_HIGH"), X = c(-1.5, 1.5), stringsAsFactors = FALSE ) unit_prediction <- predict_mfrm_units( fit, new_units, person_data = new_person_data, n_draws = 2, seed = 1 ) plausible_values <- sample_mfrm_plausible_values( fit, new_units, person_data = new_person_data, n_draws = 2, seed = 1 ) list( fit = fit, unit_prediction = unit_prediction, plausible_values = plausible_values ) }) fixture }) test_that("build_mfrm_manifest captures reproducibility metadata", { manifest <- build_mfrm_manifest( fit = export_bundle_fixture$fit, diagnostics = export_bundle_fixture$diagnostics, bias_results = export_bundle_fixture$bias_all ) expect_s3_class(manifest, "mfrm_manifest") expect_true(is.data.frame(manifest$summary)) expect_true(is.data.frame(manifest$environment)) expect_true(is.data.frame(manifest$available_outputs)) expect_true(any(manifest$available_outputs$Component == "residual_pca")) expect_true( manifest$available_outputs$Available[manifest$available_outputs$Component == "bias_results"][1] ) expect_equal(manifest$summary$Method[[1]], "JML") expect_equal(manifest$summary$MethodUsed[[1]], "JMLE") expect_equal(manifest$summary$Observations[[1]], nrow(export_bundle_fixture$fit$prep$data)) expect_equal(manifest$summary$Persons[[1]], export_bundle_fixture$fit$config$n_person) }) test_that("build_mfrm_manifest and replay script support FACETS-mode runs", { manifest <- build_mfrm_manifest(export_bundle_fixture$run) replay <- build_mfrm_replay_script( export_bundle_fixture$run, bias_results = export_bundle_fixture$bias_all, data_file = "analysis_data.csv" ) expect_s3_class(manifest, "mfrm_manifest") expect_s3_class(replay, "mfrm_replay_script") expect_match(replay$script, "run_mfrm_facets\\(") expect_match(replay$script, "analysis_data\\.csv") expect_match(replay$script, "estimate_bias\\(") expect_match(replay$script, "# posterior_basis = legacy_mml", fixed = TRUE) }) test_that("build_mfrm_manifest records optional prediction artifacts", { manifest <- build_mfrm_manifest( fit = prediction_bundle_fixture$fit, diagnostics = prediction_bundle_fixture$diagnostics, population_prediction = prediction_bundle_fixture$population_prediction, unit_prediction = prediction_bundle_fixture$unit_prediction, plausible_values = prediction_bundle_fixture$plausible_values ) expect_s3_class(manifest, "mfrm_manifest") expect_true(any(manifest$available_outputs$Component == "population_prediction")) expect_true(any(manifest$available_outputs$Component == "unit_prediction")) expect_true(any(manifest$available_outputs$Component == "plausible_values")) expect_true( manifest$available_outputs$Available[manifest$available_outputs$Component == "population_prediction"][1] ) expect_true( manifest$available_outputs$Available[manifest$available_outputs$Component == "unit_prediction"][1] ) expect_true( manifest$available_outputs$Available[manifest$available_outputs$Component == "plausible_values"][1] ) }) test_that("build_mfrm_manifest rejects bounded GPCM fits outside the validated export boundary", { dat <- load_mfrmr_data("example_core") keep_people <- unique(dat$Person)[1:14] dat <- dat[dat$Person %in% keep_people, , drop = FALSE] fit_gpcm <- suppressWarnings( fit_mfrm( dat, "Person", c("Rater", "Criterion"), "Score", method = "MML", model = "GPCM", step_facet = "Criterion", quad_points = 5, maxit = 20 ) ) expect_error( build_mfrm_manifest(fit_gpcm), "export bundle helpers", fixed = TRUE ) }) test_that("build_mfrm_replay_script reproduces optional prediction artifacts", { replay <- build_mfrm_replay_script( fit = prediction_bundle_fixture$fit, diagnostics = prediction_bundle_fixture$diagnostics, population_prediction = prediction_bundle_fixture$population_prediction, unit_prediction = prediction_bundle_fixture$unit_prediction, plausible_values = prediction_bundle_fixture$plausible_values, include_bundle = TRUE, bundle_prefix = "bundle_pred_test", data_file = "analysis_data.csv" ) expect_s3_class(replay, "mfrm_replay_script") expect_match(replay$script, "predict_mfrm_population\\(") expect_match(replay$script, "predict_mfrm_units\\(") expect_match(replay$script, "sample_mfrm_plausible_values\\(") expect_match( replay$script, 'include = c\\("core_tables", "checklist", "dashboard", "manifest", "html",\\s*"predictions"\\)' ) expect_true(replay$summary$PopulationPrediction[[1]]) expect_true(replay$summary$UnitPrediction[[1]]) expect_true(replay$summary$PlausibleValues[[1]]) expect_identical(as.character(replay$summary$FitPosteriorBasis[[1]]), "legacy_mml") }) test_that("build_mfrm_replay_script preserves latent-regression scoring inputs", { replay <- build_mfrm_replay_script( fit = latent_prediction_bundle_fixture$fit, unit_prediction = latent_prediction_bundle_fixture$unit_prediction, plausible_values = latent_prediction_bundle_fixture$plausible_values, data_file = "analysis_data.csv" ) expect_s3_class(replay, "mfrm_replay_script") expect_match(replay$script, "fit_person_data <-") expect_match(replay$script, "population_formula = ~X", fixed = TRUE) expect_match(replay$script, "person_data = fit_person_data", fixed = TRUE) expect_match(replay$script, 'person_id = "Person"', fixed = TRUE) expect_match(replay$script, "unit_prediction_person_data <-") expect_match(replay$script, "plausible_value_person_data <-") expect_match(replay$script, "person_data = unit_prediction_person_data", fixed = TRUE) expect_match(replay$script, "person_data = plausible_value_person_data", fixed = TRUE) expect_match(replay$script, 'population_policy = "error"', fixed = TRUE) expect_identical(as.character(replay$summary$FitPosteriorBasis[[1]]), "population_model") }) test_that("build_conquest_overlap_bundle returns a minimal exact-overlap bundle", { bundle <- build_conquest_overlap_bundle() expect_s3_class(bundle, "mfrm_conquest_overlap_bundle") expect_true(is.data.frame(bundle$summary)) expect_true(is.data.frame(bundle$comparison_targets)) expect_true(is.data.frame(bundle$response_wide)) expect_true(is.data.frame(bundle$person_data)) expect_true(is.data.frame(bundle$item_map)) expect_true(is.data.frame(bundle$mfrmr_population)) expect_true(is.data.frame(bundle$mfrmr_item_estimates)) expect_true(is.data.frame(bundle$mfrmr_case_eap)) expect_equal(bundle$summary$Case[[1]], "synthetic_latent_regression") expect_equal(bundle$summary$Persons[[1]], 60) expect_equal(bundle$summary$Items[[1]], 6) expect_true(all(c("Person", "X", sprintf("I%03d", 1:6)) %in% names(bundle$response_wide))) expect_match(bundle$conquest_command, "filetype=csv", fixed = TRUE) expect_match(bundle$conquest_command, "regression X;", fixed = TRUE) expect_match(bundle$conquest_command, "model item;", fixed = TRUE) expect_match(bundle$conquest_command, "show cases ! estimates=eap", fixed = TRUE) s <- summary(bundle) expect_s3_class(s, "summary.mfrm_bundle") expect_identical(as.character(s$overview$Class[1]), "mfrm_conquest_overlap_bundle") }) test_that("build_conquest_overlap_bundle writes expected external-comparison files", { out_dir <- file.path(tempdir(), "mfrmr-conquest-overlap") if (dir.exists(out_dir)) unlink(out_dir, recursive = TRUE, force = TRUE) dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) bundle <- build_conquest_overlap_bundle( output_dir = out_dir, prefix = "cq_overlap_test", overwrite = TRUE ) expect_s3_class(bundle, "mfrm_conquest_overlap_bundle") expect_true(is.data.frame(bundle$written_files)) expect_true(any(bundle$written_files$Component == "response_wide")) expect_true(any(bundle$written_files$Component == "conquest_command")) expect_true(file.exists(file.path(out_dir, "cq_overlap_test_wide.csv"))) expect_true(file.exists(file.path(out_dir, "cq_overlap_test.cqc"))) expect_true(file.exists(file.path(out_dir, "cq_overlap_test_mfrmr_population.csv"))) expect_true(file.exists(file.path(out_dir, "cq_overlap_test_mfrmr_item_estimates.csv"))) expect_true(file.exists(file.path(out_dir, "cq_overlap_test_mfrmr_case_eap.csv"))) expect_true(file.exists(file.path(out_dir, "cq_overlap_test_README.txt"))) }) test_that("audit_conquest_overlap compares normalized ConQuest tables", { bundle <- build_conquest_overlap_bundle() cq_pop <- data.frame( Term = bundle$mfrmr_population$Parameter, Est = bundle$mfrmr_population$Estimate, stringsAsFactors = FALSE ) cq_item <- data.frame( ItemID = bundle$mfrmr_item_estimates$ResponseVar, Est = bundle$mfrmr_item_estimates$Estimate, stringsAsFactors = FALSE ) cq_case <- data.frame( PID = bundle$mfrmr_case_eap$Person, EAP = bundle$mfrmr_case_eap$Estimate, stringsAsFactors = FALSE ) audit <- audit_conquest_overlap( bundle = bundle, conquest_population = cq_pop, conquest_item_estimates = cq_item, conquest_case_eap = cq_case, conquest_population_term = "Term", conquest_population_estimate = "Est", conquest_item_id = "ItemID", conquest_item_estimate = "Est", conquest_case_person = "PID", conquest_case_estimate = "EAP" ) expect_s3_class(audit, "mfrm_conquest_overlap_audit") expect_true(is.data.frame(audit$overall)) expect_true(is.data.frame(audit$population_comparison)) expect_true(is.data.frame(audit$item_comparison)) expect_true(is.data.frame(audit$case_comparison)) expect_equal(audit$overall$AttentionItems[[1]], 0) expect_true(all(abs(audit$population_comparison$Difference[audit$population_comparison$Status == "Compared"]) < 1e-10)) expect_true(all(abs(audit$item_comparison$CenteredDifference[audit$item_comparison$Status == "Compared"]) < 1e-10)) expect_true(all(abs(audit$case_comparison$Difference[audit$case_comparison$Status == "Compared"]) < 1e-10)) s <- summary(audit) expect_s3_class(s, "summary.mfrm_bundle") expect_identical(as.character(s$overview$Class[1]), "mfrm_conquest_overlap_audit") }) test_that("normalize_conquest_overlap_tables standardizes extracted tables", { bundle <- build_conquest_overlap_bundle() normalized <- normalize_conquest_overlap_tables( conquest_population = data.frame( Term = bundle$mfrmr_population$Parameter, Est = bundle$mfrmr_population$Estimate, Group = "population", stringsAsFactors = FALSE ), conquest_item_estimates = data.frame( ItemCode = bundle$mfrmr_item_estimates$ResponseVar, Est = bundle$mfrmr_item_estimates$Estimate, Source = "items", stringsAsFactors = FALSE ), conquest_case_eap = data.frame( PID = bundle$mfrmr_case_eap$Person, EAP = bundle$mfrmr_case_eap$Estimate, Batch = "cases", stringsAsFactors = FALSE ), conquest_population_term = "Term", conquest_population_estimate = "Est", conquest_item_id = "ItemCode", conquest_item_estimate = "Est", conquest_case_person = "PID", conquest_case_estimate = "EAP" ) expect_s3_class(normalized, "mfrm_conquest_overlap_tables") expect_true(all(c("Parameter", "Estimate", "Group") %in% names(normalized$conquest_population))) expect_true(all(c("ItemID", "Estimate", "Source") %in% names(normalized$conquest_item_estimates))) expect_true(all(c("Person", "Estimate", "Batch") %in% names(normalized$conquest_case_eap))) expect_true(is.numeric(normalized$conquest_population$Estimate)) expect_true(is.numeric(normalized$conquest_item_estimates$Estimate)) expect_true(is.numeric(normalized$conquest_case_eap$Estimate)) expect_equal(normalized$summary$PopulationRows[[1]], nrow(bundle$mfrmr_population)) expect_equal(normalized$summary$ItemRows[[1]], nrow(bundle$mfrmr_item_estimates)) expect_equal(normalized$summary$CaseRows[[1]], nrow(bundle$mfrmr_case_eap)) s <- summary(normalized) expect_s3_class(s, "summary.mfrm_bundle") expect_identical(as.character(s$overview$Class[1]), "mfrm_conquest_overlap_tables") }) test_that("audit_conquest_overlap accepts normalized contract objects", { bundle <- build_conquest_overlap_bundle() normalized <- normalize_conquest_overlap_tables( conquest_population = data.frame( Term = bundle$mfrmr_population$Parameter, Est = bundle$mfrmr_population$Estimate, stringsAsFactors = FALSE ), conquest_item_estimates = data.frame( ItemCode = bundle$mfrmr_item_estimates$ResponseVar, Est = bundle$mfrmr_item_estimates$Estimate, stringsAsFactors = FALSE ), conquest_case_eap = data.frame( PID = bundle$mfrmr_case_eap$Person, EAP = bundle$mfrmr_case_eap$Estimate, stringsAsFactors = FALSE ), conquest_population_term = "Term", conquest_population_estimate = "Est", conquest_item_id = "ItemCode", conquest_item_estimate = "Est", conquest_case_person = "PID", conquest_case_estimate = "EAP" ) audit <- audit_conquest_overlap(bundle, normalized) expect_s3_class(audit, "mfrm_conquest_overlap_audit") expect_equal(audit$overall$AttentionItems[[1]], 0) expect_true(all(abs(audit$population_comparison$Difference[audit$population_comparison$Status == "Compared"]) < 1e-10)) expect_true(all(abs(audit$item_comparison$CenteredDifference[audit$item_comparison$Status == "Compared"]) < 1e-10)) expect_true(all(abs(audit$case_comparison$Difference[audit$case_comparison$Status == "Compared"]) < 1e-10)) expect_identical(as.character(audit$settings$Value[audit$settings$Setting == "conquest_item_id"][1]), "ItemID") }) test_that("normalize_conquest_overlap_files reads extracted csv/tsv tables", { bundle <- build_conquest_overlap_bundle() out_dir <- file.path(tempdir(), "mfrmr-conquest-normalize-files") if (dir.exists(out_dir)) unlink(out_dir, recursive = TRUE, force = TRUE) dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) pop_path <- file.path(out_dir, "cq_pop.csv") item_path <- file.path(out_dir, "cq_item.tsv") case_path <- file.path(out_dir, "cq_case.txt") utils::write.csv( data.frame( Term = bundle$mfrmr_population$Parameter, Est = bundle$mfrmr_population$Estimate, stringsAsFactors = FALSE ), pop_path, row.names = FALSE ) utils::write.table( data.frame( Item = bundle$mfrmr_item_estimates$ResponseVar, Est = bundle$mfrmr_item_estimates$Estimate, stringsAsFactors = FALSE ), item_path, sep = "\t", row.names = FALSE ) utils::write.table( data.frame( PID = bundle$mfrmr_case_eap$Person, EAP = bundle$mfrmr_case_eap$Estimate, stringsAsFactors = FALSE ), case_path, sep = ";", row.names = FALSE ) normalized <- normalize_conquest_overlap_files( population_file = pop_path, item_file = item_path, case_file = case_path, conquest_population_term = "Term", conquest_population_estimate = "Est", conquest_item_id = "Item", conquest_item_estimate = "Est", conquest_case_person = "PID", conquest_case_estimate = "EAP" ) expect_s3_class(normalized, "mfrm_conquest_overlap_tables") expect_true(is.data.frame(normalized$source_files)) expect_equal(normalized$source_files$Delimiter[[1]], ",") expect_equal(normalized$source_files$Delimiter[[2]], "\t") expect_equal(normalized$source_files$Delimiter[[3]], ";") audit <- audit_conquest_overlap(bundle, normalized) expect_s3_class(audit, "mfrm_conquest_overlap_audit") expect_equal(audit$overall$AttentionItems[[1]], 0) }) test_that("ConQuest overlap helpers auto-resolve conservative alias columns", { bundle <- build_conquest_overlap_bundle() normalized <- normalize_conquest_overlap_tables( conquest_population = data.frame( Term = bundle$mfrmr_population$Parameter, Est = bundle$mfrmr_population$Estimate, stringsAsFactors = FALSE ), conquest_item_estimates = data.frame( Label = bundle$mfrmr_item_estimates$ResponseVar, Facility = bundle$mfrmr_item_estimates$Estimate, stringsAsFactors = FALSE ), conquest_case_eap = data.frame( PID = bundle$mfrmr_case_eap$Person, EAP_1 = bundle$mfrmr_case_eap$Estimate, stringsAsFactors = FALSE ) ) expect_s3_class(normalized, "mfrm_conquest_overlap_tables") expect_equal(names(normalized$conquest_population)[1:2], c("Parameter", "Estimate")) expect_equal(names(normalized$conquest_item_estimates)[1:2], c("ItemID", "Estimate")) expect_equal(names(normalized$conquest_case_eap)[1:2], c("Person", "Estimate")) audit <- audit_conquest_overlap( bundle, conquest_population = data.frame( Term = bundle$mfrmr_population$Parameter, Est = bundle$mfrmr_population$Estimate, stringsAsFactors = FALSE ), conquest_item_estimates = data.frame( Label = bundle$mfrmr_item_estimates$ResponseVar, Facility = bundle$mfrmr_item_estimates$Estimate, stringsAsFactors = FALSE ), conquest_case_eap = data.frame( PID = bundle$mfrmr_case_eap$Person, EAP_1 = bundle$mfrmr_case_eap$Estimate, stringsAsFactors = FALSE ) ) expect_s3_class(audit, "mfrm_conquest_overlap_audit") expect_equal(audit$overall$AttentionItems[[1]], 0) }) test_that("build_mfrm_replay_script preserves keep_original and rating range", { dat <- mfrmr:::sample_mfrm_data(seed = 42) |> dplyr::filter(.data$Score %in% c(1, 3, 5)) fit <- suppressWarnings(fit_mfrm( dat, "Person", c("Rater", "Task", "Criterion"), "Score", method = "JML", maxit = 25, keep_original = TRUE )) replay <- build_mfrm_replay_script(fit, data_file = "analysis_data.csv") expect_match(replay$script, "keep_original = TRUE", fixed = TRUE) expect_match(replay$script, "rating_min = 1", fixed = TRUE) expect_match(replay$script, "rating_max = 5", fixed = TRUE) expect_match(replay$script, "# Model: RSM | Method: JML | InternalMethod: JMLE", fixed = TRUE) expect_match(replay$script, "# population_active = FALSE", fixed = TRUE) expect_match(replay$script, "# posterior_basis = legacy_mml", fixed = TRUE) expect_match(replay$script, 'method = "JML"', fixed = TRUE) }) test_that("export_mfrm_bundle writes requested tables and html output", { out_dir <- file.path(tempdir(), "mfrmr-export-bundle-test") if (dir.exists(out_dir)) unlink(out_dir, recursive = TRUE, force = TRUE) dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) expect_no_warning( bundle <- export_mfrm_bundle( fit = export_bundle_fixture$fit, diagnostics = export_bundle_fixture$diagnostics, bias_results = export_bundle_fixture$bias_all, output_dir = out_dir, prefix = "bundle_test", include = c("core_tables", "checklist", "dashboard", "apa", "anchors", "manifest", "visual_summaries", "script", "html"), overwrite = TRUE ) ) expect_s3_class(bundle, "mfrm_export_bundle") expect_true(is.data.frame(bundle$written_files)) expect_true(any(bundle$written_files$Component == "bundle_html")) expect_true(any(grepl("bundle_test_manifest_summary.csv$", bundle$written_files$Path))) expect_true(any(grepl("bundle_test_checklist.csv$", bundle$written_files$Path))) expect_true(any(grepl("bundle_test_facet_dashboard_detail.csv$", bundle$written_files$Path))) expect_true(any(grepl("bundle_test_replay.R$", bundle$written_files$Path))) expect_true(any(grepl("bundle_test_visual_warning_counts.csv$", bundle$written_files$Path))) expect_true(file.exists(file.path(out_dir, "bundle_test_bundle.html"))) expect_true(file.exists(file.path(out_dir, "bundle_test_manifest.txt"))) expect_true(file.exists(file.path(out_dir, "bundle_test_replay.R"))) expect_true(file.exists(file.path(out_dir, "bundle_test_visual_warning_map.txt"))) }) test_that("export_mfrm_bundle writes optional prediction artifacts", { out_dir <- file.path(tempdir(), "mfrmr-export-bundle-predictions") if (dir.exists(out_dir)) unlink(out_dir, recursive = TRUE, force = TRUE) dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) bundle <- export_mfrm_bundle( fit = prediction_bundle_fixture$fit, diagnostics = prediction_bundle_fixture$diagnostics, population_prediction = prediction_bundle_fixture$population_prediction, unit_prediction = prediction_bundle_fixture$unit_prediction, plausible_values = prediction_bundle_fixture$plausible_values, output_dir = out_dir, prefix = "bundle_pred_test", include = c("manifest", "predictions", "html"), overwrite = TRUE ) expect_s3_class(bundle, "mfrm_export_bundle") expect_true(any(bundle$written_files$Component == "population_prediction_forecast")) expect_true(any(bundle$written_files$Component == "unit_prediction_estimates")) expect_true(any(bundle$written_files$Component == "plausible_values")) expect_true(file.exists(file.path(out_dir, "bundle_pred_test_population_prediction_forecast.csv"))) expect_true(file.exists(file.path(out_dir, "bundle_pred_test_unit_prediction_estimates.csv"))) expect_true(file.exists(file.path(out_dir, "bundle_pred_test_plausible_values.csv"))) expect_true(file.exists(file.path(out_dir, "bundle_pred_test_population_prediction_ademp.csv"))) expect_true(file.exists(file.path(out_dir, "bundle_pred_test_population_prediction_sim_spec_settings.csv"))) expect_true(file.exists(file.path(out_dir, "bundle_pred_test_population_prediction_sim_spec_thresholds.csv"))) expect_true(file.exists(file.path(out_dir, "bundle_pred_test_unit_prediction_input.csv"))) expect_true(file.exists(file.path(out_dir, "bundle_pred_test_plausible_value_input.csv"))) expect_true(file.exists(file.path(out_dir, "bundle_pred_test_bundle.html"))) html_lines <- readLines(file.path(out_dir, "bundle_pred_test_bundle.html"), warn = FALSE) html_text <- paste(html_lines, collapse = "\n") expect_match(html_text, "

population_prediction_forecast

", fixed = TRUE) expect_match(html_text, "

unit_prediction_estimates

", fixed = TRUE) expect_match(html_text, "

plausible_value_summary

", fixed = TRUE) unit_settings <- utils::read.csv( file.path(out_dir, "bundle_pred_test_unit_prediction_settings.csv"), stringsAsFactors = FALSE ) expect_true(any(unit_settings$Setting == "source_columns.person")) expect_false(any(grepl("summary_fit_table_index", fixed = TRUE) expect_match(html_text, "

summary_fit_table_catalog

", fixed = TRUE) expect_match(html_text, "

summary_fit_reporting_map

", fixed = TRUE) expect_match(html_text, "

summary_checklist_action_items

", fixed = TRUE) expect_match(html_text, "

summary_apa_components

", fixed = TRUE) }) test_that("export_summary_appendix writes appendix-ready summary artifacts without requiring fit export inputs", { out_dir <- file.path(tempdir(), "mfrmr-summary-appendix-export") if (dir.exists(out_dir)) unlink(out_dir, recursive = TRUE, force = TRUE) dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) chk <- reporting_checklist(export_bundle_fixture$fit, diagnostics = export_bundle_fixture$diagnostics) appendix <- export_summary_appendix( list( fit = summary(export_bundle_fixture$fit), diagnostics = export_bundle_fixture$diagnostics, checklist = chk ), output_dir = out_dir, prefix = "appendix_test", include_html = TRUE, overwrite = TRUE ) expect_s3_class(appendix, "mfrm_summary_appendix_export") appendix_summary <- summary(appendix) expect_s3_class(appendix_summary, "summary.mfrm_bundle") expect_identical(appendix_summary$preview_name, "written_files") expect_true(is.data.frame(appendix_summary$format_summary)) expect_true(is.data.frame(appendix_summary$artifact_catalog)) expect_true(is.data.frame(appendix_summary$selection_summary)) expect_true(is.data.frame(appendix_summary$selection_table_summary)) expect_true(is.data.frame(appendix_summary$selection_handoff_table_summary)) expect_true(is.data.frame(appendix_summary$selection_handoff_preset_summary)) expect_true(is.data.frame(appendix_summary$selection_handoff_summary)) expect_true(is.data.frame(appendix_summary$selection_handoff_role_summary)) expect_true(is.data.frame(appendix_summary$selection_handoff_role_section_summary)) expect_true(is.data.frame(appendix_summary$selection_role_summary)) expect_true(is.data.frame(appendix_summary$selection_section_summary)) expect_true(is.data.frame(appendix_summary$selection_catalog)) expect_true(is.data.frame(appendix_summary$reporting_map)) expect_true(all(c("TablesAvailable", "SelectionFraction", "PlotReadyFraction", "NumericFraction") %in% names(appendix_summary$selection_summary))) expect_true(all(c("Preset", "AppendixSection", "Role", "Bundle", "Table", "Rows", "NumericColumns", "PlotReady", "ExportReady", "ApaTableReady") %in% names(appendix_summary$selection_handoff_table_summary))) expect_true(all(c("PlotReadyFraction", "NumericFraction") %in% names(appendix_summary$selection_handoff_summary))) expect_true(all(c("PlotReadyFraction", "NumericFraction") %in% names(appendix_summary$selection_handoff_role_summary))) expect_true(all(c("PlotReadyFraction", "NumericFraction") %in% names(appendix_summary$selection_handoff_role_section_summary))) expect_true(all(c("PlotReadyFraction", "NumericFraction") %in% names(appendix_summary$selection_role_summary))) expect_true(all(c("PlotReadyFraction", "NumericFraction") %in% names(appendix_summary$selection_section_summary))) expect_true(any(appendix_summary$artifact_catalog$ArtifactGroup == "summary_surface")) expect_true(any(appendix_summary$artifact_catalog$ArtifactGroup == "html_review")) appendix_plot <- plot(appendix, type = "formats", draw = FALSE) expect_s3_class(appendix_plot, "mfrm_plot_data") expect_identical(appendix_plot$name, "export_bundle") expect_identical(appendix_plot$data$plot, "formats") appendix_selection_plot <- plot(appendix, type = "selection_bundles", draw = FALSE) expect_s3_class(appendix_selection_plot, "mfrm_plot_data") expect_identical(appendix_selection_plot$data$plot, "selection_bundles") appendix_table_plot <- plot(appendix, type = "selection_tables", draw = FALSE) expect_s3_class(appendix_table_plot, "mfrm_plot_data") expect_identical(appendix_table_plot$data$plot, "selection_tables") appendix_handoff_preset_plot <- plot(appendix, type = "selection_handoff_presets", draw = FALSE) expect_s3_class(appendix_handoff_preset_plot, "mfrm_plot_data") expect_identical(appendix_handoff_preset_plot$data$plot, "selection_handoff_presets") appendix_handoff_plot <- plot(appendix, type = "selection_handoff", draw = FALSE) expect_s3_class(appendix_handoff_plot, "mfrm_plot_data") expect_identical(appendix_handoff_plot$data$plot, "selection_handoff") appendix_handoff_fraction_plot <- plot(appendix, type = "selection_handoff", selection_value = "fraction", draw = FALSE) expect_s3_class(appendix_handoff_fraction_plot, "mfrm_plot_data") expect_identical(appendix_handoff_fraction_plot$data$plot, "selection_handoff") expect_identical(appendix_handoff_fraction_plot$data$selection_value, "fraction") appendix_handoff_bundle_plot <- plot(appendix, type = "selection_handoff_bundles", draw = FALSE) expect_s3_class(appendix_handoff_bundle_plot, "mfrm_plot_data") expect_identical(appendix_handoff_bundle_plot$data$plot, "selection_handoff_bundles") appendix_handoff_role_plot <- plot(appendix, type = "selection_handoff_roles", draw = FALSE) expect_s3_class(appendix_handoff_role_plot, "mfrm_plot_data") expect_identical(appendix_handoff_role_plot$data$plot, "selection_handoff_roles") appendix_handoff_role_section_plot <- plot(appendix, type = "selection_handoff_role_sections", draw = FALSE) expect_s3_class(appendix_handoff_role_section_plot, "mfrm_plot_data") expect_identical(appendix_handoff_role_section_plot$data$plot, "selection_handoff_role_sections") appendix_section_plot <- plot(appendix, type = "selection_sections", draw = FALSE) expect_s3_class(appendix_section_plot, "mfrm_plot_data") expect_identical(appendix_section_plot$data$plot, "selection_sections") expect_error( plot(appendix, type = "selection_tables", selection_value = "fraction", draw = FALSE), "not available for `type = \"selection_tables\"`", fixed = TRUE ) expect_identical( unique(appendix$written_files$Component[appendix$written_files$Component == "summary_fit_reporting_map"]), "summary_fit_reporting_map" ) expect_equal( sum(appendix$written_files$Component == "summary_fit_reporting_map"), 1L ) expect_true(any(appendix$written_files$Component == "appendix_selection_summary")) expect_true(any(appendix$written_files$Component == "appendix_selection_table_summary")) expect_true(any(appendix$written_files$Component == "appendix_selection_handoff_table_summary")) expect_true(any(appendix$written_files$Component == "appendix_selection_handoff_preset_summary")) expect_true(any(appendix$written_files$Component == "appendix_selection_handoff_summary")) expect_true(any(appendix$written_files$Component == "appendix_selection_handoff_role_summary")) expect_true(any(appendix$written_files$Component == "appendix_selection_handoff_role_section_summary")) expect_true(any(appendix$written_files$Component == "appendix_selection_role_summary")) expect_true(any(appendix$written_files$Component == "appendix_selection_section_summary")) expect_true(any(appendix$written_files$Component == "appendix_selection_catalog")) expect_true(any(appendix$written_files$Component == "summary_fit_table_catalog")) expect_true(any(appendix$written_files$Component == "summary_fit_reporting_map")) expect_true(any(appendix$written_files$Component == "appendix_html")) expect_true(file.exists(file.path(out_dir, "appendix_test_summary_fit_table_catalog.csv"))) expect_true(file.exists(file.path(out_dir, "appendix_test_summary_fit_reporting_map.csv"))) expect_true(file.exists(file.path(out_dir, "appendix_test_appendix_selection_summary.csv"))) expect_true(file.exists(file.path(out_dir, "appendix_test_appendix_selection_table_summary.csv"))) expect_true(file.exists(file.path(out_dir, "appendix_test_appendix_selection_handoff_table_summary.csv"))) expect_true(file.exists(file.path(out_dir, "appendix_test_appendix_selection_handoff_preset_summary.csv"))) expect_true(file.exists(file.path(out_dir, "appendix_test_appendix_selection_handoff_summary.csv"))) expect_true(file.exists(file.path(out_dir, "appendix_test_appendix_selection_handoff_role_summary.csv"))) expect_true(file.exists(file.path(out_dir, "appendix_test_appendix_selection_handoff_role_section_summary.csv"))) expect_true(file.exists(file.path(out_dir, "appendix_test_appendix_selection_role_summary.csv"))) expect_true(file.exists(file.path(out_dir, "appendix_test_appendix_selection_section_summary.csv"))) expect_true(file.exists(file.path(out_dir, "appendix_test_appendix_selection_catalog.csv"))) expect_true(file.exists(file.path(out_dir, "appendix_test_appendix.html"))) expect_match(as.character(appendix_summary$overview$Class[1]), "mfrm_summary_appendix_export", fixed = TRUE) html_lines <- readLines(file.path(out_dir, "appendix_test_appendix.html"), warn = FALSE) html_text <- paste(html_lines, collapse = "\n") expect_match(html_text, "

summary_fit_table_catalog

", fixed = TRUE) expect_match(html_text, "

summary_fit_reporting_map

", fixed = TRUE) expect_match(html_text, "

summary_checklist_action_items

", fixed = TRUE) expect_match(html_text, "

appendix_selection_summary

", fixed = TRUE) expect_match(html_text, "

appendix_selection_table_summary

", fixed = TRUE) expect_match(html_text, "

appendix_selection_handoff_table_summary

", fixed = TRUE) expect_match(html_text, "

appendix_selection_handoff_preset_summary

", fixed = TRUE) expect_match(html_text, "

appendix_selection_handoff_summary

", fixed = TRUE) expect_match(html_text, "

appendix_selection_handoff_bundle_summary

", fixed = TRUE) expect_match(html_text, "

appendix_selection_handoff_role_summary

", fixed = TRUE) expect_match(html_text, "

appendix_selection_handoff_role_section_summary

", fixed = TRUE) expect_match(html_text, "

appendix_selection_role_summary

", fixed = TRUE) expect_match(html_text, "

appendix_selection_section_summary

", fixed = TRUE) }) test_that("export_summary_appendix preset trims bridge-only and preview-only tables", { out_dir <- file.path(tempdir(), "mfrmr-summary-appendix-recommended") if (dir.exists(out_dir)) unlink(out_dir, recursive = TRUE, force = TRUE) dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) chk <- reporting_checklist(export_bundle_fixture$fit, diagnostics = export_bundle_fixture$diagnostics) apa <- build_apa_outputs(export_bundle_fixture$fit, diagnostics = export_bundle_fixture$diagnostics) appendix <- export_summary_appendix( list( fit = summary(export_bundle_fixture$fit), checklist = chk, apa = apa ), output_dir = out_dir, prefix = "appendix_recommended", preset = "recommended", include_html = FALSE, overwrite = TRUE ) expect_s3_class(appendix, "mfrm_summary_appendix_export") expect_true(all(appendix$selection_summary$Preset == "recommended")) expect_true(all(appendix$selection_table_summary$Preset == "recommended")) expect_true(all(appendix$selection_handoff_preset_summary$Preset == "recommended")) expect_true(all(appendix$selection_handoff_summary$Preset == "recommended")) expect_true(all(appendix$selection_handoff_role_summary$Preset == "recommended")) expect_true(all(appendix$selection_handoff_role_section_summary$Preset == "recommended")) expect_true(all(appendix$selection_role_summary$Preset == "recommended")) expect_true(all(appendix$selection_section_summary$Preset == "recommended")) expect_true(any(appendix$written_files$Component == "summary_fit_reporting_map")) expect_false(any(appendix$written_files$Component == "summary_checklist_action_items")) expect_false(any(appendix$written_files$Component == "summary_apa_preview")) expect_true(any(appendix$written_files$Component == "summary_fit_overview")) expect_true(any(appendix$written_files$Component == "summary_checklist_section_summary")) expect_true(any(appendix$written_files$Component == "summary_apa_components")) expect_false(any( appendix$selection_catalog$Bundle == "fit" & appendix$selection_catalog$Table == "reporting_map" & appendix$selection_catalog$Selected %in% TRUE )) expect_true(any(appendix$selection_catalog$Selected %in% TRUE)) expect_true(any(appendix$selection_catalog$Selected %in% FALSE)) expect_true(all(appendix$selection_catalog$Preset == "recommended")) expect_true(any(appendix$selection_section_summary$AppendixSection %in% c("methods", "results", "diagnostics", "reporting"))) }) test_that("export_summary_appendix supports section-aware appendix presets", { out_dir <- file.path(tempdir(), "mfrmr-summary-appendix-methods") if (dir.exists(out_dir)) unlink(out_dir, recursive = TRUE, force = TRUE) dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) appendix <- export_summary_appendix( list( fit = summary(export_bundle_fixture$fit), diagnostics = export_bundle_fixture$diagnostics, checklist = reporting_checklist(export_bundle_fixture$fit, diagnostics = export_bundle_fixture$diagnostics) ), output_dir = out_dir, prefix = "appendix_methods", preset = "methods", include_html = FALSE, overwrite = TRUE ) expect_s3_class(appendix, "mfrm_summary_appendix_export") expect_true(all(appendix$selection_summary$Preset == "methods")) expect_true(all(appendix$selection_table_summary$Preset == "methods")) expect_true(all(appendix$selection_handoff_preset_summary$Preset == "methods")) expect_true(all(appendix$selection_handoff_summary$Preset == "methods")) expect_true(all(appendix$selection_handoff_bundle_summary$Preset == "methods")) expect_true(all(appendix$selection_handoff_role_summary$Preset == "methods")) expect_true(all(appendix$selection_handoff_role_section_summary$Preset == "methods")) expect_true(all(appendix$selection_role_summary$Preset == "methods")) expect_true(all(appendix$selection_section_summary$Preset == "methods")) expect_true(any(appendix$selection_catalog$Selected %in% TRUE)) expect_true(all( appendix$selection_catalog$AppendixSection[appendix$selection_catalog$Selected %in% TRUE] %in% "methods" )) expect_true(all(appendix$selection_section_summary$AppendixSection %in% "methods")) expect_true(any(appendix$written_files$Component == "summary_fit_overview")) expect_true(any(appendix$written_files$Component == "summary_diagnostics_overview")) }) test_that("export_summary_appendix supports future arbitrary-facet active-branch inputs", { out_dir <- file.path(tempdir(), "mfrmr-summary-appendix-future-branch") if (dir.exists(out_dir)) unlink(out_dir, recursive = TRUE, force = TRUE) dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) spec <- build_mfrm_sim_spec( n_person = 12, n_rater = 3, n_criterion = 4, raters_per_person = 2, assignment = "rotating", facet_names = c("Judge", "Task") ) active <- spec$planning_schema$future_branch_active_branch appendix <- export_summary_appendix( active, output_dir = out_dir, prefix = "appendix_future_branch", include_html = FALSE, overwrite = TRUE ) expect_s3_class(appendix, "mfrm_summary_appendix_export") appendix_summary <- summary(appendix) expect_true(is.data.frame(appendix_summary$selection_handoff_preset_summary)) expect_true(is.data.frame(appendix_summary$selection_handoff_bundle_summary)) expect_true(is.data.frame(appendix_summary$selection_handoff_role_summary)) expect_true(is.data.frame(appendix_summary$selection_handoff_role_section_summary)) expect_true(any(appendix$written_files$Component == "summary_mfrm_future_branch_active_branch_future_branch_overview")) expect_true(any(appendix$written_files$Component == "summary_mfrm_future_branch_active_branch_future_branch_recommendation")) expect_true(any(appendix$written_files$Component == "appendix_selection_handoff_preset_summary")) expect_true(any(appendix$written_files$Component == "appendix_selection_handoff_bundle_summary")) expect_true(any(appendix$written_files$Component == "appendix_selection_handoff_role_summary")) expect_true(any(appendix$written_files$Component == "appendix_selection_handoff_role_section_summary")) expect_true(file.exists(file.path( out_dir, "appendix_future_branch_summary_mfrm_future_branch_active_branch_future_branch_recommendation.csv" ))) }) test_that("export_summary_appendix applies appendix presets to future arbitrary-facet active-branch inputs", { out_dir <- file.path(tempdir(), "mfrmr-summary-appendix-future-branch-recommended") if (dir.exists(out_dir)) unlink(out_dir, recursive = TRUE, force = TRUE) dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) spec <- build_mfrm_sim_spec( n_person = 12, n_rater = 3, n_criterion = 4, raters_per_person = 2, assignment = "rotating", facet_names = c("Judge", "Task") ) active <- spec$planning_schema$future_branch_active_branch appendix <- export_summary_appendix( active, output_dir = out_dir, prefix = "appendix_future_branch_recommended", preset = "recommended", include_html = FALSE, overwrite = TRUE ) expect_s3_class(appendix, "mfrm_summary_appendix_export") expect_true(all(appendix$selection_summary$Preset == "recommended")) expect_true(all(appendix$selection_table_summary$Preset == "recommended")) expect_true(all(appendix$selection_handoff_preset_summary$Preset == "recommended")) expect_true(all(appendix$selection_handoff_bundle_summary$Preset == "recommended")) expect_true(all(appendix$selection_handoff_role_summary$Preset == "recommended")) expect_true(all(appendix$selection_handoff_role_section_summary$Preset == "recommended")) expect_true(any(appendix$written_files$Component == "summary_mfrm_future_branch_active_branch_future_branch_overview")) expect_true(any(appendix$written_files$Component == "summary_mfrm_future_branch_active_branch_future_branch_profile")) expect_true(any(appendix$written_files$Component == "summary_mfrm_future_branch_active_branch_future_branch_readiness")) expect_true(any(appendix$written_files$Component == "summary_mfrm_future_branch_active_branch_future_branch_recommendation")) expect_false(any(appendix$written_files$Component == "summary_mfrm_future_branch_active_branch_future_branch_load_balance")) expect_false(any(appendix$written_files$Component == "summary_mfrm_future_branch_active_branch_future_branch_coverage")) expect_false(any(appendix$written_files$Component == "summary_mfrm_future_branch_active_branch_future_branch_guardrails")) expect_true(all( appendix$selection_catalog$AppendixSection[appendix$selection_catalog$Selected %in% TRUE] %in% c("methods", "diagnostics") )) }) test_that("export_mfrm_bundle requires explicit prediction objects for prediction export", { out_dir <- file.path(tempdir(), "mfrmr-export-bundle-predictions-missing") if (dir.exists(out_dir)) unlink(out_dir, recursive = TRUE, force = TRUE) dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) expect_error( export_mfrm_bundle( fit = export_bundle_fixture$fit, diagnostics = export_bundle_fixture$diagnostics, output_dir = out_dir, prefix = "bundle_pred_missing", include = c("predictions"), overwrite = TRUE ), "`include = 'predictions'` requires at least one of `population_prediction`, `unit_prediction`, or `plausible_values`.", fixed = TRUE ) }) test_that("export_mfrm_bundle rejects malformed bias_results inputs early", { out_dir <- file.path(tempdir(), "mfrmr-export-bundle-bad-bias") if (dir.exists(out_dir)) unlink(out_dir, recursive = TRUE, force = TRUE) dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) expect_error( export_mfrm_bundle( fit = export_bundle_fixture$fit, diagnostics = export_bundle_fixture$diagnostics, bias_results = list(bad = data.frame(x = 1)), output_dir = out_dir, prefix = "bundle_bad_bias", include = c("manifest"), overwrite = TRUE ), "`bias_results` in export helpers must be NULL, output from estimate_bias\\(\\), an `mfrm_bias_collection`, or a list of `mfrm_bias` objects." ) }) test_that("export_mfrm_bundle does not change the caller working directory", { out_dir <- file.path(tempdir(), "mfrmr-export-bundle-wd") if (dir.exists(out_dir)) unlink(out_dir, recursive = TRUE, force = TRUE) dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) original_wd <- getwd() bundle <- export_mfrm_bundle( fit = export_bundle_fixture$fit, diagnostics = export_bundle_fixture$diagnostics, output_dir = out_dir, prefix = "bundle_zip_test", include = c("manifest"), zip_bundle = TRUE, overwrite = TRUE ) expect_identical(getwd(), original_wd) expect_s3_class(bundle, "mfrm_export_bundle") expect_true(any(bundle$written_files$Component == "bundle_zip")) expect_true(file.exists(file.path(out_dir, "bundle_zip_test_bundle.zip"))) }) test_that("export_mfrm_bundle respects overwrite for zip bundles", { out_dir <- file.path(tempdir(), "mfrmr-export-bundle-zip-overwrite") if (dir.exists(out_dir)) unlink(out_dir, recursive = TRUE, force = TRUE) dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) expect_no_warning( export_mfrm_bundle( fit = export_bundle_fixture$fit, diagnostics = export_bundle_fixture$diagnostics, output_dir = out_dir, prefix = "bundle_zip_overwrite", include = c("manifest"), zip_bundle = TRUE, overwrite = TRUE ) ) expect_error( export_mfrm_bundle( fit = export_bundle_fixture$fit, diagnostics = export_bundle_fixture$diagnostics, output_dir = out_dir, prefix = "bundle_zip_overwrite", include = c("manifest"), zip_bundle = TRUE, overwrite = FALSE ), "File already exists:", fixed = TRUE ) })