use std::path::PathBuf;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ClasspathScope {
pub module_name: String,
pub module_root: PathBuf,
pub is_direct: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClasspathProvenance {
pub jar_path: PathBuf,
pub coordinates: Option<String>,
pub is_direct: bool,
#[serde(default)]
pub scopes: Vec<ClasspathScope>,
}
impl ClasspathProvenance {
#[must_use]
pub fn has_direct_scope(&self) -> bool {
self.scopes.iter().any(|scope| scope.is_direct)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_provenance_roundtrip_json() {
let prov = ClasspathProvenance {
jar_path: PathBuf::from("/home/user/.m2/repository/guava-33.0.0.jar"),
coordinates: Some("com.google.guava:guava:33.0.0".to_owned()),
is_direct: true,
scopes: vec![ClasspathScope {
module_name: "app".to_owned(),
module_root: PathBuf::from("/repo/app"),
is_direct: true,
}],
};
let json = serde_json::to_string(&prov).unwrap();
let deserialized: ClasspathProvenance = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized.jar_path, prov.jar_path);
assert_eq!(deserialized.coordinates, prov.coordinates);
assert_eq!(deserialized.is_direct, prov.is_direct);
}
#[test]
fn test_provenance_transitive_no_coordinates() {
let prov = ClasspathProvenance {
jar_path: PathBuf::from("/tmp/some-transitive-1.0.jar"),
coordinates: None,
is_direct: false,
scopes: vec![ClasspathScope {
module_name: "lib".to_owned(),
module_root: PathBuf::from("/repo/lib"),
is_direct: false,
}],
};
assert!(!prov.is_direct);
assert!(prov.coordinates.is_none());
}
#[test]
fn test_provenance_postcard_roundtrip() {
let prov = ClasspathProvenance {
jar_path: PathBuf::from("/repo/.gradle/caches/guava-33.jar"),
coordinates: Some("com.google.guava:guava:33.0.0".to_owned()),
is_direct: false,
scopes: vec![ClasspathScope {
module_name: "app".to_owned(),
module_root: PathBuf::from("/repo/app"),
is_direct: false,
}],
};
let bytes = postcard::to_allocvec(&prov).unwrap();
let deserialized: ClasspathProvenance = postcard::from_bytes(&bytes).unwrap();
assert_eq!(deserialized.jar_path, prov.jar_path);
assert_eq!(deserialized.coordinates, prov.coordinates);
assert_eq!(deserialized.is_direct, prov.is_direct);
}
}