1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cstdio>
18 #include <string>
19
20 #include <android-base/file.h>
21 #include <android-base/test_utils.h>
22 #include <gtest/gtest.h>
23
24 #include "Common.h"
25 #include "sysprop.pb.h"
26
27 namespace {
28
29 constexpr const char* kDuplicatedField =
30 R"(
31 owner: Vendor
32 module: "com.error.DuplicatedField"
33 prop {
34 api_name: "dup"
35 type: Integer
36 scope: Internal
37 access: Readonly
38 }
39 prop {
40 api_name: "dup"
41 type: Long
42 scope: Public
43 access: ReadWrite
44 }
45 )";
46
47 constexpr const char* kEmptyProp =
48 R"(
49 owner: Vendor
50 module: "com.google.EmptyProp"
51 )";
52
53 constexpr const char* kInvalidApiName =
54 R"(
55 owner: Odm
56 module: "odm.invalid.prop.name"
57 prop {
58 api_name: "!@#$"
59 type: Integer
60 scope: Public
61 access: ReadWrite
62 }
63 )";
64
65 constexpr const char* kInvalidPropName =
66 R"(
67 owner: Vendor
68 module: "vendor.module.name"
69 prop {
70 api_name: "foo"
71 type: Integer
72 scope: Internal
73 access: Readonly
74 prop_name: "foo$bar"
75 }
76 )";
77
78 constexpr const char* kEmptyEnumValues =
79 R"(
80 owner: Odm
81 module: "test.manufacturer"
82 prop {
83 api_name: "empty_enum_value"
84 type: Enum
85 scope: Internal
86 access: ReadWrite
87 }
88 )";
89
90 constexpr const char* kDuplicatedEnumValue =
91 R"(
92 owner: Vendor
93 module: "vendor.module.name"
94 prop {
95 api_name: "status"
96 type: Enum
97 enum_values: "oN|off|intermediate|On"
98 scope: Public
99 access: ReadWrite
100 }
101 )";
102
103 constexpr const char* kInvalidModuleName =
104 R"(
105 owner: Platform
106 module: ""
107 prop {
108 api_name: "integer"
109 type: Integer
110 scope: Public
111 access: ReadWrite
112 }
113 )";
114
115 constexpr const char* kInvalidNamespaceForPlatform =
116 R"(
117 owner: Platform
118 module: "android.PlatformProperties"
119 prop {
120 api_name: "vendor_build_utc_long"
121 prop_name: "vendor.build.utc_long"
122 type: Long
123 scope: Public
124 access: ReadWrite
125 }
126 )";
127
128 constexpr const char* kRoPrefixForReadWriteProperty =
129 R"(
130 owner: Vendor
131 module: "com.android.VendorProp"
132 prop {
133 api_name: "i_am_readwrite"
134 type: Long
135 scope: Public
136 prop_name: "ro.vendor.i_am_readwrite"
137 access: ReadWrite
138 }
139 )";
140
141 constexpr const char* kIntegerAsBoolWithWrongType =
142 R"(
143 owner: Platform
144 module: "android.os.LongProp"
145 prop {
146 api_name: "longprop"
147 type: Long
148 scope: Internal
149 prop_name: "long.prop"
150 access: ReadWrite
151 integer_as_bool: true
152 }
153 )";
154
155 constexpr const char* kTypeMismatch =
156 R"(
157 owner: Platform
158 module: "android.os.Type"
159 prop {
160 prop_name: "prop"
161 type: Double
162 scope: Public
163 access: ReadWrite
164 api_name: "prop"
165 }
166 prop {
167 prop_name: "prop2"
168 legacy_prop_name: "prop"
169 type: Enum
170 enum_values: "a|b|c"
171 scope: Public
172 access: Readonly
173 api_name: "prop2"
174 }
175 )";
176
177 constexpr const char* kLegacyNotReadonly =
178 R"(
179 owner: Platform
180 module: "android.os.Sysprop"
181 prop {
182 prop_name: "prop"
183 type: String
184 scope: Public
185 access: ReadWrite
186 api_name: "prop"
187 legacy_prop_name: "legacy_prop"
188 }
189 )";
190
191 constexpr const char* kTestCasesAndExpectedErrors[][2] = {
192 {kDuplicatedField, "Duplicated API name \"dup\""},
193 {kEmptyProp, "There is no defined property"},
194 {kInvalidApiName, "Invalid API name \"!@#$\""},
195 {kInvalidPropName, "Invalid prop name \"foo$bar\""},
196 {kEmptyEnumValues, "Invalid enum value \"\" for API \"empty_enum_value\""},
197 {kDuplicatedEnumValue, "Duplicated enum value \"On\" for API \"status\""},
198 {kInvalidModuleName, "Invalid module name \"\""},
199 {kInvalidNamespaceForPlatform,
200 "Prop \"vendor.build.utc_long\" owned by platform cannot have vendor. or "
201 "odm. "
202 "namespace"},
203 {kRoPrefixForReadWriteProperty,
204 "Prop \"ro.vendor.i_am_readwrite\" is ReadWrite and also have prefix "
205 "\"ro.\""},
206 {kIntegerAsBoolWithWrongType,
207 "Prop \"long.prop\" has integer_as_bool: true, but not a boolean"},
208 {kTypeMismatch, "Type error on prop \"prop\": it's Enum but was Double"},
209 {kLegacyNotReadonly,
210 "Prop \"prop\" which has legacy_prop_name must be Readonly"},
211 };
212
213 } // namespace
214
TEST(SyspropTest,InvalidSyspropTest)215 TEST(SyspropTest, InvalidSyspropTest) {
216 TemporaryFile file;
217 close(file.fd);
218 file.fd = -1;
219
220 for (auto [test_case, expected_error] : kTestCasesAndExpectedErrors) {
221 ASSERT_TRUE(android::base::WriteStringToFile(test_case, file.path));
222 auto res = ParseProps(file.path);
223 EXPECT_FALSE(res.ok());
224 EXPECT_EQ(res.error().message(), expected_error);
225 }
226 }
227