1mod file_cache;
7
8pub use file_cache::{CacheStats, FileParseCache};
9
10use std::sync::LazyLock;
11
12pub static GLOBAL_FILE_CACHE: LazyLock<FileParseCache> = LazyLock::new(FileParseCache::new);
14
15pub fn global_cache() -> &'static FileParseCache {
17 &GLOBAL_FILE_CACHE
18}
19
20pub fn clear_global_cache() {
22 GLOBAL_FILE_CACHE.clear();
23}
24
25#[cfg(test)]
26mod tests {
27 use super::*;
28 use serial_test::serial;
29 use std::fs::File;
30 use std::io::Write;
31 use tempfile::tempdir;
32
33 #[test]
34 #[serial(global_cache)]
35 fn test_global_cache_exists() {
36 let cache = global_cache();
38 let _stats = cache.stats();
39
40 }
42
43 #[test]
44 #[serial(global_cache)]
45 fn test_global_cache_singleton() {
46 let cache1 = global_cache();
48 let cache2 = global_cache();
49
50 assert!(std::ptr::eq(cache1, cache2));
52 }
53
54 #[test]
55 #[serial(global_cache)]
56 fn test_global_cache_clear() {
57 let cache = global_cache();
59
60 let dir = tempdir().unwrap();
62 let file_path = dir.path().join("test.jsonl");
63 let mut file = File::create(&file_path).unwrap();
64 writeln!(
65 file,
66 r#"{{"timestamp":"2026-07-12T00:00:00Z","type":"session_meta","payload":{{"type":"session_meta","id":"clear"}}}}"#
67 )
68 .unwrap();
69 drop(file);
70
71 let _ = cache.get_or_parse(&file_path);
73
74 clear_global_cache();
76
77 let stats_after = cache.stats();
79 assert_eq!(stats_after.entry_count, 0);
80 }
81
82 #[test]
83 #[serial(global_cache)]
84 fn test_global_cache_persistence_across_calls() {
85 let cache = global_cache();
87 clear_global_cache();
88
89 let dir = tempdir().unwrap();
90 let file_path = dir.path().join("test.jsonl");
91 let mut file = File::create(&file_path).unwrap();
92 writeln!(
93 file,
94 r#"{{"timestamp":"2026-07-12T00:00:00Z","type":"session_meta","payload":{{"type":"session_meta","id":"persistent"}}}}"#
95 )
96 .unwrap();
97 drop(file);
98
99 cache.get_or_parse(&file_path).unwrap();
101 let stats1 = cache.stats();
102 let count1 = stats1.entry_count;
103
104 cache.get_or_parse(&file_path).unwrap();
106 let stats2 = cache.stats();
107
108 assert_eq!(stats2.entry_count, count1);
110 }
111
112 #[test]
113 #[serial(global_cache)]
114 fn test_global_cache_stats() {
115 clear_global_cache();
117 let cache = global_cache();
118
119 let stats = cache.stats();
120
121 assert_eq!(stats.entry_count, 0);
123 }
124
125 #[test]
126 #[serial(global_cache)]
127 fn test_clear_global_cache_multiple_times() {
128 clear_global_cache();
130 clear_global_cache();
131 clear_global_cache();
132
133 let cache = global_cache();
134 let stats = cache.stats();
135
136 assert_eq!(stats.entry_count, 0);
137 }
138
139 #[test]
140 #[serial(global_cache)]
141 fn test_global_cache_thread_safety() {
142 use std::thread;
144
145 clear_global_cache();
146
147 let handles: Vec<_> = (0..5)
148 .map(|_| {
149 thread::spawn(|| {
150 let cache = global_cache();
151 let _ = cache.stats();
152 })
153 })
154 .collect();
155
156 for handle in handles {
157 handle.join().unwrap();
158 }
159
160 let cache = global_cache();
162 let _ = cache.stats();
163 }
164
165 #[test]
166 #[serial(global_cache)]
167 fn test_global_cache_with_operations() {
168 clear_global_cache();
170 let cache = global_cache();
171
172 let dir = tempdir().unwrap();
173
174 let file1 = dir.path().join("test1.jsonl");
176 let mut f = File::create(&file1).unwrap();
177 writeln!(
178 f,
179 r#"{{"timestamp":"2026-07-12T00:00:00Z","type":"session_meta","payload":{{"type":"session_meta","id":"one"}}}}"#
180 )
181 .unwrap();
182 drop(f);
183
184 let file2 = dir.path().join("test2.jsonl");
185 let mut f = File::create(&file2).unwrap();
186 writeln!(
187 f,
188 r#"{{"timestamp":"2026-07-12T00:00:00Z","type":"session_meta","payload":{{"type":"session_meta","id":"two"}}}}"#
189 )
190 .unwrap();
191 drop(f);
192
193 cache.get_or_parse(&file1).unwrap();
195 cache.get_or_parse(&file2).unwrap();
196
197 let stats = cache.stats();
198 assert!(stats.entry_count >= 2);
199 }
200}