Skip to content

Commit 3f264af

Browse files
committed
sort out how expectations can be expressed in test suite (#450)
Some possible states are still missing though, like deletion in pushes.
1 parent 6713793 commit 3f264af

File tree

4 files changed

+96
-42
lines changed

4 files changed

+96
-42
lines changed

git-refspec/src/lib.rs

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,35 +23,7 @@ pub struct RefSpec {
2323
dest: Option<bstr::BString>,
2424
}
2525

26-
mod types;
27-
pub use types::{Instruction, Mode, Operation};
28-
29-
mod spec {
30-
use crate::{Instruction, Mode, RefSpec, RefSpecRef};
31-
32-
/// Access
33-
impl RefSpecRef<'_> {
34-
/// Return the refspec mode.
35-
pub fn mode(&self) -> Mode {
36-
self.mode
37-
}
26+
mod spec;
3827

39-
/// Transform the state of the refspec into an instruction making clear what to do with it.
40-
pub fn instruction(&self) -> Instruction<'_> {
41-
todo!()
42-
}
43-
}
44-
45-
/// Conversion
46-
impl RefSpecRef<'_> {
47-
/// Convert this ref into a standalone, owned copy.
48-
pub fn to_owned(&self) -> RefSpec {
49-
RefSpec {
50-
mode: self.mode,
51-
op: self.op,
52-
src: self.src.map(ToOwned::to_owned),
53-
dest: self.dest.map(ToOwned::to_owned),
54-
}
55-
}
56-
}
57-
}
28+
mod types;
29+
pub use types::{Fetch, Instruction, Mode, Operation, Push};

git-refspec/src/spec.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use crate::types::Push;
2+
use crate::{Instruction, Mode, Operation, RefSpec, RefSpecRef};
3+
use bstr::BStr;
4+
5+
/// Access
6+
impl RefSpecRef<'_> {
7+
/// Return the refspec mode.
8+
pub fn mode(&self) -> Mode {
9+
self.mode
10+
}
11+
12+
/// Transform the state of the refspec into an instruction making clear what to do with it.
13+
pub fn instruction(&self) -> Instruction<'_> {
14+
fn has_pattern(item: &BStr) -> bool {
15+
item.contains(&b'*')
16+
}
17+
match (self.op, self.mode, self.src, self.dest) {
18+
(Operation::Push, Mode::Normal | Mode::Force, Some(src), None) => Instruction::Push(Push::Single {
19+
src,
20+
dest: src,
21+
allow_non_fast_forward: matches!(self.mode, Mode::Force),
22+
}),
23+
(Operation::Push, Mode::Normal | Mode::Force, None, None) => Instruction::Push(Push::AllMatchingBranches {
24+
allow_non_fast_forward: matches!(self.mode, Mode::Force),
25+
}),
26+
(Operation::Push, Mode::Normal | Mode::Force, Some(src), Some(dest)) if has_pattern(src) => {
27+
Instruction::Push(Push::MultipleWithGlob {
28+
src,
29+
dest,
30+
allow_non_fast_forward: matches!(self.mode, Mode::Force),
31+
})
32+
}
33+
(Operation::Push, Mode::Normal | Mode::Force, Some(src), Some(dest)) => Instruction::Push(Push::Single {
34+
src,
35+
dest,
36+
allow_non_fast_forward: matches!(self.mode, Mode::Force),
37+
}),
38+
(Operation::Push, Mode::Negative, Some(src), None) if has_pattern(src) => {
39+
Instruction::Push(Push::ExcludeMultipleWithGlob { src })
40+
}
41+
(Operation::Push, Mode::Negative, Some(src), None) => Instruction::Push(Push::ExcludeSingle { src }),
42+
(op, mode, src, dest) => {
43+
unreachable!(
44+
"BUG: instructions with {:?} {:?} {:?} {:?} are not possible",
45+
op, mode, src, dest
46+
)
47+
}
48+
}
49+
}
50+
}
51+
52+
/// Conversion
53+
impl RefSpecRef<'_> {
54+
/// Convert this ref into a standalone, owned copy.
55+
pub fn to_owned(&self) -> RefSpec {
56+
RefSpec {
57+
mode: self.mode,
58+
op: self.op,
59+
src: self.src.map(ToOwned::to_owned),
60+
dest: self.dest.map(ToOwned::to_owned),
61+
}
62+
}
63+
}

git-refspec/src/types.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ pub enum Operation {
2020
Fetch,
2121
}
2222

23+
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
2324
pub enum Instruction<'a> {
2425
Push(Push<'a>),
2526
Fetch(Fetch<'a>),
2627
}
2728

29+
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
2830
pub enum Push<'a> {
29-
/// Push a single ref knowing only one ref name.
30-
SingleMatching {
31-
/// The name of the ref to push from `src` to `dest`.
32-
src_and_dest: &'a BStr,
33-
/// If true, allow non-fast-forward updates of `dest`.
31+
/// Push all local branches to the matching destination on the remote, which has to exist to be updated.
32+
AllMatchingBranches {
33+
/// If true, allow non-fast-forward updates of the matched destination branch.
3434
allow_non_fast_forward: bool,
3535
},
3636
/// Exclude a single ref.
@@ -63,6 +63,7 @@ pub enum Push<'a> {
6363
},
6464
}
6565

66+
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
6667
pub enum Fetch<'a> {
6768
Only {
6869
/// The ref name to fetch on the remote side, without updating the local side.
@@ -96,3 +97,12 @@ pub enum Fetch<'a> {
9697
allow_non_fast_forward: bool,
9798
},
9899
}
100+
101+
impl Instruction<'_> {
102+
pub fn operation(&self) -> Operation {
103+
match self {
104+
Instruction::Push(_) => Operation::Push,
105+
Instruction::Fetch(_) => Operation::Fetch,
106+
}
107+
}
108+
}

git-refspec/tests/parse/mod.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,26 +72,35 @@ mod invalid {
7272

7373
mod push {
7474
use crate::parse::assert_parse;
75-
use git_refspec::{Mode, Operation};
75+
use git_refspec::{Instruction, Push};
7676

7777
#[test]
7878
#[ignore]
7979
fn colon_alone_is_for_pushing_matching_refs() {
80-
assert_parse(":", Operation::Push, None, None, Mode::Normal);
80+
assert_parse(
81+
":",
82+
Instruction::Push(Push::AllMatchingBranches {
83+
allow_non_fast_forward: false,
84+
}),
85+
);
8186
}
8287
}
8388
}
8489

8590
mod util {
86-
use git_refspec::{Mode, Operation, RefSpecRef};
91+
use git_refspec::{Instruction, Operation, RefSpecRef};
92+
93+
// pub fn b(input: &str) -> &bstr::BStr {
94+
// input.into()
95+
// }
8796

8897
pub fn try_parse(spec: &str, op: Operation) -> Result<RefSpecRef<'_>, git_refspec::parse::Error> {
8998
git_refspec::parse(spec.into(), op)
9099
}
91100

92-
pub fn assert_parse(spec: &str, op: Operation, _src: Option<&str>, _dest: Option<&str>, mode: Mode) {
93-
let spec = try_parse(spec, op).expect("no error");
94-
assert_eq!(spec.mode(), mode);
101+
pub fn assert_parse(spec: &str, expected: Instruction<'_>) {
102+
let spec = try_parse(spec, expected.operation()).expect("no error");
103+
assert_eq!(spec.instruction(), expected)
95104
}
96105
}
97106
pub use util::*;

0 commit comments

Comments
 (0)