#[cfg(test)]
use proptest::collection::vec;
#[cfg(test)]
use proptest::prelude::*;
use std::fmt;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Name {
Backslash,
Branch,
Remote,
Ahead,
Behind,
Conflict,
Added,
Untracked,
Modified,
Unstaged,
Deleted,
DeletedStaged,
Renamed,
Stashed,
Quote,
}
impl fmt::Display for Name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let literal = match self {
Name::Stashed => "h",
Name::Branch => "b",
Name::Remote => "B",
Name::Ahead => "+",
Name::Behind => "-",
Name::Conflict => "u",
Name::Added => "A",
Name::Untracked => "a",
Name::Modified => "M",
Name::Unstaged => "m",
Name::Deleted => "d",
Name::DeletedStaged => "D",
Name::Renamed => "R",
Name::Backslash => "\\",
Name::Quote => "\'",
};
write!(f, "{}", literal)
}
}
#[cfg(test)]
pub fn arb_name() -> impl Strategy<Value = Name> {
use self::Name::*;
prop_oneof![
Just(Backslash),
Just(Branch),
Just(Remote),
Just(Ahead),
Just(Behind),
Just(Conflict),
Just(Added),
Just(Untracked),
Just(Modified),
Just(Unstaged),
Just(Deleted),
Just(DeletedStaged),
Just(Renamed),
Just(Stashed),
Just(Quote),
]
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Color {
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
Black,
RGB(u8, u8, u8),
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Style {
Reset,
Bold,
Underline,
Italic,
Fg(Color),
Bg(Color),
Number(u8),
}
impl fmt::Display for Style {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Color::*;
match self {
Style::Reset => write!(f, "~")?,
Style::Bold => write!(f, "*")?,
Style::Underline => write!(f, "_")?,
Style::Italic => write!(f, "i")?,
Style::Fg(Red) => write!(f, "r")?,
Style::Bg(Red) => write!(f, "R")?,
Style::Fg(Green) => write!(f, "g")?,
Style::Bg(Green) => write!(f, "G")?,
Style::Fg(Yellow) => write!(f, "y")?,
Style::Bg(Yellow) => write!(f, "Y")?,
Style::Fg(Blue) => write!(f, "b")?,
Style::Bg(Blue) => write!(f, "B")?,
Style::Fg(Magenta) => write!(f, "m")?,
Style::Bg(Magenta) => write!(f, "M")?,
Style::Fg(Cyan) => write!(f, "c")?,
Style::Bg(Cyan) => write!(f, "C")?,
Style::Fg(White) => write!(f, "w")?,
Style::Bg(White) => write!(f, "W")?,
Style::Fg(Black) => write!(f, "k")?,
Style::Bg(Black) => write!(f, "K")?,
&Style::Fg(RGB(r, g, b)) => write!(f, "[{},{},{}]", r, g, b)?,
&Style::Bg(RGB(r, g, b)) => write!(f, "{{{},{},{}}}", r, g, b)?,
&Style::Number(n) => write!(f, "{}", n)?,
};
Ok(())
}
}
#[cfg(test)]
pub fn arb_style() -> impl Strategy<Value = Style> {
use self::Color::*;
use self::Style::*;
prop_oneof![
Just(Reset),
Just(Bold),
Just(Underline),
Just(Italic),
Just(Fg(Red)),
Just(Bg(Red)),
Just(Fg(Green)),
Just(Bg(Green)),
Just(Fg(Yellow)),
Just(Bg(Yellow)),
Just(Fg(Blue)),
Just(Bg(Blue)),
Just(Fg(Magenta)),
Just(Bg(Magenta)),
Just(Fg(Cyan)),
Just(Bg(Cyan)),
Just(Fg(White)),
Just(Bg(White)),
Just(Fg(Black)),
Just(Bg(Black)),
any::<(u8, u8, u8)>().prop_map(|(r, g, b)| Fg(RGB(r, g, b))),
any::<(u8, u8, u8)>().prop_map(|(r, g, b)| Bg(RGB(r, g, b))),
any::<u8>().prop_map(|n| Number(n)),
]
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Expression {
Named {
name: Name,
sub: Tree,
},
Format { style: Vec<Style>, sub: Tree },
Group {
l: String,
r: String,
sub: Tree,
},
Literal(String),
}
impl fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expression::Named { ref name, ref sub } => {
write!(f, "\\{}", name)?;
if sub.0.is_empty() {
Ok(())
} else {
write!(f, "({})", sub)?;
Ok(())
}
}
Expression::Group {
ref l,
ref r,
ref sub,
} => write!(f, "\\{}{}{}", l, sub, r),
Expression::Format { ref style, ref sub } => {
write!(f, "#")?;
if let Some((first, ss)) = style.split_first() {
write!(f, "{}", first)?;
for s in ss {
write!(f, ";{}", s)?;
}
}
write!(f, "({})", sub)
}
Expression::Literal(ref string) => write!(f, "'{}'", string),
}
}
}
#[cfg(test)]
pub fn arb_expression() -> impl Strategy<Value = Expression> {
use self::Expression::*;
let leaf = prop_oneof![
arb_name().prop_map(|name| Named {
name: name,
sub: Tree::new(),
}),
vec(arb_style(), 1..5).prop_map(|style| Format {
style: style,
sub: Tree::new(),
}),
"[^']*".prop_map(Literal),
];
leaf.prop_recursive(8, 64, 10, |inner| {
prop_oneof![
(arb_name(), vec(inner.clone(), 0..10)).prop_map(|(name, sub)| Named {
name: name,
sub: Tree(sub)
}),
(vec(arb_style(), 1..10), vec(inner.clone(), 0..10)).prop_map(|(style, sub)| Format {
style: style,
sub: Tree(sub)
}),
vec(inner.clone(), 0..10).prop_map(|sub| Group {
l: "{".to_string(),
r: "}".to_string(),
sub: Tree(sub)
}),
vec(inner.clone(), 0..10).prop_map(|sub| Group {
l: "(".to_string(),
r: ")".to_string(),
sub: Tree(sub)
}),
vec(inner.clone(), 0..10).prop_map(|sub| Group {
l: "<".to_string(),
r: ">".to_string(),
sub: Tree(sub)
}),
vec(inner.clone(), 0..10).prop_map(|sub| Group {
l: "[".to_string(),
r: "]".to_string(),
sub: Tree(sub)
}),
]
})
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Tree(pub Vec<Expression>);
impl Tree {
pub fn new() -> Tree {
Tree(Vec::new())
}
}
impl Default for Tree {
fn default() -> Self {
Tree(Vec::new())
}
}
impl fmt::Display for Tree {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for exp in &self.0 {
write!(f, "{}", exp)?;
}
Ok(())
}
}
#[cfg(test)]
pub fn arb_tree(n: usize) -> impl Strategy<Value = Tree> {
vec(arb_expression(), 0..n).prop_map(Tree)
}