1 /* Copyright (C) 2023 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 #include <android-base/file.h>
16 #include <android-base/test_utils.h>
17 #include <gtest/gtest.h>
18 #include <unistd.h>
19 
20 #include <string>
21 
22 #include "RustGen.h"
23 
24 namespace {
25 
26 constexpr const char* kTestSyspropFile =
27     R"(owner: Platform
28 module: "android.sysprop.PlatformProperties"
29 prop {
30     api_name: "test_double"
31     type: Double
32     prop_name: "android.test_double"
33     scope: Internal
34     access: ReadWrite
35 }
36 prop {
37     api_name: "test_int"
38     type: Integer
39     prop_name: "android.test_int"
40     scope: Public
41     access: ReadWrite
42 }
43 prop {
44     api_name: "test_string"
45     type: String
46     prop_name: "android.test.string"
47     scope: Public
48     access: Readonly
49     legacy_prop_name: "legacy.android.test.string"
50 }
51 prop {
52     api_name: "test_enum"
53     type: Enum
54     prop_name: "android.test.enum"
55     enum_values: "a|b|c|D|e|f|G"
56     scope: Internal
57     access: ReadWrite
58 }
59 prop {
60     api_name: "test_BOOLeaN"
61     type: Boolean
62     prop_name: "ro.android.test.b"
63     scope: Public
64     access: Writeonce
65 }
66 prop {
67     api_name: "android_os_test-long"
68     type: Long
69     scope: Public
70     access: ReadWrite
71 }
72 prop {
73     api_name: "test_double_list"
74     type: DoubleList
75     scope: Internal
76     access: ReadWrite
77 }
78 prop {
79     api_name: "test_list_int"
80     type: IntegerList
81     scope: Public
82     access: ReadWrite
83 }
84 prop {
85     api_name: "test_strlist"
86     type: StringList
87     scope: Public
88     access: ReadWrite
89     deprecated: true
90 }
91 prop {
92     api_name: "el"
93     type: EnumList
94     enum_values: "enu|mva|lue"
95     scope: Internal
96     access: ReadWrite
97     deprecated: true
98 }
99 )";
100 
101 constexpr const char* kExpectedPublicOutput =
102     R"(//! Autogenerated system property accessors.
103 //!
104 //! This is an autogenerated module. The module contains methods for typed access to
105 //! Android system properties.
106 
107 // Generated by the sysprop generator. DO NOT EDIT!
108 
109 use std::fmt;
110 use rustutils::system_properties::{self, error::SysPropError, parsers_formatters};
111 
112 /// Returns the value of the property 'android.test_int' if set.
113 pub fn test_int() -> std::result::Result<Option<i32>, SysPropError> {
114     let result = match system_properties::read("android.test_int") {
115         Err(e) => Err(SysPropError::FetchError(e)),
116         Ok(Some(val)) => parsers_formatters::parse(val.as_str()).map_err(SysPropError::ParseError).map(Some),
117         Ok(None) => Ok(None),
118     };
119     result
120 }
121 
122 /// Sets the value of the property 'android.test_int', returns 'Ok' if successful.
123 pub fn set_test_int(v: i32) -> std::result::Result<(), SysPropError> {
124     let value = parsers_formatters::format(&v);
125     system_properties::write("android.test_int", value.as_str()).map_err(SysPropError::SetError)
126 }
127 
128 /// Returns the value of the property 'android.test.string' if set.
129 pub fn test_string() -> std::result::Result<Option<String>, SysPropError> {
130     let result = match system_properties::read("android.test.string") {
131         Err(e) => Err(SysPropError::FetchError(e)),
132         Ok(Some(val)) => parsers_formatters::parse(val.as_str()).map_err(SysPropError::ParseError).map(Some),
133         Ok(None) => Ok(None),
134     };
135     if result.is_ok() { return result; }
136     log::debug!("Failed to fetch the original property 'android.test.string' ('{}'), falling back to the legacy one 'legacy.android.test.string'.", result.unwrap_err());
137     match system_properties::read("legacy.android.test.string") {
138         Err(e) => Err(SysPropError::FetchError(e)),
139         Ok(Some(val)) => parsers_formatters::parse(val.as_str()).map_err(SysPropError::ParseError).map(Some),
140         Ok(None) => Ok(None),
141     }
142 }
143 
144 /// Returns the value of the property 'ro.android.test.b' if set.
145 pub fn test_boo_lea_n() -> std::result::Result<Option<bool>, SysPropError> {
146     let result = match system_properties::read("ro.android.test.b") {
147         Err(e) => Err(SysPropError::FetchError(e)),
148         Ok(Some(val)) => parsers_formatters::parse_bool(val.as_str()).map_err(SysPropError::ParseError).map(Some),
149         Ok(None) => Ok(None),
150     };
151     result
152 }
153 
154 /// Sets the value of the property 'ro.android.test.b', returns 'Ok' if successful.
155 pub fn set_test_boo_lea_n(v: bool) -> std::result::Result<(), SysPropError> {
156     let value = parsers_formatters::format_bool(&v);
157     system_properties::write("ro.android.test.b", value.as_str()).map_err(SysPropError::SetError)
158 }
159 
160 /// Returns the value of the property 'android_os_test-long' if set.
161 pub fn android_os_test_long() -> std::result::Result<Option<i64>, SysPropError> {
162     let result = match system_properties::read("android_os_test-long") {
163         Err(e) => Err(SysPropError::FetchError(e)),
164         Ok(Some(val)) => parsers_formatters::parse(val.as_str()).map_err(SysPropError::ParseError).map(Some),
165         Ok(None) => Ok(None),
166     };
167     result
168 }
169 
170 /// Sets the value of the property 'android_os_test-long', returns 'Ok' if successful.
171 pub fn set_android_os_test_long(v: i64) -> std::result::Result<(), SysPropError> {
172     let value = parsers_formatters::format(&v);
173     system_properties::write("android_os_test-long", value.as_str()).map_err(SysPropError::SetError)
174 }
175 
176 /// Returns the value of the property 'test_list_int' if set.
177 pub fn test_list_int() -> std::result::Result<Option<Vec<i32>>, SysPropError> {
178     let result = match system_properties::read("test_list_int") {
179         Err(e) => Err(SysPropError::FetchError(e)),
180         Ok(Some(val)) => parsers_formatters::parse_list(val.as_str()).map_err(SysPropError::ParseError).map(Some),
181         Ok(None) => Ok(None),
182     };
183     result
184 }
185 
186 /// Sets the value of the property 'test_list_int', returns 'Ok' if successful.
187 pub fn set_test_list_int(v: &[i32]) -> std::result::Result<(), SysPropError> {
188     let value = parsers_formatters::format_list(v);
189     system_properties::write("test_list_int", value.as_str()).map_err(SysPropError::SetError)
190 }
191 
192 /// Returns the value of the property 'test_strlist' if set.
193 #[deprecated]
194 pub fn test_strlist() -> std::result::Result<Option<Vec<String>>, SysPropError> {
195     let result = match system_properties::read("test_strlist") {
196         Err(e) => Err(SysPropError::FetchError(e)),
197         Ok(Some(val)) => parsers_formatters::parse_list(val.as_str()).map_err(SysPropError::ParseError).map(Some),
198         Ok(None) => Ok(None),
199     };
200     result
201 }
202 
203 /// Sets the value of the property 'test_strlist', returns 'Ok' if successful.
204 #[deprecated]
205 pub fn set_test_strlist(v: &[String]) -> std::result::Result<(), SysPropError> {
206     let value = parsers_formatters::format_list(v);
207     system_properties::write("test_strlist", value.as_str()).map_err(SysPropError::SetError)
208 }
209 
210 )";
211 
212 constexpr const char* kExpectedInternalOutput =
213     R"(//! Autogenerated system property accessors.
214 //!
215 //! This is an autogenerated module. The module contains methods for typed access to
216 //! Android system properties.
217 
218 // Generated by the sysprop generator. DO NOT EDIT!
219 
220 use std::fmt;
221 use rustutils::system_properties::{self, error::SysPropError, parsers_formatters};
222 
223 /// Returns the value of the property 'android.test_double' if set.
224 pub fn test_double() -> std::result::Result<Option<f64>, SysPropError> {
225     let result = match system_properties::read("android.test_double") {
226         Err(e) => Err(SysPropError::FetchError(e)),
227         Ok(Some(val)) => parsers_formatters::parse(val.as_str()).map_err(SysPropError::ParseError).map(Some),
228         Ok(None) => Ok(None),
229     };
230     result
231 }
232 
233 /// Sets the value of the property 'android.test_double', returns 'Ok' if successful.
234 pub fn set_test_double(v: f64) -> std::result::Result<(), SysPropError> {
235     let value = parsers_formatters::format(&v);
236     system_properties::write("android.test_double", value.as_str()).map_err(SysPropError::SetError)
237 }
238 
239 /// Returns the value of the property 'android.test_int' if set.
240 pub fn test_int() -> std::result::Result<Option<i32>, SysPropError> {
241     let result = match system_properties::read("android.test_int") {
242         Err(e) => Err(SysPropError::FetchError(e)),
243         Ok(Some(val)) => parsers_formatters::parse(val.as_str()).map_err(SysPropError::ParseError).map(Some),
244         Ok(None) => Ok(None),
245     };
246     result
247 }
248 
249 /// Sets the value of the property 'android.test_int', returns 'Ok' if successful.
250 pub fn set_test_int(v: i32) -> std::result::Result<(), SysPropError> {
251     let value = parsers_formatters::format(&v);
252     system_properties::write("android.test_int", value.as_str()).map_err(SysPropError::SetError)
253 }
254 
255 /// Returns the value of the property 'android.test.string' if set.
256 pub fn test_string() -> std::result::Result<Option<String>, SysPropError> {
257     let result = match system_properties::read("android.test.string") {
258         Err(e) => Err(SysPropError::FetchError(e)),
259         Ok(Some(val)) => parsers_formatters::parse(val.as_str()).map_err(SysPropError::ParseError).map(Some),
260         Ok(None) => Ok(None),
261     };
262     if result.is_ok() { return result; }
263     log::debug!("Failed to fetch the original property 'android.test.string' ('{}'), falling back to the legacy one 'legacy.android.test.string'.", result.unwrap_err());
264     match system_properties::read("legacy.android.test.string") {
265         Err(e) => Err(SysPropError::FetchError(e)),
266         Ok(Some(val)) => parsers_formatters::parse(val.as_str()).map_err(SysPropError::ParseError).map(Some),
267         Ok(None) => Ok(None),
268     }
269 }
270 
271 #[allow(missing_docs)]
272 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash, Ord)]
273 pub enum TestEnumValues {
274     A,
275     B,
276     C,
277     D,
278     E,
279     F,
280     G,
281 }
282 
283 impl std::str::FromStr for TestEnumValues {
284     type Err = String;
285 
286     fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
287         match s {
288             "a" => Ok(TestEnumValues::A),
289             "b" => Ok(TestEnumValues::B),
290             "c" => Ok(TestEnumValues::C),
291             "D" => Ok(TestEnumValues::D),
292             "e" => Ok(TestEnumValues::E),
293             "f" => Ok(TestEnumValues::F),
294             "G" => Ok(TestEnumValues::G),
295             _ => Err(format!("'{}' cannot be parsed for TestEnumValues", s)),
296         }
297     }
298 }
299 
300 impl fmt::Display for TestEnumValues {
301     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302         match self {
303             TestEnumValues::A => write!(f, "a"),
304             TestEnumValues::B => write!(f, "b"),
305             TestEnumValues::C => write!(f, "c"),
306             TestEnumValues::D => write!(f, "D"),
307             TestEnumValues::E => write!(f, "e"),
308             TestEnumValues::F => write!(f, "f"),
309             TestEnumValues::G => write!(f, "G"),
310         }
311     }
312 }
313 
314 /// Returns the value of the property 'android.test.enum' if set.
315 pub fn test_enum() -> std::result::Result<Option<TestEnumValues>, SysPropError> {
316     let result = match system_properties::read("android.test.enum") {
317         Err(e) => Err(SysPropError::FetchError(e)),
318         Ok(Some(val)) => parsers_formatters::parse(val.as_str()).map_err(SysPropError::ParseError).map(Some),
319         Ok(None) => Ok(None),
320     };
321     result
322 }
323 
324 /// Sets the value of the property 'android.test.enum', returns 'Ok' if successful.
325 pub fn set_test_enum(v: TestEnumValues) -> std::result::Result<(), SysPropError> {
326     let value = parsers_formatters::format(&v);
327     system_properties::write("android.test.enum", value.as_str()).map_err(SysPropError::SetError)
328 }
329 
330 /// Returns the value of the property 'ro.android.test.b' if set.
331 pub fn test_boo_lea_n() -> std::result::Result<Option<bool>, SysPropError> {
332     let result = match system_properties::read("ro.android.test.b") {
333         Err(e) => Err(SysPropError::FetchError(e)),
334         Ok(Some(val)) => parsers_formatters::parse_bool(val.as_str()).map_err(SysPropError::ParseError).map(Some),
335         Ok(None) => Ok(None),
336     };
337     result
338 }
339 
340 /// Sets the value of the property 'ro.android.test.b', returns 'Ok' if successful.
341 pub fn set_test_boo_lea_n(v: bool) -> std::result::Result<(), SysPropError> {
342     let value = parsers_formatters::format_bool(&v);
343     system_properties::write("ro.android.test.b", value.as_str()).map_err(SysPropError::SetError)
344 }
345 
346 /// Returns the value of the property 'android_os_test-long' if set.
347 pub fn android_os_test_long() -> std::result::Result<Option<i64>, SysPropError> {
348     let result = match system_properties::read("android_os_test-long") {
349         Err(e) => Err(SysPropError::FetchError(e)),
350         Ok(Some(val)) => parsers_formatters::parse(val.as_str()).map_err(SysPropError::ParseError).map(Some),
351         Ok(None) => Ok(None),
352     };
353     result
354 }
355 
356 /// Sets the value of the property 'android_os_test-long', returns 'Ok' if successful.
357 pub fn set_android_os_test_long(v: i64) -> std::result::Result<(), SysPropError> {
358     let value = parsers_formatters::format(&v);
359     system_properties::write("android_os_test-long", value.as_str()).map_err(SysPropError::SetError)
360 }
361 
362 /// Returns the value of the property 'test_double_list' if set.
363 pub fn test_double_list() -> std::result::Result<Option<Vec<f64>>, SysPropError> {
364     let result = match system_properties::read("test_double_list") {
365         Err(e) => Err(SysPropError::FetchError(e)),
366         Ok(Some(val)) => parsers_formatters::parse_list(val.as_str()).map_err(SysPropError::ParseError).map(Some),
367         Ok(None) => Ok(None),
368     };
369     result
370 }
371 
372 /// Sets the value of the property 'test_double_list', returns 'Ok' if successful.
373 pub fn set_test_double_list(v: &[f64]) -> std::result::Result<(), SysPropError> {
374     let value = parsers_formatters::format_list(v);
375     system_properties::write("test_double_list", value.as_str()).map_err(SysPropError::SetError)
376 }
377 
378 /// Returns the value of the property 'test_list_int' if set.
379 pub fn test_list_int() -> std::result::Result<Option<Vec<i32>>, SysPropError> {
380     let result = match system_properties::read("test_list_int") {
381         Err(e) => Err(SysPropError::FetchError(e)),
382         Ok(Some(val)) => parsers_formatters::parse_list(val.as_str()).map_err(SysPropError::ParseError).map(Some),
383         Ok(None) => Ok(None),
384     };
385     result
386 }
387 
388 /// Sets the value of the property 'test_list_int', returns 'Ok' if successful.
389 pub fn set_test_list_int(v: &[i32]) -> std::result::Result<(), SysPropError> {
390     let value = parsers_formatters::format_list(v);
391     system_properties::write("test_list_int", value.as_str()).map_err(SysPropError::SetError)
392 }
393 
394 /// Returns the value of the property 'test_strlist' if set.
395 #[deprecated]
396 pub fn test_strlist() -> std::result::Result<Option<Vec<String>>, SysPropError> {
397     let result = match system_properties::read("test_strlist") {
398         Err(e) => Err(SysPropError::FetchError(e)),
399         Ok(Some(val)) => parsers_formatters::parse_list(val.as_str()).map_err(SysPropError::ParseError).map(Some),
400         Ok(None) => Ok(None),
401     };
402     result
403 }
404 
405 /// Sets the value of the property 'test_strlist', returns 'Ok' if successful.
406 #[deprecated]
407 pub fn set_test_strlist(v: &[String]) -> std::result::Result<(), SysPropError> {
408     let value = parsers_formatters::format_list(v);
409     system_properties::write("test_strlist", value.as_str()).map_err(SysPropError::SetError)
410 }
411 
412 #[allow(missing_docs)]
413 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash, Ord)]
414 pub enum ElValues {
415     Enu,
416     Mva,
417     Lue,
418 }
419 
420 impl std::str::FromStr for ElValues {
421     type Err = String;
422 
423     fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
424         match s {
425             "enu" => Ok(ElValues::Enu),
426             "mva" => Ok(ElValues::Mva),
427             "lue" => Ok(ElValues::Lue),
428             _ => Err(format!("'{}' cannot be parsed for ElValues", s)),
429         }
430     }
431 }
432 
433 impl fmt::Display for ElValues {
434     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435         match self {
436             ElValues::Enu => write!(f, "enu"),
437             ElValues::Mva => write!(f, "mva"),
438             ElValues::Lue => write!(f, "lue"),
439         }
440     }
441 }
442 
443 /// Returns the value of the property 'el' if set.
444 #[deprecated]
445 pub fn el() -> std::result::Result<Option<Vec<ElValues>>, SysPropError> {
446     let result = match system_properties::read("el") {
447         Err(e) => Err(SysPropError::FetchError(e)),
448         Ok(Some(val)) => parsers_formatters::parse_list(val.as_str()).map_err(SysPropError::ParseError).map(Some),
449         Ok(None) => Ok(None),
450     };
451     result
452 }
453 
454 /// Sets the value of the property 'el', returns 'Ok' if successful.
455 #[deprecated]
456 pub fn set_el(v: &[ElValues]) -> std::result::Result<(), SysPropError> {
457     let value = parsers_formatters::format_list(v);
458     system_properties::write("el", value.as_str()).map_err(SysPropError::SetError)
459 }
460 
461 )";
462 
463 }  // namespace
464 
465 using namespace std::string_literals;
466 
TEST(SyspropTest,RustGenTest)467 TEST(SyspropTest, RustGenTest) {
468   TemporaryFile temp_file;
469 
470   // strlen is optimized for constants, so don't worry about it.
471   ASSERT_EQ(write(temp_file.fd, kTestSyspropFile, strlen(kTestSyspropFile)),
472             strlen(kTestSyspropFile));
473   close(temp_file.fd);
474   temp_file.fd = -1;
475 
476   TemporaryDir temp_dir;
477 
478   std::pair<sysprop::Scope, const char*> tests[] = {
479       {sysprop::Scope::Internal, kExpectedInternalOutput},
480       {sysprop::Scope::Public, kExpectedPublicOutput},
481   };
482 
483   for (auto [scope, expected_output] : tests) {
484     std::string rust_output_path = temp_dir.path + "/mod.rs"s;
485 
486     ASSERT_RESULT_OK(GenerateRustLibrary(temp_file.path, scope, temp_dir.path));
487 
488     std::string rust_output;
489     ASSERT_TRUE(
490         android::base::ReadFileToString(rust_output_path, &rust_output, true));
491     EXPECT_EQ(rust_output, expected_output);
492 
493     unlink(rust_output.c_str());
494     rmdir((temp_dir.path + "/com/somecompany"s).c_str());
495     rmdir((temp_dir.path + "/com"s).c_str());
496   }
497 }