use crate::spec::parse::{parse, try_parse}; #[test] fn regex_parsing_ignores_ranges_as_opposed_to_git() { for spec in [":/a..b", ":/a...b"] { let rec = parse(spec); assert!(rec.kind.is_none()); assert_eq!( rec.patterns, vec![(spec[2..].into(), false)], "git parses ranges but I think it's merely coincidental rather than intended, not doing so allows to use '.' more liberally" ); } } #[test] fn index_lookups_ignores_ranges_as_opposed_to_git() { for spec in [":a..b", ":a...b"] { let rec = parse(spec); assert!(rec.kind.is_none()); assert_eq!( rec.index_lookups, vec![(spec[1..].into(), 0)], "git parses ranges but it's never useful as these specs only ever produce blob ids" ); } } #[test] fn various_forms_of_regex() { for (spec, (regex, negated)) in [ (":/simple", ("simple", false)), (":/!-negated", ("negated", true)), (":/^from start", ("^from start", false)), (":/!!leading exclamation mark", ("!leading exclamation mark", false)), (":/with count{1}", ("with count{1}", false)), ( ":/all-consuming makes navigation impossible^5~10", ("all-consuming makes navigation impossible^5~10", false), ), ] { let rec = parse(spec); assert!(rec.kind.is_none()); assert_eq!(rec.find_ref[0], None); assert_eq!(rec.prefix[0], None); assert_eq!(rec.patterns, vec![(regex.into(), negated)]); assert_eq!(rec.calls, 1); } } #[test] fn regex_do_not_get_any_backslash_processing() { for (spec, regex) in [(r#":/{"#, "{"), (r":/\{\}", r"\{\}"), (r":/\\\\\}", r"\\\\\}")] { let rec = parse(spec); assert_eq!(rec.patterns, vec![(regex.into(), false)]); assert_eq!(rec.calls, 1); } } #[test] fn various_valid_index_lookups_by_path() { for spec in [ ":path", ":dir/path", ":./relative-to.cwd", ":../relative-to-cwd-too", ":navigation/is/ignored~10^^^", ] { let rec = parse(spec); assert!(rec.kind.is_none()); assert_eq!(rec.find_ref[0], None); assert_eq!(rec.prefix[0], None); assert_eq!(rec.index_lookups, vec![(spec[1..].into(), 0)]); assert_eq!(rec.peel_to, vec![], "peeling only works for anchors"); assert_eq!(rec.calls, 1); } } #[test] fn various_valid_index_lookups_by_path_and_stage() { for (spec, path, stage) in [ (":0:path", "path", 0), (":1:dir/path", "dir/path", 1), (":2:dir/path@{part-of-path}", "dir/path@{part-of-path}", 2), ] { let rec = parse(spec); assert!(rec.kind.is_none()); assert_eq!(rec.find_ref[0], None); assert_eq!(rec.prefix[0], None); assert_eq!(rec.index_lookups, vec![(path.into(), stage)]); assert_eq!(rec.peel_to, vec![], "peeling only works for anchors"); assert_eq!(rec.calls, 1); } } #[test] fn empty_top_level_regex_are_invalid() { let err = try_parse(":/").unwrap_err(); // git also can't do it, finds nothing instead. It could be the youngest commit in theory, but isn't insta::assert_snapshot!(err, @"':/' must be followed by a regular expression"); } #[test] fn regex_with_empty_exclamation_mark_prefix_is_invalid() { let err = try_parse(r#":/!hello"#).unwrap_err(); assert_eq!(err.input.as_ref().map(AsRef::as_ref), Some(b"!hello".as_ref())); insta::assert_snapshot!(err, @"need one character after /!, typically -: !hello"); } #[test] fn needs_suffix() { let err = try_parse(":").unwrap_err(); // git also can't do it, finds nothing instead. It could be the youngest commit in theory, but isn't insta::assert_snapshot!(err, @"':' must be followed by either slash and regex or path to lookup in HEAD tree"); } #[test] fn invalid_index_stage_is_part_of_path() { for spec in [":4:file", ":5:file", ":01:file", ":10:file"] { let rec = parse(spec); assert!(rec.kind.is_none()); assert_eq!(rec.find_ref[0], None); assert_eq!(rec.prefix[0], None); assert_eq!(rec.patterns, vec![]); assert_eq!( rec.index_lookups, vec![(spec[1..].into(), 0)], "these count as stage 0 lookups" ); assert_eq!(rec.peel_to, vec![]); assert_eq!(rec.calls, 1); } }