]>
Commit | Line | Data |
---|---|---|
3dfed10e XL |
1 | // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT\r |
2 | // file at the top-level directory of this distribution and at\r | |
3 | // http://rust-lang.org/COPYRIGHT.\r | |
4 | //\r | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\r | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license\r | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your\r | |
8 | // option. This file may not be copied, modified, or distributed\r | |
9 | // except according to those terms.\r | |
10 | \r | |
11 | //! The `version` module gives you tools to create and compare SemVer-compliant\r | |
12 | //! versions.\r | |
13 | \r | |
14 | use std::cmp::{self, Ordering};\r | |
15 | use std::error::Error;\r | |
16 | use std::fmt;\r | |
17 | use std::hash;\r | |
18 | \r | |
19 | use std::result;\r | |
20 | use std::str;\r | |
21 | \r | |
22 | use semver_parser;\r | |
23 | \r | |
24 | #[cfg(feature = "serde")]\r | |
25 | use serde::de::{self, Deserialize, Deserializer, Visitor};\r | |
26 | #[cfg(feature = "serde")]\r | |
27 | use serde::ser::{Serialize, Serializer};\r | |
28 | \r | |
29 | /// An identifier in the pre-release or build metadata.\r | |
30 | ///\r | |
31 | /// See sections 9 and 10 of the spec for more about pre-release identifers and\r | |
32 | /// build metadata.\r | |
33 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]\r | |
34 | pub enum Identifier {\r | |
35 | /// An identifier that's solely numbers.\r | |
36 | Numeric(u64),\r | |
37 | /// An identifier with letters and numbers.\r | |
38 | AlphaNumeric(String),\r | |
39 | }\r | |
40 | \r | |
41 | impl From<semver_parser::version::Identifier> for Identifier {\r | |
42 | fn from(other: semver_parser::version::Identifier) -> Identifier {\r | |
43 | match other {\r | |
44 | semver_parser::version::Identifier::Numeric(n) => Identifier::Numeric(n),\r | |
45 | semver_parser::version::Identifier::AlphaNumeric(s) => Identifier::AlphaNumeric(s),\r | |
46 | }\r | |
47 | }\r | |
48 | }\r | |
49 | \r | |
50 | impl fmt::Display for Identifier {\r | |
51 | #[inline]\r | |
52 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\r | |
53 | match *self {\r | |
54 | Identifier::Numeric(ref n) => fmt::Display::fmt(n, f),\r | |
55 | Identifier::AlphaNumeric(ref s) => fmt::Display::fmt(s, f),\r | |
56 | }\r | |
57 | }\r | |
58 | }\r | |
59 | \r | |
60 | #[cfg(feature = "serde")]\r | |
61 | impl Serialize for Identifier {\r | |
62 | fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>\r | |
63 | where\r | |
64 | S: Serializer,\r | |
65 | {\r | |
66 | // Serialize Identifier as a number or string.\r | |
67 | match *self {\r | |
68 | Identifier::Numeric(n) => serializer.serialize_u64(n),\r | |
69 | Identifier::AlphaNumeric(ref s) => serializer.serialize_str(s),\r | |
70 | }\r | |
71 | }\r | |
72 | }\r | |
73 | \r | |
74 | #[cfg(feature = "serde")]\r | |
75 | impl<'de> Deserialize<'de> for Identifier {\r | |
76 | fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>\r | |
77 | where\r | |
78 | D: Deserializer<'de>,\r | |
79 | {\r | |
80 | struct IdentifierVisitor;\r | |
81 | \r | |
82 | // Deserialize Identifier from a number or string.\r | |
83 | impl<'de> Visitor<'de> for IdentifierVisitor {\r | |
84 | type Value = Identifier;\r | |
85 | \r | |
86 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {\r | |
87 | formatter.write_str("a SemVer pre-release or build identifier")\r | |
88 | }\r | |
89 | \r | |
90 | fn visit_u64<E>(self, numeric: u64) -> result::Result<Self::Value, E>\r | |
91 | where\r | |
92 | E: de::Error,\r | |
93 | {\r | |
94 | Ok(Identifier::Numeric(numeric))\r | |
95 | }\r | |
96 | \r | |
97 | fn visit_str<E>(self, alphanumeric: &str) -> result::Result<Self::Value, E>\r | |
98 | where\r | |
99 | E: de::Error,\r | |
100 | {\r | |
101 | Ok(Identifier::AlphaNumeric(alphanumeric.to_owned()))\r | |
102 | }\r | |
103 | }\r | |
104 | \r | |
105 | deserializer.deserialize_any(IdentifierVisitor)\r | |
106 | }\r | |
107 | }\r | |
108 | \r | |
109 | /// Represents a version number conforming to the semantic versioning scheme.\r | |
110 | #[derive(Clone, Eq, Debug)]\r | |
111 | #[cfg_attr(feature = "diesel", derive(AsExpression, FromSqlRow))]\r | |
112 | #[cfg_attr(feature = "diesel", sql_type = "diesel::sql_types::Text")]\r | |
113 | pub struct Version {\r | |
114 | /// The major version, to be incremented on incompatible changes.\r | |
115 | pub major: u64,\r | |
116 | /// The minor version, to be incremented when functionality is added in a\r | |
117 | /// backwards-compatible manner.\r | |
118 | pub minor: u64,\r | |
119 | /// The patch version, to be incremented when backwards-compatible bug\r | |
120 | /// fixes are made.\r | |
121 | pub patch: u64,\r | |
122 | /// The pre-release version identifier, if one exists.\r | |
123 | pub pre: Vec<Identifier>,\r | |
124 | /// The build metadata, ignored when determining version precedence.\r | |
125 | pub build: Vec<Identifier>,\r | |
126 | }\r | |
127 | \r | |
128 | impl From<semver_parser::version::Version> for Version {\r | |
129 | fn from(other: semver_parser::version::Version) -> Version {\r | |
130 | Version {\r | |
131 | major: other.major,\r | |
132 | minor: other.minor,\r | |
133 | patch: other.patch,\r | |
134 | pre: other.pre.into_iter().map(From::from).collect(),\r | |
135 | build: other.build.into_iter().map(From::from).collect(),\r | |
136 | }\r | |
137 | }\r | |
138 | }\r | |
139 | \r | |
140 | #[cfg(feature = "serde")]\r | |
141 | impl Serialize for Version {\r | |
142 | fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>\r | |
143 | where\r | |
144 | S: Serializer,\r | |
145 | {\r | |
146 | // Serialize Version as a string.\r | |
147 | serializer.collect_str(self)\r | |
148 | }\r | |
149 | }\r | |
150 | \r | |
151 | #[cfg(feature = "serde")]\r | |
152 | impl<'de> Deserialize<'de> for Version {\r | |
153 | fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>\r | |
154 | where\r | |
155 | D: Deserializer<'de>,\r | |
156 | {\r | |
157 | struct VersionVisitor;\r | |
158 | \r | |
159 | // Deserialize Version from a string.\r | |
160 | impl<'de> Visitor<'de> for VersionVisitor {\r | |
161 | type Value = Version;\r | |
162 | \r | |
163 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {\r | |
164 | formatter.write_str("a SemVer version as a string")\r | |
165 | }\r | |
166 | \r | |
167 | fn visit_str<E>(self, v: &str) -> result::Result<Self::Value, E>\r | |
168 | where\r | |
169 | E: de::Error,\r | |
170 | {\r | |
171 | Version::parse(v).map_err(de::Error::custom)\r | |
172 | }\r | |
173 | }\r | |
174 | \r | |
175 | deserializer.deserialize_str(VersionVisitor)\r | |
176 | }\r | |
177 | }\r | |
178 | \r | |
179 | /// An error type for this crate\r | |
180 | ///\r | |
181 | /// Currently, just a generic error. Will make this nicer later.\r | |
182 | #[derive(Clone, PartialEq, Debug, PartialOrd)]\r | |
183 | pub enum SemVerError {\r | |
184 | /// An error ocurred while parsing.\r | |
185 | ParseError(String),\r | |
186 | }\r | |
187 | \r | |
188 | impl fmt::Display for SemVerError {\r | |
189 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\r | |
190 | match self {\r | |
191 | SemVerError::ParseError(ref m) => write!(f, "{}", m),\r | |
192 | }\r | |
193 | }\r | |
194 | }\r | |
195 | \r | |
196 | impl Error for SemVerError {}\r | |
197 | \r | |
198 | /// A Result type for errors\r | |
199 | pub type Result<T> = result::Result<T, SemVerError>;\r | |
200 | \r | |
201 | impl Version {\r | |
202 | /// Contructs the simple case without pre or build.\r | |
203 | pub fn new(major: u64, minor: u64, patch: u64) -> Version {\r | |
204 | Version {\r | |
205 | major,\r | |
206 | minor,\r | |
207 | patch,\r | |
208 | pre: Vec::new(),\r | |
209 | build: Vec::new(),\r | |
210 | }\r | |
211 | }\r | |
212 | \r | |
213 | /// Parse a string into a semver object.\r | |
214 | ///\r | |
215 | /// # Errors\r | |
216 | ///\r | |
217 | /// Returns an error variant if the input could not be parsed as a semver object.\r | |
218 | ///\r | |
219 | /// In general, this means that the provided string does not conform to the\r | |
220 | /// [semver spec][semver].\r | |
221 | ///\r | |
222 | /// An error for overflow is returned if any numeric component is larger than what can be\r | |
223 | /// stored in `u64`.\r | |
224 | ///\r | |
225 | /// The following are examples for other common error causes:\r | |
226 | ///\r | |
227 | /// * `1.0` - too few numeric components are used. Exactly 3 are expected.\r | |
228 | /// * `1.0.01` - a numeric component has a leading zero.\r | |
229 | /// * `1.0.foo` - uses a non-numeric components where one is expected.\r | |
230 | /// * `1.0.0foo` - metadata is not separated using a legal character like, `+` or `-`.\r | |
231 | /// * `1.0.0+foo_123` - contains metadata with an illegal character (`_`).\r | |
232 | /// Legal characters for metadata include `a-z`, `A-Z`, `0-9`, `-`, and `.` (dot).\r | |
233 | ///\r | |
234 | /// [semver]: https://semver.org\r | |
235 | pub fn parse(version: &str) -> Result<Version> {\r | |
236 | let res = semver_parser::version::parse(version);\r | |
237 | \r | |
238 | match res {\r | |
239 | // Convert plain String error into proper ParseError\r | |
240 | Err(e) => Err(SemVerError::ParseError(e)),\r | |
241 | Ok(v) => Ok(From::from(v)),\r | |
242 | }\r | |
243 | }\r | |
244 | \r | |
245 | /// Clears the build metadata\r | |
246 | fn clear_metadata(&mut self) {\r | |
247 | self.build = Vec::new();\r | |
248 | self.pre = Vec::new();\r | |
249 | }\r | |
250 | \r | |
251 | /// Increments the patch number for this Version (Must be mutable)\r | |
252 | pub fn increment_patch(&mut self) {\r | |
253 | self.patch += 1;\r | |
254 | self.clear_metadata();\r | |
255 | }\r | |
256 | \r | |
257 | /// Increments the minor version number for this Version (Must be mutable)\r | |
258 | ///\r | |
259 | /// As instructed by section 7 of the spec, the patch number is reset to 0.\r | |
260 | pub fn increment_minor(&mut self) {\r | |
261 | self.minor += 1;\r | |
262 | self.patch = 0;\r | |
263 | self.clear_metadata();\r | |
264 | }\r | |
265 | \r | |
266 | /// Increments the major version number for this Version (Must be mutable)\r | |
267 | ///\r | |
268 | /// As instructed by section 8 of the spec, the minor and patch numbers are\r | |
269 | /// reset to 0\r | |
270 | pub fn increment_major(&mut self) {\r | |
271 | self.major += 1;\r | |
272 | self.minor = 0;\r | |
273 | self.patch = 0;\r | |
274 | self.clear_metadata();\r | |
275 | }\r | |
276 | \r | |
277 | /// Checks to see if the current Version is in pre-release status\r | |
278 | pub fn is_prerelease(&self) -> bool {\r | |
279 | !self.pre.is_empty()\r | |
280 | }\r | |
281 | }\r | |
282 | \r | |
283 | impl str::FromStr for Version {\r | |
284 | type Err = SemVerError;\r | |
285 | \r | |
286 | fn from_str(s: &str) -> Result<Version> {\r | |
287 | Version::parse(s)\r | |
288 | }\r | |
289 | }\r | |
290 | \r | |
291 | impl fmt::Display for Version {\r | |
292 | #[inline]\r | |
293 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\r | |
294 | let mut result = format!("{}.{}.{}", self.major, self.minor, self.patch);\r | |
295 | \r | |
296 | if !self.pre.is_empty() {\r | |
297 | result.push_str("-");\r | |
298 | for (i, x) in self.pre.iter().enumerate() {\r | |
299 | if i != 0 {\r | |
300 | result.push_str(".");\r | |
301 | }\r | |
302 | result.push_str(format!("{}", x).as_ref());\r | |
303 | }\r | |
304 | }\r | |
305 | if !self.build.is_empty() {\r | |
306 | result.push_str("+");\r | |
307 | for (i, x) in self.build.iter().enumerate() {\r | |
308 | if i != 0 {\r | |
309 | result.push_str(".");\r | |
310 | }\r | |
311 | result.push_str(format!("{}", x).as_ref());\r | |
312 | }\r | |
313 | }\r | |
314 | \r | |
315 | f.pad(result.as_ref())?;\r | |
316 | Ok(())\r | |
317 | }\r | |
318 | }\r | |
319 | \r | |
320 | impl cmp::PartialEq for Version {\r | |
321 | #[inline]\r | |
322 | fn eq(&self, other: &Version) -> bool {\r | |
323 | // We should ignore build metadata here, otherwise versions v1 and v2\r | |
324 | // can exist such that !(v1 < v2) && !(v1 > v2) && v1 != v2, which\r | |
325 | // violate strict total ordering rules.\r | |
326 | self.major == other.major\r | |
327 | && self.minor == other.minor\r | |
328 | && self.patch == other.patch\r | |
329 | && self.pre == other.pre\r | |
330 | }\r | |
331 | }\r | |
332 | \r | |
333 | impl cmp::PartialOrd for Version {\r | |
334 | fn partial_cmp(&self, other: &Version) -> Option<Ordering> {\r | |
335 | Some(self.cmp(other))\r | |
336 | }\r | |
337 | }\r | |
338 | \r | |
339 | impl cmp::Ord for Version {\r | |
340 | fn cmp(&self, other: &Version) -> Ordering {\r | |
341 | match self.major.cmp(&other.major) {\r | |
342 | Ordering::Equal => {}\r | |
343 | r => return r,\r | |
344 | }\r | |
345 | \r | |
346 | match self.minor.cmp(&other.minor) {\r | |
347 | Ordering::Equal => {}\r | |
348 | r => return r,\r | |
349 | }\r | |
350 | \r | |
351 | match self.patch.cmp(&other.patch) {\r | |
352 | Ordering::Equal => {}\r | |
353 | r => return r,\r | |
354 | }\r | |
355 | \r | |
356 | // NB: semver spec says 0.0.0-pre < 0.0.0\r | |
357 | // but the version of ord defined for vec\r | |
358 | // says that [] < [pre] so we alter it here\r | |
359 | match (self.pre.len(), other.pre.len()) {\r | |
360 | (0, 0) => Ordering::Equal,\r | |
361 | (0, _) => Ordering::Greater,\r | |
362 | (_, 0) => Ordering::Less,\r | |
363 | (_, _) => self.pre.cmp(&other.pre),\r | |
364 | }\r | |
365 | }\r | |
366 | }\r | |
367 | \r | |
368 | impl hash::Hash for Version {\r | |
369 | fn hash<H: hash::Hasher>(&self, into: &mut H) {\r | |
370 | self.major.hash(into);\r | |
371 | self.minor.hash(into);\r | |
372 | self.patch.hash(into);\r | |
373 | self.pre.hash(into);\r | |
374 | }\r | |
375 | }\r | |
376 | \r | |
377 | impl From<(u64, u64, u64)> for Version {\r | |
378 | fn from(tuple: (u64, u64, u64)) -> Version {\r | |
379 | let (major, minor, patch) = tuple;\r | |
380 | Version::new(major, minor, patch)\r | |
381 | }\r | |
382 | }\r | |
383 | \r | |
384 | #[cfg(test)]\r | |
385 | mod tests {\r | |
386 | use super::Identifier;\r | |
387 | use super::SemVerError;\r | |
388 | use super::Version;\r | |
389 | use std::result;\r | |
390 | \r | |
391 | #[test]\r | |
392 | fn test_parse() {\r | |
393 | fn parse_error(e: &str) -> result::Result<Version, SemVerError> {\r | |
394 | return Err(SemVerError::ParseError(e.to_string()));\r | |
395 | }\r | |
396 | \r | |
397 | assert_eq!(\r | |
398 | Version::parse(""),\r | |
399 | parse_error("Error parsing major identifier")\r | |
400 | );\r | |
401 | assert_eq!(\r | |
402 | Version::parse(" "),\r | |
403 | parse_error("Error parsing major identifier")\r | |
404 | );\r | |
405 | assert_eq!(Version::parse("1"), parse_error("Expected dot"));\r | |
406 | assert_eq!(Version::parse("1.2"), parse_error("Expected dot"));\r | |
407 | assert_eq!(\r | |
408 | Version::parse("1.2.3-"),\r | |
409 | parse_error("Error parsing prerelease")\r | |
410 | );\r | |
411 | assert_eq!(\r | |
412 | Version::parse("a.b.c"),\r | |
413 | parse_error("Error parsing major identifier")\r | |
414 | );\r | |
415 | assert_eq!(\r | |
416 | Version::parse("1.2.3 abc"),\r | |
417 | parse_error("Extra junk after valid version: abc")\r | |
418 | );\r | |
419 | \r | |
420 | assert_eq!(\r | |
421 | Version::parse("1.2.3"),\r | |
422 | Ok(Version {\r | |
423 | major: 1,\r | |
424 | minor: 2,\r | |
425 | patch: 3,\r | |
426 | pre: Vec::new(),\r | |
427 | build: Vec::new(),\r | |
428 | })\r | |
429 | );\r | |
430 | \r | |
431 | assert_eq!(Version::parse("1.2.3"), Ok(Version::new(1, 2, 3)));\r | |
432 | \r | |
433 | assert_eq!(\r | |
434 | Version::parse(" 1.2.3 "),\r | |
435 | Ok(Version {\r | |
436 | major: 1,\r | |
437 | minor: 2,\r | |
438 | patch: 3,\r | |
439 | pre: Vec::new(),\r | |
440 | build: Vec::new(),\r | |
441 | })\r | |
442 | );\r | |
443 | assert_eq!(\r | |
444 | Version::parse("1.2.3-alpha1"),\r | |
445 | Ok(Version {\r | |
446 | major: 1,\r | |
447 | minor: 2,\r | |
448 | patch: 3,\r | |
449 | pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],\r | |
450 | build: Vec::new(),\r | |
451 | })\r | |
452 | );\r | |
453 | assert_eq!(\r | |
454 | Version::parse(" 1.2.3-alpha1 "),\r | |
455 | Ok(Version {\r | |
456 | major: 1,\r | |
457 | minor: 2,\r | |
458 | patch: 3,\r | |
459 | pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],\r | |
460 | build: Vec::new(),\r | |
461 | })\r | |
462 | );\r | |
463 | assert_eq!(\r | |
464 | Version::parse("1.2.3+build5"),\r | |
465 | Ok(Version {\r | |
466 | major: 1,\r | |
467 | minor: 2,\r | |
468 | patch: 3,\r | |
469 | pre: Vec::new(),\r | |
470 | build: vec![Identifier::AlphaNumeric(String::from("build5"))],\r | |
471 | })\r | |
472 | );\r | |
473 | assert_eq!(\r | |
474 | Version::parse(" 1.2.3+build5 "),\r | |
475 | Ok(Version {\r | |
476 | major: 1,\r | |
477 | minor: 2,\r | |
478 | patch: 3,\r | |
479 | pre: Vec::new(),\r | |
480 | build: vec![Identifier::AlphaNumeric(String::from("build5"))],\r | |
481 | })\r | |
482 | );\r | |
483 | assert_eq!(\r | |
484 | Version::parse("1.2.3-alpha1+build5"),\r | |
485 | Ok(Version {\r | |
486 | major: 1,\r | |
487 | minor: 2,\r | |
488 | patch: 3,\r | |
489 | pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],\r | |
490 | build: vec![Identifier::AlphaNumeric(String::from("build5"))],\r | |
491 | })\r | |
492 | );\r | |
493 | assert_eq!(\r | |
494 | Version::parse(" 1.2.3-alpha1+build5 "),\r | |
495 | Ok(Version {\r | |
496 | major: 1,\r | |
497 | minor: 2,\r | |
498 | patch: 3,\r | |
499 | pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],\r | |
500 | build: vec![Identifier::AlphaNumeric(String::from("build5"))],\r | |
501 | })\r | |
502 | );\r | |
503 | assert_eq!(\r | |
504 | Version::parse("1.2.3-1.alpha1.9+build5.7.3aedf "),\r | |
505 | Ok(Version {\r | |
506 | major: 1,\r | |
507 | minor: 2,\r | |
508 | patch: 3,\r | |
509 | pre: vec![\r | |
510 | Identifier::Numeric(1),\r | |
511 | Identifier::AlphaNumeric(String::from("alpha1")),\r | |
512 | Identifier::Numeric(9),\r | |
513 | ],\r | |
514 | build: vec![\r | |
515 | Identifier::AlphaNumeric(String::from("build5")),\r | |
516 | Identifier::Numeric(7),\r | |
517 | Identifier::AlphaNumeric(String::from("3aedf")),\r | |
518 | ],\r | |
519 | })\r | |
520 | );\r | |
521 | assert_eq!(\r | |
522 | Version::parse("0.4.0-beta.1+0851523"),\r | |
523 | Ok(Version {\r | |
524 | major: 0,\r | |
525 | minor: 4,\r | |
526 | patch: 0,\r | |
527 | pre: vec![\r | |
528 | Identifier::AlphaNumeric(String::from("beta")),\r | |
529 | Identifier::Numeric(1),\r | |
530 | ],\r | |
531 | build: vec![Identifier::AlphaNumeric(String::from("0851523"))],\r | |
532 | })\r | |
533 | );\r | |
534 | }\r | |
535 | \r | |
536 | #[test]\r | |
537 | fn test_increment_patch() {\r | |
538 | let mut buggy_release = Version::parse("0.1.0").unwrap();\r | |
539 | buggy_release.increment_patch();\r | |
540 | assert_eq!(buggy_release, Version::parse("0.1.1").unwrap());\r | |
541 | }\r | |
542 | \r | |
543 | #[test]\r | |
544 | fn test_increment_minor() {\r | |
545 | let mut feature_release = Version::parse("1.4.6").unwrap();\r | |
546 | feature_release.increment_minor();\r | |
547 | assert_eq!(feature_release, Version::parse("1.5.0").unwrap());\r | |
548 | }\r | |
549 | \r | |
550 | #[test]\r | |
551 | fn test_increment_major() {\r | |
552 | let mut chrome_release = Version::parse("46.1.246773").unwrap();\r | |
553 | chrome_release.increment_major();\r | |
554 | assert_eq!(chrome_release, Version::parse("47.0.0").unwrap());\r | |
555 | }\r | |
556 | \r | |
557 | #[test]\r | |
558 | fn test_increment_keep_prerelease() {\r | |
559 | let mut release = Version::parse("1.0.0-alpha").unwrap();\r | |
560 | release.increment_patch();\r | |
561 | \r | |
562 | assert_eq!(release, Version::parse("1.0.1").unwrap());\r | |
563 | \r | |
564 | release.increment_minor();\r | |
565 | \r | |
566 | assert_eq!(release, Version::parse("1.1.0").unwrap());\r | |
567 | \r | |
568 | release.increment_major();\r | |
569 | \r | |
570 | assert_eq!(release, Version::parse("2.0.0").unwrap());\r | |
571 | }\r | |
572 | \r | |
573 | #[test]\r | |
574 | fn test_increment_clear_metadata() {\r | |
575 | let mut release = Version::parse("1.0.0+4442").unwrap();\r | |
576 | release.increment_patch();\r | |
577 | \r | |
578 | assert_eq!(release, Version::parse("1.0.1").unwrap());\r | |
579 | release = Version::parse("1.0.1+hello").unwrap();\r | |
580 | \r | |
581 | release.increment_minor();\r | |
582 | \r | |
583 | assert_eq!(release, Version::parse("1.1.0").unwrap());\r | |
584 | release = Version::parse("1.1.3747+hello").unwrap();\r | |
585 | \r | |
586 | release.increment_major();\r | |
587 | \r | |
588 | assert_eq!(release, Version::parse("2.0.0").unwrap());\r | |
589 | }\r | |
590 | \r | |
591 | #[test]\r | |
592 | fn test_eq() {\r | |
593 | assert_eq!(Version::parse("1.2.3"), Version::parse("1.2.3"));\r | |
594 | assert_eq!(\r | |
595 | Version::parse("1.2.3-alpha1"),\r | |
596 | Version::parse("1.2.3-alpha1")\r | |
597 | );\r | |
598 | assert_eq!(\r | |
599 | Version::parse("1.2.3+build.42"),\r | |
600 | Version::parse("1.2.3+build.42")\r | |
601 | );\r | |
602 | assert_eq!(\r | |
603 | Version::parse("1.2.3-alpha1+42"),\r | |
604 | Version::parse("1.2.3-alpha1+42")\r | |
605 | );\r | |
606 | assert_eq!(Version::parse("1.2.3+23"), Version::parse("1.2.3+42"));\r | |
607 | }\r | |
608 | \r | |
609 | #[test]\r | |
610 | fn test_ne() {\r | |
611 | assert!(Version::parse("0.0.0") != Version::parse("0.0.1"));\r | |
612 | assert!(Version::parse("0.0.0") != Version::parse("0.1.0"));\r | |
613 | assert!(Version::parse("0.0.0") != Version::parse("1.0.0"));\r | |
614 | assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta"));\r | |
615 | }\r | |
616 | \r | |
617 | #[test]\r | |
618 | fn test_show() {\r | |
619 | assert_eq!(\r | |
620 | format!("{}", Version::parse("1.2.3").unwrap()),\r | |
621 | "1.2.3".to_string()\r | |
622 | );\r | |
623 | assert_eq!(\r | |
624 | format!("{}", Version::parse("1.2.3-alpha1").unwrap()),\r | |
625 | "1.2.3-alpha1".to_string()\r | |
626 | );\r | |
627 | assert_eq!(\r | |
628 | format!("{}", Version::parse("1.2.3+build.42").unwrap()),\r | |
629 | "1.2.3+build.42".to_string()\r | |
630 | );\r | |
631 | assert_eq!(\r | |
632 | format!("{}", Version::parse("1.2.3-alpha1+42").unwrap()),\r | |
633 | "1.2.3-alpha1+42".to_string()\r | |
634 | );\r | |
635 | }\r | |
636 | \r | |
637 | #[test]\r | |
638 | fn test_display() {\r | |
639 | let version = Version::parse("1.2.3-rc1").unwrap();\r | |
640 | assert_eq!(format!("{:20}", version), "1.2.3-rc1 ");\r | |
641 | assert_eq!(format!("{:*^20}", version), "*****1.2.3-rc1******");\r | |
642 | assert_eq!(format!("{:.4}", version), "1.2.");\r | |
643 | }\r | |
644 | \r | |
645 | #[test]\r | |
646 | fn test_to_string() {\r | |
647 | assert_eq!(\r | |
648 | Version::parse("1.2.3").unwrap().to_string(),\r | |
649 | "1.2.3".to_string()\r | |
650 | );\r | |
651 | assert_eq!(\r | |
652 | Version::parse("1.2.3-alpha1").unwrap().to_string(),\r | |
653 | "1.2.3-alpha1".to_string()\r | |
654 | );\r | |
655 | assert_eq!(\r | |
656 | Version::parse("1.2.3+build.42").unwrap().to_string(),\r | |
657 | "1.2.3+build.42".to_string()\r | |
658 | );\r | |
659 | assert_eq!(\r | |
660 | Version::parse("1.2.3-alpha1+42").unwrap().to_string(),\r | |
661 | "1.2.3-alpha1+42".to_string()\r | |
662 | );\r | |
663 | }\r | |
664 | \r | |
665 | #[test]\r | |
666 | fn test_lt() {\r | |
667 | assert!(Version::parse("0.0.0") < Version::parse("1.2.3-alpha2"));\r | |
668 | assert!(Version::parse("1.0.0") < Version::parse("1.2.3-alpha2"));\r | |
669 | assert!(Version::parse("1.2.0") < Version::parse("1.2.3-alpha2"));\r | |
670 | assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3"));\r | |
671 | assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3-alpha2"));\r | |
672 | assert!(!(Version::parse("1.2.3-alpha2") < Version::parse("1.2.3-alpha2")));\r | |
673 | assert!(!(Version::parse("1.2.3+23") < Version::parse("1.2.3+42")));\r | |
674 | }\r | |
675 | \r | |
676 | #[test]\r | |
677 | fn test_le() {\r | |
678 | assert!(Version::parse("0.0.0") <= Version::parse("1.2.3-alpha2"));\r | |
679 | assert!(Version::parse("1.0.0") <= Version::parse("1.2.3-alpha2"));\r | |
680 | assert!(Version::parse("1.2.0") <= Version::parse("1.2.3-alpha2"));\r | |
681 | assert!(Version::parse("1.2.3-alpha1") <= Version::parse("1.2.3-alpha2"));\r | |
682 | assert!(Version::parse("1.2.3-alpha2") <= Version::parse("1.2.3-alpha2"));\r | |
683 | assert!(Version::parse("1.2.3+23") <= Version::parse("1.2.3+42"));\r | |
684 | }\r | |
685 | \r | |
686 | #[test]\r | |
687 | fn test_gt() {\r | |
688 | assert!(Version::parse("1.2.3-alpha2") > Version::parse("0.0.0"));\r | |
689 | assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.0.0"));\r | |
690 | assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0"));\r | |
691 | assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha1"));\r | |
692 | assert!(Version::parse("1.2.3") > Version::parse("1.2.3-alpha2"));\r | |
693 | assert!(!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha2")));\r | |
694 | assert!(!(Version::parse("1.2.3+23") > Version::parse("1.2.3+42")));\r | |
695 | }\r | |
696 | \r | |
697 | #[test]\r | |
698 | fn test_ge() {\r | |
699 | assert!(Version::parse("1.2.3-alpha2") >= Version::parse("0.0.0"));\r | |
700 | assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.0.0"));\r | |
701 | assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.0"));\r | |
702 | assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha1"));\r | |
703 | assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha2"));\r | |
704 | assert!(Version::parse("1.2.3+23") >= Version::parse("1.2.3+42"));\r | |
705 | }\r | |
706 | \r | |
707 | #[test]\r | |
708 | fn test_prerelease_check() {\r | |
709 | assert!(Version::parse("1.0.0").unwrap().is_prerelease() == false);\r | |
710 | assert!(Version::parse("0.0.1").unwrap().is_prerelease() == false);\r | |
711 | assert!(Version::parse("4.1.4-alpha").unwrap().is_prerelease());\r | |
712 | assert!(Version::parse("1.0.0-beta294296").unwrap().is_prerelease());\r | |
713 | }\r | |
714 | \r | |
715 | #[test]\r | |
716 | fn test_spec_order() {\r | |
717 | let vs = [\r | |
718 | "1.0.0-alpha",\r | |
719 | "1.0.0-alpha.1",\r | |
720 | "1.0.0-alpha.beta",\r | |
721 | "1.0.0-beta",\r | |
722 | "1.0.0-beta.2",\r | |
723 | "1.0.0-beta.11",\r | |
724 | "1.0.0-rc.1",\r | |
725 | "1.0.0",\r | |
726 | ];\r | |
727 | let mut i = 1;\r | |
728 | while i < vs.len() {\r | |
729 | let a = Version::parse(vs[i - 1]);\r | |
730 | let b = Version::parse(vs[i]);\r | |
731 | assert!(a < b, "nope {:?} < {:?}", a, b);\r | |
732 | i += 1;\r | |
733 | }\r | |
734 | }\r | |
735 | \r | |
736 | #[test]\r | |
737 | fn test_from_str() {\r | |
738 | assert_eq!(\r | |
739 | "1.2.3".parse(),\r | |
740 | Ok(Version {\r | |
741 | major: 1,\r | |
742 | minor: 2,\r | |
743 | patch: 3,\r | |
744 | pre: Vec::new(),\r | |
745 | build: Vec::new(),\r | |
746 | })\r | |
747 | );\r | |
748 | assert_eq!(\r | |
749 | " 1.2.3 ".parse(),\r | |
750 | Ok(Version {\r | |
751 | major: 1,\r | |
752 | minor: 2,\r | |
753 | patch: 3,\r | |
754 | pre: Vec::new(),\r | |
755 | build: Vec::new(),\r | |
756 | })\r | |
757 | );\r | |
758 | assert_eq!(\r | |
759 | "1.2.3-alpha1".parse(),\r | |
760 | Ok(Version {\r | |
761 | major: 1,\r | |
762 | minor: 2,\r | |
763 | patch: 3,\r | |
764 | pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],\r | |
765 | build: Vec::new(),\r | |
766 | })\r | |
767 | );\r | |
768 | assert_eq!(\r | |
769 | " 1.2.3-alpha1 ".parse(),\r | |
770 | Ok(Version {\r | |
771 | major: 1,\r | |
772 | minor: 2,\r | |
773 | patch: 3,\r | |
774 | pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],\r | |
775 | build: Vec::new(),\r | |
776 | })\r | |
777 | );\r | |
778 | assert_eq!(\r | |
779 | "1.2.3+build5".parse(),\r | |
780 | Ok(Version {\r | |
781 | major: 1,\r | |
782 | minor: 2,\r | |
783 | patch: 3,\r | |
784 | pre: Vec::new(),\r | |
785 | build: vec![Identifier::AlphaNumeric(String::from("build5"))],\r | |
786 | })\r | |
787 | );\r | |
788 | assert_eq!(\r | |
789 | " 1.2.3+build5 ".parse(),\r | |
790 | Ok(Version {\r | |
791 | major: 1,\r | |
792 | minor: 2,\r | |
793 | patch: 3,\r | |
794 | pre: Vec::new(),\r | |
795 | build: vec![Identifier::AlphaNumeric(String::from("build5"))],\r | |
796 | })\r | |
797 | );\r | |
798 | assert_eq!(\r | |
799 | "1.2.3-alpha1+build5".parse(),\r | |
800 | Ok(Version {\r | |
801 | major: 1,\r | |
802 | minor: 2,\r | |
803 | patch: 3,\r | |
804 | pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],\r | |
805 | build: vec![Identifier::AlphaNumeric(String::from("build5"))],\r | |
806 | })\r | |
807 | );\r | |
808 | assert_eq!(\r | |
809 | " 1.2.3-alpha1+build5 ".parse(),\r | |
810 | Ok(Version {\r | |
811 | major: 1,\r | |
812 | minor: 2,\r | |
813 | patch: 3,\r | |
814 | pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],\r | |
815 | build: vec![Identifier::AlphaNumeric(String::from("build5"))],\r | |
816 | })\r | |
817 | );\r | |
818 | assert_eq!(\r | |
819 | "1.2.3-1.alpha1.9+build5.7.3aedf ".parse(),\r | |
820 | Ok(Version {\r | |
821 | major: 1,\r | |
822 | minor: 2,\r | |
823 | patch: 3,\r | |
824 | pre: vec![\r | |
825 | Identifier::Numeric(1),\r | |
826 | Identifier::AlphaNumeric(String::from("alpha1")),\r | |
827 | Identifier::Numeric(9),\r | |
828 | ],\r | |
829 | build: vec![\r | |
830 | Identifier::AlphaNumeric(String::from("build5")),\r | |
831 | Identifier::Numeric(7),\r | |
832 | Identifier::AlphaNumeric(String::from("3aedf")),\r | |
833 | ],\r | |
834 | })\r | |
835 | );\r | |
836 | assert_eq!(\r | |
837 | "0.4.0-beta.1+0851523".parse(),\r | |
838 | Ok(Version {\r | |
839 | major: 0,\r | |
840 | minor: 4,\r | |
841 | patch: 0,\r | |
842 | pre: vec![\r | |
843 | Identifier::AlphaNumeric(String::from("beta")),\r | |
844 | Identifier::Numeric(1),\r | |
845 | ],\r | |
846 | build: vec![Identifier::AlphaNumeric(String::from("0851523"))],\r | |
847 | })\r | |
848 | );\r | |
849 | }\r | |
850 | \r | |
851 | #[test]\r | |
852 | fn test_from_str_errors() {\r | |
853 | fn parse_error(e: &str) -> result::Result<Version, SemVerError> {\r | |
854 | return Err(SemVerError::ParseError(e.to_string()));\r | |
855 | }\r | |
856 | \r | |
857 | assert_eq!("".parse(), parse_error("Error parsing major identifier"));\r | |
858 | assert_eq!(" ".parse(), parse_error("Error parsing major identifier"));\r | |
859 | assert_eq!("1".parse(), parse_error("Expected dot"));\r | |
860 | assert_eq!("1.2".parse(), parse_error("Expected dot"));\r | |
861 | assert_eq!("1.2.3-".parse(), parse_error("Error parsing prerelease"));\r | |
862 | assert_eq!(\r | |
863 | "a.b.c".parse(),\r | |
864 | parse_error("Error parsing major identifier")\r | |
865 | );\r | |
866 | assert_eq!(\r | |
867 | "1.2.3 abc".parse(),\r | |
868 | parse_error("Extra junk after valid version: abc")\r | |
869 | );\r | |
870 | }\r | |
871 | }\r |