gof <- hydroeval_release_get_export("gof") test_that("gof stays release-stable for default, all, and explicit metric selection", { scenario <- hydroeval_release_scenario("positive_reference") default_summary <- gof(scenario$observed, scenario$simulated) all_summary <- gof(scenario$observed, scenario$simulated, metrics = "all") explicit_summary <- gof( scenario$observed, scenario$simulated, metrics = c("pbias", "rho", "kge_2012") ) expect_s3_class(default_summary, "hydroeval_gof") expect_identical(default_summary$metric_ids, hydroeval_release_gof_default_metric_ids) expect_identical(default_summary$request$metrics, "default") expect_identical(default_summary$request$resolved_metric_ids, hydroeval_release_gof_default_metric_ids) expect_identical(default_summary$request$selection_mode, "gof_default") expect_s3_class(all_summary, "hydroeval_gof") expect_identical(all_summary$metric_ids, hydroeval_release_gof_all_metric_ids) expect_identical(all_summary$request$metrics, "all") expect_identical(all_summary$request$resolved_metric_ids, hydroeval_release_gof_all_metric_ids) expect_identical(all_summary$request$selection_mode, "gof_all") expect_identical(explicit_summary$metric_ids, c("pbias", "rho", "kge_2012")) expect_identical(explicit_summary$display_labels, c("PBIAS (%)", "\u03C1", "KGE (2012)")) expect_identical(explicit_summary$request$metrics, c("pbias", "rho", "kge_2012")) expect_identical(explicit_summary$request$selection_mode, "gof_explicit") }) test_that("gof values agree with standalone public wrappers and coercion views", { scenario <- hydroeval_release_scenario("positive_reference") summary <- gof(scenario$observed, scenario$simulated) expected_values <- vapply( hydroeval_release_gof_default_metric_ids, FUN.VALUE = numeric(1), FUN = function(metric_name) { hydroeval_release_call_wrapper(metric_name, scenario$observed, scenario$simulated) } ) expect_named(summary, c("values", "metric_ids", "display_labels", "request")) expect_identical(names(summary$values), summary$metric_ids) expect_equal(summary$values, expected_values, tolerance = 1e-12) hydroeval_release_expect_gof_views_agree(summary) }) test_that("gof display-label governance stays registry-facing rather than canonical-id-facing", { scenario <- hydroeval_release_scenario("positive_reference") summary <- gof( scenario$observed, scenario$simulated, metrics = c("pbias", "nrmse", "kge_2009", "kge_2012", "r_squared", "rho") ) printed <- paste(capture.output(print(summary)), collapse = "\n") expect_identical( rownames(as.matrix(summary)), c("PBIAS (%)", "NRMSE", "KGE (2009)", "KGE (2012)", "R\u00B2", "\u03C1") ) expect_match(printed, "PBIAS \\(%\\)") expect_match(printed, "NRMSE") expect_match(printed, "KGE \\(2009\\)") expect_match(printed, "KGE \\(2012\\)") expect_match(printed, "R\u00B2") expect_match(printed, "\u03C1") expect_no_match(printed, "kge_2009") expect_no_match(printed, "r_squared") }) test_that("gof handles perfect-fit, missing-data, and invalid-selection public contracts", { perfect <- hydroeval_release_scenario("perfect_fit") missing <- hydroeval_release_scenario("missing_omit") single_point <- hydroeval_release_scenario("single_point") scenario <- hydroeval_release_scenario("positive_reference") perfect_summary <- gof(perfect$observed, perfect$simulated) omit_summary <- gof( missing$observed, missing$simulated, metrics = c("mae", "nse", "kge_2009"), na_policy = "omit" ) kept_summary <- gof( missing$kept_observed, missing$kept_simulated, metrics = c("mae", "nse", "kge_2009"), na_policy = "omit" ) expect_length(perfect_summary$values, length(hydroeval_release_gof_default_metric_ids)) expect_equal(perfect_summary$values[["me"]], 0, tolerance = 1e-12) expect_equal(perfect_summary$values[["nse"]], 1, tolerance = 1e-12) expect_equal(perfect_summary$values[["kge_2012"]], 1, tolerance = 1e-12) expect_equal(omit_summary$values, kept_summary$values, tolerance = 1e-12) expect_error( gof( missing$observed, missing$simulated, metrics = c("mae", "nse", "kge_2009"), na_policy = "fail" ), class = "hydroeval_validation_error", regexp = "Missing `NA` values are not allowed" ) expect_error( gof(single_point$observed, single_point$simulated), class = "hydroeval_validation_error", regexp = "Need at least 2 complete paired observations" ) expect_error( gof(scenario$observed, scenario$simulated, metrics = c("MAE")), class = "hydroeval_metric_plan_error", regexp = "Metric `MAE`" ) }) test_that("gof rejects malformed metric selectors and preserves request metadata", { scenario <- hydroeval_release_scenario("positive_reference") summary <- gof( scenario$observed, scenario$simulated, metrics = c("mae", "rsr", "kge_2012"), na_policy = "omit" ) expect_identical(summary$request$metrics, c("mae", "rsr", "kge_2012")) expect_identical(summary$request$resolved_metric_ids, c("mae", "rsr", "kge_2012")) expect_identical(summary$request$na_policy, "omit") expect_identical(summary$request$default_metric_ids, hydroeval_release_gof_default_metric_ids) expect_error( gof(scenario$observed, scenario$simulated, metrics = c("all", "mae")), class = "hydroeval_metric_plan_error", regexp = "mixture" ) expect_error( gof(scenario$observed, scenario$simulated, metrics = c("mae", "not_a_metric")), class = "hydroeval_metric_plan_error", regexp = "not_a_metric" ) })