Skip to main content

fallow_config/config/
health.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4const fn default_max_cyclomatic() -> u16 {
5    20
6}
7
8const fn default_max_cognitive() -> u16 {
9    15
10}
11
12/// Configuration for complexity health metrics (`fallow health`).
13#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
14#[serde(rename_all = "camelCase")]
15pub struct HealthConfig {
16    /// Maximum allowed cyclomatic complexity per function (default: 20).
17    /// Functions exceeding this threshold are reported.
18    #[serde(default = "default_max_cyclomatic")]
19    pub max_cyclomatic: u16,
20
21    /// Maximum allowed cognitive complexity per function (default: 15).
22    /// Functions exceeding this threshold are reported.
23    #[serde(default = "default_max_cognitive")]
24    pub max_cognitive: u16,
25
26    /// Glob patterns to exclude from complexity analysis.
27    #[serde(default)]
28    pub ignore: Vec<String>,
29}
30
31impl Default for HealthConfig {
32    fn default() -> Self {
33        Self {
34            max_cyclomatic: default_max_cyclomatic(),
35            max_cognitive: default_max_cognitive(),
36            ignore: vec![],
37        }
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn health_config_defaults() {
47        let config = HealthConfig::default();
48        assert_eq!(config.max_cyclomatic, 20);
49        assert_eq!(config.max_cognitive, 15);
50        assert!(config.ignore.is_empty());
51    }
52
53    #[test]
54    fn health_config_json_all_fields() {
55        let json = r#"{
56            "maxCyclomatic": 30,
57            "maxCognitive": 25,
58            "ignore": ["**/generated/**", "vendor/**"]
59        }"#;
60        let config: HealthConfig = serde_json::from_str(json).unwrap();
61        assert_eq!(config.max_cyclomatic, 30);
62        assert_eq!(config.max_cognitive, 25);
63        assert_eq!(config.ignore, vec!["**/generated/**", "vendor/**"]);
64    }
65
66    #[test]
67    fn health_config_json_partial_uses_defaults() {
68        let json = r#"{"maxCyclomatic": 10}"#;
69        let config: HealthConfig = serde_json::from_str(json).unwrap();
70        assert_eq!(config.max_cyclomatic, 10);
71        assert_eq!(config.max_cognitive, 15); // default
72        assert!(config.ignore.is_empty()); // default
73    }
74
75    #[test]
76    fn health_config_json_empty_object_uses_all_defaults() {
77        let config: HealthConfig = serde_json::from_str("{}").unwrap();
78        assert_eq!(config.max_cyclomatic, 20);
79        assert_eq!(config.max_cognitive, 15);
80        assert!(config.ignore.is_empty());
81    }
82
83    #[test]
84    fn health_config_json_only_ignore() {
85        let json = r#"{"ignore": ["test/**"]}"#;
86        let config: HealthConfig = serde_json::from_str(json).unwrap();
87        assert_eq!(config.max_cyclomatic, 20); // default
88        assert_eq!(config.max_cognitive, 15); // default
89        assert_eq!(config.ignore, vec!["test/**"]);
90    }
91}