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 }