//! Test the JUnit parser //! //! Some tests may seem duplicate since they test start-end elements and //! empty-element tags but the parser uses different codepaths use junit_parser; use std::io::Cursor; #[test] /// Test that the report is parsed with a doctype /// Following tests will not have one fn skip_doctype() { let xml = r#""#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.time, 0f64); assert_eq!(t.tests, 0u64); assert_eq!(t.errors, 0u64); assert_eq!(t.failures, 0u64); assert_eq!(t.skipped, 0u64); assert_eq!(t.name, ""); assert_eq!(t.suites.len(), 0); } #[test] /// Test with an empty-element `testsuites` tag fn empty_test_suites() { let xml = r#""#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.time, 0f64); assert_eq!(t.tests, 0u64); assert_eq!(t.errors, 0u64); assert_eq!(t.failures, 0u64); assert_eq!(t.skipped, 0u64); assert_eq!(t.name, ""); assert_eq!(t.suites.len(), 0); } #[test] /// Test with an empty-element `testrun` tag fn empty_test_run() { let xml = r#""#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.time, 0f64); assert_eq!(t.tests, 0u64); assert_eq!(t.errors, 0u64); assert_eq!(t.failures, 0u64); assert_eq!(t.skipped, 0u64); assert_eq!(t.name, ""); assert_eq!(t.suites.len(), 0); } #[test] /// Test a `testsuites` tag with empty attributes fn empty_test_suites_empty_attributes() { let xml = r#""#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.time, 0f64); assert_eq!(t.tests, 0u64); assert_eq!(t.errors, 0u64); assert_eq!(t.failures, 0u64); assert_eq!(t.skipped, 0u64); assert_eq!(t.name, ""); assert_eq!(t.suites.len(), 0); } #[test] /// Test a `testsuites` element with no content fn empty_test_suites_start_end() { let xml = r#""#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.time, 0f64); assert_eq!(t.tests, 0u64); assert_eq!(t.errors, 0u64); assert_eq!(t.failures, 0u64); assert_eq!(t.skipped, 0u64); assert_eq!(t.name, ""); assert_eq!(t.suites.len(), 0); } #[test] /// Test a `testrun` element with no content fn empty_testrun_start_end() { let xml = r#""#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.time, 0f64); assert_eq!(t.tests, 0u64); assert_eq!(t.errors, 0u64); assert_eq!(t.failures, 0u64); assert_eq!(t.skipped, 0u64); assert_eq!(t.name, ""); assert_eq!(t.suites.len(), 0); } #[test] /// Test an empty-element `testsuites` tag with attributes fn empty_test_suites_with_attributes() { let xml = r#""#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.time, 38730.23f64); assert_eq!(t.tests, 22u64); assert_eq!(t.errors, 5u64); assert_eq!(t.failures, 9u64); assert_eq!(t.skipped, 3u64); assert_eq!(t.name, "AllTests"); assert_eq!(t.suites.len(), 0); } #[test] /// Test a `testsuites` element with attributes but no content fn empty_test_suites_start_end_with_attributes() { let xml = r#""#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.time, 38730.23f64); assert_eq!(t.tests, 22u64); assert_eq!(t.errors, 5u64); assert_eq!(t.failures, 9u64); assert_eq!(t.skipped, 3u64); assert_eq!(t.name, "AllTests"); assert_eq!(t.suites.len(), 0); } #[test] /// Test a `testsuites` element with an empty-element `testsuite` fn empty_test_suite() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let t = &t.suites[0]; assert_eq!(t.cases.len(), 0); } #[test] /// Test a `testsuites` element with an empty-element `testsuite` with empty /// attributes fn empty_test_suite_empty_attributes() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let t = &t.suites[0]; assert_eq!(t.time, 0f64); assert_eq!(t.tests, 0u64); assert_eq!(t.errors, 0u64); assert_eq!(t.failures, 0u64); assert_eq!(t.skipped, 0u64); assert_eq!(t.cases.len(), 0); assert_eq!(t.name, ""); } #[test] /// Test an empty-element `testsuite` fn empty_test_suite_start_end() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let t = &t.suites[0]; assert_eq!(t.time, 0f64); assert_eq!(t.tests, 0u64); assert_eq!(t.errors, 0u64); assert_eq!(t.failures, 0u64); assert_eq!(t.skipped, 0u64); assert_eq!(t.name, ""); assert_eq!(t.cases.len(), 0); } #[test] /// Test an empty-element `testsuite` with attributes fn empty_test_suite_with_attributes() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let t = &t.suites[0]; assert_eq!(t.time, 38730.23f64); assert_eq!(t.tests, 22u64); assert_eq!(t.errors, 5u64); assert_eq!(t.failures, 9u64); assert_eq!(t.skipped, 3u64); assert_eq!(t.name, "AllTests"); assert_eq!(t.cases.len(), 0); } #[test] /// Test a single element `testsuite` with attributes but no content fn empty_test_suite_start_end_with_attributes() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let t = &t.suites[0]; assert_eq!(t.time, 38730.23f64); assert_eq!(t.tests, 22u64); assert_eq!(t.errors, 5u64); assert_eq!(t.failures, 9u64); assert_eq!(t.skipped, 3u64); assert_eq!(t.name, "AllTests"); assert_eq!(t.cases.len(), 0); } #[test] /// Test a single empty-element `testsuite`, not in a `testsuites` element fn no_suites_empty_test_suite() { let xml = r#""#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let t = &t.suites[0]; assert_eq!(t.cases.len(), 0); } #[test] /// Test a single empty-element `testsuite` with attributes, not in a `testsuites` element fn no_suites_empty_test_suite_empty_attributes() { let xml = r#""#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let t = &t.suites[0]; assert_eq!(t.time, 0f64); assert_eq!(t.tests, 0u64); assert_eq!(t.errors, 0u64); assert_eq!(t.failures, 0u64); assert_eq!(t.skipped, 0u64); assert_eq!(t.name, ""); assert_eq!(t.cases.len(), 0); } #[test] /// Test a single empty-element `testsuite`, not in a `testsuites` element fn no_suites_empty_test_suites_start_end() { let xml = r#""#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let t = &t.suites[0]; assert_eq!(t.time, 0f64); assert_eq!(t.tests, 0u64); assert_eq!(t.errors, 0u64); assert_eq!(t.failures, 0u64); assert_eq!(t.skipped, 0u64); assert_eq!(t.name, ""); assert_eq!(t.cases.len(), 0); } #[test] /// Test a single empty-element `testsuite`, not in a `testsuites` element, /// with attributes fn no_suites_empty_test_suites_with_attributes() { let xml = r#""#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let t = &t.suites[0]; assert_eq!(t.time, 38730.23f64); assert_eq!(t.tests, 22u64); assert_eq!(t.errors, 5u64); assert_eq!(t.failures, 9u64); assert_eq!(t.skipped, 3u64); assert_eq!(t.name, "AllTests"); assert_eq!(t.cases.len(), 0); } #[test] /// Test a single start-end element `testsuite`, not in a `testsuites` element, /// with attributes fn no_suites_empty_test_suites_start_end_with_attributes() { let xml = r#""#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let t = &t.suites[0]; assert_eq!(t.time, 38730.23f64); assert_eq!(t.tests, 22u64); assert_eq!(t.errors, 5u64); assert_eq!(t.failures, 9u64); assert_eq!(t.skipped, 3u64); assert_eq!(t.name, "AllTests"); assert_eq!(t.cases.len(), 0); } #[test] /// Test a testcase in success fn test_case_success() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let ts = &t.suites[0]; assert_eq!(ts.cases.len(), 1); let tc = &ts.cases[0]; assert_eq!(tc.time, 12.34f64); assert_eq!(tc.name, "bar"); assert!(tc.status.is_success()); } #[test] /// Test a testcase in error with empty-element `error` fn test_case_error_empty() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let ts = &t.suites[0]; assert_eq!(ts.cases.len(), 1); let tc = &ts.cases[0]; assert_eq!(tc.time, 12.34f64); assert_eq!(tc.name, "bar"); assert!(tc.status.is_error()); } #[test] /// Test a testcase in error with empty-element `error` with messages attribute fn test_case_error_message() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let ts = &t.suites[0]; assert_eq!(ts.cases.len(), 1); let tc = &ts.cases[0]; assert_eq!(tc.time, 12.34f64); assert_eq!(tc.name, "bar"); assert!(tc.status.is_error()); let te = tc.status.error_as_ref(); assert_eq!(te.error_type, "error"); assert_eq!(te.message, "exception raised"); } #[test] /// Test a testcase in error with messages attribute and content fn test_case_error_message_text() { let xml = r#" foo::bar asserted! "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let ts = &t.suites[0]; assert_eq!(ts.cases.len(), 1); let tc = &ts.cases[0]; assert_eq!(tc.time, 12.34f64); assert_eq!(tc.name, "bar"); assert!(tc.status.is_error()); let te = tc.status.error_as_ref(); assert_eq!(te.error_type, "error"); assert_eq!(te.message, "exception raised"); assert_eq!(te.text, "foo::bar asserted!"); } #[test] /// Test a testcase in failure with empty-element `failure` fn test_case_failure_empty() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let ts = &t.suites[0]; assert_eq!(ts.cases.len(), 1); let tc = &ts.cases[0]; assert_eq!(tc.time, 12.34f64); assert_eq!(tc.name, "bar"); assert!(tc.status.is_failure()); } #[test] /// Test a testcase in failure with empty-element `failure` with messages attribute fn test_case_failure_message() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let ts = &t.suites[0]; assert_eq!(ts.cases.len(), 1); let tc = &ts.cases[0]; assert_eq!(tc.time, 12.34f64); assert_eq!(tc.name, "bar"); assert!(tc.status.is_failure()); let te = tc.status.failure_as_ref(); assert_eq!(te.failure_type, "failure"); assert_eq!(te.message, "test failed"); } #[test] /// Test a testcase in failure with messages attribute and content fn test_case_failure_message_text() { let xml = r#" foo::bar failed! "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let ts = &t.suites[0]; assert_eq!(ts.cases.len(), 1); let tc = &ts.cases[0]; assert_eq!(tc.time, 12.34f64); assert_eq!(tc.name, "bar"); assert!(tc.status.is_failure()); let te = tc.status.failure_as_ref(); assert_eq!(te.failure_type, "failure"); assert_eq!(te.message, "test failed"); assert_eq!(te.text, "foo::bar failed!"); } #[test] /// Test a skipped testcase with empty-element `skipped` with messages attribute fn test_case_skipped_empty() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); debug_assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let ts = &t.suites[0]; assert_eq!(ts.cases.len(), 1); let tc = &ts.cases[0]; assert_eq!(tc.time, 12.34f64); assert_eq!(tc.name, "bar"); assert!(tc.status.is_skipped()); } #[test] /// Test a skipped testcase with empty-element `skipped` with messages attribute fn test_case_skipped_message() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let ts = &t.suites[0]; assert_eq!(ts.cases.len(), 1); let tc = &ts.cases[0]; assert_eq!(tc.time, 12.34f64); assert_eq!(tc.name, "bar"); assert!(tc.status.is_skipped()); let te = tc.status.skipped_as_ref(); assert_eq!(te.skipped_type, "skipped"); assert_eq!(te.message, "test skipped"); } #[test] /// Test a skipped testcase with messages attribute and content fn test_case_skipped_message_text() { let xml = r#" foo::bar skipped for some reason "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let t = r.unwrap(); assert_eq!(t.suites.len(), 1); let ts = &t.suites[0]; assert_eq!(ts.cases.len(), 1); let tc = &ts.cases[0]; assert_eq!(tc.time, 12.34f64); assert_eq!(tc.name, "bar"); assert!(tc.status.is_skipped()); let te = tc.status.skipped_as_ref(); assert_eq!(te.skipped_type, "skipped"); assert_eq!(te.message, "test skipped"); assert_eq!(te.text, "foo::bar skipped for some reason"); } #[test] /// Duplicate test suites are all stored fn test_duplicate_suites() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let tss = r.unwrap(); assert_eq!(tss.suites.len(), 2); let ts = &tss.suites[0]; assert_eq!(ts.name, "foo"); assert_eq!(ts.errors, 1); let ts = &tss.suites[1]; assert_eq!(ts.name, "foo"); assert_eq!(ts.errors, 2); } #[test] /// Duplicate test cases are all stored fn test_duplicate_cases() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let tss = r.unwrap(); assert_eq!(tss.suites.len(), 1); let ts = &tss.suites[0]; assert_eq!(ts.cases.len(), 4); let tc = &ts.cases[0]; assert_eq!(tc.name, "foo"); assert!(tc.status.is_success()); let tc = &ts.cases[1]; assert_eq!(tc.name, "foo"); assert!(tc.status.is_error()); let tc = &ts.cases[2]; assert_eq!(tc.name, "foo"); assert!(tc.status.is_failure()); let tc = &ts.cases[3]; assert_eq!(tc.name, "foo"); assert!(tc.status.is_skipped()); } #[test] /// Test optional TestSuite attributes fn test_optional_test_suite_attributes() { let xml = r#" "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let tss = r.unwrap(); assert_eq!(tss.suites.len(), 1); let ts = &tss.suites[0]; assert_eq!(ts.assertions, Some(42)); assert_eq!(ts.timestamp, Some("2023-09-14T23:43:28+02:00".to_string())); assert_eq!(ts.hostname, Some("mycomputer.local".to_string())); assert_eq!(ts.id, Some("TestSuiteId".to_string())); assert_eq!(ts.package, Some("TestPackage".to_string())); assert_eq!(ts.file, Some("test.rs".to_string())); assert_eq!(ts.log, Some("mylog".to_string())); assert_eq!(ts.url, Some("test://my.test/".to_string())); assert_eq!(ts.version, Some("3.1459".to_string())); } #[test] /// Test with multiple test cases /// Also test parsing TestCase's attributes `classname`, `group`, /// `file` and `line` fn test_large_test_suite() { let xml = r#" details about failure "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let tss = r.unwrap(); assert_eq!(tss.suites.len(), 1); let ts = &tss.suites[0]; assert_eq!(ts.cases.len(), 3); let tc = &ts.cases[0]; assert_eq!(tc.original_name, "ASuccessfulTest"); assert_eq!(tc.classname, Some("foo1".to_string())); assert_eq!(tc.name, "foo1::ASuccessfulTest"); assert_eq!(tc.group, Some("gr1".to_string())); assert!(tc.status.is_success()); let tc = &ts.cases[1]; assert_eq!(tc.original_name, "AnotherSuccessfulTest"); assert_eq!(tc.classname, None); assert_eq!(tc.name, "gr2::AnotherSuccessfulTest"); assert_eq!(tc.group, Some("gr2".to_string())); assert!(tc.status.is_success()); let tc = &ts.cases[2]; assert_eq!(tc.original_name, "AFailingTest"); assert_eq!(tc.classname, Some("foo3".to_string())); assert_eq!(tc.name, "foo3::AFailingTest"); assert_eq!(tc.group, None); assert_eq!(tc.file, Some("foo.rs".to_string())); assert_eq!(tc.line, Some(63)); assert!(tc.status.is_failure()); let tf = tc.status.failure_as_ref(); assert_eq!(tf.failure_type, "NotEnoughFoo"); assert_eq!(tf.message, ""); assert_eq!(tf.text, "details about failure"); } #[test] /// Test with multiple `testsuite` fn test_large_test_suites() { let xml = r#" details about failure details about failure "#; let cursor = Cursor::new(xml); let r = junit_parser::from_reader(cursor); assert!(r.is_ok()); let tss = r.unwrap(); assert_eq!(tss.suites.len(), 2); let ts = &tss.suites[0]; assert_eq!(ts.cases.len(), 3); let tc = &ts.cases[0]; assert_eq!(tc.original_name, "ASuccessfulTest"); assert!(tc.status.is_success()); let tc = &ts.cases[1]; assert_eq!(tc.original_name, "AnotherSuccessfulTest"); assert!(tc.status.is_success()); let tc = &ts.cases[2]; assert_eq!(tc.original_name, "AFailingTest"); assert!(tc.status.is_failure()); let tf = tc.status.failure_as_ref(); assert_eq!(tf.failure_type, "NotEnoughFoo"); assert_eq!(tf.message, ""); assert_eq!(tf.text, "details about failure"); let ts = &tss.suites[1]; assert_eq!(ts.cases.len(), 3); let tc = &ts.cases[0]; assert_eq!(tc.original_name, "ASuccessfulTest"); assert!(tc.status.is_success()); let tc = &ts.cases[1]; assert_eq!(tc.original_name, "AnotherSuccessfulTest"); assert!(tc.status.is_success()); let tc = &ts.cases[2]; assert_eq!(tc.original_name, "AFailingTest"); assert!(tc.status.is_failure()); let tf = tc.status.failure_as_ref(); assert_eq!(tf.failure_type, "NotEnoughBar"); assert_eq!(tf.message, ""); assert_eq!(tf.text, "details about failure"); } #[test] /// Test that unknown tags are skipped fn test_large_test_suites_added_tags() { let xml = r#"