junitify 0.1.18

Takes cargo test JSON and transform to JUnit XML
//     junitify - Takes cargo test JSON and transform to JUnit XML
//
//         The MIT License (MIT)
//
//      Copyright (c) KoresFramework (https://gitlab.com/Kores/)
//      Copyright (c) contributors
//
//      Permission is hereby granted, free of charge, to any person obtaining a copy
//      of this software and associated documentation files (the "Software"), to deal
//      in the Software without restriction, including without limitation the rights
//      to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//      copies of the Software, and to permit persons to whom the Software is
//      furnished to do so, subject to the following conditions:
//
//      The above copyright notice and this permission notice shall be included in
//      all copies or substantial portions of the Software.
//
//      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//      OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//      THE SOFTWARE.
use crate::test_parser::{ParsedTest, TestStatus};
use crate::{ParsedTestSuite, TestParser};
use serde;
use serde::{Deserialize, Serialize};
use serde_xml_rs::Error;

#[derive(Deserialize, Serialize, Debug, PartialEq)]
#[serde(rename = "testsuite")]
pub(crate) struct TestSuite {
    pub(crate) name: String,
    pub(crate) tests: usize,
    pub(crate) skipped: usize,
    pub(crate) failures: usize,
    pub(crate) errors: usize,
    pub(crate) timestamp: String,
    pub(crate) hostname: String,
    pub(crate) time: f64,
    #[serde(rename = "testcase")]
    pub(crate) test_cases: Option<Vec<TestCase>>,
    #[serde(rename = "system-out")]
    pub(crate) std_out: Option<String>,
    #[serde(rename = "system-err")]
    pub(crate) std_err: Option<String>,
}

#[derive(Deserialize, Serialize, Debug, PartialEq)]
#[serde(rename = "testcase")]
pub(crate) struct TestCase {
    pub(crate) name: String,
    pub(crate) classname: String,
    pub(crate) time: f64,
    pub(crate) failure: Option<Failure>,
}

#[derive(Deserialize, Serialize, Debug, PartialEq)]
#[serde(rename = "failure")]
pub(crate) struct Failure {
    pub(crate) message: String,
    #[serde(rename = "$value")]
    pub(crate) content: Option<String>,
}

/// A parser for JUnit tests, only supports the tests generated by junitify.
pub(crate) struct JUnitTestParser {}

impl JUnitTestParser {
    pub(crate) fn new() -> Self {
        Self {}
    }
}

impl TestParser for JUnitTestParser {
    type Error = Error;

    fn multi_line(&self) -> bool {
        false
    }

    fn parse(&mut self, text: &str) -> Result<Option<ParsedTestSuite>, Error> {
        let test_suite: TestSuite = serde_xml_rs::from_str(text)?;

        let tests = test_suite
            .test_cases
            .map(|v| {
                v.iter()
                    .map(|e| ParsedTest {
                        full_name: e.name.clone(),
                        name: e.name.clone(),
                        module: Some(e.classname.clone()),
                        exec_time: Some(e.time),
                        status: e
                            .failure
                            .as_ref()
                            .map(|_| TestStatus::Failed)
                            .unwrap_or(TestStatus::Ok),
                        std_out: e.failure.as_ref().map(|e| e.content.clone()).flatten(),
                    })
                    .collect::<Vec<_>>()
            })
            .unwrap_or(vec![]);

        Ok(Some(ParsedTestSuite {
            suite_name: test_suite.name,
            test_count: test_suite.tests,
            passed: test_suite.tests - test_suite.failures,
            failed: test_suite.failures,
            errors: test_suite.errors,
            allowed_fail: 0,
            ignored: test_suite.skipped,
            measured: 0,
            filtered_out: 0,
            exec_time: test_suite.time,
            tests,
        }))
    }

    fn reset(&mut self) {}
}