supercov_engine/
test_kind.rs1const KINDS: &[(&str, &[&str])] = &[
9 ("unit", &["unit"]),
10 ("component", &["component", "components", "ct"]),
11 ("integration", &["integration", "int", "requests"]),
12 ("e2e", &["e2e", "end-to-end", "offline", "online"]),
13];
14
15const DIRECTORIES: &[(&str, &str)] = &[("system", "e2e"), ("features", "e2e")];
17
18fn segment_kind(segment: &str) -> Option<&'static str> {
21 let mut spaced = String::new();
23 let mut previous: Option<char> = None;
24 for character in segment.chars() {
25 if character.is_ascii_uppercase()
26 && previous.is_some_and(|before| before.is_ascii_lowercase() || before.is_ascii_digit())
27 {
28 spaced.push(' ');
29 }
30 spaced.push(if matches!(character, '_' | '.') {
31 ' '
32 } else {
33 character.to_ascii_lowercase()
34 });
35 previous = Some(character);
36 }
37 let spaced = spaced.replace("end-to-end", "end~to~end").replace('-', " ");
38 let mut best = None;
39 for (position, word) in spaced.split(' ').enumerate() {
40 let word = word.replace('~', "-");
41 if let Some((kind, _)) = KINDS
42 .iter()
43 .find(|(_, words)| words.contains(&word.as_str()))
44 {
45 best = Some((position, *kind));
46 }
47 }
48 best.map(|(_, kind)| kind)
49}
50
51pub fn from_tags(tags: &[String]) -> Option<&'static str> {
54 tags.iter().find_map(
55 |tag| match tag.trim_start_matches('@').to_ascii_lowercase().as_str() {
56 "unit" => Some("unit"),
57 "component" => Some("component"),
58 "integration" => Some("integration"),
59 "e2e" => Some("e2e"),
60 _ => None,
61 },
62 )
63}
64
65pub fn with_tags(file: Option<&str>, tags: &[String]) -> &'static str {
67 from_tags(tags).unwrap_or_else(|| from_path(file))
68}
69
70pub fn from_path(file: Option<&str>) -> &'static str {
71 let Some(file) = file else {
72 return "unit";
73 };
74 let segments = file.split(['/', '\\']).collect::<Vec<_>>();
75 let (name, directories) = segments.split_last().unwrap_or((&"", &[]));
76 directories
77 .iter()
78 .rev()
79 .find_map(|directory| {
80 DIRECTORIES
81 .iter()
82 .find(|(name, _)| directory.eq_ignore_ascii_case(name))
83 .map(|(_, kind)| *kind)
84 .or_else(|| segment_kind(directory))
85 })
86 .or_else(|| segment_kind(name))
87 .unwrap_or("unit")
88}
89
90#[cfg(test)]
91mod tests {
92 use super::{from_path, from_tags, with_tags};
93
94 #[test]
95 fn a_tag_naming_a_level_is_the_kind_and_outranks_the_path() {
96 let tags = |values: &[&str]| {
97 values
98 .iter()
99 .map(|value| value.to_string())
100 .collect::<Vec<_>>()
101 };
102 assert_eq!(from_tags(&tags(&["api", "@E2E"])), Some("e2e"));
103 assert_eq!(from_tags(&tags(&["api", "smoke"])), None);
104 assert_eq!(
105 with_tags(Some("spec/models/a_spec.rb"), &tags(&["integration"])),
106 "integration"
107 );
108 assert_eq!(
109 with_tags(Some("test/e2e/a_test.py"), &tags(&["api"])),
110 "e2e"
111 );
112 }
113
114 #[test]
115 fn a_test_is_the_kind_its_directory_names() {
116 assert_eq!(from_path(Some("test/system/composer_test.rb")), "e2e");
117 assert_eq!(from_path(Some("spec/features/sign_in_spec.rb")), "e2e");
118 assert_eq!(
119 from_path(Some("spec/requests/rooms_spec.rb")),
120 "integration"
121 );
122 assert_eq!(
123 from_path(Some("tests/integration/test_api.py")),
124 "integration"
125 );
126 assert_eq!(from_path(Some("tests/e2e/test_flow.py")), "e2e");
127 assert_eq!(from_path(Some("test/models/user_test.rb")), "unit");
128 assert_eq!(from_path(Some("tests/e2e/unit/test_x.py")), "unit");
130 assert_eq!(from_path(Some("tests/test_checkout_e2e.py")), "e2e");
131 assert_eq!(from_path(Some("tests/end-to-end/test_x.py")), "e2e");
132 assert_eq!(
133 from_path(Some("spec/apiIntegration_spec.rb")),
134 "integration"
135 );
136 assert_eq!(from_path(Some("tests/interior/test_x.py")), "unit");
138 assert_eq!(from_path(None), "unit");
139 }
140}