1use std::path::Path;
2
3use crate::error::ApiError;
4use crate::schema::ApiSnapshot;
5
6pub fn save_baseline(snapshot: &ApiSnapshot, path: &Path) -> Result<(), ApiError> {
8 let json = serde_json::to_string_pretty(snapshot)?;
9 std::fs::write(path, json)?;
10 Ok(())
11}
12
13pub fn load_baseline(path: &Path) -> Result<ApiSnapshot, ApiError> {
15 if !path.exists() {
16 return Err(ApiError::BaselineNotFound(
17 path.to_string_lossy().to_string(),
18 ));
19 }
20 let contents = std::fs::read_to_string(path)?;
21 let snapshot: ApiSnapshot = serde_json::from_str(&contents)?;
22 Ok(snapshot)
23}
24
25pub fn save_current(snapshot: &ApiSnapshot, path: &Path) -> Result<(), ApiError> {
27 save_baseline(snapshot, path)
28}
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33 use crate::schema::{ApiItem, ApiItemKind, Visibility};
34
35 fn sample_snapshot() -> ApiSnapshot {
36 ApiSnapshot {
37 crate_name: "test-crate".into(),
38 version: Some("0.1.0".into()),
39 items: vec![ApiItem {
40 kind: ApiItemKind::Function,
41 name: "hello".into(),
42 module_path: vec![],
43 signature: "fn hello()".into(),
44 visibility: Visibility::Public,
45 trait_associations: vec![],
46 stability: None,
47 doc_summary: None,
48 span_file: None,
49 span_line: None,
50 }],
51 extracted_at: "2026-01-01T00:00:00Z".into(),
52 }
53 }
54
55 #[test]
56 fn save_load_roundtrip() {
57 let dir = tempfile::tempdir().unwrap();
58 let path = dir.path().join("baseline.json");
59 let snap = sample_snapshot();
60 save_baseline(&snap, &path).unwrap();
61 let loaded = load_baseline(&path).unwrap();
62 assert_eq!(loaded.crate_name, snap.crate_name);
63 assert_eq!(loaded.items.len(), 1);
64 assert_eq!(loaded.items[0], snap.items[0]);
65 }
66
67 #[test]
68 fn load_missing_baseline() {
69 let result = load_baseline(Path::new("/nonexistent/baseline.json"));
70 assert!(result.is_err());
71 assert!(matches!(result.unwrap_err(), ApiError::BaselineNotFound(_)));
72 }
73
74 #[test]
75 fn save_current_works() {
76 let dir = tempfile::tempdir().unwrap();
77 let path = dir.path().join("current.json");
78 let snap = sample_snapshot();
79 save_current(&snap, &path).unwrap();
80 let loaded = load_baseline(&path).unwrap();
81 assert_eq!(loaded.crate_name, snap.crate_name);
82 }
83}