validation tests with some restructuring
This commit is contained in:
parent
98c6512e95
commit
e0db95158a
106
src/cmd/edit.rs
106
src/cmd/edit.rs
|
|
@ -20,6 +20,22 @@ enum ValidationResult {
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Problem {
|
||||||
|
line_number: usize,
|
||||||
|
text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Problems {
|
||||||
|
warnings: Vec<Problem>,
|
||||||
|
errors: Vec<Problem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Problem {
|
||||||
|
fn new(line_number: usize, text: String) -> Self {
|
||||||
|
Problem { line_number, text }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Run for Edit {
|
impl Run for Edit {
|
||||||
fn run(&self) -> Result<()> {
|
fn run(&self) -> Result<()> {
|
||||||
while let Some(db_edits) = get_db_edits()? {
|
while let Some(db_edits) = get_db_edits()? {
|
||||||
|
|
@ -61,11 +77,11 @@ fn get_db_edits() -> Result<Option<String>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_db(db: &mut Database, db_edits: String) -> ValidationResult {
|
fn get_problems(db: &mut Database, db_edits: String) -> Problems {
|
||||||
let lines = db_edits.lines();
|
let lines = db_edits.lines();
|
||||||
|
|
||||||
let mut errors: Vec<(usize, String)> = Vec::new();
|
let mut errors: Vec<Problem> = Vec::new();
|
||||||
let mut warnings: Vec<(usize, String)> = Vec::new();
|
let mut warnings: Vec<Problem> = Vec::new();
|
||||||
|
|
||||||
for (index, line) in lines.enumerate() {
|
for (index, line) in lines.enumerate() {
|
||||||
let line_number = index + 1;
|
let line_number = index + 1;
|
||||||
|
|
@ -80,19 +96,20 @@ fn validate_db(db: &mut Database, db_edits: String) -> ValidationResult {
|
||||||
let mut split = line.split(',');
|
let mut split = line.split(',');
|
||||||
let (last_accessed_txt, rank_txt, path_txt) = (split.next(), split.next(), split.next());
|
let (last_accessed_txt, rank_txt, path_txt) = (split.next(), split.next(), split.next());
|
||||||
if split.next().is_some() {
|
if split.next().is_some() {
|
||||||
errors.push((line_number, "Too many values on line".to_string()));
|
errors.push(Problem::new(line_number, "too many values on line".to_string()));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let last_accessed: Option<Epoch> = match last_accessed_txt {
|
let last_accessed: Option<Epoch> = match last_accessed_txt {
|
||||||
Some(value) => match value.trim().parse::<Epoch>() {
|
Some(value) => match value.trim().parse::<Epoch>() {
|
||||||
Ok(value) => Some(value),
|
Ok(value) => Some(value),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
errors.push((line_number, e.to_string()));
|
errors.push(Problem::new(line_number, e.to_string()));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
errors.push((line_number, "Cannot parse 'last_accessed' field".to_string()));
|
errors.push(Problem::new(line_number, "Cannot parse 'last_accessed' field".to_string()));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -101,12 +118,12 @@ fn validate_db(db: &mut Database, db_edits: String) -> ValidationResult {
|
||||||
Some(value) => match value.trim().parse::<Rank>() {
|
Some(value) => match value.trim().parse::<Rank>() {
|
||||||
Ok(value) => Some(value),
|
Ok(value) => Some(value),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
errors.push((line_number, e.to_string()));
|
errors.push(Problem::new(line_number, e.to_string()));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
errors.push((line_number, "Cannot parse 'rank' field".to_string()));
|
errors.push(Problem::new(line_number, "Cannot parse 'rank' field".to_string()));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -114,23 +131,23 @@ fn validate_db(db: &mut Database, db_edits: String) -> ValidationResult {
|
||||||
let path: Option<String> = match path_txt {
|
let path: Option<String> = match path_txt {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
if value.trim() != value {
|
if value.trim() != value {
|
||||||
warnings.push((line_number, "path contains trailing whitespace".to_string()));
|
warnings.push(Problem::new(line_number, "path contains trailing whitespace".to_string()));
|
||||||
}
|
}
|
||||||
match resolve_path(&PathBuf::from(value)) {
|
match resolve_path(&PathBuf::from(value)) {
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
if v.to_str().unwrap() != value {
|
if v.to_str().unwrap() != value {
|
||||||
errors.push((line_number, "path must be an absolute path".to_string()));
|
errors.push(Problem::new(line_number, "path must be an absolute path".to_string()));
|
||||||
}
|
}
|
||||||
Some(value.to_string())
|
Some(value.to_string())
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
errors.push((line_number, e.to_string()));
|
errors.push(Problem::new(line_number, e.to_string()));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
errors.push((line_number, "Cannot parse 'path' field".to_string()));
|
errors.push(Problem::new(line_number, "cannot parse 'path' field".to_string()));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -139,19 +156,25 @@ fn validate_db(db: &mut Database, db_edits: String) -> ValidationResult {
|
||||||
db.add(&path, last_accessed, rank);
|
db.add(&path, last_accessed, rank);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Problems { warnings, errors }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_problems(problems: Problems) -> ValidationResult {
|
||||||
|
let warnings = problems.warnings;
|
||||||
|
let errors = problems.errors;
|
||||||
let has_warnings = !warnings.is_empty();
|
let has_warnings = !warnings.is_empty();
|
||||||
let has_errors = !errors.is_empty();
|
let has_errors = !errors.is_empty();
|
||||||
if has_warnings {
|
if has_warnings {
|
||||||
println!("Warnings:");
|
println!("Warnings:");
|
||||||
for (line_num, warning) in warnings {
|
for problem in warnings {
|
||||||
println!("{line_num}: {warning}");
|
println!("{}: {}", problem.line_number, problem.text);
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
if has_errors {
|
if has_errors {
|
||||||
println!("Errors:");
|
println!("Errors:");
|
||||||
for (line_num, error) in errors {
|
for problem in errors {
|
||||||
println!("line {line_num}: {error}");
|
println!("line {}: {}", problem.line_number, problem.text);
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
|
@ -182,3 +205,54 @@ fn validate_db(db: &mut Database, db_edits: String) -> ValidationResult {
|
||||||
}
|
}
|
||||||
ValidationResult::Success
|
ValidationResult::Success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use crate::db::DatabaseFile;
|
||||||
|
|
||||||
|
use super::get_problems;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_validtion_problems() {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let mut db_file = DatabaseFile::new(temp_dir.path());
|
||||||
|
let mut db = db_file.open().unwrap();
|
||||||
|
let problems = get_problems(&mut db, "1,1,/tmp".to_string());
|
||||||
|
assert!(problems.errors.is_empty());
|
||||||
|
assert!(problems.warnings.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case::invalid_accessed("1z,1,/tmp", "invalid digit found in string")]
|
||||||
|
#[case::negative_accessed("-1,1,/tmp", "invalid digit found in string")]
|
||||||
|
#[case::invalid_path("1,1,cool", "path must be an absolute path")]
|
||||||
|
#[case::invalid_rank("1,1z,/tmp", "invalid float literal")]
|
||||||
|
#[case::too_many_fields("1,1,1,/tmp", "too many values on line")]
|
||||||
|
#[case::too_few_fields("1,1", "cannot parse 'path' field")]
|
||||||
|
#[case::relative_path("1,1,~", "path must be an absolute path")]
|
||||||
|
fn validation_error(#[case] invalid_line: String, #[case] err_text: &str) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let mut db_file = DatabaseFile::new(temp_dir.path());
|
||||||
|
let mut db = db_file.open().unwrap();
|
||||||
|
let problems = get_problems(&mut db, invalid_line);
|
||||||
|
assert_eq!(problems.errors.len(), 1);
|
||||||
|
assert!(problems.warnings.is_empty());
|
||||||
|
assert_eq!(problems.errors[0].line_number, 1);
|
||||||
|
assert_eq!(problems.errors[0].text, err_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validation_warning() {
|
||||||
|
let invalid_line = "1,1,/tmp ".to_string();
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let mut db_file = DatabaseFile::new(temp_dir.path());
|
||||||
|
let mut db = db_file.open().unwrap();
|
||||||
|
let problems = get_problems(&mut db, invalid_line);
|
||||||
|
assert_eq!(problems.warnings.len(), 1);
|
||||||
|
assert!(problems.errors.is_empty());
|
||||||
|
assert_eq!(problems.warnings[0].line_number, 1);
|
||||||
|
assert_eq!(problems.warnings[0].text, "path contains trailing whitespace");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue