| 362 | } |
| 363 | |
| 364 | fn parse_groundtruth_csv( |
| 365 | path: std::path::PathBuf, |
| 366 | ) -> anyhow::Result<HashMap<String, Vec<GroundTruthEntry>>> { |
| 367 | // Keep track of all the tests by filename so we can |
| 368 | let mut tests = HashMap::new(); |
| 369 | let mut add_test = |name: String, entries: Vec<GroundTruthEntry>| { |
| 370 | if tests.insert(name.clone(), entries).is_some() { |
| 371 | anyhow::bail!("Duplicate entry for: {}", name) |
| 372 | } |
| 373 | Ok(()) |
| 374 | }; |
| 375 | |
| 376 | let reader = std::io::BufReader::new( |
| 377 | std::fs::File::open(&path) |
| 378 | .with_context(|| format!("failed to open: {}", path.display()))?, |
| 379 | ); |
| 380 | |
| 381 | let mut current_file = None; |
| 382 | let mut entries_for_file = vec![]; |
| 383 | // Iterate through all lines the csv file, skipping the header field. |
| 384 | for (i, line) in reader.lines().enumerate().skip(1) { |
| 385 | let line = line?; |
| 386 | let line_num = i + 1; |
| 387 | let mut fragment = line.as_str(); |
| 388 | |
| 389 | // Check whether the current line is the start of a new file or a continuation of the |
| 390 | // previous file. |
| 391 | if !line.starts_with('\t') { |
| 392 | let Some((filename, rest)) = line.split_once('\t') |
| 393 | else { |
| 394 | anyhow::bail!("Expected \\t character after filename on line: {line_num}"); |
| 395 | }; |
| 396 | fragment = rest; |
| 397 | |
| 398 | // Add all tests for the previous file to the map and start record for the current file. |
| 399 | if let Some(name) = current_file.replace(filename.to_string()) { |
| 400 | add_test(name, std::mem::take(&mut entries_for_file))?; |
| 401 | } |
| 402 | } |
| 403 | else { |
| 404 | anyhow::ensure!(current_file.is_some(), "File missing on line: {line_num}"); |
| 405 | fragment = fragment.trim_start(); |
| 406 | } |
| 407 | |
| 408 | // Parse the testcase for the current line. |
| 409 | match GroundTruthEntry::from_line(fragment, line_num) { |
| 410 | Some(entry) => entries_for_file.push(entry), |
| 411 | None => anyhow::bail!("Invalid entry on line: {line_num}"), |
| 412 | } |
| 413 | } |
| 414 | |
| 415 | // Add final test. |
| 416 | if let Some(name) = current_file { |
| 417 | add_test(name, entries_for_file)?; |
| 418 | } |
| 419 | |
| 420 | Ok(tests) |
| 421 | } |