History

refactor tests (#331)

Be closer to the (maybe future) layout of the crate itself, and similar to how it's done throughout gitoxide.

Sebastian Thiel committed 4 years ago

Commit f943d2a1 parent 322f82513 files · +397 −415Browse files

Unified · Split

13 files
  1. git-config/tests/config.rs +6 −0
  2. git-config/tests/git_config/mod.rs +0 −0
  3. git-config/tests/integration_tests/main.rs +0 −12
  4. git-config/tests/integration_tests/values_integration_tests.rs +0 −403
  5. git-config/tests/parser/mod.rs +0 −0
  6. git-config/tests/value/mod.rs +0 −0
  7. git-config/tests/values/boolean.rs +48 −0
  8. git-config/tests/values/color_attribute.rs +44 −0
  9. git-config/tests/values/color_value.rs +51 −0
  10. git-config/tests/values/integer.rs +84 −0
  11. git-config/tests/values/mod.rs +16 −0
  12. git-config/tests/values/normalize.rs +51 −0
  13. git-config/tests/values/path.rs +97 −0
git-config/tests/config.rs+6−0
@@ -0,0 +1,6 @@
1+type Result = std::result::Result<(), Box<dyn std::error::Error>>;
2+
3+mod git_config;
4+mod parser;
5+mod value;
6+mod values;
git-config/tests/git_config/mod.rsrenamed from git-config/tests/integration_tests/git_config_integration_tests.rs+0−0

File renamed without changes.

git-config/tests/integration_tests/main.rs+0−12
@@ -1,12 +0,0 @@
1−// See https://matklad.github.io/2021/02/27/delete-cargo-integration-tests.html
2−// for an explanation of why the integration tests are laid out like this.
3−//
4−// TL;DR single mod makes integration tests faster to compile, test, and with
5−// less build artifacts.
6−
7−type Result = std::result::Result<(), Box<dyn std::error::Error>>;
8−
9−mod git_config_integration_tests;
10−mod parser_integration_tests;
11−mod value_integration_tests;
12−mod values_integration_tests;
git-config/tests/integration_tests/values_integration_tests.rs+0−403
@@ -1,403 +0,0 @@
1−/// Converts string to byte slice
2−#[cfg(test)]
3−fn b(s: &str) -> &[u8] {
4− s.as_bytes()
5−}
6−
7−#[cfg(test)]
8−mod normalize {
9− use git_config::values::normalize_str;
10− use std::borrow::Cow;
11−
12− #[test]
13− fn not_modified_is_borrowed() {
14− assert_eq!(normalize_str("hello world"), Cow::Borrowed(b"hello world"));
15− }
16−
17− #[test]
18− fn modified_is_owned() {
19− assert_eq!(
20− normalize_str("hello \"world\""),
21− Cow::<[u8]>::Owned(b"hello world".to_vec())
22− );
23− }
24−
25− #[test]
26− fn all_quoted_is_optimized() {
27− assert_eq!(normalize_str("\"hello world\""), Cow::Borrowed(b"hello world"));
28− }
29−
30− #[test]
31− fn all_quote_optimization_is_correct() {
32− assert_eq!(normalize_str(r#""hello" world\""#), Cow::Borrowed(b"hello world\""));
33− }
34−
35− #[test]
36− fn quotes_right_next_to_each_other() {
37− assert_eq!(
38− normalize_str("\"hello\"\" world\""),
39− Cow::<[u8]>::Owned(b"hello world".to_vec())
40− );
41− }
42−
43− #[test]
44− fn escaped_quotes_are_kept() {
45− assert_eq!(
46− normalize_str(r#""hello \"\" world""#),
47− Cow::<[u8]>::Owned(b"hello \"\" world".to_vec())
48− );
49− }
50−
51− #[test]
52− fn empty_string() {
53− assert_eq!(normalize_str(""), Cow::Borrowed(b""));
54− }
55−
56− #[test]
57− fn empty_normalized_string_is_optimized() {
58− assert_eq!(normalize_str("\"\""), Cow::Borrowed(b""));
59− }
60−}
61−
62−#[cfg(test)]
63−mod boolean {
64− use crate::values_integration_tests::b;
65− use git_config::values::{Boolean, TrueVariant};
66− use std::convert::TryFrom;
67−
68− #[test]
69− fn from_str_false() {
70− assert_eq!(Boolean::try_from(b("no")), Ok(Boolean::False("no".into())));
71− assert_eq!(Boolean::try_from(b("off")), Ok(Boolean::False("off".into())));
72− assert_eq!(Boolean::try_from(b("false")), Ok(Boolean::False("false".into())));
73− assert_eq!(Boolean::try_from(b("zero")), Ok(Boolean::False("zero".into())));
74− assert_eq!(Boolean::try_from(b("\"\"")), Ok(Boolean::False("\"\"".into())));
75− }
76−
77− #[test]
78− fn from_str_true() {
79− assert_eq!(
80− Boolean::try_from(b("yes")),
81− Ok(Boolean::True(TrueVariant::Explicit("yes".into())))
82− );
83− assert_eq!(
84− Boolean::try_from(b("on")),
85− Ok(Boolean::True(TrueVariant::Explicit("on".into())))
86− );
87− assert_eq!(
88− Boolean::try_from(b("true")),
89− Ok(Boolean::True(TrueVariant::Explicit("true".into())))
90− );
91− assert_eq!(
92− Boolean::try_from(b("one")),
93− Ok(Boolean::True(TrueVariant::Explicit("one".into())))
94− );
95− }
96−
97− #[test]
98− fn ignores_case() {
99− // Random subset
100− for word in &["no", "yes", "off", "true", "zero"] {
101− let first: bool = Boolean::try_from(b(word)).unwrap().into();
102− let second: bool = Boolean::try_from(b(&*word.to_uppercase())).unwrap().into();
103− assert_eq!(first, second);
104− }
105− }
106−
107− #[test]
108− fn from_str_err() {
109− assert!(Boolean::try_from(b("yesn't")).is_err());
110− assert!(Boolean::try_from(b("yesno")).is_err());
111− }
112−}
113−
114−#[cfg(test)]
115−mod integer {
116− use crate::values_integration_tests::b;
117− use git_config::values::{Integer, IntegerSuffix};
118− use std::convert::TryFrom;
119−
120− #[test]
121− fn from_str_no_suffix() {
122− assert_eq!(Integer::try_from(b("1")).unwrap(), Integer { value: 1, suffix: None });
123−
124− assert_eq!(
125− Integer::try_from(b("-1")).unwrap(),
126− Integer {
127− value: -1,
128− suffix: None
129− }
130− );
131− }
132−
133− #[test]
134− fn from_str_with_suffix() {
135− assert_eq!(
136− Integer::try_from(b("1k")).unwrap(),
137− Integer {
138− value: 1,
139− suffix: Some(IntegerSuffix::Kibi),
140− }
141− );
142−
143− assert_eq!(
144− Integer::try_from(b("1m")).unwrap(),
145− Integer {
146− value: 1,
147− suffix: Some(IntegerSuffix::Mebi),
148− }
149− );
150−
151− assert_eq!(
152− Integer::try_from(b("1g")).unwrap(),
153− Integer {
154− value: 1,
155− suffix: Some(IntegerSuffix::Gibi),
156− }
157− );
158− }
159−
160− #[test]
161− fn invalid_from_str() {
162− assert!(Integer::try_from(b("")).is_err());
163− assert!(Integer::try_from(b("-")).is_err());
164− assert!(Integer::try_from(b("k")).is_err());
165− assert!(Integer::try_from(b("m")).is_err());
166− assert!(Integer::try_from(b("g")).is_err());
167− assert!(Integer::try_from(b("123123123123123123123123")).is_err());
168− assert!(Integer::try_from(b("gg")).is_err());
169− }
170−
171− #[test]
172− fn as_decimal() {
173− assert_eq!(
174− Integer::try_from(b("12")).unwrap().as_decimal().unwrap(),
175− 12,
176− "works without suffix"
177− );
178− assert_eq!(
179− Integer::try_from(b("13k")).unwrap().as_decimal().unwrap(),
180− 13 * 1024,
181− "works with kilobyte suffix"
182− );
183− assert_eq!(
184− Integer::try_from(b("14m")).unwrap().as_decimal().unwrap(),
185− 14 * 1048576,
186− "works with megabyte suffix"
187− );
188− assert_eq!(
189− Integer::try_from(b("15g")).unwrap().as_decimal().unwrap(),
190− 15 * 1073741824,
191− "works with gigabyte suffix"
192− );
193−
194− let max_i64 = format!("{}g", i64::MAX);
195− assert!(
196− Integer::try_from(b(&max_i64)).unwrap().as_decimal().is_none(),
197− "overflow results in None"
198− );
199− }
200−}
201−
202−#[cfg(test)]
203−mod color_value {
204− use git_config::values::ColorValue;
205− use std::str::FromStr;
206−
207− #[test]
208− fn non_bright() {
209− assert_eq!(ColorValue::from_str("normal"), Ok(ColorValue::Normal));
210− assert_eq!(ColorValue::from_str("black"), Ok(ColorValue::Black));
211− assert_eq!(ColorValue::from_str("red"), Ok(ColorValue::Red));
212− assert_eq!(ColorValue::from_str("green"), Ok(ColorValue::Green));
213− assert_eq!(ColorValue::from_str("yellow"), Ok(ColorValue::Yellow));
214− assert_eq!(ColorValue::from_str("blue"), Ok(ColorValue::Blue));
215− assert_eq!(ColorValue::from_str("magenta"), Ok(ColorValue::Magenta));
216− assert_eq!(ColorValue::from_str("cyan"), Ok(ColorValue::Cyan));
217− assert_eq!(ColorValue::from_str("white"), Ok(ColorValue::White));
218− }
219−
220− #[test]
221− fn bright() {
222− assert_eq!(ColorValue::from_str("brightblack"), Ok(ColorValue::BrightBlack));
223− assert_eq!(ColorValue::from_str("brightred"), Ok(ColorValue::BrightRed));
224− assert_eq!(ColorValue::from_str("brightgreen"), Ok(ColorValue::BrightGreen));
225− assert_eq!(ColorValue::from_str("brightyellow"), Ok(ColorValue::BrightYellow));
226− assert_eq!(ColorValue::from_str("brightblue"), Ok(ColorValue::BrightBlue));
227− assert_eq!(ColorValue::from_str("brightmagenta"), Ok(ColorValue::BrightMagenta));
228− assert_eq!(ColorValue::from_str("brightcyan"), Ok(ColorValue::BrightCyan));
229− assert_eq!(ColorValue::from_str("brightwhite"), Ok(ColorValue::BrightWhite));
230− }
231−
232− #[test]
233− fn ansi() {
234− assert_eq!(ColorValue::from_str("255"), Ok(ColorValue::Ansi(255)));
235− assert_eq!(ColorValue::from_str("0"), Ok(ColorValue::Ansi(0)));
236− }
237−
238− #[test]
239− fn hex() {
240− assert_eq!(ColorValue::from_str("#ff0010"), Ok(ColorValue::Rgb(255, 0, 16)));
241− assert_eq!(ColorValue::from_str("#ffffff"), Ok(ColorValue::Rgb(255, 255, 255)));
242− assert_eq!(ColorValue::from_str("#000000"), Ok(ColorValue::Rgb(0, 0, 0)));
243− }
244−
245− #[test]
246− fn invalid() {
247− assert!(ColorValue::from_str("brightnormal").is_err());
248− assert!(ColorValue::from_str("").is_err());
249− assert!(ColorValue::from_str("bright").is_err());
250− assert!(ColorValue::from_str("256").is_err());
251− assert!(ColorValue::from_str("#").is_err());
252− assert!(ColorValue::from_str("#fff").is_err());
253− assert!(ColorValue::from_str("#gggggg").is_err());
254− }
255−}
256−
257−#[cfg(test)]
258−mod color_attribute {
259− use git_config::values::ColorAttribute;
260− use std::str::FromStr;
261−
262− #[test]
263− fn non_inverted() {
264− assert_eq!(ColorAttribute::from_str("bold"), Ok(ColorAttribute::Bold));
265− assert_eq!(ColorAttribute::from_str("dim"), Ok(ColorAttribute::Dim));
266− assert_eq!(ColorAttribute::from_str("ul"), Ok(ColorAttribute::Ul));
267− assert_eq!(ColorAttribute::from_str("blink"), Ok(ColorAttribute::Blink));
268− assert_eq!(ColorAttribute::from_str("reverse"), Ok(ColorAttribute::Reverse));
269− assert_eq!(ColorAttribute::from_str("italic"), Ok(ColorAttribute::Italic));
270− assert_eq!(ColorAttribute::from_str("strike"), Ok(ColorAttribute::Strike));
271− }
272−
273− #[test]
274− fn inverted_no_dash() {
275− assert_eq!(ColorAttribute::from_str("nobold"), Ok(ColorAttribute::NoBold));
276− assert_eq!(ColorAttribute::from_str("nodim"), Ok(ColorAttribute::NoDim));
277− assert_eq!(ColorAttribute::from_str("noul"), Ok(ColorAttribute::NoUl));
278− assert_eq!(ColorAttribute::from_str("noblink"), Ok(ColorAttribute::NoBlink));
279− assert_eq!(ColorAttribute::from_str("noreverse"), Ok(ColorAttribute::NoReverse));
280− assert_eq!(ColorAttribute::from_str("noitalic"), Ok(ColorAttribute::NoItalic));
281− assert_eq!(ColorAttribute::from_str("nostrike"), Ok(ColorAttribute::NoStrike));
282− }
283−
284− #[test]
285− fn inverted_dashed() {
286− assert_eq!(ColorAttribute::from_str("no-bold"), Ok(ColorAttribute::NoBold));
287− assert_eq!(ColorAttribute::from_str("no-dim"), Ok(ColorAttribute::NoDim));
288− assert_eq!(ColorAttribute::from_str("no-ul"), Ok(ColorAttribute::NoUl));
289− assert_eq!(ColorAttribute::from_str("no-blink"), Ok(ColorAttribute::NoBlink));
290− assert_eq!(ColorAttribute::from_str("no-reverse"), Ok(ColorAttribute::NoReverse));
291− assert_eq!(ColorAttribute::from_str("no-italic"), Ok(ColorAttribute::NoItalic));
292− assert_eq!(ColorAttribute::from_str("no-strike"), Ok(ColorAttribute::NoStrike));
293− }
294−
295− #[test]
296− fn invalid() {
297− assert!(ColorAttribute::from_str("a").is_err());
298− assert!(ColorAttribute::from_str("no bold").is_err());
299− assert!(ColorAttribute::from_str("").is_err());
300− assert!(ColorAttribute::from_str("no").is_err());
301− assert!(ColorAttribute::from_str("no-").is_err());
302− }
303−}
304−#[cfg(test)]
305−mod interpolate_tests {
306− use crate::values_integration_tests::b;
307− use git_config::values::path::interpolate;
308− use git_config::values::Path;
309− use std::borrow::Cow;
310−
311− #[test]
312− fn no_interpolation_for_paths_without_tilde_or_prefix() {
313− let path = &b"/foo/bar"[..];
314− let actual = Path::from(Cow::Borrowed(path));
315− assert_eq!(&*actual, path);
316− assert!(
317− matches!(&actual.value, Cow::Borrowed(_)),
318− "it does not unnecessarily copy values"
319− );
320− }
321−
322− #[test]
323− fn empty_path_is_error() {
324− assert!(matches!(
325− Path::from(Cow::Borrowed(b(""))).interpolate(None),
326− Err(interpolate::Error::Missing { what: "path" })
327− ));
328− }
329−
330− #[test]
331− fn prefix_substitutes_git_install_dir() {
332− for git_install_dir in &["/tmp/git", "C:\\git"] {
333− for (val, expected) in &[
334− (&b"%(prefix)/foo/bar"[..], "foo/bar"),
335− (b"%(prefix)/foo\\bar", "foo\\bar"),
336− ] {
337− let expected =
338− &std::path::PathBuf::from(format!("{}{}{}", git_install_dir, std::path::MAIN_SEPARATOR, expected));
339− assert_eq!(
340− &*Path::from(Cow::Borrowed(*val))
341− .interpolate(Some(std::path::Path::new(git_install_dir)))
342− .unwrap(),
343− expected,
344− "prefix interpolation keeps separators as they are"
345− );
346− }
347− }
348− }
349−
350− #[test]
351− fn prefix_substitution_skipped_with_dot_slash() {
352− let path = "./%(prefix)/foo/bar";
353− let git_install_dir = "/tmp/git";
354− assert_eq!(
355− Path::from(Cow::Borrowed(b(path)))
356− .interpolate(Some(std::path::Path::new(git_install_dir)))
357− .unwrap(),
358− std::path::Path::new(path)
359− );
360− }
361−
362− #[test]
363− fn tilde_substitutes_current_user() {
364− let path = &b"~/foo/bar"[..];
365− let expected = format!(
366− "{}{}foo/bar",
367− dirs::home_dir().expect("empty home").display(),
368− std::path::MAIN_SEPARATOR
369− );
370− assert_eq!(
371− Path::from(Cow::Borrowed(path)).interpolate(None).unwrap().as_ref(),
372− std::path::Path::new(&expected),
373− "note that path separators are not turned into slashes as we work with `std::path::Path`"
374− );
375− }
376−
377− #[cfg(target_os = "windows")]
378− #[test]
379− fn tilde_with_given_user_is_unsupported_on_windows() {
380− assert!(matches!(
381− Path::from(Cow::Borrowed(&b"~baz/foo/bar"[..])).interpolate(None),
382− Err(interpolate::Error::UserInterpolationUnsupported)
383− ));
384− }
385−
386− #[cfg(not(target_os = "windows"))]
387− #[test]
388− fn tilde_with_given_user() {
389− let user = std::env::var("USER").unwrap();
390− let home = std::env::var("HOME").unwrap();
391− let specific_user_home = format!("~{}", user);
392−
393− for path_suffix in &["foo/bar", "foo\\bar", ""] {
394− let path = format!("{}{}{}", specific_user_home, std::path::MAIN_SEPARATOR, path_suffix);
395− let expected = format!("{}{}{}", home, std::path::MAIN_SEPARATOR, path_suffix);
396− assert_eq!(
397− Path::from(Cow::Borrowed(b(&path))).interpolate(None).unwrap(),
398− std::path::Path::new(&expected),
399− "it keeps path separators as is"
400− );
401− }
402− }
403−}
git-config/tests/parser/mod.rsrenamed from git-config/tests/integration_tests/parser_integration_tests.rs+0−0

File renamed without changes.

git-config/tests/value/mod.rsrenamed from git-config/tests/integration_tests/value_integration_tests.rs+0−0

File renamed without changes.

git-config/tests/values/boolean.rs+48−0
@@ -0,0 +1,48 @@
1+use crate::values::b;
2+use git_config::values::{Boolean, TrueVariant};
3+use std::convert::TryFrom;
4+
5+#[test]
6+fn from_str_false() {
7+ assert_eq!(Boolean::try_from(b("no")), Ok(Boolean::False("no".into())));
8+ assert_eq!(Boolean::try_from(b("off")), Ok(Boolean::False("off".into())));
9+ assert_eq!(Boolean::try_from(b("false")), Ok(Boolean::False("false".into())));
10+ assert_eq!(Boolean::try_from(b("zero")), Ok(Boolean::False("zero".into())));
11+ assert_eq!(Boolean::try_from(b("\"\"")), Ok(Boolean::False("\"\"".into())));
12+}
13+
14+#[test]
15+fn from_str_true() {
16+ assert_eq!(
17+ Boolean::try_from(b("yes")),
18+ Ok(Boolean::True(TrueVariant::Explicit("yes".into())))
19+ );
20+ assert_eq!(
21+ Boolean::try_from(b("on")),
22+ Ok(Boolean::True(TrueVariant::Explicit("on".into())))
23+ );
24+ assert_eq!(
25+ Boolean::try_from(b("true")),
26+ Ok(Boolean::True(TrueVariant::Explicit("true".into())))
27+ );
28+ assert_eq!(
29+ Boolean::try_from(b("one")),
30+ Ok(Boolean::True(TrueVariant::Explicit("one".into())))
31+ );
32+}
33+
34+#[test]
35+fn ignores_case() {
36+ // Random subset
37+ for word in &["no", "yes", "off", "true", "zero"] {
38+ let first: bool = Boolean::try_from(b(word)).unwrap().into();
39+ let second: bool = Boolean::try_from(b(&*word.to_uppercase())).unwrap().into();
40+ assert_eq!(first, second);
41+ }
42+}
43+
44+#[test]
45+fn from_str_err() {
46+ assert!(Boolean::try_from(b("yesn't")).is_err());
47+ assert!(Boolean::try_from(b("yesno")).is_err());
48+}
git-config/tests/values/color_attribute.rs+44−0
@@ -0,0 +1,44 @@
1+use git_config::values::ColorAttribute;
2+use std::str::FromStr;
3+
4+#[test]
5+fn non_inverted() {
6+ assert_eq!(ColorAttribute::from_str("bold"), Ok(ColorAttribute::Bold));
7+ assert_eq!(ColorAttribute::from_str("dim"), Ok(ColorAttribute::Dim));
8+ assert_eq!(ColorAttribute::from_str("ul"), Ok(ColorAttribute::Ul));
9+ assert_eq!(ColorAttribute::from_str("blink"), Ok(ColorAttribute::Blink));
10+ assert_eq!(ColorAttribute::from_str("reverse"), Ok(ColorAttribute::Reverse));
11+ assert_eq!(ColorAttribute::from_str("italic"), Ok(ColorAttribute::Italic));
12+ assert_eq!(ColorAttribute::from_str("strike"), Ok(ColorAttribute::Strike));
13+}
14+
15+#[test]
16+fn inverted_no_dash() {
17+ assert_eq!(ColorAttribute::from_str("nobold"), Ok(ColorAttribute::NoBold));
18+ assert_eq!(ColorAttribute::from_str("nodim"), Ok(ColorAttribute::NoDim));
19+ assert_eq!(ColorAttribute::from_str("noul"), Ok(ColorAttribute::NoUl));
20+ assert_eq!(ColorAttribute::from_str("noblink"), Ok(ColorAttribute::NoBlink));
21+ assert_eq!(ColorAttribute::from_str("noreverse"), Ok(ColorAttribute::NoReverse));
22+ assert_eq!(ColorAttribute::from_str("noitalic"), Ok(ColorAttribute::NoItalic));
23+ assert_eq!(ColorAttribute::from_str("nostrike"), Ok(ColorAttribute::NoStrike));
24+}
25+
26+#[test]
27+fn inverted_dashed() {
28+ assert_eq!(ColorAttribute::from_str("no-bold"), Ok(ColorAttribute::NoBold));
29+ assert_eq!(ColorAttribute::from_str("no-dim"), Ok(ColorAttribute::NoDim));
30+ assert_eq!(ColorAttribute::from_str("no-ul"), Ok(ColorAttribute::NoUl));
31+ assert_eq!(ColorAttribute::from_str("no-blink"), Ok(ColorAttribute::NoBlink));
32+ assert_eq!(ColorAttribute::from_str("no-reverse"), Ok(ColorAttribute::NoReverse));
33+ assert_eq!(ColorAttribute::from_str("no-italic"), Ok(ColorAttribute::NoItalic));
34+ assert_eq!(ColorAttribute::from_str("no-strike"), Ok(ColorAttribute::NoStrike));
35+}
36+
37+#[test]
38+fn invalid() {
39+ assert!(ColorAttribute::from_str("a").is_err());
40+ assert!(ColorAttribute::from_str("no bold").is_err());
41+ assert!(ColorAttribute::from_str("").is_err());
42+ assert!(ColorAttribute::from_str("no").is_err());
43+ assert!(ColorAttribute::from_str("no-").is_err());
44+}
git-config/tests/values/color_value.rs+51−0
@@ -0,0 +1,51 @@
1+use git_config::values::ColorValue;
2+use std::str::FromStr;
3+
4+#[test]
5+fn non_bright() {
6+ assert_eq!(ColorValue::from_str("normal"), Ok(ColorValue::Normal));
7+ assert_eq!(ColorValue::from_str("black"), Ok(ColorValue::Black));
8+ assert_eq!(ColorValue::from_str("red"), Ok(ColorValue::Red));
9+ assert_eq!(ColorValue::from_str("green"), Ok(ColorValue::Green));
10+ assert_eq!(ColorValue::from_str("yellow"), Ok(ColorValue::Yellow));
11+ assert_eq!(ColorValue::from_str("blue"), Ok(ColorValue::Blue));
12+ assert_eq!(ColorValue::from_str("magenta"), Ok(ColorValue::Magenta));
13+ assert_eq!(ColorValue::from_str("cyan"), Ok(ColorValue::Cyan));
14+ assert_eq!(ColorValue::from_str("white"), Ok(ColorValue::White));
15+}
16+
17+#[test]
18+fn bright() {
19+ assert_eq!(ColorValue::from_str("brightblack"), Ok(ColorValue::BrightBlack));
20+ assert_eq!(ColorValue::from_str("brightred"), Ok(ColorValue::BrightRed));
21+ assert_eq!(ColorValue::from_str("brightgreen"), Ok(ColorValue::BrightGreen));
22+ assert_eq!(ColorValue::from_str("brightyellow"), Ok(ColorValue::BrightYellow));
23+ assert_eq!(ColorValue::from_str("brightblue"), Ok(ColorValue::BrightBlue));
24+ assert_eq!(ColorValue::from_str("brightmagenta"), Ok(ColorValue::BrightMagenta));
25+ assert_eq!(ColorValue::from_str("brightcyan"), Ok(ColorValue::BrightCyan));
26+ assert_eq!(ColorValue::from_str("brightwhite"), Ok(ColorValue::BrightWhite));
27+}
28+
29+#[test]
30+fn ansi() {
31+ assert_eq!(ColorValue::from_str("255"), Ok(ColorValue::Ansi(255)));
32+ assert_eq!(ColorValue::from_str("0"), Ok(ColorValue::Ansi(0)));
33+}
34+
35+#[test]
36+fn hex() {
37+ assert_eq!(ColorValue::from_str("#ff0010"), Ok(ColorValue::Rgb(255, 0, 16)));
38+ assert_eq!(ColorValue::from_str("#ffffff"), Ok(ColorValue::Rgb(255, 255, 255)));
39+ assert_eq!(ColorValue::from_str("#000000"), Ok(ColorValue::Rgb(0, 0, 0)));
40+}
41+
42+#[test]
43+fn invalid() {
44+ assert!(ColorValue::from_str("brightnormal").is_err());
45+ assert!(ColorValue::from_str("").is_err());
46+ assert!(ColorValue::from_str("bright").is_err());
47+ assert!(ColorValue::from_str("256").is_err());
48+ assert!(ColorValue::from_str("#").is_err());
49+ assert!(ColorValue::from_str("#fff").is_err());
50+ assert!(ColorValue::from_str("#gggggg").is_err());
51+}
git-config/tests/values/integer.rs+84−0
@@ -0,0 +1,84 @@
1+use crate::values::b;
2+use git_config::values::{Integer, IntegerSuffix};
3+use std::convert::TryFrom;
4+
5+#[test]
6+fn from_str_no_suffix() {
7+ assert_eq!(Integer::try_from(b("1")).unwrap(), Integer { value: 1, suffix: None });
8+
9+ assert_eq!(
10+ Integer::try_from(b("-1")).unwrap(),
11+ Integer {
12+ value: -1,
13+ suffix: None
14+ }
15+ );
16+}
17+
18+#[test]
19+fn from_str_with_suffix() {
20+ assert_eq!(
21+ Integer::try_from(b("1k")).unwrap(),
22+ Integer {
23+ value: 1,
24+ suffix: Some(IntegerSuffix::Kibi),
25+ }
26+ );
27+
28+ assert_eq!(
29+ Integer::try_from(b("1m")).unwrap(),
30+ Integer {
31+ value: 1,
32+ suffix: Some(IntegerSuffix::Mebi),
33+ }
34+ );
35+
36+ assert_eq!(
37+ Integer::try_from(b("1g")).unwrap(),
38+ Integer {
39+ value: 1,
40+ suffix: Some(IntegerSuffix::Gibi),
41+ }
42+ );
43+}
44+
45+#[test]
46+fn invalid_from_str() {
47+ assert!(Integer::try_from(b("")).is_err());
48+ assert!(Integer::try_from(b("-")).is_err());
49+ assert!(Integer::try_from(b("k")).is_err());
50+ assert!(Integer::try_from(b("m")).is_err());
51+ assert!(Integer::try_from(b("g")).is_err());
52+ assert!(Integer::try_from(b("123123123123123123123123")).is_err());
53+ assert!(Integer::try_from(b("gg")).is_err());
54+}
55+
56+#[test]
57+fn as_decimal() {
58+ assert_eq!(
59+ Integer::try_from(b("12")).unwrap().as_decimal().unwrap(),
60+ 12,
61+ "works without suffix"
62+ );
63+ assert_eq!(
64+ Integer::try_from(b("13k")).unwrap().as_decimal().unwrap(),
65+ 13 * 1024,
66+ "works with kilobyte suffix"
67+ );
68+ assert_eq!(
69+ Integer::try_from(b("14m")).unwrap().as_decimal().unwrap(),
70+ 14 * 1048576,
71+ "works with megabyte suffix"
72+ );
73+ assert_eq!(
74+ Integer::try_from(b("15g")).unwrap().as_decimal().unwrap(),
75+ 15 * 1073741824,
76+ "works with gigabyte suffix"
77+ );
78+
79+ let max_i64 = format!("{}g", i64::MAX);
80+ assert!(
81+ Integer::try_from(b(&max_i64)).unwrap().as_decimal().is_none(),
82+ "overflow results in None"
83+ );
84+}
git-config/tests/values/mod.rs+16−0
@@ -0,0 +1,16 @@
1+/// Converts string to byte slice
2+fn b(s: &str) -> &[u8] {
3+ s.as_bytes()
4+}
5+
6+mod normalize;
7+
8+mod boolean;
9+
10+mod integer;
11+
12+mod color_value;
13+
14+mod color_attribute;
15+
16+mod path;
git-config/tests/values/normalize.rs+51−0
@@ -0,0 +1,51 @@
1+use git_config::values::normalize_str;
2+use std::borrow::Cow;
3+
4+#[test]
5+fn not_modified_is_borrowed() {
6+ assert_eq!(normalize_str("hello world"), Cow::Borrowed(b"hello world"));
7+}
8+
9+#[test]
10+fn modified_is_owned() {
11+ assert_eq!(
12+ normalize_str("hello \"world\""),
13+ Cow::<[u8]>::Owned(b"hello world".to_vec())
14+ );
15+}
16+
17+#[test]
18+fn all_quoted_is_optimized() {
19+ assert_eq!(normalize_str("\"hello world\""), Cow::Borrowed(b"hello world"));
20+}
21+
22+#[test]
23+fn all_quote_optimization_is_correct() {
24+ assert_eq!(normalize_str(r#""hello" world\""#), Cow::Borrowed(b"hello world\""));
25+}
26+
27+#[test]
28+fn quotes_right_next_to_each_other() {
29+ assert_eq!(
30+ normalize_str("\"hello\"\" world\""),
31+ Cow::<[u8]>::Owned(b"hello world".to_vec())
32+ );
33+}
34+
35+#[test]
36+fn escaped_quotes_are_kept() {
37+ assert_eq!(
38+ normalize_str(r#""hello \"\" world""#),
39+ Cow::<[u8]>::Owned(b"hello \"\" world".to_vec())
40+ );
41+}
42+
43+#[test]
44+fn empty_string() {
45+ assert_eq!(normalize_str(""), Cow::Borrowed(b""));
46+}
47+
48+#[test]
49+fn empty_normalized_string_is_optimized() {
50+ assert_eq!(normalize_str("\"\""), Cow::Borrowed(b""));
51+}
git-config/tests/values/path.rs+97−0
@@ -0,0 +1,97 @@
1+use crate::values::b;
2+use git_config::values::path::interpolate;
3+use git_config::values::Path;
4+use std::borrow::Cow;
5+
6+#[test]
7+fn no_interpolation_for_paths_without_tilde_or_prefix() {
8+ let path = &b"/foo/bar"[..];
9+ let actual = Path::from(Cow::Borrowed(path));
10+ assert_eq!(&*actual, path);
11+ assert!(
12+ matches!(&actual.value, Cow::Borrowed(_)),
13+ "it does not unnecessarily copy values"
14+ );
15+}
16+
17+#[test]
18+fn empty_path_is_error() {
19+ assert!(matches!(
20+ Path::from(Cow::Borrowed(b(""))).interpolate(None),
21+ Err(interpolate::Error::Missing { what: "path" })
22+ ));
23+}
24+
25+#[test]
26+fn prefix_substitutes_git_install_dir() {
27+ for git_install_dir in &["/tmp/git", "C:\\git"] {
28+ for (val, expected) in &[
29+ (&b"%(prefix)/foo/bar"[..], "foo/bar"),
30+ (b"%(prefix)/foo\\bar", "foo\\bar"),
31+ ] {
32+ let expected =
33+ &std::path::PathBuf::from(format!("{}{}{}", git_install_dir, std::path::MAIN_SEPARATOR, expected));
34+ assert_eq!(
35+ &*Path::from(Cow::Borrowed(*val))
36+ .interpolate(Some(std::path::Path::new(git_install_dir)))
37+ .unwrap(),
38+ expected,
39+ "prefix interpolation keeps separators as they are"
40+ );
41+ }
42+ }
43+}
44+
45+#[test]
46+fn prefix_substitution_skipped_with_dot_slash() {
47+ let path = "./%(prefix)/foo/bar";
48+ let git_install_dir = "/tmp/git";
49+ assert_eq!(
50+ Path::from(Cow::Borrowed(b(path)))
51+ .interpolate(Some(std::path::Path::new(git_install_dir)))
52+ .unwrap(),
53+ std::path::Path::new(path)
54+ );
55+}
56+
57+#[test]
58+fn tilde_substitutes_current_user() {
59+ let path = &b"~/foo/bar"[..];
60+ let expected = format!(
61+ "{}{}foo/bar",
62+ dirs::home_dir().expect("empty home").display(),
63+ std::path::MAIN_SEPARATOR
64+ );
65+ assert_eq!(
66+ Path::from(Cow::Borrowed(path)).interpolate(None).unwrap().as_ref(),
67+ std::path::Path::new(&expected),
68+ "note that path separators are not turned into slashes as we work with `std::path::Path`"
69+ );
70+}
71+
72+#[cfg(target_os = "windows")]
73+#[test]
74+fn tilde_with_given_user_is_unsupported_on_windows() {
75+ assert!(matches!(
76+ Path::from(Cow::Borrowed(&b"~baz/foo/bar"[..])).interpolate(None),
77+ Err(interpolate::Error::UserInterpolationUnsupported)
78+ ));
79+}
80+
81+#[cfg(not(target_os = "windows"))]
82+#[test]
83+fn tilde_with_given_user() {
84+ let user = std::env::var("USER").unwrap();
85+ let home = std::env::var("HOME").unwrap();
86+ let specific_user_home = format!("~{}", user);
87+
88+ for path_suffix in &["foo/bar", "foo\\bar", ""] {
89+ let path = format!("{}{}{}", specific_user_home, std::path::MAIN_SEPARATOR, path_suffix);
90+ let expected = format!("{}{}{}", home, std::path::MAIN_SEPARATOR, path_suffix);
91+ assert_eq!(
92+ Path::from(Cow::Borrowed(b(&path))).interpolate(None).unwrap(),
93+ std::path::Path::new(&expected),
94+ "it keeps path separators as is"
95+ );
96+ }
97+}