1pub const BONNIE_VERSION: &str = "0.3.2";
5
6#[derive(Debug, PartialEq, Eq)]
8pub enum VersionDifference {
9 TooOld,
10 TooNew,
11}
12
13#[derive(Debug, PartialEq, Eq)]
15pub enum VersionCompatibility {
16 Identical,
17 DifferentMajor(VersionDifference), DifferentMinor(VersionDifference),
19 DifferentPatch(VersionDifference),
20 DifferentBetaVersion(VersionDifference), }
22
23#[derive(Debug, PartialEq, Eq)]
24pub struct Version {
25 patch: u16,
26 minor: u16,
27 major: u16,
28}
29impl Version {
30 pub fn is_compatible_with(&self, comparison: &Version) -> VersionCompatibility {
33 let compatibility = match self.major {
34 _ if self.major > comparison.major => {
35 VersionCompatibility::DifferentMajor(VersionDifference::TooOld)
36 }
37 _ if self.major < comparison.major => {
38 VersionCompatibility::DifferentMajor(VersionDifference::TooNew)
39 }
40 _ if self.minor > comparison.minor => {
41 VersionCompatibility::DifferentMinor(VersionDifference::TooOld)
42 }
43 _ if self.minor < comparison.minor => {
44 VersionCompatibility::DifferentMinor(VersionDifference::TooNew)
45 }
46 _ if self.patch > comparison.patch => {
47 VersionCompatibility::DifferentPatch(VersionDifference::TooOld)
48 }
49 _ if self.patch < comparison.patch => {
50 VersionCompatibility::DifferentPatch(VersionDifference::TooNew)
51 }
52 _ => VersionCompatibility::Identical,
53 };
54 if self.major == 0 && !matches!(compatibility, VersionCompatibility::Identical) {
56 VersionCompatibility::DifferentBetaVersion(match compatibility {
58 VersionCompatibility::DifferentMajor(version_difference) => version_difference,
59 VersionCompatibility::DifferentMinor(version_difference) => version_difference,
60 VersionCompatibility::DifferentPatch(version_difference) => version_difference,
61 _ => panic!("Critical logic failure in version compatibility checks. You should report this as a bug."), })
63 } else {
64 compatibility
65 }
66 }
67}
68
69pub fn get_version_parts(version_str: &str) -> Result<Version, String> {
71 let split: Vec<&str> = version_str.split('.').collect();
72 let patch = split.get(2)
74 .ok_or_else(|| String::from(
75 "Couldn't extract the patch version number from the given version string. If the version string in your Bonnie configuration file is definitely of the form 'x.y.z', you should report this as a bug."
76 ))?
77 .parse::<u16>()
78 .map_err(|_| String::from(
79 "Couldn't serialize the patch version number from the given version string into an integer. If the version string in your Bonnie configuration file is definitely of the form 'x.y.z', where each of those are integers, you should report this as a bug."
80 ))?;
81 let minor = split.get(1)
82 .ok_or_else(|| String::from(
83 "Couldn't extract the minor version number from the given version string. If the version string in your Bonnie configuration file is definitely of the form 'x.y.z', you should report this as a bug."
84 ))?
85 .parse::<u16>()
86 .map_err(|_| String::from(
87 "Couldn't serialize the minor version number from the given version string into an integer. If the version string in your Bonnie configuration file is definitely of the form 'x.y.z', where each of those are integers, you should report this as a bug."
88 ))?;
89 let major = split.first()
90 .ok_or_else(|| String::from(
91 "Couldn't extract the major version number from the given version string. If the version string in your Bonnie configuration file is definitely of the form 'x.y.z', you should report this as a bug."
92 ))?
93 .parse::<u16>()
94 .map_err(|_| String::from(
95 "Couldn't serialize the major version number from the given version string into an integer. If the version string in your Bonnie configuration file is definitely of the form 'x.y.z', where each of those are integers, you should report this as a bug."
96 ))?;
97 Ok(Version {
99 patch,
100 minor,
101 major,
102 })
103}
104
105#[cfg(test)]
110fn build_version(parts: Vec<u16>) -> Version {
111 Version {
113 patch: parts[2],
114 minor: parts[1],
115 major: parts[0],
116 }
117}
118
119#[test]
122fn identifies_identical_versions() {
123 let version = build_version(vec![2, 3, 4]);
124 let comparison = build_version(vec![2, 3, 4]);
125 let compat = version.is_compatible_with(&comparison);
126
127 assert_eq!(compat, VersionCompatibility::Identical);
128}
129#[test]
130fn identifies_major_too_new() {
131 let version = build_version(vec![2, 3, 4]);
132 let comparison = build_version(vec![3, 3, 4]);
133 let compat = version.is_compatible_with(&comparison);
134
135 assert_eq!(
136 compat,
137 VersionCompatibility::DifferentMajor(VersionDifference::TooNew)
138 );
139}
140#[test]
141fn identifies_major_too_old() {
142 let version = build_version(vec![2, 3, 4]);
143 let comparison = build_version(vec![1, 3, 4]);
144 let compat = version.is_compatible_with(&comparison);
145
146 assert_eq!(
147 compat,
148 VersionCompatibility::DifferentMajor(VersionDifference::TooOld)
149 );
150}
151#[test]
152fn identifies_minor_too_new() {
153 let version = build_version(vec![2, 3, 4]);
154 let comparison = build_version(vec![2, 4, 4]);
155 let compat = version.is_compatible_with(&comparison);
156
157 assert_eq!(
158 compat,
159 VersionCompatibility::DifferentMinor(VersionDifference::TooNew)
160 );
161}
162#[test]
163fn identifies_minor_too_old() {
164 let version = build_version(vec![2, 3, 4]);
165 let comparison = build_version(vec![2, 2, 4]);
166 let compat = version.is_compatible_with(&comparison);
167
168 assert_eq!(
169 compat,
170 VersionCompatibility::DifferentMinor(VersionDifference::TooOld)
171 );
172}
173#[test]
174fn identifies_patch_too_new() {
175 let version = build_version(vec![2, 3, 4]);
176 let comparison = build_version(vec![2, 3, 5]);
177 let compat = version.is_compatible_with(&comparison);
178
179 assert_eq!(
180 compat,
181 VersionCompatibility::DifferentPatch(VersionDifference::TooNew)
182 );
183}
184#[test]
185fn identifies_patch_too_old() {
186 let version = build_version(vec![2, 3, 4]);
187 let comparison = build_version(vec![2, 3, 3]);
188 let compat = version.is_compatible_with(&comparison);
189
190 assert_eq!(
191 compat,
192 VersionCompatibility::DifferentPatch(VersionDifference::TooOld)
193 );
194}
195#[test]
197fn identifies_identical_versions_in_beta() {
198 let version = build_version(vec![0, 3, 4]);
199 let comparison = build_version(vec![0, 3, 4]);
200 let compat = version.is_compatible_with(&comparison);
201
202 assert_eq!(compat, VersionCompatibility::Identical);
203}
204#[test]
205fn identifies_major_too_new_in_beta() {
206 let version = build_version(vec![0, 3, 4]);
207 let comparison = build_version(vec![1, 3, 4]);
208 let compat = version.is_compatible_with(&comparison);
209
210 assert_eq!(
211 compat,
212 VersionCompatibility::DifferentBetaVersion(VersionDifference::TooNew)
213 );
214}
215#[test]
216fn identifies_minor_too_new_in_beta() {
217 let version = build_version(vec![0, 3, 4]);
218 let comparison = build_version(vec![0, 4, 4]);
219 let compat = version.is_compatible_with(&comparison);
220
221 assert_eq!(
222 compat,
223 VersionCompatibility::DifferentBetaVersion(VersionDifference::TooNew)
224 );
225}
226#[test]
227fn identifies_minor_too_old_in_beta() {
228 let version = build_version(vec![0, 3, 4]);
229 let comparison = build_version(vec![0, 2, 4]);
230 let compat = version.is_compatible_with(&comparison);
231
232 assert_eq!(
233 compat,
234 VersionCompatibility::DifferentBetaVersion(VersionDifference::TooOld)
235 );
236}
237#[test]
238fn identifies_patch_too_new_in_beta() {
239 let version = build_version(vec![0, 3, 4]);
240 let comparison = build_version(vec![0, 3, 5]);
241 let compat = version.is_compatible_with(&comparison);
242
243 assert_eq!(
244 compat,
245 VersionCompatibility::DifferentBetaVersion(VersionDifference::TooNew)
246 );
247}
248#[test]
249fn identifies_patch_too_old_in_beta() {
250 let version = build_version(vec![0, 3, 4]);
251 let comparison = build_version(vec![0, 3, 3]);
252 let compat = version.is_compatible_with(&comparison);
253
254 assert_eq!(
255 compat,
256 VersionCompatibility::DifferentBetaVersion(VersionDifference::TooOld)
257 );
258}
259
260#[test]
262fn returns_correct_part_division() {
263 let version = "1.2.3";
264 let parts = get_version_parts(version);
265
266 assert_eq!(parts, Ok(build_version(vec![1, 2, 3])))
267}
268#[test]
269fn returns_error_on_missing_patch_number() {
270 let version = "1.2";
271 let parts = get_version_parts(version);
272
273 if parts.is_ok() {
274 panic!("Didn't return an error on missing patch number.")
275 }
276}
277#[test]
278fn returns_error_on_missing_minor_number() {
279 let version = "1";
280 let parts = get_version_parts(version);
281
282 if parts.is_ok() {
283 panic!("Didn't return an error on missing minor number.")
284 }
285}
286#[test]
287fn returns_error_on_invalid_patch_number() {
288 let version = "1.2.x";
289 let parts = get_version_parts(version);
290
291 if parts.is_ok() {
292 panic!("Didn't return an error on invalid patch number.")
293 }
294}
295#[test]
296fn returns_error_on_invalid_minor_number() {
297 let version = "1.x.3";
298 let parts = get_version_parts(version);
299
300 if parts.is_ok() {
301 panic!("Didn't return an error on invalid minor number.")
302 }
303}
304#[test]
305fn returns_error_on_invalid_major_number() {
306 let version = "x.2.3";
307 let parts = get_version_parts(version);
308
309 if parts.is_ok() {
310 panic!("Didn't return an error on invalid major number.")
311 }
312}