Skip to main content

socorro_cli/
cache.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5use std::fs;
6use std::path::PathBuf;
7
8/// Returns the cache directory for socorro-cli, creating it if necessary.
9/// Uses the OS-standard cache directory:
10/// - Linux: ~/.cache/socorro-cli/
11/// - macOS: ~/Library/Caches/socorro-cli/
12/// - Windows: %LOCALAPPDATA%/socorro-cli/cache/
13pub fn cache_dir() -> Option<PathBuf> {
14    let dir = dirs::cache_dir()?.join("socorro-cli");
15    fs::create_dir_all(&dir).ok()?;
16    Some(dir)
17}
18
19/// Read cached data for a given key (filename).
20/// Returns None if the cache file doesn't exist or is empty.
21pub fn read_cached(key: &str) -> Option<Vec<u8>> {
22    let path = cache_dir()?.join(key);
23    let data = fs::read(&path).ok()?;
24    if data.is_empty() {
25        return None;
26    }
27    Some(data)
28}
29
30/// Write data to cache with the given key (filename).
31/// Returns true if writing succeeded.
32pub fn write_cache(key: &str, data: &[u8]) -> bool {
33    let Some(dir) = cache_dir() else {
34        return false;
35    };
36    fs::write(dir.join(key), data).is_ok()
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    #[test]
44    fn test_cache_dir_exists() {
45        let dir = cache_dir();
46        assert!(dir.is_some());
47        assert!(dir.unwrap().exists());
48    }
49
50    #[test]
51    fn test_read_nonexistent_cache() {
52        let result = read_cached("nonexistent-test-file-12345.json");
53        assert!(result.is_none());
54    }
55
56    #[test]
57    fn test_write_and_read_cache() {
58        let key = "test-cache-roundtrip.txt";
59        let data = b"hello cache";
60        assert!(write_cache(key, data));
61        let read_back = read_cached(key);
62        assert_eq!(read_back, Some(data.to_vec()));
63
64        // Cleanup
65        if let Some(dir) = cache_dir() {
66            let _ = fs::remove_file(dir.join(key));
67        }
68    }
69
70    #[test]
71    fn test_empty_cache_returns_none() {
72        let key = "test-cache-empty.txt";
73        assert!(write_cache(key, b""));
74        let result = read_cached(key);
75        assert!(result.is_none());
76
77        // Cleanup
78        if let Some(dir) = cache_dir() {
79            let _ = fs::remove_file(dir.join(key));
80        }
81    }
82}