Skip to content

Commit 79e0eaf

Browse files
committed
negative must not be empty (#450)
1 parent 32d98e9 commit 79e0eaf

File tree

5 files changed

+73
-60
lines changed

5 files changed

+73
-60
lines changed

git-refspec/src/parse.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ pub enum Error {
44
Empty,
55
#[error("Negative refspecs cannot have destinations as they exclude sources")]
66
NegativeWithDestination,
7+
#[error("Negative specs must not be empty")]
8+
NegativeEmpty,
79
#[error("Cannot push into an empty destination")]
810
PushToEmpty,
911
#[error("glob patterns may only involved a single '*' character, found {pattern:?}")]
@@ -52,12 +54,12 @@ pub(crate) mod function {
5254

5355
let (mut src, dst) = match spec.find_byte(b':') {
5456
Some(pos) => {
55-
let (src, dst) = spec.split_at(pos);
56-
let dst = &dst[1..];
5757
if mode == Mode::Negative {
5858
return Err(Error::NegativeWithDestination);
5959
}
6060

61+
let (src, dst) = spec.split_at(pos);
62+
let dst = &dst[1..];
6163
let src = (!src.is_empty()).then(|| src.as_bstr());
6264
let dst = (!dst.is_empty()).then(|| dst.as_bstr());
6365
match (src, dst) {
@@ -78,14 +80,18 @@ pub(crate) mod function {
7880
}
7981
None => {
8082
let src = (!spec.is_empty()).then(|| spec);
81-
if Operation::Fetch == operation && src.is_none() {
83+
if Operation::Fetch == operation && mode != Mode::Negative && src.is_none() {
8284
return Ok(fetch_head_only(mode));
8385
} else {
8486
(src, None)
8587
}
8688
}
8789
};
8890

91+
if mode == Mode::Negative && src.is_none() {
92+
return Err(Error::NegativeEmpty);
93+
}
94+
8995
if let Some(spec) = src.as_mut() {
9096
if *spec == "@" {
9197
*spec = "HEAD".into();
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:ace43ca904298dc76951863d41485ae0c21ee9b88abf7d604eb6c6e7efa18ab2
3-
size 9352
2+
oid sha256:6d2478d9f90c1e68924743a45cf801b4420924751c2caf7fa9a6c14291c388cd
3+
size 9356

git-refspec/tests/fixtures/make_baseline.sh

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ baseline fetch '^a:'
3030
baseline fetch '^a:b'
3131
baseline fetch '^:'
3232
baseline fetch '^:b'
33+
baseline fetch '^'
34+
baseline push '^'
3335

3436
baseline fetch '^refs/heads/qa/*/*'
3537
baseline push '^refs/heads/qa/*/*'

git-refspec/tests/parse/invalid.rs

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use crate::parse::try_parse;
2+
use git_refspec::{parse::Error, Operation};
3+
4+
#[test]
5+
fn empty() {
6+
assert!(matches!(try_parse("", Operation::Push).unwrap_err(), Error::Empty));
7+
}
8+
9+
#[test]
10+
fn negative_must_not_be_empty() {
11+
for op in [Operation::Fetch, Operation::Push] {
12+
assert!(matches!(try_parse("^", op).unwrap_err(), Error::NegativeEmpty));
13+
}
14+
}
15+
16+
#[test]
17+
fn negative_with_destination() {
18+
for op in [Operation::Fetch, Operation::Push] {
19+
for spec in ["^a:b", "^a:", "^:", "^:b"] {
20+
assert!(matches!(
21+
try_parse(spec, op).unwrap_err(),
22+
Error::NegativeWithDestination
23+
));
24+
}
25+
}
26+
}
27+
28+
#[test]
29+
fn complex_patterns_with_more_than_one_asterisk() {
30+
for op in [Operation::Fetch, Operation::Push] {
31+
for spec in ["^*/*", "a/*/c/*", "a**:**b", "+:**/"] {
32+
assert!(matches!(
33+
try_parse(spec, op).unwrap_err(),
34+
Error::PatternUnsupported { .. }
35+
));
36+
}
37+
}
38+
}
39+
40+
#[test]
41+
fn both_sides_need_pattern_if_one_uses_it() {
42+
for op in [Operation::Fetch, Operation::Push] {
43+
for spec in ["refs/*/a", ":a/*", "+:a/*", "a*:b/c", "a:b/*"] {
44+
assert!(
45+
matches!(try_parse(spec, op).unwrap_err(), Error::PatternUnbalanced),
46+
"{}",
47+
spec
48+
);
49+
}
50+
}
51+
}
52+
53+
#[test]
54+
fn push_to_empty() {
55+
assert!(matches!(
56+
try_parse("HEAD:", Operation::Push).unwrap_err(),
57+
Error::PushToEmpty
58+
));
59+
}

git-refspec/tests/parse/mod.rs

+1-55
Original file line numberDiff line numberDiff line change
@@ -56,62 +56,8 @@ fn baseline() {
5656
}
5757
}
5858

59-
mod invalid {
60-
use crate::parse::try_parse;
61-
use git_refspec::{parse::Error, Operation};
62-
63-
#[test]
64-
fn empty() {
65-
assert!(matches!(try_parse("", Operation::Push).unwrap_err(), Error::Empty));
66-
}
67-
68-
#[test]
69-
fn negative_with_destination() {
70-
for op in [Operation::Fetch, Operation::Push] {
71-
for spec in ["^a:b", "^a:", "^:", "^:b"] {
72-
assert!(matches!(
73-
try_parse(spec, op).unwrap_err(),
74-
Error::NegativeWithDestination
75-
));
76-
}
77-
}
78-
}
79-
80-
#[test]
81-
fn complex_patterns_with_more_than_one_asterisk() {
82-
for op in [Operation::Fetch, Operation::Push] {
83-
for spec in ["^*/*", "a/*/c/*", "a**:**b", "+:**/"] {
84-
assert!(matches!(
85-
try_parse(spec, op).unwrap_err(),
86-
Error::PatternUnsupported { .. }
87-
));
88-
}
89-
}
90-
}
91-
92-
#[test]
93-
fn both_sides_need_pattern_if_one_uses_it() {
94-
for op in [Operation::Fetch, Operation::Push] {
95-
for spec in ["refs/*/a", ":a/*", "+:a/*", "a*:b/c", "a:b/*"] {
96-
assert!(
97-
matches!(try_parse(spec, op).unwrap_err(), Error::PatternUnbalanced),
98-
"{}",
99-
spec
100-
);
101-
}
102-
}
103-
}
104-
105-
#[test]
106-
fn push_to_empty() {
107-
assert!(matches!(
108-
try_parse("HEAD:", Operation::Push).unwrap_err(),
109-
Error::PushToEmpty
110-
));
111-
}
112-
}
113-
11459
mod fetch;
60+
mod invalid;
11561
mod push;
11662

11763
mod util {

0 commit comments

Comments
 (0)