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