gvc 0.2.0

CLI manager for Gradle version catalogs—check, list, update, and add dependencies with automatic version aliases
use crate::error::{GvcError, Result};
use std::collections::HashMap;
use std::sync::Mutex;

#[derive(Debug, Default)]
pub(super) struct MetadataCache {
    entries: Mutex<HashMap<String, Vec<String>>>,
}

impl MetadataCache {
    pub(super) fn new() -> Self {
        Self::default()
    }

    pub(super) fn get(&self, key: &str) -> Result<Option<Vec<String>>> {
        let entries = self.entries.lock().map_err(|_| Self::lock_error())?;
        Ok(entries.get(key).cloned())
    }

    pub(super) fn insert(&self, key: String, versions: Vec<String>) -> Result<()> {
        let mut entries = self.entries.lock().map_err(|_| Self::lock_error())?;
        entries.insert(key, versions);
        Ok(())
    }

    fn lock_error() -> GvcError {
        GvcError::Io(std::io::Error::other("metadata cache lock poisoned"))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn cache_returns_cloned_versions() {
        let cache = MetadataCache::new();
        cache
            .insert(
                "https://example.test/maven-metadata.xml".to_string(),
                vec!["1.0.0".to_string()],
            )
            .unwrap();

        let mut cached = cache
            .get("https://example.test/maven-metadata.xml")
            .unwrap()
            .unwrap();
        cached.push("2.0.0".to_string());

        assert_eq!(
            cache
                .get("https://example.test/maven-metadata.xml")
                .unwrap()
                .unwrap(),
            vec!["1.0.0".to_string()]
        );
    }

    #[test]
    fn missing_cache_key_returns_none() {
        let cache = MetadataCache::new();
        assert!(cache.get("missing").unwrap().is_none());
    }
}