mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-07 08:27:12 +00:00
Add 87 unit tests for uncovered pure logic in arc-workflows
Cover format_cost, format_tokens_human, compute_stage_cost, all format_event_summary variants, validate_command, context_diff, and parse_label_filters with fast unit tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
fe9f6f6882
commit
7b39b42fda
4 changed files with 1136 additions and 0 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -620,4 +620,41 @@ mod tests {
|
|||
prune_from(&args, base).unwrap();
|
||||
assert!(!orphan_dir.exists(), "orphan directory should be deleted");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_label_filters_basic() {
|
||||
let args = vec!["env=prod".to_string()];
|
||||
let result = parse_label_filters(&args);
|
||||
assert_eq!(result, vec![("env".to_string(), "prod".to_string())]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_label_filters_multiple() {
|
||||
let args = vec!["a=1".to_string(), "b=2".to_string()];
|
||||
let result = parse_label_filters(&args);
|
||||
assert_eq!(result.len(), 2);
|
||||
assert!(result.contains(&("a".to_string(), "1".to_string())));
|
||||
assert!(result.contains(&("b".to_string(), "2".to_string())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_label_filters_value_with_equals() {
|
||||
let args = vec!["key=a=b".to_string()];
|
||||
let result = parse_label_filters(&args);
|
||||
assert_eq!(result, vec![("key".to_string(), "a=b".to_string())]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_label_filters_skips_no_equals() {
|
||||
let args = vec!["nope".to_string(), "a=1".to_string()];
|
||||
let result = parse_label_filters(&args);
|
||||
assert_eq!(result, vec![("a".to_string(), "1".to_string())]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_label_filters_empty() {
|
||||
let args: Vec<String> = vec![];
|
||||
let result = parse_label_filters(&args);
|
||||
assert!(result.is_empty());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,3 +31,61 @@ pub fn validate_command(args: &ValidateArgs, styles: &Styles) -> anyhow::Result<
|
|||
eprintln!("Validation: {}", styles.green.apply_to("OK"));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
fn validate_valid_workflow() {
|
||||
let mut tmp = tempfile::NamedTempFile::new().unwrap();
|
||||
write!(
|
||||
tmp,
|
||||
r#"digraph Simple {{
|
||||
graph [goal="Run tests and report results"]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
run_tests [label="Run Tests", prompt="Run the test suite and report results"]
|
||||
report [label="Report", prompt="Summarize the test results"]
|
||||
|
||||
start -> run_tests -> report -> exit
|
||||
}}"#
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let args = ValidateArgs {
|
||||
workflow: tmp.path().to_path_buf(),
|
||||
};
|
||||
let styles = Styles::new(false);
|
||||
let result = validate_command(&args, &styles);
|
||||
assert!(result.is_ok(), "expected Ok but got: {result:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_invalid_syntax() {
|
||||
let mut tmp = tempfile::NamedTempFile::new().unwrap();
|
||||
write!(tmp, "not a valid dot file").unwrap();
|
||||
|
||||
let args = ValidateArgs {
|
||||
workflow: tmp.path().to_path_buf(),
|
||||
};
|
||||
let styles = Styles::new(false);
|
||||
let result = validate_command(&args, &styles);
|
||||
assert!(result.is_err(), "expected Err for invalid syntax");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_missing_file() {
|
||||
let args = ValidateArgs {
|
||||
workflow: PathBuf::from("/tmp/nonexistent_workflow_12345.dot"),
|
||||
};
|
||||
let styles = Styles::new(false);
|
||||
let result = validate_command(&args, &styles);
|
||||
assert!(result.is_err(), "expected Err for missing file");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -595,4 +595,44 @@ mod tests {
|
|||
fn parse_duration_str_invalid_fallback() {
|
||||
assert_eq!(parse_duration_str("bad"), Duration::from_secs(45));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn context_diff_detects_additions() {
|
||||
let before = HashMap::new();
|
||||
let mut after = HashMap::new();
|
||||
after.insert("key".to_string(), serde_json::json!("value"));
|
||||
let diff = context_diff(&before, &after);
|
||||
assert_eq!(diff.len(), 1);
|
||||
assert_eq!(diff.get("key"), Some(&serde_json::json!("value")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn context_diff_detects_changes() {
|
||||
let mut before = HashMap::new();
|
||||
before.insert("key".to_string(), serde_json::json!("old"));
|
||||
let mut after = HashMap::new();
|
||||
after.insert("key".to_string(), serde_json::json!("new"));
|
||||
let diff = context_diff(&before, &after);
|
||||
assert_eq!(diff.len(), 1);
|
||||
assert_eq!(diff.get("key"), Some(&serde_json::json!("new")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn context_diff_ignores_unchanged() {
|
||||
let mut before = HashMap::new();
|
||||
before.insert("key".to_string(), serde_json::json!("same"));
|
||||
let mut after = HashMap::new();
|
||||
after.insert("key".to_string(), serde_json::json!("same"));
|
||||
let diff = context_diff(&before, &after);
|
||||
assert!(diff.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn context_diff_ignores_deletions() {
|
||||
let mut before = HashMap::new();
|
||||
before.insert("removed".to_string(), serde_json::json!("gone"));
|
||||
let after = HashMap::new();
|
||||
let diff = context_diff(&before, &after);
|
||||
assert!(diff.is_empty());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue