WIP: Batch 1 — backfill tests for store, search, and workflow

- store.rs: 8 tests (roundtrip, persistence, corrupt/empty file handling)
- io/search.rs: 5 tests (matching, nested dirs, gitignore, empty results)
- workflow.rs: 7 new tests (acceptance logic, summarize, can_start, record, refresh)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dave
2026-02-19 13:49:33 +00:00
parent 8f0bc971bf
commit 76e7c68b66
3 changed files with 340 additions and 0 deletions

View File

@@ -239,4 +239,145 @@ mod tests {
assert!(result.is_err());
}
#[test]
fn accepts_when_all_tests_pass() {
let results = StoryTestResults {
unit: vec![TestCaseResult {
name: "unit-1".to_string(),
status: TestStatus::Pass,
details: None,
}],
integration: vec![TestCaseResult {
name: "integration-1".to_string(),
status: TestStatus::Pass,
details: None,
}],
};
let decision = evaluate_acceptance(&results);
assert!(decision.can_accept);
assert!(decision.reasons.is_empty());
assert!(decision.warning.is_none());
}
#[test]
fn rejects_when_no_results_recorded() {
let results = StoryTestResults::default();
let decision = evaluate_acceptance(&results);
assert!(!decision.can_accept);
assert!(decision.reasons.iter().any(|r| r.contains("No test results")));
}
#[test]
fn rejects_with_single_failure_no_warning() {
let results = StoryTestResults {
unit: vec![
TestCaseResult {
name: "unit-1".to_string(),
status: TestStatus::Pass,
details: None,
},
TestCaseResult {
name: "unit-2".to_string(),
status: TestStatus::Fail,
details: None,
},
],
integration: vec![],
};
let decision = evaluate_acceptance(&results);
assert!(!decision.can_accept);
assert!(decision.reasons.iter().any(|r| r.contains("failing")));
assert!(decision.warning.is_none());
}
#[test]
fn summarize_results_counts_correctly() {
let results = StoryTestResults {
unit: vec![
TestCaseResult { name: "u1".to_string(), status: TestStatus::Pass, details: None },
TestCaseResult { name: "u2".to_string(), status: TestStatus::Fail, details: None },
],
integration: vec![
TestCaseResult { name: "i1".to_string(), status: TestStatus::Pass, details: None },
],
};
let summary = summarize_results(&results);
assert_eq!(summary.total, 3);
assert_eq!(summary.passed, 2);
assert_eq!(summary.failed, 1);
}
#[test]
fn can_start_implementation_requires_approved_plan() {
let approved = StoryMetadata {
name: Some("Test".to_string()),
test_plan: Some(TestPlanStatus::Approved),
};
assert!(can_start_implementation(&approved).is_ok());
let waiting = StoryMetadata {
name: Some("Test".to_string()),
test_plan: Some(TestPlanStatus::WaitingForApproval),
};
assert!(can_start_implementation(&waiting).is_err());
let unknown = StoryMetadata {
name: Some("Test".to_string()),
test_plan: Some(TestPlanStatus::Unknown("draft".to_string())),
};
assert!(can_start_implementation(&unknown).is_err());
let missing = StoryMetadata {
name: Some("Test".to_string()),
test_plan: None,
};
assert!(can_start_implementation(&missing).is_err());
}
#[test]
fn record_valid_results_stores_them() {
let mut state = WorkflowState::default();
let unit = vec![TestCaseResult {
name: "unit-1".to_string(),
status: TestStatus::Pass,
details: None,
}];
let integration = vec![TestCaseResult {
name: "int-1".to_string(),
status: TestStatus::Pass,
details: None,
}];
let result = state.record_test_results_validated(
"story-29".to_string(),
unit,
integration,
);
assert!(result.is_ok());
assert!(state.results.contains_key("story-29"));
assert_eq!(state.results["story-29"].unit.len(), 1);
assert_eq!(state.results["story-29"].integration.len(), 1);
}
#[test]
fn refresh_story_metadata_returns_false_when_unchanged() {
let mut state = WorkflowState::default();
let meta = StoryMetadata {
name: Some("Test".to_string()),
test_plan: Some(TestPlanStatus::Approved),
};
assert!(state.refresh_story_metadata("s1".to_string(), meta.clone()));
assert!(!state.refresh_story_metadata("s1".to_string(), meta.clone()));
let updated = StoryMetadata {
name: Some("Updated".to_string()),
test_plan: Some(TestPlanStatus::Approved),
};
assert!(state.refresh_story_metadata("s1".to_string(), updated));
}
}