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