Skip to main content

mantra_schema/report/
test_case.rs

1use relative_path::RelativePathBuf;
2
3use crate::{
4    Properties,
5    encoding::TargetEncoding,
6    product::ProductId,
7    report::{
8        product::ProductMetadata,
9        review::ReviewReference,
10        test_run::TestRunReference,
11        tests::{TestCoverage, TestRelatedRequirement, TestState},
12    },
13    test_runs::{LogOutput, TestCaseLocation},
14};
15
16#[derive(
17    Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
18)]
19#[serde(rename_all = "snake_case")]
20pub struct TestCaseReference {
21    pub product_id: ProductId,
22    pub test_run_name: String,
23    #[serde(with = "time::serde::iso8601")]
24    #[schemars(with = "String")]
25    pub test_run_date: time::OffsetDateTime,
26    pub test_case_name: String,
27    pub state: TestState,
28}
29
30impl TestCaseReference {
31    pub fn url_path(&self) -> RelativePathBuf {
32        self.encode_path(TargetEncoding::Url)
33    }
34
35    pub fn os_path(&self) -> RelativePathBuf {
36        self.encode_path(TargetEncoding::Os)
37    }
38
39    fn encode_path(&self, target: TargetEncoding) -> RelativePathBuf {
40        let test_run = TestRunReference {
41            product_id: self.product_id.clone(),
42            name: self.test_run_name.clone(),
43            utc_date: self.test_run_date,
44            state: TestState::Unknown,
45        };
46
47        let limit_test_case_name = crate::encoding::limit_str_len(&self.test_case_name);
48
49        // Note: A limited name will be a base16 hash, and therefore not contain '::'
50        let test_case_path = if limit_test_case_name.contains("::") {
51            RelativePathBuf::from_iter(
52                limit_test_case_name
53                    .split("::")
54                    .map(|name| crate::encoding::encode(name, target).to_string()),
55            )
56        } else {
57            RelativePathBuf::from(
58                crate::encoding::encode(&limit_test_case_name, target).to_string(),
59            )
60        };
61
62        let test_run_path = match target {
63            TargetEncoding::Os => test_run.os_path(),
64            TargetEncoding::Url => test_run.url_path(),
65        };
66
67        test_run_path.join(test_case_path)
68    }
69}
70
71/// Represents a test case in *mantra*.
72/// [req("testcov.test_case")]
73#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
74#[serde(rename_all = "snake_case")]
75pub struct TestCaseReportSchema {
76    /// The schema version.
77    /// [req("exchange.versioned")]
78    #[serde(serialize_with = "crate::serialize_schema_version")]
79    pub schema_version: Option<String>,
80    pub product: ProductMetadata,
81    pub test_run: TestRunReference,
82    /// The name of the test case.
83    /// [req("testcov.test_case.id")]
84    pub name: String,
85    /// Optional description of the test case.
86    pub description: Option<String>,
87    /// State of the test case.
88    /// [req("testcov.test_case.state")]
89    pub state: TestState,
90    /// Optional reason for the test case state.
91    /// [req("testcov.test_case.state.reason")]
92    pub state_properties: Option<Properties>,
93    /// Optional location of the test case.
94    /// [req("testcov.test_case.origin")]
95    pub location: Option<TestCaseLocation>,
96    /// Optional UTC date the test case execution started.
97    ///
98    /// **Note:** The date must be given in ISO8601 format.
99    #[serde(with = "time::serde::iso8601::option")]
100    #[schemars(with = "String")]
101    #[serde(default)] // Needed due to: https://github.com/serde-rs/serde/issues/2878
102    pub utc_date: Option<time::OffsetDateTime>,
103    /// Optional duration about how long the test case took.
104    #[schemars(with = "String")]
105    #[serde(with = "crate::test_runs::duration_as_saturating_seconds_f64", default)]
106    pub duration_sec: Option<time::Duration>,
107    /// Optional field to store custom properties per test case.
108    /// [req("testcov.test_case.metadata")]
109    pub properties: Option<Properties>,
110    /// Optional logs that were output during the test case execution.
111    // TODO: add req
112    pub logs: Option<Vec<LogOutput>>,
113    /// Optional list of coverage data per file that was collected during the execution of the test case.
114    /// [req("testcov.cov")]
115    pub coverage: Option<TestCoverage>,
116    pub related_reqs: Option<Vec<TestRelatedRequirement>>,
117    pub overridden_by: Option<Vec<ReviewReference>>,
118}