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
30namespace 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
40template <typename T>
41static std::string HexString(T value) {
42    std::stringstream ss;
43    ss << "0x" << std::hex << std::uppercase << value;
44    return ss.str();
45}
46
47template <typename T>
48static ::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
61class PropertiesTest : public testing::Test {
62public:
63    PropertiesTest() : mValue() {}
64protected:
65    virtual void SetUp() {
66        EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
67    }
68
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>
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
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
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
96TEST_F(PropertiesTest, SetString) {
97
98    // Null key -> unsuccessful set
99    {
100        // Null key -> fails
101        EXPECT_GT(0, property_set(/*key*/NULL, PROPERTY_TEST_VALUE_DEFAULT));
102    }
103
104    // Null value -> returns default value
105    {
106        // Null value -> OK , and it clears the value
107        EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
108        ResetValue();
109
110        // Since the value is null, default value will be returned
111        size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
112        EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len);
113        EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
114    }
115
116    // Trivial case => get returns what was set
117    {
118        size_t len = SetAndGetProperty("hello_world");
119        EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
120        EXPECT_STREQ("hello_world", mValue);
121        ResetValue();
122    }
123
124    // Set to empty string => get returns default always
125    {
126        const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
127        size_t len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
128        EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
129        EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue);
130        ResetValue();
131    }
132
133    // Set to max length => get returns what was set
134    {
135        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
136
137        int len = SetAndGetProperty(maxLengthString.c_str());
138        EXPECT_EQ(PROPERTY_VALUE_MAX-1, len) << "max length key";
139        EXPECT_STREQ(maxLengthString.c_str(), mValue);
140        ResetValue();
141    }
142
143    // Set to max length + 1 => set fails
144    {
145        const char* VALID_TEST_VALUE = "VALID_VALUE";
146        ASSERT_OK(property_set(PROPERTY_TEST_KEY, VALID_TEST_VALUE));
147
148        std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
149
150        // Expect that the value set fails since it's too long
151        EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str()));
152        size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
153
154        EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed";
155        EXPECT_STREQ(VALID_TEST_VALUE, mValue);
156        ResetValue();
157    }
158}
159
160TEST_F(PropertiesTest, GetString) {
161
162    // Try to use a default value that's too long => get truncates the value
163    {
164        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
165
166        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'a');
167        std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
168
169        // Expect that the value is truncated since it's too long (by 1)
170        int len = property_get(PROPERTY_TEST_KEY, mValue, oneLongerString.c_str());
171        EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len);
172        EXPECT_STREQ(maxLengthString.c_str(), mValue);
173        ResetValue();
174    }
175
176    // Try to use a default value that's the max length => get succeeds
177    {
178        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
179
180        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'b');
181
182        // Expect that the value matches maxLengthString
183        int len = property_get(PROPERTY_TEST_KEY, mValue, maxLengthString.c_str());
184        EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len);
185        EXPECT_STREQ(maxLengthString.c_str(), mValue);
186        ResetValue();
187    }
188
189    // Try to use a default value of length one => get succeeds
190    {
191        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
192
193        std::string oneCharString = std::string(1, 'c');
194
195        // Expect that the value matches oneCharString
196        int len = property_get(PROPERTY_TEST_KEY, mValue, oneCharString.c_str());
197        EXPECT_EQ(1, len);
198        EXPECT_STREQ(oneCharString.c_str(), mValue);
199        ResetValue();
200    }
201
202    // Try to use a default value of length zero => get succeeds
203    {
204        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
205
206        std::string zeroCharString = std::string(0, 'd');
207
208        // Expect that the value matches oneCharString
209        int len = property_get(PROPERTY_TEST_KEY, mValue, zeroCharString.c_str());
210        EXPECT_EQ(0, len);
211        EXPECT_STREQ(zeroCharString.c_str(), mValue);
212        ResetValue();
213    }
214
215    // Try to use a NULL default value => get returns 0
216    {
217        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
218
219        // Expect a return value of 0
220        int len = property_get(PROPERTY_TEST_KEY, mValue, NULL);
221        EXPECT_EQ(0, len);
222        ResetValue();
223    }
224}
225
226TEST_F(PropertiesTest, GetBool) {
227    /**
228     * TRUE
229     */
230    const char *valuesTrue[] = { "1", "true", "y", "yes", "on", };
231    for (size_t i = 0; i < arraysize(valuesTrue); ++i) {
232        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesTrue[i]));
233        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
234        EXPECT_TRUE(val) << "Property should've been TRUE for value: '" << valuesTrue[i] << "'";
235    }
236
237    /**
238     * FALSE
239     */
240    const char *valuesFalse[] = { "0", "false", "n", "no", "off", };
241    for (size_t i = 0; i < arraysize(valuesFalse); ++i) {
242        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesFalse[i]));
243        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
244        EXPECT_FALSE(val) << "Property shoud've been FALSE For string value: '" << valuesFalse[i] << "'";
245    }
246
247    /**
248     * NEITHER
249     */
250    const char *valuesNeither[] = { "x0", "x1", "2", "-2", "True", "False", "garbage", "", " ",
251            "+1", "  1  ", "  true", "  true  ", "  y  ", "  yes", "yes  ",
252            "+0", "-0", "00", "  00  ", "  false", "false  ",
253    };
254    for (size_t i = 0; i < arraysize(valuesNeither); ++i) {
255        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesNeither[i]));
256
257        // The default value should always be used
258        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
259        EXPECT_TRUE(val) << "Property should've been NEITHER (true) for string value: '" << valuesNeither[i] << "'";
260
261        val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
262        EXPECT_FALSE(val) << "Property should've been NEITHER (false) for string value: '" << valuesNeither[i] << "'";
263    }
264}
265
266TEST_F(PropertiesTest, GetInt64) {
267    const int64_t DEFAULT_VALUE = INT64_C(0xDEADBEEFBEEFDEAD);
268
269    const std::string longMaxString = ToString(INT64_MAX);
270    const std::string longStringOverflow = longMaxString + "0";
271
272    const std::string longMinString = ToString(INT64_MIN);
273    const std::string longStringUnderflow = longMinString + "0";
274
275    const char* setValues[] = {
276        // base 10
277        "1", "2", "12345", "-1", "-2", "-12345",
278        // base 16
279        "0xFF", "0x0FF", "0xC0FFEE",
280        // base 8
281        "0", "01234", "07",
282        // corner cases
283        "       2", "2      ", "+0", "-0", "  +0   ", longMaxString.c_str(), longMinString.c_str(),
284        // failing cases
285        NULL, "", " ", "    ", "hello", "     true     ", "y",
286        longStringOverflow.c_str(), longStringUnderflow.c_str(),
287    };
288
289    int64_t getValues[] = {
290        // base 10
291        1, 2, 12345, -1, -2, -12345,
292        // base 16
293        0xFF, 0x0FF, 0xC0FFEE,
294        // base 8
295        0, 01234, 07,
296        // corner cases
297        2, 2, 0, 0, 0, INT64_MAX, INT64_MIN,
298        // failing cases
299        DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
300        DEFAULT_VALUE, DEFAULT_VALUE,
301    };
302
303    ASSERT_EQ(arraysize(setValues), arraysize(getValues));
304
305    for (size_t i = 0; i < arraysize(setValues); ++i) {
306        ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
307
308        int64_t val = property_get_int64(PROPERTY_TEST_KEY, DEFAULT_VALUE);
309        EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
310    }
311}
312
313TEST_F(PropertiesTest, GetInt32) {
314    const int32_t DEFAULT_VALUE = INT32_C(0xDEADBEEF);
315
316    const std::string intMaxString = ToString(INT32_MAX);
317    const std::string intStringOverflow = intMaxString + "0";
318
319    const std::string intMinString = ToString(INT32_MIN);
320    const std::string intStringUnderflow = intMinString + "0";
321
322    const char* setValues[] = {
323        // base 10
324        "1", "2", "12345", "-1", "-2", "-12345",
325        // base 16
326        "0xFF", "0x0FF", "0xC0FFEE", "0Xf00",
327        // base 8
328        "0", "01234", "07",
329        // corner cases
330        "       2", "2      ", "+0", "-0", "  +0   ", intMaxString.c_str(), intMinString.c_str(),
331        // failing cases
332        NULL, "", " ", "    ", "hello", "     true     ", "y",
333        intStringOverflow.c_str(), intStringUnderflow.c_str(),
334    };
335
336    int32_t getValues[] = {
337        // base 10
338        1, 2, 12345, -1, -2, -12345,
339        // base 16
340        0xFF, 0x0FF, 0xC0FFEE, 0Xf00,
341        // base 8
342        0, 01234, 07,
343        // corner cases
344        2, 2, 0, 0, 0, INT32_MAX, INT32_MIN,
345        // failing cases
346        DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
347        DEFAULT_VALUE, DEFAULT_VALUE,
348    };
349
350    ASSERT_EQ(arraysize(setValues), arraysize(getValues));
351
352    for (size_t i = 0; i < arraysize(setValues); ++i) {
353        ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
354
355        int32_t val = property_get_int32(PROPERTY_TEST_KEY, DEFAULT_VALUE);
356        EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
357    }
358}
359
360} // namespace android
361