xref: /aosp_15_r20/development/tools/external_crates/test_mapping/src/json.rs (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1 // Copyright (C) 2024 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Representation of a TEST_MAPPING JSON file.
16 
17 use std::collections::BTreeSet;
18 
19 use serde::{Deserialize, Serialize};
20 
21 use crate::TestMappingError;
22 
23 #[derive(Serialize, Deserialize, Default, Debug)]
24 pub(crate) struct TestMappingJson {
25     #[serde(default, skip_serializing_if = "Vec::is_empty")]
26     pub imports: Vec<TestMappingPath>,
27     #[serde(default, skip_serializing_if = "Vec::is_empty")]
28     presubmit: Vec<TestMappingName>,
29     #[serde(default, skip_serializing_if = "Vec::is_empty", rename = "presubmit-rust")]
30     presubmit_rust: Vec<TestMappingName>,
31     #[serde(default, skip_serializing_if = "Vec::is_empty")]
32     postsubmit: Vec<TestMappingName>,
33 }
34 
35 #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
36 struct TestMappingName {
37     name: String,
38 }
39 
40 #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
41 pub(crate) struct TestMappingPath {
42     pub path: String,
43 }
44 
45 impl TestMappingJson {
parse(mut contents: String) -> Result<TestMappingJson, TestMappingError>46     pub fn parse(mut contents: String) -> Result<TestMappingJson, TestMappingError> {
47         let contents = contents.as_mut_str();
48         // Comments are not part of the JSON spec (although they are often used), and Serde won't parse them.
49         json_strip_comments::strip(contents).map_err(TestMappingError::StripJsonCommentsError)?;
50         let parsed: TestMappingJson = serde_json::from_str(contents)?;
51         Ok(parsed)
52     }
is_empty(&self) -> bool53     pub fn is_empty(&self) -> bool {
54         self.imports.is_empty()
55             && self.presubmit.is_empty()
56             && self.presubmit_rust.is_empty()
57             && self.postsubmit.is_empty()
58     }
set_presubmits(&mut self, tests: &BTreeSet<String>)59     pub fn set_presubmits(&mut self, tests: &BTreeSet<String>) {
60         self.presubmit = tests.iter().map(|t| TestMappingName { name: t.to_string() }).collect();
61         self.presubmit_rust = self.presubmit.clone();
62     }
convert_postsubmit_tests(&mut self) -> bool63     pub fn convert_postsubmit_tests(&mut self) -> bool {
64         let changed = !self.postsubmit.is_empty();
65         self.presubmit.append(&mut self.postsubmit.clone());
66         self.presubmit_rust.append(&mut self.postsubmit);
67         self.presubmit.sort();
68         self.presubmit.dedup();
69         self.presubmit_rust.sort();
70         self.presubmit_rust.dedup();
71         changed
72     }
add_new_tests_to_postsubmit(&mut self, tests: &BTreeSet<String>) -> bool73     pub fn add_new_tests_to_postsubmit(&mut self, tests: &BTreeSet<String>) -> bool {
74         let mut changed = false;
75         self.postsubmit.extend(tests.difference(&self.all_test_names()).map(|test_name| {
76             changed = true;
77             TestMappingName { name: test_name.to_string() }
78         }));
79         self.postsubmit.sort();
80         self.postsubmit.dedup();
81         changed
82     }
all_test_names(&self) -> BTreeSet<String>83     fn all_test_names(&self) -> BTreeSet<String> {
84         let mut tests = BTreeSet::new();
85         tests.extend(self.presubmit.iter().map(|t| t.name.clone()));
86         tests.extend(self.presubmit_rust.iter().map(|t| t.name.clone()));
87         tests.extend(self.postsubmit.iter().map(|t| t.name.clone()));
88         tests
89     }
90 }
91 
92 #[cfg(test)]
93 mod tests {
94     use super::*;
95 
96     static TEST_JSON: &str = r###"{
97   "imports": [
98     {
99       "path": "foo"
100     }
101   ],
102   "presubmit": [
103     {
104       "name": "bar"
105     }
106   ],
107   "presubmit-rust": [
108     {
109       "name": "baz"
110     }
111   ],
112   "postsubmit": [
113     {
114       "name": "qux"
115     }
116   ]
117 }
118 "###;
119 
120     #[test]
parse() -> Result<(), TestMappingError>121     fn parse() -> Result<(), TestMappingError> {
122         TestMappingJson::parse("{}".to_string())?;
123         TestMappingJson::parse("//comment\n{}".to_string())?;
124         TestMappingJson::parse(TEST_JSON.to_string())?;
125         assert!(TestMappingJson::parse("foo".to_string()).is_err());
126         Ok(())
127     }
128 
129     #[test]
all_test_names() -> Result<(), TestMappingError>130     fn all_test_names() -> Result<(), TestMappingError> {
131         let json = TestMappingJson::parse(TEST_JSON.to_string())?;
132         assert_eq!(
133             json.all_test_names(),
134             BTreeSet::from(["bar".to_string(), "baz".to_string(), "qux".to_string()])
135         );
136         Ok(())
137     }
138 
139     #[test]
set_presubmits() -> Result<(), TestMappingError>140     fn set_presubmits() -> Result<(), TestMappingError> {
141         let mut json = TestMappingJson::parse(TEST_JSON.to_string())?;
142         json.set_presubmits(&BTreeSet::from(["asdf".to_string()]));
143         assert_eq!(json.presubmit, vec![TestMappingName { name: "asdf".to_string() }]);
144         assert_eq!(json.presubmit, json.presubmit_rust);
145         Ok(())
146     }
147 
148     #[test]
add_new_tests_to_postsubmit() -> Result<(), TestMappingError>149     fn add_new_tests_to_postsubmit() -> Result<(), TestMappingError> {
150         let mut json = TestMappingJson::parse(TEST_JSON.to_string())?;
151         assert!(!json.add_new_tests_to_postsubmit(&BTreeSet::from(["bar".to_string()])));
152         assert!(json
153             .add_new_tests_to_postsubmit(&BTreeSet::from(["bar".to_string(), "asdf".to_string()])));
154         assert_eq!(
155             json.postsubmit,
156             vec![
157                 TestMappingName { name: "asdf".to_string() },
158                 TestMappingName { name: "qux".to_string() }
159             ]
160         );
161         Ok(())
162     }
163 
164     #[test]
is_empty() -> Result<(), TestMappingError>165     fn is_empty() -> Result<(), TestMappingError> {
166         let json = TestMappingJson::parse(TEST_JSON.to_string())?;
167         assert!(!json.is_empty());
168         assert!(TestMappingJson::default().is_empty());
169         Ok(())
170     }
171 }
172