#![cfg(feature = "templates")]
use assert_cmd::Command;
use predicates::prelude::PredicateBooleanExt;
use predicates::str::contains;
use std::fs;
use std::path::{Path, PathBuf};
use tempfile::TempDir;
fn repo_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("cli/ has a parent")
.to_path_buf()
}
fn faucet() -> Command {
let mut cmd = Command::cargo_bin("faucet").unwrap();
cmd.current_dir(repo_root());
cmd.args(["template", "test"]).arg("--no-env-file");
cmd
}
#[test]
fn the_shipped_example_suite_passes() {
faucet()
.arg("cli/examples/tests/template_suite.yaml")
.assert()
.success()
.stdout(contains("13 case(s): 13 passed, 0 failed"))
.stdout(contains("[explicit] eu-small-pages"))
.stdout(contains("[combine] "))
.stdout(contains("[auto] auto:defaults"))
.stdout(contains("[auto] auto:missing-tenant_id"));
}
#[test]
fn the_filter_narrows_the_run() {
faucet()
.arg("cli/examples/tests/template_suite.yaml")
.args(["--filter", "auto:missing-*"])
.assert()
.success()
.stdout(contains("2 case(s): 2 passed, 0 failed"))
.stdout(contains("auto:missing-api_token"))
.stdout(contains("auto:missing-tenant_id"));
}
#[test]
fn json_output_is_parseable_and_agrees_with_the_checklist() {
let out = faucet()
.arg("cli/examples/tests/template_suite.yaml")
.arg("--json")
.assert()
.success()
.get_output()
.stdout
.clone();
let v: serde_json::Value = serde_json::from_slice(&out).expect("--json emits parseable JSON");
assert_eq!(v["total"], 13);
assert_eq!(v["passed"], 13);
assert_eq!(v["failed"], 0);
assert_eq!(v["template"], "cli/examples/rest_to_jsonl_templated.yaml");
let cases = v["cases"].as_array().expect("cases array");
assert_eq!(cases.len(), 13);
assert!(
cases.iter().all(|c| c["status"] == "pass"),
"every case must report its own status: {v}"
);
let defaults = cases
.iter()
.find(|c| c["name"] == "auto:defaults")
.expect("the defaults baseline case");
assert_eq!(defaults["origin"], "auto");
assert!(defaults["params"].is_object(), "{defaults}");
}
#[test]
fn the_exit_code_is_the_failed_case_count() {
let dir = TempDir::new().unwrap();
let template = dir.path().join("tpl.yaml");
fs::write(
&template,
r#"
version: 1
params:
region: { type: string, required: true, values: [us, eu] }
pipeline:
source: { type: csv, config: { path: "./in-${param.region}.csv" } }
sink: { type: jsonl, config: { path: ./out.jsonl } }
"#,
)
.unwrap();
let suite = dir.path().join("suite.yaml");
fs::write(
&suite,
format!(
r#"
version: 1
template: {}
suite:
cases:
- name: good
params: {{ region: us }}
# Two cases that must fail: each asserts an error the run will not produce,
# because the combination is in fact valid.
- name: bad-one
params: {{ region: us }}
expect: {{ error: "no such failure" }}
- name: bad-two
params: {{ region: eu }}
expect: {{ error: "no such failure either" }}
"#,
template.display()
),
)
.unwrap();
faucet()
.arg(&suite)
.assert()
.failure()
.code(2)
.stdout(contains("3 case(s): 1 passed, 2 failed"))
.stdout(contains("FAIL [explicit] bad-one"))
.stdout(contains("FAIL [explicit] bad-two"));
}
#[test]
fn a_suite_naming_an_unregistered_template_without_a_store_is_refused() {
let dir = TempDir::new().unwrap();
let suite = dir.path().join("suite.yaml");
fs::write(
&suite,
r#"
version: 1
template: not-a-file-and-not-registered
suite:
cases:
- name: any
params: {}
"#,
)
.unwrap();
faucet()
.arg(&suite)
.assert()
.failure()
.stderr(contains("not-a-file-and-not-registered").or(contains("store")));
}
#[test]
fn schema_template_test_prints_the_suite_schema() {
Command::cargo_bin("faucet")
.unwrap()
.current_dir(repo_root())
.args(["schema", "template-test"])
.assert()
.success()
.stdout(contains("\"suite\""));
}