mars_agents/resolve/
compat.rs1use super::VersionConstraint;
2use semver::Version;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum CompatibilityResult {
7 Compatible,
9 PotentiallyConflicting,
11 Conflicting,
13}
14
15impl VersionConstraint {
16 pub fn compatible_with(&self, other: &VersionConstraint) -> CompatibilityResult {
26 use CompatibilityResult::{Compatible, Conflicting, PotentiallyConflicting};
27 use VersionConstraint::{Latest, RefPin, Semver};
28
29 match (self, other) {
30 (Latest, Latest) => Compatible,
31 (Latest, Semver(_) | RefPin(_)) | (Semver(_) | RefPin(_), Latest) => {
32 PotentiallyConflicting
33 }
34 (Semver(lhs), Semver(rhs)) => {
35 if lhs == rhs {
36 Compatible
37 } else {
38 Conflicting
39 }
40 }
41 (RefPin(lhs), RefPin(rhs)) => {
42 if lhs == rhs {
43 Compatible
44 } else {
45 Conflicting
46 }
47 }
48 (Semver(_), RefPin(_)) | (RefPin(_), Semver(_)) => Conflicting,
49 }
50 }
51
52 pub fn compatible_with_resolved(
58 &self,
59 other: &VersionConstraint,
60 resolved_version: Option<&Version>,
61 ) -> CompatibilityResult {
62 use CompatibilityResult::{Compatible, Conflicting};
63 use VersionConstraint::Semver;
64
65 match (self, other) {
66 (Semver(lhs), Semver(rhs)) => {
67 if lhs == rhs {
68 Compatible
69 } else if let Some(version) = resolved_version {
70 if lhs.matches(version) && rhs.matches(version) {
71 Compatible
72 } else {
73 Conflicting
74 }
75 } else {
76 Conflicting
77 }
78 }
79 _ => self.compatible_with(other),
80 }
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::CompatibilityResult;
87 use crate::resolve::VersionConstraint;
88 use semver::Version;
89
90 fn semver(req: &str) -> VersionConstraint {
91 VersionConstraint::Semver(req.parse().expect("valid semver requirement"))
92 }
93
94 #[test]
95 fn latest_with_latest_is_compatible() {
96 assert_eq!(
97 VersionConstraint::Latest.compatible_with(&VersionConstraint::Latest),
98 CompatibilityResult::Compatible
99 );
100 }
101
102 #[test]
103 fn same_semver_is_compatible() {
104 assert_eq!(
105 semver("^1.2").compatible_with(&semver("^1.2")),
106 CompatibilityResult::Compatible
107 );
108 }
109
110 #[test]
111 fn same_ref_pin_is_compatible() {
112 assert_eq!(
113 VersionConstraint::RefPin("main".into())
114 .compatible_with(&VersionConstraint::RefPin("main".into())),
115 CompatibilityResult::Compatible
116 );
117 }
118
119 #[test]
120 fn latest_with_semver_is_potentially_conflicting() {
121 assert_eq!(
122 VersionConstraint::Latest.compatible_with(&semver(">=1.0.0")),
123 CompatibilityResult::PotentiallyConflicting
124 );
125 }
126
127 #[test]
128 fn latest_with_ref_pin_is_potentially_conflicting() {
129 assert_eq!(
130 VersionConstraint::Latest.compatible_with(&VersionConstraint::RefPin("main".into())),
131 CompatibilityResult::PotentiallyConflicting
132 );
133 }
134
135 #[test]
136 fn different_semver_is_conflicting() {
137 assert_eq!(
138 semver("^1.0").compatible_with(&semver("^2.0")),
139 CompatibilityResult::Conflicting
140 );
141 }
142
143 #[test]
144 fn different_ref_pin_is_conflicting() {
145 assert_eq!(
146 VersionConstraint::RefPin("main".into())
147 .compatible_with(&VersionConstraint::RefPin("release".into())),
148 CompatibilityResult::Conflicting
149 );
150 }
151
152 #[test]
153 fn semver_with_ref_pin_is_conflicting() {
154 assert_eq!(
155 semver("^1.0").compatible_with(&VersionConstraint::RefPin("main".into())),
156 CompatibilityResult::Conflicting
157 );
158 }
159
160 #[test]
161 fn equivalent_semver_syntax_is_compatible_for_resolved_version() {
162 let resolved = Version::new(1, 4, 2);
163 assert_eq!(
164 semver("^1.0").compatible_with_resolved(&semver(">=1.0.0, <2.0.0"), Some(&resolved)),
165 CompatibilityResult::Compatible
166 );
167 }
168
169 #[test]
170 fn incompatible_semver_syntax_is_conflicting_for_resolved_version() {
171 let resolved = Version::new(2, 0, 0);
172 assert_eq!(
173 semver("^1.0").compatible_with_resolved(&semver(">=1.0.0, <2.0.0"), Some(&resolved)),
174 CompatibilityResult::Conflicting
175 );
176 }
177}