Skip to content

Commit

Permalink
sort out how expectations can be expressed in test suite (#450)
Browse files Browse the repository at this point in the history
Some possible states are still missing though, like deletion in pushes.
  • Loading branch information
Byron committed Aug 6, 2022
1 parent 6713793 commit 3f264af
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 42 deletions.
34 changes: 3 additions & 31 deletions git-refspec/src/lib.rs
Expand Up @@ -23,35 +23,7 @@ pub struct RefSpec {
dest: Option<bstr::BString>,
}

mod types;
pub use types::{Instruction, Mode, Operation};

mod spec {
use crate::{Instruction, Mode, RefSpec, RefSpecRef};

/// Access
impl RefSpecRef<'_> {
/// Return the refspec mode.
pub fn mode(&self) -> Mode {
self.mode
}
mod spec;

/// Transform the state of the refspec into an instruction making clear what to do with it.
pub fn instruction(&self) -> Instruction<'_> {
todo!()
}
}

/// Conversion
impl RefSpecRef<'_> {
/// Convert this ref into a standalone, owned copy.
pub fn to_owned(&self) -> RefSpec {
RefSpec {
mode: self.mode,
op: self.op,
src: self.src.map(ToOwned::to_owned),
dest: self.dest.map(ToOwned::to_owned),
}
}
}
}
mod types;
pub use types::{Fetch, Instruction, Mode, Operation, Push};
63 changes: 63 additions & 0 deletions git-refspec/src/spec.rs
@@ -0,0 +1,63 @@
use crate::types::Push;
use crate::{Instruction, Mode, Operation, RefSpec, RefSpecRef};
use bstr::BStr;

/// Access
impl RefSpecRef<'_> {
/// Return the refspec mode.
pub fn mode(&self) -> Mode {
self.mode
}

/// Transform the state of the refspec into an instruction making clear what to do with it.
pub fn instruction(&self) -> Instruction<'_> {
fn has_pattern(item: &BStr) -> bool {
item.contains(&b'*')
}
match (self.op, self.mode, self.src, self.dest) {
(Operation::Push, Mode::Normal | Mode::Force, Some(src), None) => Instruction::Push(Push::Single {
src,
dest: src,
allow_non_fast_forward: matches!(self.mode, Mode::Force),
}),
(Operation::Push, Mode::Normal | Mode::Force, None, None) => Instruction::Push(Push::AllMatchingBranches {
allow_non_fast_forward: matches!(self.mode, Mode::Force),
}),
(Operation::Push, Mode::Normal | Mode::Force, Some(src), Some(dest)) if has_pattern(src) => {
Instruction::Push(Push::MultipleWithGlob {
src,
dest,
allow_non_fast_forward: matches!(self.mode, Mode::Force),
})
}
(Operation::Push, Mode::Normal | Mode::Force, Some(src), Some(dest)) => Instruction::Push(Push::Single {
src,
dest,
allow_non_fast_forward: matches!(self.mode, Mode::Force),
}),
(Operation::Push, Mode::Negative, Some(src), None) if has_pattern(src) => {
Instruction::Push(Push::ExcludeMultipleWithGlob { src })
}
(Operation::Push, Mode::Negative, Some(src), None) => Instruction::Push(Push::ExcludeSingle { src }),
(op, mode, src, dest) => {
unreachable!(
"BUG: instructions with {:?} {:?} {:?} {:?} are not possible",
op, mode, src, dest
)
}
}
}
}

/// Conversion
impl RefSpecRef<'_> {
/// Convert this ref into a standalone, owned copy.
pub fn to_owned(&self) -> RefSpec {
RefSpec {
mode: self.mode,
op: self.op,
src: self.src.map(ToOwned::to_owned),
dest: self.dest.map(ToOwned::to_owned),
}
}
}
20 changes: 15 additions & 5 deletions git-refspec/src/types.rs
Expand Up @@ -20,17 +20,17 @@ pub enum Operation {
Fetch,
}

#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
pub enum Instruction<'a> {
Push(Push<'a>),
Fetch(Fetch<'a>),
}

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

#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
pub enum Fetch<'a> {
Only {
/// The ref name to fetch on the remote side, without updating the local side.
Expand Down Expand Up @@ -96,3 +97,12 @@ pub enum Fetch<'a> {
allow_non_fast_forward: bool,
},
}

impl Instruction<'_> {
pub fn operation(&self) -> Operation {
match self {
Instruction::Push(_) => Operation::Push,
Instruction::Fetch(_) => Operation::Fetch,
}
}
}
21 changes: 15 additions & 6 deletions git-refspec/tests/parse/mod.rs
Expand Up @@ -72,26 +72,35 @@ mod invalid {

mod push {
use crate::parse::assert_parse;
use git_refspec::{Mode, Operation};
use git_refspec::{Instruction, Push};

#[test]
#[ignore]
fn colon_alone_is_for_pushing_matching_refs() {
assert_parse(":", Operation::Push, None, None, Mode::Normal);
assert_parse(
":",
Instruction::Push(Push::AllMatchingBranches {
allow_non_fast_forward: false,
}),
);
}
}
}

mod util {
use git_refspec::{Mode, Operation, RefSpecRef};
use git_refspec::{Instruction, Operation, RefSpecRef};

// pub fn b(input: &str) -> &bstr::BStr {
// input.into()
// }

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

pub fn assert_parse(spec: &str, op: Operation, _src: Option<&str>, _dest: Option<&str>, mode: Mode) {
let spec = try_parse(spec, op).expect("no error");
assert_eq!(spec.mode(), mode);
pub fn assert_parse(spec: &str, expected: Instruction<'_>) {
let spec = try_parse(spec, expected.operation()).expect("no error");
assert_eq!(spec.instruction(), expected)
}
}
pub use util::*;

0 comments on commit 3f264af

Please sign in to comment.