use crate::reference::TypeReference;
use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};
#[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Clone, Default)]
pub struct AnalysisOptions {
pub recursive: bool,
pub include_tests: bool,
pub expand_groups: bool,
pub resolve_globs: bool,
}
#[derive(Debug, Clone)]
pub struct AnalysisResult {
module_path: String,
dependencies: HashMap<String, HashSet<TypeReference>>,
source_file: PathBuf,
}
impl AnalysisResult {
#[must_use]
pub(crate) fn new(
module_path: impl Into<String>,
dependencies: HashMap<String, HashSet<TypeReference>>,
source_file: PathBuf,
) -> Self {
Self {
module_path: module_path.into(),
dependencies,
source_file,
}
}
#[must_use]
pub fn module_path(&self) -> &str {
&self.module_path
}
#[must_use]
pub const fn dependencies(&self) -> &HashMap<String, HashSet<TypeReference>> {
&self.dependencies
}
#[must_use]
pub fn source_file(&self) -> &Path {
&self.source_file
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.dependencies.is_empty()
}
#[must_use]
pub fn len(&self) -> usize {
self.dependencies.len()
}
#[must_use]
pub fn into_sorted_vec(self) -> Vec<TypeReference> {
let all_deps_unique: HashSet<_> = self.dependencies.values().flatten().cloned().collect();
let mut all_deps_unique: Vec<TypeReference> = all_deps_unique.into_iter().collect();
all_deps_unique.sort_by_key(TypeReference::to_path_string);
all_deps_unique
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_analysis_options_default() {
let options = AnalysisOptions::default();
assert!(!options.include_tests);
assert!(!options.expand_groups);
}
#[test]
fn test_analysis_result_source_file() {
let result = AnalysisResult::new(
"foo::bar".to_owned(),
HashMap::new(),
PathBuf::from("/tmp/test.rs"),
);
assert_eq!(result.source_file(), Path::new("/tmp/test.rs"));
}
#[test]
fn test_analysis_result_len_and_is_empty() {
let empty_result = AnalysisResult::new("empty".to_owned(), HashMap::new(), PathBuf::new());
assert_eq!(empty_result.len(), 0);
assert!(empty_result.is_empty());
let mut deps = HashMap::new();
deps.insert("mod_a".to_owned(), HashSet::new());
deps.insert("mod_b".to_owned(), HashSet::new());
let non_empty_result = AnalysisResult::new("root".to_owned(), deps, PathBuf::new());
assert_eq!(non_empty_result.len(), 2);
assert!(!non_empty_result.is_empty());
}
#[test]
fn test_analysis_result_module_path() {
let result =
AnalysisResult::new("foo::bar::baz".to_owned(), HashMap::new(), PathBuf::new());
assert_eq!(result.module_path(), "foo::bar::baz");
}
#[test]
fn test_into_sorted_vec_deduplicates_and_sorts() {
use crate::reference::TypeReference;
let r1 = TypeReference::new(["z_module", "Type"]);
let r2 = TypeReference::new(["a_module", "Type"]);
let r3 = TypeReference::new(["z_module", "Type"]);
let mut deps = HashMap::new();
deps.insert("mod_a".to_owned(), HashSet::from([r1.clone(), r2.clone()]));
deps.insert("mod_b".to_owned(), HashSet::from([r3]));
let result = AnalysisResult::new("root".to_owned(), deps, PathBuf::new());
let sorted = result.into_sorted_vec();
assert_eq!(sorted.len(), 2);
assert_eq!(sorted[0], r2); assert_eq!(sorted[1], r1);
}
}