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, PotentiallyConflicting};
63 use VersionConstraint::{Latest, 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 (Latest, Semver(req)) | (Semver(req), Latest) => {
82 if let Some(version) = resolved_version {
83 if req.matches(version) {
84 Compatible
85 } else {
86 PotentiallyConflicting
87 }
88 } else {
89 PotentiallyConflicting
90 }
91 }
92 _ => self.compatible_with(other),
93 }
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::CompatibilityResult;
100 use crate::resolve::VersionConstraint;
101 use semver::Version;
102
103 fn semver(req: &str) -> VersionConstraint {
104 VersionConstraint::Semver(req.parse().expect("valid semver requirement"))
105 }
106
107 #[test]
108 fn latest_with_latest_is_compatible() {
109 assert_eq!(
110 VersionConstraint::Latest.compatible_with(&VersionConstraint::Latest),
111 CompatibilityResult::Compatible
112 );
113 }
114
115 #[test]
116 fn same_semver_is_compatible() {
117 assert_eq!(
118 semver("^1.2").compatible_with(&semver("^1.2")),
119 CompatibilityResult::Compatible
120 );
121 }
122
123 #[test]
124 fn same_ref_pin_is_compatible() {
125 assert_eq!(
126 VersionConstraint::RefPin("main".into())
127 .compatible_with(&VersionConstraint::RefPin("main".into())),
128 CompatibilityResult::Compatible
129 );
130 }
131
132 #[test]
133 fn latest_with_semver_is_potentially_conflicting() {
134 assert_eq!(
135 VersionConstraint::Latest.compatible_with(&semver(">=1.0.0")),
136 CompatibilityResult::PotentiallyConflicting
137 );
138 }
139
140 #[test]
141 fn latest_with_ref_pin_is_potentially_conflicting() {
142 assert_eq!(
143 VersionConstraint::Latest.compatible_with(&VersionConstraint::RefPin("main".into())),
144 CompatibilityResult::PotentiallyConflicting
145 );
146 }
147
148 #[test]
149 fn different_semver_is_conflicting() {
150 assert_eq!(
151 semver("^1.0").compatible_with(&semver("^2.0")),
152 CompatibilityResult::Conflicting
153 );
154 }
155
156 #[test]
157 fn different_ref_pin_is_conflicting() {
158 assert_eq!(
159 VersionConstraint::RefPin("main".into())
160 .compatible_with(&VersionConstraint::RefPin("release".into())),
161 CompatibilityResult::Conflicting
162 );
163 }
164
165 #[test]
166 fn semver_with_ref_pin_is_conflicting() {
167 assert_eq!(
168 semver("^1.0").compatible_with(&VersionConstraint::RefPin("main".into())),
169 CompatibilityResult::Conflicting
170 );
171 }
172
173 #[test]
174 fn equivalent_semver_syntax_is_compatible_for_resolved_version() {
175 let resolved = Version::new(1, 4, 2);
176 assert_eq!(
177 semver("^1.0").compatible_with_resolved(&semver(">=1.0.0, <2.0.0"), Some(&resolved)),
178 CompatibilityResult::Compatible
179 );
180 }
181
182 #[test]
183 fn incompatible_semver_syntax_is_conflicting_for_resolved_version() {
184 let resolved = Version::new(2, 0, 0);
185 assert_eq!(
186 semver("^1.0").compatible_with_resolved(&semver(">=1.0.0, <2.0.0"), Some(&resolved)),
187 CompatibilityResult::Conflicting
188 );
189 }
190
191 #[test]
192 fn latest_with_semver_compatible_when_resolved_matches() {
193 let resolved = Version::new(0, 2, 1);
194 assert_eq!(
195 VersionConstraint::Latest.compatible_with_resolved(&semver("=0.2.1"), Some(&resolved)),
196 CompatibilityResult::Compatible
197 );
198 assert_eq!(
200 semver("=0.2.1").compatible_with_resolved(&VersionConstraint::Latest, Some(&resolved)),
201 CompatibilityResult::Compatible
202 );
203 }
204
205 #[test]
206 fn latest_with_semver_potentially_conflicting_when_resolved_mismatches() {
207 let resolved = Version::new(0, 3, 0);
208 assert_eq!(
209 VersionConstraint::Latest.compatible_with_resolved(&semver("=0.2.1"), Some(&resolved)),
210 CompatibilityResult::PotentiallyConflicting
211 );
212 }
213
214 #[test]
215 fn latest_with_semver_potentially_conflicting_without_resolved() {
216 assert_eq!(
217 VersionConstraint::Latest.compatible_with_resolved(&semver("=0.2.1"), None),
218 CompatibilityResult::PotentiallyConflicting
219 );
220 }
221}