diff --git a/Cargo.lock b/Cargo.lock index 37a7756..90616f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,6 +31,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "doc-comment" version = "0.3.3" @@ -50,6 +56,7 @@ dependencies = [ "derive-getters", "doc-comment", "once_cell", + "pretty_assertions", "quick-xml", "regex", "strip-ansi-escapes", @@ -74,6 +81,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "proc-macro2" version = "1.0.69" @@ -241,3 +258,9 @@ dependencies = [ "proc-macro2", "quote", ] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/Cargo.toml b/Cargo.toml index d44db23..afbb1f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,4 +18,5 @@ time = { version = "0.3.4", features = ["formatting", "macros"] } [dev-dependencies] doc-comment = "0.3.3" once_cell = "1.14" +pretty_assertions = "1.4.0" regex = "1.6" diff --git a/src/collections.rs b/src/collections.rs index e4f7960..67eb95c 100644 --- a/src/collections.rs +++ b/src/collections.rs @@ -149,8 +149,16 @@ pub struct TestCase { pub enum TestResult { Success, Skipped, - Error { type_: String, message: String }, - Failure { type_: String, message: String }, + Error { + type_: String, + message: String, + cause: Option, + }, + Failure { + type_: String, + message: String, + cause: Option, + }, } impl TestCase { @@ -202,6 +210,7 @@ impl TestCase { result: TestResult::Error { type_: type_.into(), message: message.into(), + cause: None, }, classname: None, filepath: None, @@ -225,6 +234,7 @@ impl TestCase { result: TestResult::Failure { type_: type_.into(), message: message.into(), + cause: None, }, classname: None, filepath: None, @@ -297,6 +307,18 @@ impl TestCaseBuilder { self } + /// Set the `result.trace` for the `TestCase` + /// + /// It has no effect on successful `TestCase`s. + pub fn set_trace(&mut self, trace: &str) -> &mut Self { + match self.testcase.result { + TestResult::Error { ref mut cause, .. } => *cause = Some(trace.to_owned()), + TestResult::Failure { ref mut cause, .. } => *cause = Some(trace.to_owned()), + _ => {} + } + self + } + /// Creates a new TestCaseBuilder for an erroneous `TestCase` /// /// An erroneous `TestCase` is one that encountered an unexpected error condition. diff --git a/src/lib.rs b/src/lib.rs index e083df5..aab0678 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,7 @@ mod tests { datetime, Duration, Report, ReportBuilder, TestCase, TestCaseBuilder, TestSuite, TestSuiteBuilder, }; + use pretty_assertions::assert_eq; #[test] fn empty_testsuites() { @@ -360,10 +361,78 @@ mod tests { \ \ \ - \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +", + ); + } + + #[test] + fn test_cases_with_trace() { + let timestamp = datetime!(1970-01-01 01:01 UTC); + + let test_success = TestCaseBuilder::success("good test", Duration::milliseconds(15001)) + .set_classname("MyClass") + .set_filepath("./foo.rs") + .set_trace("Some trace message") // This should be ignored + .build(); + let test_error = TestCaseBuilder::error( + "error test", + Duration::seconds(5), + "git error", + "unable to fetch", + ) + .set_trace("Some error trace") + .build(); + let test_failure = TestCaseBuilder::failure( + "failure test", + Duration::seconds(10), + "assert_eq", + "not equal", + ) + .set_trace("Some failure trace") + .build(); + + let ts1 = TestSuiteBuilder::new("ts1") + .set_timestamp(timestamp) + .build(); + let ts2 = TestSuiteBuilder::new("ts2") + .set_timestamp(timestamp) + .add_testcase(test_success) + .add_testcase(test_error) + .add_testcase(test_failure) + .build(); + + let r = ReportBuilder::new() + .add_testsuite(ts1) + .add_testsuite(ts2) + .build(); + + let mut out: Vec = Vec::new(); + + r.write_xml(&mut out).unwrap(); + + // language=xml + assert_eq!( + String::from_utf8(out).unwrap(), + "\ +\ +\ + \ + \ + \ + \ + \ \ \ - \ + \ \ \ ", diff --git a/src/reports.rs b/src/reports.rs index 6014196..a1576cd 100644 --- a/src/reports.rs +++ b/src/reports.rs @@ -119,18 +119,11 @@ impl TestCase { }, |w| { match self.result { - TestResult::Success => w - .write_opt(self.system_out.as_ref(), |w, out| { - w.create_element("system-out") - .write_cdata_content(BytesCData::new(out.as_str())) - })? - .write_opt(self.system_err.as_ref(), |w, err| { - w.create_element("system-err") - .write_cdata_content(BytesCData::new(err.as_str())) - }), + TestResult::Success => Ok(w), TestResult::Error { ref type_, ref message, + ref cause, } => w .create_element("error") .with_attributes([ @@ -138,17 +131,10 @@ impl TestCase { ("message", message.as_str()), ]) .write_empty_or_inner( - |_| self.system_out.is_none() && self.system_err.is_none(), + |_| cause.is_none(), |w| { - w.write_opt(self.system_out.as_ref(), |w, stdout| { - let data = strip_ansi_escapes::strip(stdout); - w.write_event(Event::CData(BytesCData::new( - String::from_utf8_lossy(&data), - ))) - .map(|_| w) - })? - .write_opt(self.system_err.as_ref(), |w, stderr| { - let data = strip_ansi_escapes::strip(stderr); + w.write_opt(cause.as_ref(), |w, cause| { + let data = BytesCData::new(cause.as_str()); w.write_event(Event::CData(BytesCData::new( String::from_utf8_lossy(&data), ))) @@ -160,6 +146,7 @@ impl TestCase { TestResult::Failure { ref type_, ref message, + ref cause, } => w .create_element("failure") .with_attributes([ @@ -167,17 +154,10 @@ impl TestCase { ("message", message.as_str()), ]) .write_empty_or_inner( - |_| self.system_out.is_none() && self.system_err.is_none(), + |_| cause.is_none(), |w| { - w.write_opt(self.system_out.as_ref(), |w, stdout| { - let data = strip_ansi_escapes::strip(stdout); - w.write_event(Event::CData(BytesCData::new( - String::from_utf8_lossy(&data), - ))) - .map(|_| w) - })? - .write_opt(self.system_err.as_ref(), |w, stderr| { - let data = strip_ansi_escapes::strip(stderr); + w.write_opt(cause.as_ref(), |w, cause| { + let data = BytesCData::new(cause.as_str()); w.write_event(Event::CData(BytesCData::new( String::from_utf8_lossy(&data), ))) @@ -187,7 +167,15 @@ impl TestCase { }, ), TestResult::Skipped => w.create_element("skipped").write_empty(), - } + }? + .write_opt(self.system_out.as_ref(), |w, out| { + w.create_element("system-out") + .write_cdata_content(BytesCData::new(out.as_str())) + })? + .write_opt(self.system_err.as_ref(), |w, err| { + w.create_element("system-err") + .write_cdata_content(BytesCData::new(err.as_str())) + }) .map(drop) }, )