allure_core/
enums.rs

1//! Allure enums for test result status, stage, severity, and other classifications.
2
3use serde::{Deserialize, Serialize};
4use std::fmt;
5
6/// Test result status indicating the outcome of a test.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
8#[serde(rename_all = "lowercase")]
9#[non_exhaustive]
10pub enum Status {
11    /// Test passed successfully
12    Passed,
13    /// Test failed due to assertion failure (product defect)
14    Failed,
15    /// Test broken due to unexpected error (test defect)
16    Broken,
17    /// Test was skipped
18    Skipped,
19    /// Test status is unknown
20    #[default]
21    Unknown,
22}
23
24impl fmt::Display for Status {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        match self {
27            Status::Passed => write!(f, "passed"),
28            Status::Failed => write!(f, "failed"),
29            Status::Broken => write!(f, "broken"),
30            Status::Skipped => write!(f, "skipped"),
31            Status::Unknown => write!(f, "unknown"),
32        }
33    }
34}
35
36/// Test execution stage.
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
38#[serde(rename_all = "lowercase")]
39#[non_exhaustive]
40pub enum Stage {
41    /// Test is scheduled but not started
42    Scheduled,
43    /// Test is currently running
44    Running,
45    /// Test has finished execution
46    #[default]
47    Finished,
48    /// Test is pending
49    Pending,
50    /// Test was interrupted
51    Interrupted,
52}
53
54impl fmt::Display for Stage {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        match self {
57            Stage::Scheduled => write!(f, "scheduled"),
58            Stage::Running => write!(f, "running"),
59            Stage::Finished => write!(f, "finished"),
60            Stage::Pending => write!(f, "pending"),
61            Stage::Interrupted => write!(f, "interrupted"),
62        }
63    }
64}
65
66/// Test severity level for prioritization.
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
68#[serde(rename_all = "lowercase")]
69#[non_exhaustive]
70pub enum Severity {
71    /// System is unusable, blocker issue
72    Blocker,
73    /// Major functionality is broken
74    Critical,
75    /// Standard test importance
76    #[default]
77    Normal,
78    /// Minor issues
79    Minor,
80    /// Cosmetic or trivial issues
81    Trivial,
82}
83
84impl Severity {
85    /// Returns the string representation used in Allure labels.
86    pub fn as_str(&self) -> &'static str {
87        match self {
88            Severity::Blocker => "blocker",
89            Severity::Critical => "critical",
90            Severity::Normal => "normal",
91            Severity::Minor => "minor",
92            Severity::Trivial => "trivial",
93        }
94    }
95}
96
97impl fmt::Display for Severity {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        write!(f, "{}", self.as_str())
100    }
101}
102
103/// Link type for external references.
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
105#[serde(rename_all = "lowercase")]
106#[non_exhaustive]
107pub enum LinkType {
108    /// Default link type
109    #[default]
110    #[serde(rename = "link")]
111    Default,
112    /// Link to issue tracker
113    Issue,
114    /// Link to test management system
115    Tms,
116}
117
118impl fmt::Display for LinkType {
119    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120        match self {
121            LinkType::Default => write!(f, "link"),
122            LinkType::Issue => write!(f, "issue"),
123            LinkType::Tms => write!(f, "tms"),
124        }
125    }
126}
127
128/// Parameter display mode in reports.
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
130#[serde(rename_all = "lowercase")]
131#[non_exhaustive]
132pub enum ParameterMode {
133    /// Show parameter value as-is
134    #[default]
135    Default,
136    /// Hide parameter value completely
137    Hidden,
138    /// Mask parameter value (e.g., for passwords)
139    Masked,
140}
141
142impl fmt::Display for ParameterMode {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        match self {
145            ParameterMode::Default => write!(f, "default"),
146            ParameterMode::Hidden => write!(f, "hidden"),
147            ParameterMode::Masked => write!(f, "masked"),
148        }
149    }
150}
151
152/// Content type for attachments.
153#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
154#[serde(rename_all = "lowercase")]
155#[non_exhaustive]
156pub enum ContentType {
157    /// Plain text content
158    #[default]
159    Text,
160    /// JSON content
161    Json,
162    /// XML content
163    Xml,
164    /// HTML content
165    Html,
166    /// CSV (comma-separated values) content
167    Csv,
168    /// TSV (tab-separated values) content
169    Tsv,
170    /// CSS stylesheet content
171    Css,
172    /// URI list content
173    Uri,
174    /// SVG image content
175    Svg,
176    /// PNG image content
177    Png,
178    /// JPEG image content
179    Jpeg,
180    /// WebM video content
181    Webm,
182    /// MP4 video content
183    Mp4,
184    /// ZIP archive content
185    Zip,
186    /// Allure image diff content
187    #[serde(rename = "imagediff")]
188    ImageDiff,
189}
190
191impl ContentType {
192    /// Returns the MIME type string.
193    pub fn as_mime(&self) -> &'static str {
194        match self {
195            ContentType::Text => "text/plain",
196            ContentType::Json => "application/json",
197            ContentType::Xml => "application/xml",
198            ContentType::Html => "text/html",
199            ContentType::Csv => "text/csv",
200            ContentType::Tsv => "text/tab-separated-values",
201            ContentType::Css => "text/css",
202            ContentType::Uri => "text/uri-list",
203            ContentType::Svg => "image/svg+xml",
204            ContentType::Png => "image/png",
205            ContentType::Jpeg => "image/jpeg",
206            ContentType::Webm => "video/webm",
207            ContentType::Mp4 => "video/mp4",
208            ContentType::Zip => "application/zip",
209            ContentType::ImageDiff => "application/vnd.allure.image.diff",
210        }
211    }
212
213    /// Returns the file extension for this content type.
214    pub fn extension(&self) -> &'static str {
215        match self {
216            ContentType::Text => "txt",
217            ContentType::Json => "json",
218            ContentType::Xml => "xml",
219            ContentType::Html => "html",
220            ContentType::Csv => "csv",
221            ContentType::Tsv => "tsv",
222            ContentType::Css => "css",
223            ContentType::Uri => "uri",
224            ContentType::Svg => "svg",
225            ContentType::Png => "png",
226            ContentType::Jpeg => "jpg",
227            ContentType::Webm => "webm",
228            ContentType::Mp4 => "mp4",
229            ContentType::Zip => "zip",
230            ContentType::ImageDiff => "imagediff",
231        }
232    }
233}
234
235impl fmt::Display for ContentType {
236    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237        write!(f, "{}", self.as_mime())
238    }
239}
240
241/// Reserved label names used by Allure for special purposes.
242#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
243#[non_exhaustive]
244pub enum LabelName {
245    /// Allure test case ID (AS_ID)
246    #[serde(rename = "AS_ID")]
247    AllureId,
248    /// Test suite name
249    #[serde(rename = "suite")]
250    Suite,
251    /// Parent suite name
252    #[serde(rename = "parentSuite")]
253    ParentSuite,
254    /// Sub-suite name
255    #[serde(rename = "subSuite")]
256    SubSuite,
257    /// Epic (top-level business capability)
258    #[serde(rename = "epic")]
259    Epic,
260    /// Feature under epic
261    #[serde(rename = "feature")]
262    Feature,
263    /// User story under feature
264    #[serde(rename = "story")]
265    Story,
266    /// Test severity
267    #[serde(rename = "severity")]
268    Severity,
269    /// Test tag
270    #[default]
271    #[serde(rename = "tag")]
272    Tag,
273    /// Test owner/maintainer
274    #[serde(rename = "owner")]
275    Owner,
276    /// Execution host
277    #[serde(rename = "host")]
278    Host,
279    /// Thread ID
280    #[serde(rename = "thread")]
281    Thread,
282    /// Test method name
283    #[serde(rename = "testMethod")]
284    TestMethod,
285    /// Test class name
286    #[serde(rename = "testClass")]
287    TestClass,
288    /// Package/module name
289    #[serde(rename = "package")]
290    Package,
291    /// Test framework name
292    #[serde(rename = "framework")]
293    Framework,
294    /// Programming language
295    #[serde(rename = "language")]
296    Language,
297}
298
299impl LabelName {
300    /// Returns the string name used in Allure JSON.
301    pub fn as_str(&self) -> &'static str {
302        match self {
303            LabelName::AllureId => "AS_ID",
304            LabelName::Suite => "suite",
305            LabelName::ParentSuite => "parentSuite",
306            LabelName::SubSuite => "subSuite",
307            LabelName::Epic => "epic",
308            LabelName::Feature => "feature",
309            LabelName::Story => "story",
310            LabelName::Severity => "severity",
311            LabelName::Tag => "tag",
312            LabelName::Owner => "owner",
313            LabelName::Host => "host",
314            LabelName::Thread => "thread",
315            LabelName::TestMethod => "testMethod",
316            LabelName::TestClass => "testClass",
317            LabelName::Package => "package",
318            LabelName::Framework => "framework",
319            LabelName::Language => "language",
320        }
321    }
322}
323
324impl fmt::Display for LabelName {
325    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326        write!(f, "{}", self.as_str())
327    }
328}
329
330#[cfg(test)]
331mod tests {
332    use super::*;
333
334    #[test]
335    fn test_status_serialization() {
336        assert_eq!(
337            serde_json::to_string(&Status::Passed).unwrap(),
338            "\"passed\""
339        );
340        assert_eq!(
341            serde_json::to_string(&Status::Failed).unwrap(),
342            "\"failed\""
343        );
344        assert_eq!(
345            serde_json::to_string(&Status::Broken).unwrap(),
346            "\"broken\""
347        );
348        assert_eq!(
349            serde_json::to_string(&Status::Skipped).unwrap(),
350            "\"skipped\""
351        );
352        assert_eq!(
353            serde_json::to_string(&Status::Unknown).unwrap(),
354            "\"unknown\""
355        );
356    }
357
358    #[test]
359    fn test_stage_serialization() {
360        assert_eq!(
361            serde_json::to_string(&Stage::Finished).unwrap(),
362            "\"finished\""
363        );
364        assert_eq!(
365            serde_json::to_string(&Stage::Running).unwrap(),
366            "\"running\""
367        );
368    }
369
370    #[test]
371    fn test_severity_as_str() {
372        assert_eq!(Severity::Blocker.as_str(), "blocker");
373        assert_eq!(Severity::Critical.as_str(), "critical");
374        assert_eq!(Severity::Normal.as_str(), "normal");
375    }
376
377    #[test]
378    fn test_content_type_mime() {
379        assert_eq!(ContentType::Json.as_mime(), "application/json");
380        assert_eq!(ContentType::Png.as_mime(), "image/png");
381    }
382
383    #[test]
384    fn test_label_name_as_str() {
385        assert_eq!(LabelName::Epic.as_str(), "epic");
386        assert_eq!(LabelName::AllureId.as_str(), "AS_ID");
387        assert_eq!(LabelName::ParentSuite.as_str(), "parentSuite");
388    }
389
390    #[test]
391    fn test_status_display() {
392        assert_eq!(format!("{}", Status::Passed), "passed");
393        assert_eq!(format!("{}", Status::Failed), "failed");
394        assert_eq!(format!("{}", Status::Broken), "broken");
395    }
396
397    #[test]
398    fn test_stage_display() {
399        assert_eq!(format!("{}", Stage::Running), "running");
400        assert_eq!(format!("{}", Stage::Finished), "finished");
401    }
402
403    #[test]
404    fn test_severity_display() {
405        assert_eq!(format!("{}", Severity::Critical), "critical");
406        assert_eq!(format!("{}", Severity::Blocker), "blocker");
407    }
408
409    #[test]
410    fn test_link_type_display() {
411        assert_eq!(format!("{}", LinkType::Issue), "issue");
412        assert_eq!(format!("{}", LinkType::Tms), "tms");
413        assert_eq!(format!("{}", LinkType::Default), "link");
414    }
415
416    #[test]
417    fn test_parameter_mode_display() {
418        assert_eq!(format!("{}", ParameterMode::Default), "default");
419        assert_eq!(format!("{}", ParameterMode::Hidden), "hidden");
420        assert_eq!(format!("{}", ParameterMode::Masked), "masked");
421    }
422
423    #[test]
424    fn test_content_type_display() {
425        assert_eq!(format!("{}", ContentType::Json), "application/json");
426        assert_eq!(format!("{}", ContentType::Png), "image/png");
427    }
428
429    #[test]
430    fn test_label_name_display() {
431        assert_eq!(format!("{}", LabelName::Epic), "epic");
432        assert_eq!(format!("{}", LabelName::AllureId), "AS_ID");
433    }
434
435    #[test]
436    fn test_stage_pending_and_interrupted_display() {
437        assert_eq!(format!("{}", Stage::Pending), "pending");
438        assert_eq!(format!("{}", Stage::Interrupted), "interrupted");
439    }
440
441    #[test]
442    fn test_content_type_extension_and_image_diff() {
443        assert_eq!(ContentType::ImageDiff.extension(), "imagediff");
444        assert_eq!(ContentType::Zip.extension(), "zip");
445    }
446
447    #[test]
448    fn test_severity_minor_and_trivial() {
449        assert_eq!(Severity::Minor.to_string(), "minor");
450        assert_eq!(Severity::Trivial.to_string(), "trivial");
451    }
452
453    #[test]
454    fn test_status_and_stage_cover_all_variants() {
455        assert_eq!(Status::Skipped.to_string(), "skipped");
456        assert_eq!(Status::Unknown.to_string(), "unknown");
457        assert_eq!(Stage::Scheduled.to_string(), "scheduled");
458    }
459
460    #[test]
461    fn test_content_type_mime_and_extension_variants() {
462        assert_eq!(ContentType::Tsv.as_mime(), "text/tab-separated-values");
463        assert_eq!(ContentType::Css.as_mime(), "text/css");
464        assert_eq!(ContentType::Uri.extension(), "uri");
465        assert_eq!(ContentType::Svg.extension(), "svg");
466    }
467
468    #[test]
469    fn test_label_name_as_str_additional_variants() {
470        assert_eq!(LabelName::Package.as_str(), "package");
471        assert_eq!(LabelName::TestClass.as_str(), "testClass");
472        assert_eq!(LabelName::TestMethod.as_str(), "testMethod");
473    }
474}