use crate::junit_parser::{Failure, TestCase, TestSuite};
use crate::test_parser::{ParsedTestSuite, TestStatus};
use chrono::Utc;
use quick_xml::events::{BytesDecl, Event};
use quick_xml::se::Serializer;
use quick_xml::Writer;
use serde::Serialize;
use std::io::ErrorKind;
pub(crate) struct TestProducer {}
#[derive(Debug)]
pub(crate) struct RenderedSuite {
pub(crate) name: String,
pub(crate) rendered: String,
}
impl TestProducer {
pub(crate) fn produce(
tests: Vec<ParsedTestSuite>,
) -> Result<Vec<RenderedSuite>, anyhow::Error> {
let host = hostname::get();
let host_string = host.and_then(|s| {
s.into_string()
.map_err(|_| std::io::Error::from(ErrorKind::InvalidData))
});
let host_string = host_string.unwrap_or("".to_string());
let host_string = host_string.as_str();
let mut rendered: Vec<RenderedSuite> = vec![];
for suite in tests {
let parsed_suite = TestSuite {
name: suite.suite_name.clone(),
tests: suite.test_count,
skipped: suite.ignored,
failures: suite.failed,
errors: suite.errors,
timestamp: timestamp(),
hostname: host_string.to_string(),
time: suite.exec_time,
test_cases: Some(
suite
.tests
.into_iter()
.map(|t| TestCase {
name: t.full_name,
classname: t.module.unwrap_or(t.name),
time: t.exec_time.unwrap_or(0.0f64),
failure: match t.status {
TestStatus::Ok => None,
TestStatus::Failed => Some(Failure {
message: "assertion failed".to_string(),
content: t.std_out,
}),
TestStatus::Ignored => None,
},
})
.collect(),
),
std_out: None,
std_err: None,
};
let mut contents = Vec::new();
let mut writer = Writer::new_with_indent(&mut contents, ' ' as u8, 4);
writer
.write_event(Event::Decl(BytesDecl::new(b"1.0", Some(b"UTF-8"), None)))
.unwrap();
let mut serializer = Serializer::with_root(writer, None);
parsed_suite.serialize(&mut serializer).unwrap();
let render = String::from_utf8(contents).unwrap();
rendered.push(RenderedSuite {
name: suite.suite_name,
rendered: render,
})
}
return Ok(rendered);
}
}
fn timestamp() -> String {
let now = Utc::now();
now.format("%Y-%m-%dT%H:%M:%S").to_string()
}