1 /*
2 * Copyright (C) 2014 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 #define LOG_TAG "Properties_test"
18
19 #include <limits.h>
20
21 #include <iostream>
22 #include <sstream>
23 #include <string>
24
25 #include <android/log.h>
26 #include <android-base/macros.h>
27 #include <cutils/properties.h>
28 #include <gtest/gtest.h>
29
30 namespace android {
31
32 #define STRINGIFY_INNER(x) #x
33 #define STRINGIFY(x) STRINGIFY_INNER(x)
34 #define ASSERT_OK(x) ASSERT_EQ(0, (x))
35 #define EXPECT_OK(x) EXPECT_EQ(0, (x))
36
37 #define PROPERTY_TEST_KEY "libcutils.test.key"
38 #define PROPERTY_TEST_VALUE_DEFAULT "<<<default_value>>>"
39
40 template <typename T>
HexString(T value)41 static std::string HexString(T value) {
42 std::stringstream ss;
43 ss << "0x" << std::hex << std::uppercase << value;
44 return ss.str();
45 }
46
47 template <typename T>
AssertEqualHex(const char * mExpr,const char * nExpr,T m,T n)48 static ::testing::AssertionResult AssertEqualHex(const char *mExpr,
49 const char *nExpr,
50 T m,
51 T n) {
52 if (m == n) {
53 return ::testing::AssertionSuccess();
54 }
55
56 return ::testing::AssertionFailure()
57 << mExpr << " and " << nExpr << " (expected: " << HexString(m) <<
58 ", actual: " << HexString(n) << ") are not equal";
59 }
60
61 class PropertiesTest : public testing::Test {
62 public:
PropertiesTest()63 PropertiesTest() : mValue() {}
64 protected:
SetUp()65 virtual void SetUp() {
66 EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
67 }
68
TearDown()69 virtual void TearDown() {
70 EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
71 }
72
73 char mValue[PROPERTY_VALUE_MAX];
74
75 template <typename T>
ToString(T value)76 static std::string ToString(T value) {
77 std::stringstream ss;
78 ss << value;
79
80 return ss.str();
81 }
82
83 // Return length of property read; value is written into mValue
SetAndGetProperty(const char * value,const char * defaultValue=PROPERTY_TEST_VALUE_DEFAULT)84 int SetAndGetProperty(const char* value, const char* defaultValue = PROPERTY_TEST_VALUE_DEFAULT) {
85 EXPECT_OK(property_set(PROPERTY_TEST_KEY, value)) << "value: '" << value << "'";
86 return property_get(PROPERTY_TEST_KEY, mValue, defaultValue);
87 }
88
ResetValue(unsigned char c=0xFF)89 void ResetValue(unsigned char c = 0xFF) {
90 for (size_t i = 0; i < arraysize(mValue); ++i) {
91 mValue[i] = (char) c;
92 }
93 }
94 };
95
TEST_F(PropertiesTest,property_set_null_key)96 TEST_F(PropertiesTest, property_set_null_key) {
97 // Null key -> unsuccessful set
98 EXPECT_GT(0, property_set(/*key*/ NULL, PROPERTY_TEST_VALUE_DEFAULT));
99 }
100
TEST_F(PropertiesTest,property_set_null_value)101 TEST_F(PropertiesTest, property_set_null_value) {
102 // Null value -> OK, and it clears the value
103 EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/ NULL));
104 ResetValue();
105
106 // Since the value is null, default value will be returned
107 size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
108 EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len);
109 EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
110 }
111
TEST_F(PropertiesTest,property_set)112 TEST_F(PropertiesTest, property_set) {
113 // Trivial case => get returns what was set
114 size_t len = SetAndGetProperty("hello_world");
115 EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
116 EXPECT_STREQ("hello_world", mValue);
117 ResetValue();
118 }
119
TEST_F(PropertiesTest,property_set_empty)120 TEST_F(PropertiesTest, property_set_empty) {
121 // Set to empty string => get returns default always
122 const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
123 size_t len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
124 EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
125 EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue);
126 ResetValue();
127 }
128
TEST_F(PropertiesTest,property_set_max_length)129 TEST_F(PropertiesTest, property_set_max_length) {
130 // Set to max length => get returns what was set
131 std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'a');
132
133 int len = SetAndGetProperty(maxLengthString.c_str());
134 EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len) << "max length key";
135 EXPECT_STREQ(maxLengthString.c_str(), mValue);
136 ResetValue();
137 }
138
TEST_F(PropertiesTest,property_set_too_long)139 TEST_F(PropertiesTest, property_set_too_long) {
140 // Set to max length + 1 => set fails
141 const char* VALID_TEST_VALUE = "VALID_VALUE";
142 ASSERT_OK(property_set(PROPERTY_TEST_KEY, VALID_TEST_VALUE));
143
144 std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
145
146 // Expect that the value set fails since it's too long
147 EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str()));
148 size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
149
150 EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed";
151 EXPECT_STREQ(VALID_TEST_VALUE, mValue);
152 ResetValue();
153 }
154
TEST_F(PropertiesTest,property_get_too_long)155 TEST_F(PropertiesTest, property_get_too_long) {
156 // Try to use a default value that's too long => get truncates the value
157 ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
158
159 std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'a');
160 std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
161
162 // Expect that the value is truncated since it's too long (by 1)
163 int len = property_get(PROPERTY_TEST_KEY, mValue, oneLongerString.c_str());
164 EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len);
165 EXPECT_STREQ(maxLengthString.c_str(), mValue);
166 ResetValue();
167 }
168
TEST_F(PropertiesTest,property_get_default_too_long)169 TEST_F(PropertiesTest, property_get_default_too_long) {
170 // Try to use a default value that's the max length => get succeeds
171 ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
172
173 std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'b');
174
175 // Expect that the value matches maxLengthString
176 int len = property_get(PROPERTY_TEST_KEY, mValue, maxLengthString.c_str());
177 EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len);
178 EXPECT_STREQ(maxLengthString.c_str(), mValue);
179 ResetValue();
180 }
181
TEST_F(PropertiesTest,property_get_default_okay)182 TEST_F(PropertiesTest, property_get_default_okay) {
183 // Try to use a default value of length one => get succeeds
184 ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
185
186 std::string oneCharString = std::string(1, 'c');
187
188 // Expect that the value matches oneCharString
189 int len = property_get(PROPERTY_TEST_KEY, mValue, oneCharString.c_str());
190 EXPECT_EQ(1, len);
191 EXPECT_STREQ(oneCharString.c_str(), mValue);
192 ResetValue();
193 }
194
TEST_F(PropertiesTest,property_get_default_empty)195 TEST_F(PropertiesTest, property_get_default_empty) {
196 // Try to use a default value of length zero => get succeeds
197 ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
198
199 std::string zeroCharString = std::string(0, 'd');
200
201 // Expect that the value matches oneCharString
202 int len = property_get(PROPERTY_TEST_KEY, mValue, zeroCharString.c_str());
203 EXPECT_EQ(0, len);
204 EXPECT_STREQ(zeroCharString.c_str(), mValue);
205 ResetValue();
206 }
207
TEST_F(PropertiesTest,property_get_default_NULL)208 TEST_F(PropertiesTest, property_get_default_NULL) {
209 // Try to use a NULL default value => get returns 0
210 ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
211
212 // Expect a return value of 0
213 int len = property_get(PROPERTY_TEST_KEY, mValue, NULL);
214 EXPECT_EQ(0, len);
215 ResetValue();
216 }
217
TEST_F(PropertiesTest,property_get_bool_0)218 TEST_F(PropertiesTest, property_get_bool_0) {
219 ASSERT_OK(property_set(PROPERTY_TEST_KEY, "0"));
220 ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
221 }
222
TEST_F(PropertiesTest,property_get_bool_1)223 TEST_F(PropertiesTest, property_get_bool_1) {
224 ASSERT_OK(property_set(PROPERTY_TEST_KEY, "1"));
225 ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
226 }
227
TEST_F(PropertiesTest,property_get_bool_false)228 TEST_F(PropertiesTest, property_get_bool_false) {
229 ASSERT_OK(property_set(PROPERTY_TEST_KEY, "false"));
230 ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
231 }
232
TEST_F(PropertiesTest,property_get_bool_n)233 TEST_F(PropertiesTest, property_get_bool_n) {
234 ASSERT_OK(property_set(PROPERTY_TEST_KEY, "n"));
235 ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
236 }
237
TEST_F(PropertiesTest,property_get_bool_no)238 TEST_F(PropertiesTest, property_get_bool_no) {
239 ASSERT_OK(property_set(PROPERTY_TEST_KEY, "no"));
240 ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
241 }
242
TEST_F(PropertiesTest,property_get_bool_off)243 TEST_F(PropertiesTest, property_get_bool_off) {
244 ASSERT_OK(property_set(PROPERTY_TEST_KEY, "off"));
245 ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
246 }
247
TEST_F(PropertiesTest,property_get_bool_on)248 TEST_F(PropertiesTest, property_get_bool_on) {
249 ASSERT_OK(property_set(PROPERTY_TEST_KEY, "on"));
250 ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
251 }
252
TEST_F(PropertiesTest,property_get_bool_true)253 TEST_F(PropertiesTest, property_get_bool_true) {
254 ASSERT_OK(property_set(PROPERTY_TEST_KEY, "true"));
255 ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
256 }
257
TEST_F(PropertiesTest,property_get_bool_y)258 TEST_F(PropertiesTest, property_get_bool_y) {
259 ASSERT_OK(property_set(PROPERTY_TEST_KEY, "y"));
260 ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
261 }
262
TEST_F(PropertiesTest,property_get_bool_yes)263 TEST_F(PropertiesTest, property_get_bool_yes) {
264 ASSERT_OK(property_set(PROPERTY_TEST_KEY, "yes"));
265 ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
266 }
267
TEST_F(PropertiesTest,property_get_bool_neither)268 TEST_F(PropertiesTest, property_get_bool_neither) {
269 const char *valuesNeither[] = { "x0", "x1", "2", "-2", "True", "False", "garbage", "", " ",
270 "+1", " 1 ", " true", " true ", " y ", " yes", "yes ",
271 "+0", "-0", "00", " 00 ", " false", "false ",
272 };
273 for (size_t i = 0; i < arraysize(valuesNeither); ++i) {
274 ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesNeither[i]));
275
276 // The default value should always be used
277 bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
278 EXPECT_TRUE(val) << "Property should've been NEITHER (true) for string value: '" << valuesNeither[i] << "'";
279
280 val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
281 EXPECT_FALSE(val) << "Property should've been NEITHER (false) for string value: '" << valuesNeither[i] << "'";
282 }
283 }
284
TEST_F(PropertiesTest,property_get_int64)285 TEST_F(PropertiesTest, property_get_int64) {
286 const int64_t DEFAULT_VALUE = INT64_C(0xDEADBEEFBEEFDEAD);
287
288 const std::string longMaxString = ToString(INT64_MAX);
289 const std::string longStringOverflow = longMaxString + "0";
290
291 const std::string longMinString = ToString(INT64_MIN);
292 const std::string longStringUnderflow = longMinString + "0";
293
294 const char* setValues[] = {
295 // base 10
296 "1", "2", "12345", "-1", "-2", "-12345",
297 // base 16
298 "0xFF", "0x0FF", "0xC0FFEE",
299 // base 8
300 "0", "01234", "07",
301 // corner cases
302 " 2", "2 ", "+0", "-0", " +0 ", longMaxString.c_str(), longMinString.c_str(),
303 // failing cases
304 NULL, "", " ", " ", "hello", " true ", "y",
305 longStringOverflow.c_str(), longStringUnderflow.c_str(),
306 };
307
308 int64_t getValues[] = {
309 // base 10
310 1, 2, 12345, -1, -2, -12345,
311 // base 16
312 0xFF, 0x0FF, 0xC0FFEE,
313 // base 8
314 0, 01234, 07,
315 // corner cases
316 2, 2, 0, 0, 0, INT64_MAX, INT64_MIN,
317 // failing cases
318 DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
319 DEFAULT_VALUE, DEFAULT_VALUE,
320 };
321
322 ASSERT_EQ(arraysize(setValues), arraysize(getValues));
323
324 for (size_t i = 0; i < arraysize(setValues); ++i) {
325 ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
326
327 int64_t val = property_get_int64(PROPERTY_TEST_KEY, DEFAULT_VALUE);
328 EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
329 }
330 }
331
TEST_F(PropertiesTest,property_get_int32)332 TEST_F(PropertiesTest, property_get_int32) {
333 const int32_t DEFAULT_VALUE = INT32_C(0xDEADBEEF);
334
335 const std::string intMaxString = ToString(INT32_MAX);
336 const std::string intStringOverflow = intMaxString + "0";
337
338 const std::string intMinString = ToString(INT32_MIN);
339 const std::string intStringUnderflow = intMinString + "0";
340
341 const char* setValues[] = {
342 // base 10
343 "1", "2", "12345", "-1", "-2", "-12345",
344 // base 16
345 "0xFF", "0x0FF", "0xC0FFEE", "0Xf00",
346 // base 8
347 "0", "01234", "07",
348 // corner cases
349 " 2", "2 ", "+0", "-0", " +0 ", intMaxString.c_str(), intMinString.c_str(),
350 // failing cases
351 NULL, "", " ", " ", "hello", " true ", "y",
352 intStringOverflow.c_str(), intStringUnderflow.c_str(),
353 };
354
355 int32_t getValues[] = {
356 // base 10
357 1, 2, 12345, -1, -2, -12345,
358 // base 16
359 0xFF, 0x0FF, 0xC0FFEE, 0Xf00,
360 // base 8
361 0, 01234, 07,
362 // corner cases
363 2, 2, 0, 0, 0, INT32_MAX, INT32_MIN,
364 // failing cases
365 DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
366 DEFAULT_VALUE, DEFAULT_VALUE,
367 };
368
369 ASSERT_EQ(arraysize(setValues), arraysize(getValues));
370
371 for (size_t i = 0; i < arraysize(setValues); ++i) {
372 ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
373
374 int32_t val = property_get_int32(PROPERTY_TEST_KEY, DEFAULT_VALUE);
375 EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
376 }
377 }
378
379 } // namespace android
380