#![allow(unused)] use patch::Patch;
use scanf::sscanf;
use std::{
collections::HashMap,
fs::{self, File},
io,
iter::Map,
path::{Path, PathBuf},
result,
time::Duration, panic,
};
#[derive(Debug)]
pub struct TestCase {
pub name: String,
pub result: TestResult,
pub diff: String,
}
#[derive(Debug)]
pub struct Model {
pub path: PathBuf,
pub name: String,
pub cases: Vec<TestCase>,
}
#[derive(Debug, PartialEq)]
pub enum State {
PASSED,
FAILED,
IGNORED,
}
#[derive(Debug)]
pub struct TestResult {
pub state: State,
pub runtime: Duration,
}
impl Model {
pub fn new(path: &Path) -> Model {
let results = read_results(read_file(path, "regression.out"));
let diffs = read_diffs(read_file(path, "regression.diffs"));
let mut cases: Vec<TestCase> = Vec::new();
for (name, result) in results {
cases.push(TestCase {
result: result,
diff: match &diffs {
Ok(d) => d.get(&name).unwrap_or(&String::new()).to_owned(),
Err(err) => String::from(*err)
},
name: name,
});
}
let suite_name = String::from(path.to_str().unwrap());
return Model {
path: path.to_path_buf(),
name: suite_name,
cases,
};
}
pub fn save(&self) {
let mut out_path = self.path.clone();
out_path.push("regression.xml");
let mut file = File::create(out_path).unwrap();
use std::io::prelude::*;
file.write_all(self.to_junit().as_bytes());
}
pub fn to_junit(&self) -> String {
use quick_junit::*;
let mut report = Report::new("my-test-run");
let mut test_suite = TestSuite::new(&self.name);
for case in &self.cases {
let mut status = match case.result.state {
State::IGNORED => TestCaseStatus::skipped(),
State::PASSED => TestCaseStatus::success(),
State::FAILED => TestCaseStatus::non_success(NonSuccessKind::Failure),
};
status.set_description(case.diff.clone());
TestCaseStatus::success();
let mut out_case = TestCase::new(&case.name, status);
out_case.set_time(case.result.runtime);
out_case.set_system_out("asd");
test_suite.add_test_case(out_case);
}
report.add_test_suite(test_suite);
return report.to_string().unwrap();
}
}
fn read_file(path: &Path, file: &str) -> String {
let mut file_path = path.to_path_buf();
file_path.push(file);
fs::read_to_string(file_path).unwrap()
}
fn read_results(results: String) -> HashMap<String, TestResult> {
let mut res = HashMap::new();
for line in results.split_terminator("\n") {
if line.starts_with("parallel") {
continue;
}
let (test_name, result) = parse_result_line(line);
res.insert(test_name, result);
}
res
}
fn parse_result_line(line: &str) -> (String, TestResult) {
let mut name: String = Default::default();
let mut state: String = Default::default();
let mut time: f64 = Default::default();
let line = &line.replace("failed (ignored)", "ignored")[5..];
sscanf!(line, "{} ... {} {} ms", name, state, time);
let state = match state.as_str() {
"FAILED" => State::FAILED,
"ok" => State::PASSED,
"ignored" => State::IGNORED,
_ => todo!("unhandled state >{:?}<?!", state),
};
(
name,
TestResult {
runtime: Duration::from_secs_f64(time / 1000.0),
state: state,
},
)
}
fn read_diffs(diffs: String) -> Result<HashMap<String, String>, &'static str> {
let mut res = HashMap::new();
if diffs.is_empty(){
return Ok(res);
}
let result = panic::catch_unwind(|| {
Patch::from_multiple(&diffs)
});
if result.is_err() {
return Err("Panic during processing diffs!");
}
let patches = result.unwrap();
if patches.is_err() {
return Err("Parse error during processing diffs!");
}
for patch in patches.unwrap() {
let path = patch.old.path.to_string();
let name = Path::new(&path).with_extension("");
let name = name.file_name().unwrap();
let name = String::from(name.to_str().unwrap());
res.insert(name, patch.to_string());
}
Ok(res)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_result_line_failed() {
let (name, res) =
parse_result_line("test misc ... FAILED 283 ms");
assert_eq!(name, "misc");
assert_eq!(res.state, State::FAILED);
assert_eq!(res.runtime.as_secs_f32(), 0.283);
}
#[test]
fn test_parse_result_line_ok() {
let (name, res) = parse_result_line("test misc ... ok 283.3 ms");
assert_eq!(name, "misc");
assert_eq!(res.state, State::PASSED);
assert_eq!(res.runtime.as_secs_f32(), 0.2833);
}
#[test]
fn test_parse_result_line_ignore() {
let (name, res) = parse_result_line("test misc ... failed (ignored) 283.3 ms");
assert_eq!(name, "misc");
assert_eq!(res.state, State::IGNORED);
assert_eq!(res.runtime.as_secs_f32(), 0.2833);
}
}