Files
src/src-revision/tests/revision/spec/parse/anchor/at_symbol.rs
2026-03-11 02:04:19 -07:00

227 lines
7.2 KiB
Rust

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"
);
}