use crate::spec::parse::{parse, try_parse}; #[test] fn braces_must_be_closed() { for unclosed_spec in ["@{something", "@{", "@{..@"] { let err = try_parse(unclosed_spec).unwrap_err(); assert_eq!( err.input.as_ref().map(std::convert::AsRef::as_ref), Some(&unclosed_spec.as_bytes()[1..]) ); } } #[test] #[cfg(target_pointer_width = "64")] // Only works this way on 64-bit systems. fn fuzzed() { let rec = parse("@{-9223372036854775808}"); assert_eq!(rec.nth_checked_out_branch, [Some(9223372036854775808), None]); } #[test] fn reflog_by_entry_for_current_branch() { for (spec, expected_entry) in [("@{0}", 0), ("@{42}", 42), ("@{00100}", 100)] { let rec = parse(spec); assert!(rec.kind.is_none()); assert_eq!(rec.find_ref[0], None); assert_eq!( rec.prefix[0], None, "neither ref nor prefixes are set, straight to navigation" ); assert_eq!(rec.current_branch_reflog_entry[0], Some(expected_entry.to_string())); assert_eq!(rec.calls, 1); } } #[test] fn reflog_by_date_for_current_branch() { let rec = parse("@{42 +0030}"); assert!(rec.kind.is_none()); assert_eq!(rec.find_ref[0], None); assert_eq!( rec.prefix[0], None, "neither ref nor prefixes are set, straight to navigation" ); assert_eq!(rec.current_branch_reflog_entry[0], Some("42 +0030".to_string())); assert_eq!(rec.calls, 1); } #[test] fn reflog_by_unix_timestamp_for_current_branch() { let rec = parse("@{100000000}"); assert!(rec.kind.is_none()); assert_eq!(rec.find_ref[0], None); assert_eq!( rec.prefix[0], None, "neither ref nor prefixes are set, straight to navigation" ); assert_eq!( rec.current_branch_reflog_entry[0], Some("100000000 +0000".to_string()), "This number is the first to count as date" ); assert_eq!(rec.calls, 1); let rec = parse("@{99999999}"); assert_eq!( rec.current_branch_reflog_entry[0], Some("99999999".to_string()), "one less is an offset though" ); } #[test] fn reflog_by_date_with_date_parse_failure() { let err = try_parse("@{foo}").unwrap_err(); insta::assert_snapshot!(err, @"could not parse time for reflog lookup: foo"); } #[test] fn reflog_by_date_for_hash_is_invalid() { for (spec, full_name) in [ ("1234@{42 +0030}", "1234"), ("abcd-dirty@{42 +0030}", "abcd-dirty"), ("v1.2.3-0-g1234@{42 +0030}", "v1.2.3-0-g1234"), ] { let err = try_parse(spec).unwrap_err(); assert_eq!(err.input.as_ref().map(AsRef::as_ref), Some(full_name.as_bytes())); assert!(err.message.contains("reflog entries require a ref name")); } } #[test] fn reflog_by_date_for_given_ref_name() { for (spec, expected_ref) in [ ("main@{42 +0030}", "main"), ("refs/heads/other@{42 +0030}", "refs/heads/other"), ("refs/worktree/feature/a@{42 +0030}", "refs/worktree/feature/a"), ] { let rec = parse(spec); assert!(rec.kind.is_none()); assert_eq!(rec.get_ref(0), expected_ref); assert_eq!(rec.prefix[0], None); assert_eq!(rec.current_branch_reflog_entry[0], Some("42 +0030".to_string())); assert_eq!(rec.calls, 2, "first the ref, then the reflog entry"); } } #[test] fn reflog_by_entry_for_given_ref_name() { for (spec, expected_ref, expected_entry) in [ ("main@{0}", "main", 0), ("refs/heads/other@{42}", "refs/heads/other", 42), ("refs/worktree/feature/a@{00100}", "refs/worktree/feature/a", 100), ] { let rec = parse(spec); assert!(rec.kind.is_none()); assert_eq!(rec.get_ref(0), expected_ref); assert_eq!(rec.prefix[0], None); assert_eq!(rec.current_branch_reflog_entry[0], Some(expected_entry.to_string())); assert_eq!(rec.calls, 2, "first the ref, then the reflog entry"); } } #[test] fn reflog_by_entry_for_hash_is_invalid() { for (spec, full_name) in [ ("1234@{0}", "1234"), ("abcd-dirty@{1}", "abcd-dirty"), ("v1.2.3-0-g1234@{2}", "v1.2.3-0-g1234"), ] { let err = try_parse(spec).unwrap_err(); assert_eq!(err.input.as_ref().map(AsRef::as_ref), Some(full_name.as_bytes())); assert!(err.message.contains("reflog entries require a ref name")); } } #[test] fn sibling_branch_current_branch() { for (spec, kind_name) in [("@{u}", "Upstream"), ("@{push}", "Push"), ("@{UPSTREAM}", "Upstream")] { let rec = parse(spec); assert!(rec.kind.is_none()); assert_eq!(rec.find_ref[0], None); assert_eq!(rec.prefix[0], None, "neither ref nor prefix are explicitly set"); assert_eq!(rec.sibling_branch[0].as_deref(), Some(kind_name)); assert_eq!(rec.calls, 1); } } #[test] fn sibling_branch_for_branch_name() { for (spec, ref_name, kind_name) in [ ("r1@{U}", "r1", "Upstream"), ("refs/heads/main@{Push}", "refs/heads/main", "Push"), ("refs/worktree/private@{UpStreaM}", "refs/worktree/private", "Upstream"), ] { let rec = parse(spec); assert!(rec.kind.is_none()); assert_eq!(rec.get_ref(0), ref_name); assert_eq!(rec.prefix[0], None, "neither ref nor prefix are explicitly set"); assert_eq!( rec.sibling_branch[0].as_deref(), Some(kind_name), "note that we do not know if something is a branch or not and make the call even if it would not be allowed. Configuration decides" ); assert_eq!(rec.calls, 2); } } #[test] fn sibling_branch_for_hash_is_invalid() { for (spec, full_name) in [ ("1234@{u}", "1234"), ("abcd-dirty@{push}", "abcd-dirty"), ("v1.2.3-0-g1234@{upstream}", "v1.2.3-0-g1234"), ] { let err = try_parse(spec).unwrap_err(); assert_eq!(err.input.as_ref().map(AsRef::as_ref), Some(full_name.as_bytes())); assert!(err.message.contains("sibling branches")); } } #[test] fn nth_checked_out_branch_for_refname_is_invalid() { let err = try_parse("r1@{-1}").unwrap_err(); // its undefined how to handle negative numbers and specified ref names insta::assert_snapshot!(err, @"reference name must be followed by positive numbers in @{n}: -1"); } #[test] fn nth_checked_out_branch() { for (spec, expected_branch) in [("@{-1}", 1), ("@{-42}", 42), ("@{-00100}", 100)] { let rec = parse(spec); assert!(rec.kind.is_none()); assert_eq!(rec.find_ref[0], None); assert_eq!( rec.prefix[0], None, "neither ref nor prefixes are set, straight to navigation" ); assert_eq!(rec.nth_checked_out_branch[0], Some(expected_branch)); assert_eq!(rec.calls, 1); } } #[test] fn numbers_within_braces_cannot_be_negative_zero() { let err = try_parse("@{-0}").unwrap_err(); // negative zero is not accepted, even though it could easily be defaulted to 0 which is a valid value insta::assert_snapshot!(err, @"negative zero is invalid - remove the minus sign: -0"); } #[test] fn numbers_within_braces_can_be_positive_zero() { assert_eq!( parse("@{+0}"), parse("@{0}"), "+ prefixes are allowed though and the same as without it" ); }