changeset_operations/traits/
inherited_version_checker.rs1use std::path::Path;
2
3use changeset_core::PackageInfo;
4
5use crate::Result;
6
7pub trait InheritedVersionChecker: Send + Sync {
9 fn has_inherited_version(&self, manifest_path: &Path) -> Result<bool>;
13
14 fn find_packages_with_inherited_versions(
18 &self,
19 packages: &[PackageInfo],
20 ) -> Result<Vec<String>> {
21 let mut inherited = Vec::new();
22 for pkg in packages {
23 let manifest_path = pkg.path.join("Cargo.toml");
24 if self.has_inherited_version(&manifest_path)? {
25 inherited.push(pkg.name.clone());
26 }
27 }
28 Ok(inherited)
29 }
30}
31
32#[cfg(test)]
33mod tests {
34 use super::*;
35 use std::path::PathBuf;
36
37 struct TestChecker {
38 inherited: std::collections::HashSet<PathBuf>,
39 fail_on: Option<PathBuf>,
40 }
41
42 impl TestChecker {
43 fn new() -> Self {
44 Self {
45 inherited: std::collections::HashSet::new(),
46 fail_on: None,
47 }
48 }
49
50 fn with_inherited(mut self, path: PathBuf) -> Self {
51 self.inherited.insert(path);
52 self
53 }
54
55 fn failing_on(mut self, path: PathBuf) -> Self {
56 self.fail_on = Some(path);
57 self
58 }
59 }
60
61 impl InheritedVersionChecker for TestChecker {
62 fn has_inherited_version(&self, manifest_path: &Path) -> Result<bool> {
63 if let Some(ref fail_path) = self.fail_on {
64 if manifest_path == fail_path {
65 return Err(crate::OperationError::Io(std::io::Error::new(
66 std::io::ErrorKind::PermissionDenied,
67 "mock failure",
68 )));
69 }
70 }
71 Ok(self.inherited.contains(manifest_path))
72 }
73 }
74
75 fn make_package(name: &str, path: &str) -> PackageInfo {
76 PackageInfo {
77 name: name.to_string(),
78 version: "1.0.0".parse().expect("valid version"),
79 path: PathBuf::from(path),
80 }
81 }
82
83 #[test]
84 fn find_packages_returns_empty_for_no_inherited() {
85 let checker = TestChecker::new();
86 let packages = vec![make_package("crate-a", "/pkg/a")];
87
88 let result = checker
89 .find_packages_with_inherited_versions(&packages)
90 .expect("should succeed");
91
92 assert!(result.is_empty());
93 }
94
95 #[test]
96 fn find_packages_returns_inherited_package_names() {
97 let checker = TestChecker::new()
98 .with_inherited(PathBuf::from("/pkg/a/Cargo.toml"))
99 .with_inherited(PathBuf::from("/pkg/c/Cargo.toml"));
100
101 let packages = vec![
102 make_package("crate-a", "/pkg/a"),
103 make_package("crate-b", "/pkg/b"),
104 make_package("crate-c", "/pkg/c"),
105 ];
106
107 let result = checker
108 .find_packages_with_inherited_versions(&packages)
109 .expect("should succeed");
110
111 assert_eq!(result, vec!["crate-a", "crate-c"]);
112 }
113
114 #[test]
115 fn find_packages_propagates_errors() {
116 let checker = TestChecker::new().failing_on(PathBuf::from("/pkg/b/Cargo.toml"));
117
118 let packages = vec![
119 make_package("crate-a", "/pkg/a"),
120 make_package("crate-b", "/pkg/b"),
121 ];
122
123 let result = checker.find_packages_with_inherited_versions(&packages);
124
125 assert!(result.is_err());
126 }
127}