Skip to main content

chant/score/
ac_quality.rs

1//! Acceptance criteria quality scoring.
2//!
3//! Simple scoring based on whether the spec has acceptance criteria checkboxes.
4//! The presence of checkboxes indicates testable requirements.
5
6use crate::scoring::ACQualityGrade;
7
8/// Calculate acceptance criteria quality grade.
9///
10/// Simple grading based on number of criteria:
11/// - Grade A: 4+ criteria (well-defined, multiple verification points)
12/// - Grade B: 2-3 criteria (adequate coverage)
13/// - Grade C: 1 criterion (minimal but present)
14/// - Grade D: 0 criteria (no acceptance criteria)
15///
16/// # Arguments
17///
18/// * `criteria` - Slice of acceptance criteria strings
19///
20/// # Returns
21///
22/// An `ACQualityGrade` based on criteria count
23pub fn calculate_ac_quality(criteria: &[String]) -> ACQualityGrade {
24    match criteria.len() {
25        0 => ACQualityGrade::D,
26        1 => ACQualityGrade::C,
27        2 | 3 => ACQualityGrade::B,
28        _ => ACQualityGrade::A,
29    }
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35
36    #[test]
37    fn test_empty_criteria_returns_grade_d() {
38        let criteria: Vec<String> = vec![];
39        assert_eq!(calculate_ac_quality(&criteria), ACQualityGrade::D);
40    }
41
42    #[test]
43    fn test_single_criterion_returns_grade_c() {
44        let criteria = vec!["File exists".to_string()];
45        assert_eq!(calculate_ac_quality(&criteria), ACQualityGrade::C);
46    }
47
48    #[test]
49    fn test_two_criteria_returns_grade_b() {
50        let criteria = vec![
51            "File exists".to_string(),
52            "Output matches expected".to_string(),
53        ];
54        assert_eq!(calculate_ac_quality(&criteria), ACQualityGrade::B);
55    }
56
57    #[test]
58    fn test_three_criteria_returns_grade_b() {
59        let criteria = vec![
60            "File exists".to_string(),
61            "Output matches expected".to_string(),
62            "No errors in log".to_string(),
63        ];
64        assert_eq!(calculate_ac_quality(&criteria), ACQualityGrade::B);
65    }
66
67    #[test]
68    fn test_four_or_more_criteria_returns_grade_a() {
69        let criteria = vec![
70            "File exists".to_string(),
71            "Output matches expected".to_string(),
72            "No errors in log".to_string(),
73            "Performance under 100ms".to_string(),
74        ];
75        assert_eq!(calculate_ac_quality(&criteria), ACQualityGrade::A);
76    }
77
78    #[test]
79    fn test_many_criteria_returns_grade_a() {
80        let criteria = vec![
81            "One".to_string(),
82            "Two".to_string(),
83            "Three".to_string(),
84            "Four".to_string(),
85            "Five".to_string(),
86        ];
87        assert_eq!(calculate_ac_quality(&criteria), ACQualityGrade::A);
88    }
89
90    #[test]
91    fn test_any_content_counts() {
92        // Content doesn't matter, only count
93        let criteria = vec![
94            "hello.sh file exists".to_string(), // declarative - should work
95        ];
96        assert_eq!(calculate_ac_quality(&criteria), ACQualityGrade::C);
97    }
98}