use crate::config::error::LoadError;
use crate::config::workflow::{Budgets, Workflow};
use std::path::Path;
fn parse(raw: &str) -> Result<Workflow, LoadError> {
Workflow::parse(raw, Path::new("<commit>:workflow.yaml"))
}
#[test]
fn parses_explicit_budgets_block() {
let w = parse("events: {}\nbudgets:\n max_total_tokens: 2000000\n max_wall_seconds: 3600\n max_depth: 4\n").unwrap();
assert_eq!(w.budgets.max_total_tokens, Some(2_000_000));
assert_eq!(w.budgets.max_wall_seconds, Some(3600));
assert_eq!(w.budgets.max_depth, Some(4));
}
#[test]
fn omitted_budgets_block_is_all_unbounded() {
let w = parse("events:\n user_message:\n - land_compaction\n").unwrap();
assert_eq!(w.budgets, Budgets::default());
assert!(w.budgets.max_total_tokens.is_none());
assert!(w.budgets.max_wall_seconds.is_none());
assert!(w.budgets.max_depth.is_none());
}
#[test]
fn the_shipped_template_bounds_depth_alone() {
let raw = crate::template::TEMPLATE
.get_file("workflow.yaml")
.expect("the template ships a workflow.yaml")
.contents_utf8()
.expect("utf8");
let w = parse(raw).unwrap();
assert_eq!(
w.budgets.max_depth,
Some(5),
"a root plus five levels of delegation; see workflow.yaml before moving it"
);
assert_eq!(
w.budgets.max_total_tokens, None,
"a whole-tree token ceiling is the operator's to declare (2026-08-16)"
);
assert_eq!(
w.budgets.max_wall_seconds, None,
"a whole-tree wall ceiling is the operator's to declare (2026-08-16)"
);
}
#[test]
fn partial_budgets_leaves_the_other_axes_unbounded() {
let w = parse("events: {}\nbudgets:\n max_total_tokens: 500\n").unwrap();
assert_eq!(w.budgets.max_total_tokens, Some(500));
assert!(w.budgets.max_wall_seconds.is_none());
assert!(w.budgets.max_depth.is_none());
}