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