2 use std
::str::from_utf8
;
6 use common
::{self, numeric_identifier}
;
8 #[derive(Clone, Debug, PartialEq, Eq)]
13 pub pre
: Vec
<Identifier
>,
14 pub build
: Vec
<Identifier
>,
17 #[derive(Clone, Debug, PartialEq, Eq)]
19 /// An identifier that's solely numbers.
21 /// An identifier with letters and numbers.
25 pub fn parse(version
: &str) -> Result
<Version
, String
> {
26 let s
= version
.trim().as_bytes();
28 let major
= if let Some((major
, len
)) = numeric_identifier(&s
[i
..]) {
32 return Err("Error parsing major identifier".to_string());
34 if let Some(len
) = b'
.'
.p(&s
[i
..]) {
37 return Err("Expected dot".to_string());
39 let minor
= if let Some((minor
, len
)) = numeric_identifier(&s
[i
..]) {
43 return Err("Error parsing minor identifier".to_string());
45 if let Some(len
) = b'
.'
.p(&s
[i
..]) {
48 return Err("Expected dot".to_string());
50 let patch
= if let Some((patch
, len
)) = numeric_identifier(&s
[i
..]) {
54 return Err("Error parsing patch identifier".to_string());
56 let (pre
, pre_len
) = common
::parse_optional_meta(&s
[i
..], b'
-'
)?
;
58 let (build
, build_len
) = common
::parse_optional_meta(&s
[i
..], b'
+'
)?
;
61 return Err("Extra junk after valid version: ".to_string() +
62 from_utf8(&s
[i
..]).unwrap());
73 impl fmt
::Display
for Version
{
74 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
75 try
!(write
!(f
, "{}.{}.{}", self.major
, self.minor
, self.patch
));
76 if !self.pre
.is_empty() {
78 self.pre
.iter().map(ToString
::to_string
).collect();
79 try
!(write
!(f
, "-{}", strs
.join(".")));
81 if !self.build
.is_empty() {
83 self.build
.iter().map(ToString
::to_string
).collect();
84 try
!(write
!(f
, "+{}", strs
.join(".")));
90 impl fmt
::Display
for Identifier
{
91 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
93 Identifier
::Numeric(ref id
) => id
.fmt(f
),
94 Identifier
::AlphaNumeric(ref id
) => id
.fmt(f
),
108 let parsed
= version
::parse(version
);
110 assert
!(parsed
.is_err(), "empty string incorrectly considered a valid parse");
117 let parsed
= version
::parse(version
);
119 assert
!(parsed
.is_err(), "blank string incorrectly considered a valid parse");
123 fn parse_no_minor_patch() {
126 let parsed
= version
::parse(version
);
128 assert
!(parsed
.is_err(), format
!("'{}' incorrectly considered a valid parse", version
));
132 fn parse_no_patch() {
135 let parsed
= version
::parse(version
);
137 assert
!(parsed
.is_err(), format
!("'{}' incorrectly considered a valid parse", version
));
141 fn parse_empty_pre() {
142 let version
= "1.2.3-";
144 let parsed
= version
::parse(version
);
146 assert
!(parsed
.is_err(), format
!("'{}' incorrectly considered a valid parse", version
));
151 let version
= "a.b.c";
153 let parsed
= version
::parse(version
);
155 assert
!(parsed
.is_err(), format
!("'{}' incorrectly considered a valid parse", version
));
159 fn parse_with_letters() {
160 let version
= "1.2.3 a.b.c";
162 let parsed
= version
::parse(version
);
164 assert
!(parsed
.is_err(), format
!("'{}' incorrectly considered a valid parse", version
));
168 fn parse_basic_version() {
169 let version
= "1.2.3";
171 let parsed
= version
::parse(version
).unwrap();
173 assert_eq
!(1, parsed
.major
);
174 assert_eq
!(2, parsed
.minor
);
175 assert_eq
!(3, parsed
.patch
);
179 fn parse_trims_input() {
180 let version
= " 1.2.3 ";
182 let parsed
= version
::parse(version
).unwrap();
184 assert_eq
!(1, parsed
.major
);
185 assert_eq
!(2, parsed
.minor
);
186 assert_eq
!(3, parsed
.patch
);
190 fn parse_no_major_leading_zeroes() {
191 let version
= "01.0.0";
193 let parsed
= version
::parse(version
);
195 assert
!(parsed
.is_err(), "01 incorrectly considered a valid major version");
199 fn parse_no_minor_leading_zeroes() {
200 let version
= "0.01.0";
202 let parsed
= version
::parse(version
);
204 assert
!(parsed
.is_err(), "01 incorrectly considered a valid minor version");
208 fn parse_no_patch_leading_zeroes() {
209 let version
= "0.0.01";
211 let parsed
= version
::parse(version
);
213 assert
!(parsed
.is_err(), "01 incorrectly considered a valid patch version");
217 fn parse_no_major_overflow() {
218 let version
= "98765432109876543210.0.0";
220 let parsed
= version
::parse(version
);
222 assert
!(parsed
.is_err(), "98765432109876543210 incorrectly considered a valid major version");
226 fn parse_no_minor_overflow() {
227 let version
= "0.98765432109876543210.0";
229 let parsed
= version
::parse(version
);
231 assert
!(parsed
.is_err(), "98765432109876543210 incorrectly considered a valid minor version");
235 fn parse_no_patch_overflow() {
236 let version
= "0.0.98765432109876543210";
238 let parsed
= version
::parse(version
);
240 assert
!(parsed
.is_err(), "98765432109876543210 incorrectly considered a valid patch version");
244 fn parse_basic_prerelease() {
245 let version
= "1.2.3-pre";
247 let parsed
= version
::parse(version
).unwrap();
249 let expected_pre
= vec
![Identifier
::AlphaNumeric(String
::from("pre"))];
250 assert_eq
!(expected_pre
, parsed
.pre
);
254 fn parse_prerelease_alphanumeric() {
255 let version
= "1.2.3-alpha1";
257 let parsed
= version
::parse(version
).unwrap();
259 let expected_pre
= vec
![Identifier
::AlphaNumeric(String
::from("alpha1"))];
260 assert_eq
!(expected_pre
, parsed
.pre
);
264 fn parse_prerelease_zero() {
265 let version
= "1.2.3-pre.0";
267 let parsed
= version
::parse(version
).unwrap();
269 let expected_pre
= vec
![Identifier
::AlphaNumeric(String
::from("pre")),
270 Identifier
::Numeric(0)];
271 assert_eq
!(expected_pre
, parsed
.pre
);
275 fn parse_basic_build() {
276 let version
= "1.2.3+build";
278 let parsed
= version
::parse(version
).unwrap();
280 let expected_build
= vec
![Identifier
::AlphaNumeric(String
::from("build"))];
281 assert_eq
!(expected_build
, parsed
.build
);
285 fn parse_build_alphanumeric() {
286 let version
= "1.2.3+build5";
288 let parsed
= version
::parse(version
).unwrap();
290 let expected_build
= vec
![Identifier
::AlphaNumeric(String
::from("build5"))];
291 assert_eq
!(expected_build
, parsed
.build
);
295 fn parse_pre_and_build() {
296 let version
= "1.2.3-alpha1+build5";
298 let parsed
= version
::parse(version
).unwrap();
300 let expected_pre
= vec
![Identifier
::AlphaNumeric(String
::from("alpha1"))];
301 assert_eq
!(expected_pre
, parsed
.pre
);
303 let expected_build
= vec
![Identifier
::AlphaNumeric(String
::from("build5"))];
304 assert_eq
!(expected_build
, parsed
.build
);
308 fn parse_complex_metadata_01() {
309 let version
= "1.2.3-1.alpha1.9+build5.7.3aedf ";
311 let parsed
= version
::parse(version
).unwrap();
313 let expected_pre
= vec
![Identifier
::Numeric(1),
314 Identifier
::AlphaNumeric(String
::from("alpha1")),
315 Identifier
::Numeric(9)];
316 assert_eq
!(expected_pre
, parsed
.pre
);
318 let expected_build
= vec
![Identifier
::AlphaNumeric(String
::from("build5")),
319 Identifier
::Numeric(7),
320 Identifier
::AlphaNumeric(String
::from("3aedf"))];
321 assert_eq
!(expected_build
, parsed
.build
);
325 fn parse_complex_metadata_02() {
326 let version
= "0.4.0-beta.1+0851523";
328 let parsed
= version
::parse(version
).unwrap();
330 let expected_pre
= vec
![Identifier
::AlphaNumeric(String
::from("beta")),
331 Identifier
::Numeric(1)];
332 assert_eq
!(expected_pre
, parsed
.pre
);
334 let expected_build
= vec
![Identifier
::AlphaNumeric(String
::from("0851523"))];
335 assert_eq
!(expected_build
, parsed
.build
);
339 fn parse_metadata_overflow() {
340 let version
= "0.4.0-beta.1+98765432109876543210";
342 let parsed
= version
::parse(version
).unwrap();
344 let expected_pre
= vec
![Identifier
::AlphaNumeric(String
::from("beta")),
345 Identifier
::Numeric(1)];
346 assert_eq
!(expected_pre
, parsed
.pre
);
348 let expected_build
= vec
![Identifier
::AlphaNumeric(String
::from("98765432109876543210"))];
349 assert_eq
!(expected_build
, parsed
.build
);
353 fn parse_regression_01() {
354 let version
= "0.0.0-WIP";
356 let parsed
= version
::parse(version
).unwrap();
358 assert_eq
!(0, parsed
.major
);
359 assert_eq
!(0, parsed
.minor
);
360 assert_eq
!(0, parsed
.patch
);
362 let expected_pre
= vec
![Identifier
::AlphaNumeric(String
::from("WIP"))];
363 assert_eq
!(expected_pre
, parsed
.pre
);