Implement Display trait on Expression and all types it depends on

This commit is contained in:
Oliver Hamlet
2018-10-06 10:36:39 +01:00
parent 5d9441623a
commit 77c58c965f
2 changed files with 189 additions and 0 deletions
+97
View File
@@ -1,3 +1,4 @@
use std::fmt;
use std::path::PathBuf; use std::path::PathBuf;
use regex::Regex; use regex::Regex;
@@ -16,6 +17,20 @@ pub enum ComparisonOperator {
GreaterThanOrEqual, GreaterThanOrEqual,
} }
impl fmt::Display for ComparisonOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::ComparisonOperator::*;
match self {
Equal => write!(f, "=="),
NotEqual => write!(f, "=="),
LessThan => write!(f, "<"),
GreaterThan => write!(f, ">"),
LessThanOrEqual => write!(f, "<="),
GreaterThanOrEqual => write!(f, ">="),
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum Function { pub enum Function {
FilePath(PathBuf), FilePath(PathBuf),
@@ -28,6 +43,22 @@ pub enum Function {
Version(PathBuf, String, ComparisonOperator), Version(PathBuf, String, ComparisonOperator),
} }
impl fmt::Display for Function {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Function::*;
match self {
FilePath(p) => write!(f, "file(\"{}\")", p.display()),
FileRegex(p, r) => write!(f, "file(\"{}/{}\")", p.display(), r),
ActivePath(p) => write!(f, "active(\"{}\")", p.display()),
ActiveRegex(r) => write!(f, "active(\"{}\")", r),
Many(p, r) => write!(f, "many(\"{}/{}\")", p.display(), r),
ManyActive(r) => write!(f, "many_active(\"{}\")", r),
Checksum(p, c) => write!(f, "checksum(\"{}\", {:02X?})", p.display(), c),
Version(p, v, c) => write!(f, "version(\"{}\", \"{}\", {})", p.display(), v, c),
}
}
}
impl PartialEq for Function { impl PartialEq for Function {
fn eq(&self, other: &Function) -> bool { fn eq(&self, other: &Function) -> bool {
use Function::*; use Function::*;
@@ -63,6 +94,72 @@ mod tests {
Regex::new(string).unwrap() Regex::new(string).unwrap()
} }
#[test]
fn function_fmt_for_file_path_should_format_correctly() {
let function = Function::FilePath("subdir/Blank.esm".into());
assert_eq!("file(\"subdir/Blank.esm\")", &format!("{}", function));
}
#[test]
fn function_fmt_for_file_regex_should_format_correctly() {
let function = Function::FileRegex("subdir".into(), regex("Blank.*"));
assert_eq!("file(\"subdir/Blank.*\")", &format!("{}", function));
}
#[test]
fn function_fmt_for_active_path_should_format_correctly() {
let function = Function::ActivePath("Blank.esm".into());
assert_eq!("active(\"Blank.esm\")", &format!("{}", function));
}
#[test]
fn function_fmt_for_active_regex_should_format_correctly() {
let function = Function::ActiveRegex(regex("Blank.*"));
assert_eq!("active(\"Blank.*\")", &format!("{}", function));
}
#[test]
fn function_fmt_for_many_should_format_correctly() {
let function = Function::Many("subdir".into(), regex("Blank.*"));
assert_eq!("many(\"subdir/Blank.*\")", &format!("{}", function));
}
#[test]
fn function_fmt_for_many_active_should_format_correctly() {
let function = Function::ManyActive(regex("Blank.*"));
assert_eq!("many_active(\"Blank.*\")", &format!("{}", function));
}
#[test]
fn function_fmt_for_checksum_should_format_correctly() {
let function = Function::Checksum("subdir/Blank.esm".into(), 0xDEADBEEF);
assert_eq!(
"checksum(\"subdir/Blank.esm\", DEADBEEF)",
&format!("{}", function)
);
}
#[test]
fn function_fmt_for_version_should_format_correctly() {
let function = Function::Version(
"subdir/Blank.esm".into(),
"1.2a".into(),
ComparisonOperator::Equal,
);
assert_eq!(
"version(\"subdir/Blank.esm\", \"1.2a\", ==)",
&format!("{}", function)
);
}
#[test] #[test]
fn function_eq_for_file_path_should_check_pathbuf() { fn function_eq_for_file_path_should_check_pathbuf() {
assert_eq!( assert_eq!(
+92
View File
@@ -13,6 +13,7 @@ mod version;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::ffi::OsStr; use std::ffi::OsStr;
use std::fmt;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str; use std::str;
@@ -116,6 +117,13 @@ impl Expression {
} }
} }
impl fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let strings: Vec<String> = self.0.iter().map(CompoundCondition::to_string).collect();
write!(f, "{}", strings.join(" or "))
}
}
// Conditions joined by 'and' // Conditions joined by 'and'
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
struct CompoundCondition(Vec<Condition>); struct CompoundCondition(Vec<Condition>);
@@ -139,6 +147,13 @@ impl CompoundCondition {
} }
} }
impl fmt::Display for CompoundCondition {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let strings: Vec<String> = self.0.iter().map(Condition::to_string).collect();
write!(f, "{}", strings.join(" and "))
}
}
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
enum Condition { enum Condition {
Function(Function), Function(Function),
@@ -174,6 +189,17 @@ impl Condition {
} }
} }
impl fmt::Display for Condition {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Condition::*;
match self {
Function(function) => write!(f, "{}", function),
InvertedFunction(function) => write!(f, "not {}", function),
Expression(e) => write!(f, "({})", e),
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -478,6 +504,30 @@ mod tests {
assert!(condition.eval(&state).unwrap()); assert!(condition.eval(&state).unwrap());
} }
#[test]
fn condition_fmt_should_format_function_correctly() {
let condition = Condition::Function(Function::FilePath(PathBuf::from("Cargo.toml")));
assert_eq!("file(\"Cargo.toml\")", &format!("{}", condition));
}
#[test]
fn condition_fmt_should_format_inverted_function_correctly() {
let condition =
Condition::InvertedFunction(Function::FilePath(PathBuf::from("Cargo.toml")));
assert_eq!("not file(\"Cargo.toml\")", &format!("{}", condition));
}
#[test]
fn condition_fmt_should_format_expression_correctly() {
let condition = Condition::Expression(Expression(vec![CompoundCondition(vec![
Condition::Function(Function::FilePath(PathBuf::from("Cargo.toml"))),
])]));
assert_eq!("(file(\"Cargo.toml\"))", &format!("{}", condition));
}
#[test] #[test]
fn compound_condition_eval_should_be_true_if_all_conditions_are_true() { fn compound_condition_eval_should_be_true_if_all_conditions_are_true() {
let state = state("."); let state = state(".");
@@ -502,6 +552,25 @@ mod tests {
assert!(!compound_condition.eval(&state).unwrap()); assert!(!compound_condition.eval(&state).unwrap());
} }
#[test]
fn compound_condition_fmt_should_format_correctly() {
let compound_condition = CompoundCondition(vec![
Condition::Function(Function::FilePath(PathBuf::from("Cargo.toml"))),
Condition::Function(Function::FilePath(PathBuf::from("missing"))),
]);
assert_eq!(
"file(\"Cargo.toml\") and file(\"missing\")",
&format!("{}", compound_condition)
);
let compound_condition = CompoundCondition(vec![Condition::Function(Function::FilePath(
PathBuf::from("Cargo.toml"),
))]);
assert_eq!("file(\"Cargo.toml\")", &format!("{}", compound_condition));
}
#[test] #[test]
fn expression_eval_should_be_true_if_any_compound_condition_is_true() { fn expression_eval_should_be_true_if_any_compound_condition_is_true() {
let state = state("."); let state = state(".");
@@ -531,4 +600,27 @@ mod tests {
]); ]);
assert!(!expression.eval(&state).unwrap()); assert!(!expression.eval(&state).unwrap());
} }
#[test]
fn expression_fmt_should_format_correctly() {
let expression = Expression(vec![
CompoundCondition(vec![Condition::Function(Function::FilePath(
PathBuf::from("Cargo.toml"),
))]),
CompoundCondition(vec![Condition::Function(Function::FilePath(
PathBuf::from("missing"),
))]),
]);
assert_eq!(
"file(\"Cargo.toml\") or file(\"missing\")",
&format!("{}", expression)
);
let expression = Expression(vec![CompoundCondition(vec![Condition::Function(
Function::FilePath(PathBuf::from("Cargo.toml")),
)])]);
assert_eq!("file(\"Cargo.toml\")", &format!("{}", expression));
}
} }