the_code_graph_eval/
lib.rs1pub mod adapters;
2pub mod dataset;
3pub mod metrics;
4pub mod report;
5pub mod runner;
6
7use domain::error::Result;
8use report::SuiteResult;
9
10#[derive(Debug, Clone)]
12pub enum Suite {
13 Search,
14 Impact,
15 All,
16}
17
18#[derive(Debug, Clone)]
20pub struct SuiteConfig {
21 pub suite: Suite,
22 pub no_cache: bool,
23 pub suites_dir: std::path::PathBuf,
24 pub search_limit: usize,
25}
26
27pub fn run_suite(config: &SuiteConfig) -> Result<SuiteResult> {
29 let search_result = match config.suite {
30 Suite::Search | Suite::All => Some(runner::run_search_suite(config)?),
31 _ => None,
32 };
33 let impact_result = match config.suite {
34 Suite::Impact | Suite::All => Some(runner::run_impact_suite(config)?),
35 _ => None,
36 };
37 Ok(SuiteResult {
38 search: search_result,
39 impact: impact_result,
40 })
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46 use std::path::PathBuf;
47
48 fn suites_dir() -> PathBuf {
50 let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
51 manifest_dir
52 .parent()
53 .unwrap()
54 .parent()
55 .unwrap()
56 .join("eval")
57 .join("suites")
58 }
59
60 #[test]
61 fn eval_crate_is_workspace_member() {
62 let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
63 let root_cargo = manifest_dir
64 .parent()
65 .unwrap()
66 .parent()
67 .unwrap()
68 .join("Cargo.toml");
69 let content =
70 std::fs::read_to_string(&root_cargo).expect("root Cargo.toml should be readable");
71 let doc: toml::Value =
72 toml::from_str(&content).expect("root Cargo.toml should be valid TOML");
73 let members = doc["workspace"]["members"]
74 .as_array()
75 .expect("workspace.members should be an array");
76 assert_eq!(members.len(), 9, "workspace should have 9 members");
77 let has_eval = members.iter().any(|m| m.as_str() == Some("crates/eval"));
78 assert!(has_eval, "workspace members should include crates/eval");
79 }
80
81 #[test]
82 fn suite_config_search() {
83 let config = SuiteConfig {
84 suite: Suite::Search,
85 no_cache: false,
86 suites_dir: PathBuf::from("/tmp/suites"),
87 search_limit: 10,
88 };
89 assert!(matches!(config.suite, Suite::Search));
90 assert!(!config.no_cache);
91 assert_eq!(config.suites_dir, PathBuf::from("/tmp/suites"));
92 assert_eq!(config.search_limit, 10);
93 }
94
95 #[test]
96 fn suite_config_impact() {
97 let config = SuiteConfig {
98 suite: Suite::Impact,
99 no_cache: true,
100 suites_dir: PathBuf::from("/tmp/suites"),
101 search_limit: 5,
102 };
103 assert!(matches!(config.suite, Suite::Impact));
104 assert!(config.no_cache);
105 assert_eq!(config.suites_dir, PathBuf::from("/tmp/suites"));
106 assert_eq!(config.search_limit, 5);
107 }
108
109 #[test]
110 fn manifest_files_are_valid_json() {
111 let base = suites_dir();
112 let search_manifest = base.join("search").join("manifest.json");
113 let impact_manifest = base.join("impact").join("manifest.json");
114
115 let sm = dataset::parse_manifest(&search_manifest).expect("search manifest should parse");
116 assert!(!sm.repos.is_empty(), "search manifest should have repos");
117
118 let im = dataset::parse_manifest(&impact_manifest).expect("impact manifest should parse");
119 assert!(!im.repos.is_empty(), "impact manifest should have repos");
120 }
121
122 #[test]
123 fn search_query_files_are_valid_json() {
124 let dir = suites_dir().join("search").join("queries");
125 let entries: Vec<_> = std::fs::read_dir(&dir)
126 .expect("search queries dir should be readable")
127 .filter_map(|e| e.ok())
128 .filter(|e| e.path().extension().map_or(false, |ext| ext == "json"))
129 .collect();
130 assert!(
131 !entries.is_empty(),
132 "there should be at least one search query file"
133 );
134 for entry in entries {
135 let path = entry.path();
136 dataset::parse_search_queries(&path)
137 .unwrap_or_else(|e| panic!("{} should parse: {e}", path.display()));
138 }
139 }
140
141 #[test]
142 fn impact_query_files_are_valid_json() {
143 let dir = suites_dir().join("impact").join("queries");
144 let entries: Vec<_> = std::fs::read_dir(&dir)
145 .expect("impact queries dir should be readable")
146 .filter_map(|e| e.ok())
147 .filter(|e| e.path().extension().map_or(false, |ext| ext == "json"))
148 .collect();
149 assert!(
150 !entries.is_empty(),
151 "there should be at least one impact query file"
152 );
153 for entry in entries {
154 let path = entry.path();
155 dataset::parse_impact_queries(&path)
156 .unwrap_or_else(|e| panic!("{} should parse: {e}", path.display()));
157 }
158 }
159
160 #[test]
161 fn search_query_count_meets_minimum() {
162 let dir = suites_dir().join("search").join("queries");
163 let total: usize = std::fs::read_dir(&dir)
164 .expect("search queries dir should be readable")
165 .filter_map(|e| e.ok())
166 .filter(|e| e.path().extension().map_or(false, |ext| ext == "json"))
167 .map(|e| {
168 dataset::parse_search_queries(&e.path())
169 .unwrap_or_else(|err| panic!("parse failed: {err}"))
170 .len()
171 })
172 .sum();
173 assert!(total >= 50, "expected >= 50 search queries, found {total}");
174 }
175
176 #[test]
177 fn impact_scenario_count_meets_minimum() {
178 let dir = suites_dir().join("impact").join("queries");
179 let total: usize = std::fs::read_dir(&dir)
180 .expect("impact queries dir should be readable")
181 .filter_map(|e| e.ok())
182 .filter(|e| e.path().extension().map_or(false, |ext| ext == "json"))
183 .map(|e| {
184 dataset::parse_impact_queries(&e.path())
185 .unwrap_or_else(|err| panic!("parse failed: {err}"))
186 .len()
187 })
188 .sum();
189 assert!(
190 total >= 20,
191 "expected >= 20 impact scenarios, found {total}"
192 );
193 }
194}