gather_all_code_from_crates/
effective_config.rs

1crate::ix!();
2
3#[derive(Debug, Clone, Builder, Getters, Setters)]
4#[builder(setter(into))]
5#[getset(get = "pub", set = "pub")]
6pub struct EffectiveConfig {
7
8    #[builder(default)]
9    crates: Vec<PathBuf>,
10
11    #[builder(default)]
12    criteria: AstFilterCriteria,
13}
14
15impl EffectiveConfig {
16
17    pub fn from_cli_and_global(cli: &Cli, global_cfg: &GlobalConfig) -> AppResult<Self> {
18        let mut criteria_builder = AstFilterCriteriaBuilder::default();
19        criteria_builder
20            .include_tests(*cli.include_tests() || *global_cfg.default_include_tests())
21            .single_test_name(cli.single_test_name().clone())
22            .omit_private(*cli.omit_private())
23            .omit_bodies(*cli.omit_bodies() || *global_cfg.default_omit_bodies())
24            .single_function_name(cli.single_function_name().clone())
25            .excluded_files(cli.excluded_files().clone())
26            .exclude_main_file(*cli.exclude_main_file())
27            .remove_doc_comments(*cli.remove_doc_comments());
28
29        let criteria = criteria_builder.build().map_err(|_|AppError::Config{reason:ErrorReason::Config})?;
30
31        let crates = if !cli.crates().is_empty() {
32            cli.crates().clone()
33        } else {
34            let cur = std::env::current_dir().map_err(|e|AppError::Io{code:e.kind()})?;
35            vec![cur]
36        };
37
38        EffectiveConfigBuilder::default()
39            .crates(crates)
40            .criteria(criteria)
41            .build()
42            .map_err(|_|AppError::Config{reason:ErrorReason::Config})
43    }
44}
45
46#[cfg(test)]
47mod effective_config_tests {
48    use super::*;
49
50    #[test]
51    fn test_merge_global_config_with_cli_single_test() {
52        let global_cfg = GlobalConfigBuilder::default()
53            .default_include_tests(false)
54            .default_omit_bodies(false)
55            .build().unwrap();
56
57        let cli = CliBuilder::default()
58            .crates(vec![])
59            .include_tests(true)
60            .single_test_name(Some("test_me".to_string()))
61            .omit_private(false)
62            .omit_bodies(false)
63            .single_function_name(None)
64            .excluded_files(vec![])
65            .exclude_main_file(false)
66            .remove_doc_comments(false)
67            .build()
68            .unwrap();
69
70        let eff = EffectiveConfig::from_cli_and_global(&cli, &global_cfg).unwrap();
71        assert_eq!(*eff.criteria.include_tests(), true);
72        assert_eq!(*eff.criteria.single_test_name(), Some("test_me".to_string()));
73    }
74
75    #[test]
76    fn test_effective_config_from_cli_and_global() {
77        let global_cfg = GlobalConfigBuilder::default()
78            .default_include_tests(true)
79            .default_omit_bodies(false)
80            .build().unwrap();
81
82        let cli = CliBuilder::default()
83            .crates(vec![])
84            .include_tests(false)
85            .single_test_name(None)
86            .omit_private(true)
87            .omit_bodies(false)
88            .single_function_name(None)
89            .excluded_files(vec![])
90            .exclude_main_file(false)
91            .remove_doc_comments(false)
92            .build()
93            .unwrap();
94
95        let eff = EffectiveConfig::from_cli_and_global(&cli, &global_cfg).unwrap();
96        // Global says include_tests=true, CLI says include_tests=false. By the code, we OR them:
97        // The code: `.include_tests(*cli.include_tests() || *global_cfg.default_include_tests())`
98        // CLI=false, global=true => final = true
99        assert_eq!(*eff.criteria().include_tests(), true);
100        assert_eq!(*eff.criteria().omit_private(), true); // from CLI
101        assert_eq!(*eff.criteria().omit_bodies(), false); // global false, CLI false
102    }
103
104    #[test]
105    fn test_effective_config_global_only() {
106        // No CLI overrides, rely entirely on global defaults.
107        let global_cfg = GlobalConfigBuilder::default()
108            .default_include_tests(true)
109            .default_omit_bodies(true)
110            .build().unwrap();
111
112        let cli = CliBuilder::default()
113            .crates(vec![])
114            .include_tests(false) // Not used since global overrides (OR) logic
115            .omit_bodies(false)   // Not used
116            .build()
117            .unwrap();
118
119        let eff = EffectiveConfig::from_cli_and_global(&cli, &global_cfg).unwrap();
120        // include_tests = true (global or CLI)
121        // omit_bodies = true (global)
122        assert_eq!(*eff.criteria().include_tests(), true);
123        assert_eq!(*eff.criteria().omit_bodies(), true);
124    }
125
126    #[test]
127    fn test_effective_config_cli_only_no_global() {
128        // Global defaults are all false, CLI sets values directly.
129        let global_cfg = GlobalConfigBuilder::default()
130            .default_include_tests(false)
131            .default_omit_bodies(false)
132            .build().unwrap();
133
134        let cli = CliBuilder::default()
135            .crates(vec![])
136            .include_tests(true)
137            .omit_private(true)
138            .omit_bodies(true)
139            .excluded_files(vec!["some_file.rs".to_string()])
140            .build()
141            .unwrap();
142
143        let eff = EffectiveConfig::from_cli_and_global(&cli, &global_cfg).unwrap();
144        assert_eq!(*eff.criteria().include_tests(), true);
145        assert_eq!(*eff.criteria().omit_private(), true);
146        assert_eq!(*eff.criteria().omit_bodies(), true);
147        assert!(eff.criteria().excluded_files().contains(&"some_file.rs".to_string()));
148    }
149
150    #[test]
151    fn test_effective_config_with_project_override() {
152        // Suppose global config has a project-specific override that changes omit_private
153        let mut project_overrides = HashMap::new();
154        project_overrides.insert("mycrate".to_string(), {
155            AstFilterCriteriaBuilder::default()
156                .omit_private(true)
157                .build().unwrap()
158        });
159
160        let global_cfg = GlobalConfigBuilder::default()
161            .project_overrides(project_overrides)
162            .default_include_tests(false)
163            .default_omit_bodies(false)
164            .build().unwrap();
165
166        // CLI does not request omit_private, but global override does
167        let cli = CliBuilder::default()
168            .crates(vec![])
169            .include_tests(false)
170            .build()
171            .unwrap();
172
173        let eff = EffectiveConfig::from_cli_and_global(&cli, &global_cfg).unwrap();
174        // There's currently no direct project key usage in from_cli_and_global, 
175        // but if you ever integrate project-specific logic, this test is ready.
176        // For now, this confirms that loading doesn't fail and that defaults still apply.
177        assert_eq!(*eff.criteria().omit_private(), false, "No direct logic ties project overrides to CLI test, consider integrating logic if needed.");
178    }
179
180    #[test]
181    fn test_effective_config_conflict_resolution() {
182        // CLI says omit_bodies=false, global says default_omit_bodies=true
183        let global_cfg = GlobalConfigBuilder::default()
184            .default_omit_bodies(true)
185            .default_include_tests(false)
186            .build().unwrap();
187
188        let cli = CliBuilder::default()
189            .crates(vec![])
190            .omit_bodies(false)
191            .build()
192            .unwrap();
193
194        // The code sets omit_bodies to CLI value or global default. There's no OR logic here,
195        // it's a direct assignment: `.omit_bodies(*cli.omit_bodies() || *global_cfg.default_omit_bodies())`
196        // With cli.omit_bodies=false, global_omit_bodies=true => final = true (OR logic).
197        let eff = EffectiveConfig::from_cli_and_global(&cli, &global_cfg).unwrap();
198        assert_eq!(*eff.criteria().omit_bodies(), true); // Because true || false = true
199    }
200
201    #[test]
202    fn test_effective_config_excluded_files_merge() {
203        let global_cfg = GlobalConfigBuilder::default()
204            .build().unwrap();
205
206        let cli = CliBuilder::default()
207            .crates(vec![])
208            .excluded_files(vec!["src/exclude_this.rs".to_string()])
209            .build().unwrap();
210
211        let eff = EffectiveConfig::from_cli_and_global(&cli, &global_cfg).unwrap();
212        assert!(eff.criteria.excluded_files().contains(&"src/exclude_this.rs".to_string()));
213    }
214
215    #[test]
216    fn test_effective_config_with_single_function_name() {
217        let global_cfg = GlobalConfigBuilder::default()
218            .default_include_tests(false)
219            .build().unwrap();
220
221        let cli = CliBuilder::default()
222            .crates(vec![])
223            .single_function_name(Some("specific_func".into()))
224            .build()
225            .unwrap();
226
227        let eff = EffectiveConfig::from_cli_and_global(&cli, &global_cfg).unwrap();
228        assert_eq!(*eff.criteria().single_function_name(), Some("specific_func".to_string()));
229    }
230}