1 /*
2  * Copyright 2023 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 <gestures/PropertyProvider.h>
18 #include <gmock/gmock.h>
19 #include <gtest/gtest.h>
20 
21 #include "TestConstants.h"
22 #include "include/gestures.h"
23 
24 namespace android {
25 
26 using testing::ElementsAre;
27 
28 class PropertyProviderTest : public testing::Test {
29 protected:
30     PropertyProvider mProvider;
31 };
32 
TEST_F(PropertyProviderTest,Int_Create)33 TEST_F(PropertyProviderTest, Int_Create) {
34     const size_t COUNT = 4;
35     int intData[COUNT] = {0, 0, 0, 0};
36     int initialValues[COUNT] = {1, 2, 3, 4};
37     gesturePropProvider.create_int_fn(&mProvider, "Some Integers", intData, COUNT, initialValues);
38 
39     ASSERT_TRUE(mProvider.hasProperty("Some Integers"));
40     GesturesProp& prop = mProvider.getProperty("Some Integers");
41     EXPECT_EQ(prop.getName(), "Some Integers");
42     EXPECT_EQ(prop.getCount(), COUNT);
43     EXPECT_THAT(intData, ElementsAre(1, 2, 3, 4));
44 }
45 
TEST_F(PropertyProviderTest,Int_Get)46 TEST_F(PropertyProviderTest, Int_Get) {
47     const size_t COUNT = 4;
48     int intData[COUNT] = {0, 0, 0, 0};
49     int initialValues[COUNT] = {9, 9, 9, 9};
50     GesturesProp* propPtr = gesturePropProvider.create_int_fn(&mProvider, "Some Integers", intData,
51                                                               COUNT, initialValues);
52 
53     // Get handlers are supposed to be called before the property's data is accessed, so they can
54     // update it if necessary. This getter updates the values, so that the ordering can be checked.
55     GesturesPropGetHandler getter{[](void* handlerData) -> GesturesPropBool {
56         int* array = static_cast<int*>(handlerData);
57         array[0] = 1;
58         array[1] = 2;
59         array[2] = 3;
60         array[3] = 4;
61         return true;
62     }};
63     gesturePropProvider.register_handlers_fn(&mProvider, propPtr, /* handler_data= */ intData,
64                                              getter, nullptr);
65 
66     ASSERT_TRUE(mProvider.hasProperty("Some Integers"));
67     GesturesProp& prop = mProvider.getProperty("Some Integers");
68     EXPECT_THAT(prop.getIntValues(), ElementsAre(1, 2, 3, 4));
69 }
70 
TEST_F(PropertyProviderTest,Int_Set)71 TEST_F(PropertyProviderTest, Int_Set) {
72     const size_t COUNT = 4;
73     int intData[COUNT] = {0, 0, 0, 0};
74     int initialValues[COUNT] = {9, 9, 9, 9};
75     GesturesProp* propPtr = gesturePropProvider.create_int_fn(&mProvider, "Some Integers", intData,
76                                                               COUNT, initialValues);
77 
78     struct SetterData {
79         bool setterCalled;
80         int* propertyData;
81     };
82     SetterData setterData = {false, intData};
83     GesturesPropSetHandler setter{[](void* handlerData) {
84         SetterData* data = static_cast<SetterData*>(handlerData);
85         // Set handlers should be called after the property's data has changed, so check the data.
86         EXPECT_EQ(data->propertyData[0], 1);
87         EXPECT_EQ(data->propertyData[1], 2);
88         EXPECT_EQ(data->propertyData[2], 3);
89         EXPECT_EQ(data->propertyData[3], 4);
90         data->setterCalled = true;
91     }};
92     gesturePropProvider.register_handlers_fn(&mProvider, propPtr, /* handler_data= */ &setterData,
93                                              nullptr, setter);
94 
95     ASSERT_TRUE(mProvider.hasProperty("Some Integers"));
96     GesturesProp& prop = mProvider.getProperty("Some Integers");
97     prop.setIntValues({1, 2, 3, 4});
98     EXPECT_THAT(intData, ElementsAre(1, 2, 3, 4));
99     EXPECT_TRUE(setterData.setterCalled);
100     EXPECT_THAT(prop.getIntValues(), ElementsAre(1, 2, 3, 4));
101 }
102 
TEST_F(PropertyProviderTest,Bool_Create)103 TEST_F(PropertyProviderTest, Bool_Create) {
104     const size_t COUNT = 3;
105     GesturesPropBool boolData[COUNT] = {false, false, false};
106     GesturesPropBool initialValues[COUNT] = {true, false, false};
107     gesturePropProvider.create_bool_fn(&mProvider, "Some Booleans", boolData, COUNT, initialValues);
108 
109     ASSERT_TRUE(mProvider.hasProperty("Some Booleans"));
110     GesturesProp& prop = mProvider.getProperty("Some Booleans");
111     EXPECT_EQ(prop.getName(), "Some Booleans");
112     EXPECT_EQ(prop.getCount(), COUNT);
113     EXPECT_THAT(boolData, ElementsAre(true, false, false));
114 }
115 
TEST_F(PropertyProviderTest,Bool_Get)116 TEST_F(PropertyProviderTest, Bool_Get) {
117     const size_t COUNT = 3;
118     GesturesPropBool boolData[COUNT] = {false, false, false};
119     GesturesPropBool initialValues[COUNT] = {true, false, false};
120     GesturesProp* propPtr = gesturePropProvider.create_bool_fn(&mProvider, "Some Booleans",
121                                                                boolData, COUNT, initialValues);
122 
123     // Get handlers are supposed to be called before the property's data is accessed, so they can
124     // update it if necessary. This getter updates the values, so that the ordering can be checked.
125     GesturesPropGetHandler getter{[](void* handlerData) -> GesturesPropBool {
126         GesturesPropBool* array = static_cast<GesturesPropBool*>(handlerData);
127         array[0] = false;
128         array[1] = true;
129         array[2] = true;
130         return true;
131     }};
132     gesturePropProvider.register_handlers_fn(&mProvider, propPtr, /* handler_data= */ boolData,
133                                              getter, nullptr);
134 
135     ASSERT_TRUE(mProvider.hasProperty("Some Booleans"));
136     GesturesProp& prop = mProvider.getProperty("Some Booleans");
137     EXPECT_THAT(prop.getBoolValues(), ElementsAre(false, true, true));
138 }
139 
TEST_F(PropertyProviderTest,Bool_Set)140 TEST_F(PropertyProviderTest, Bool_Set) {
141     const size_t COUNT = 3;
142     GesturesPropBool boolData[COUNT] = {false, false, false};
143     GesturesPropBool initialValues[COUNT] = {true, false, false};
144     GesturesProp* propPtr = gesturePropProvider.create_bool_fn(&mProvider, "Some Booleans",
145                                                                boolData, COUNT, initialValues);
146 
147     struct SetterData {
148         bool setterCalled;
149         GesturesPropBool* propertyData;
150     };
151     SetterData setterData = {false, boolData};
152     GesturesPropSetHandler setter{[](void* handlerData) {
153         SetterData* data = static_cast<SetterData*>(handlerData);
154         // Set handlers should be called after the property's data has changed, so check the data.
155         EXPECT_EQ(data->propertyData[0], false);
156         EXPECT_EQ(data->propertyData[1], true);
157         EXPECT_EQ(data->propertyData[2], true);
158         data->setterCalled = true;
159     }};
160     gesturePropProvider.register_handlers_fn(&mProvider, propPtr, /* handler_data= */ &setterData,
161                                              nullptr, setter);
162 
163     ASSERT_TRUE(mProvider.hasProperty("Some Booleans"));
164     GesturesProp& prop = mProvider.getProperty("Some Booleans");
165     prop.setBoolValues({false, true, true});
166     EXPECT_THAT(boolData, ElementsAre(false, true, true));
167     EXPECT_TRUE(setterData.setterCalled);
168     EXPECT_THAT(prop.getBoolValues(), ElementsAre(false, true, true));
169 }
170 
TEST_F(PropertyProviderTest,Real_Create)171 TEST_F(PropertyProviderTest, Real_Create) {
172     const size_t COUNT = 3;
173     double realData[COUNT] = {0.0, 0.0, 0.0};
174     double initialValues[COUNT] = {3.14, 0.7, -5.0};
175     gesturePropProvider.create_real_fn(&mProvider, "Some Reals", realData, COUNT, initialValues);
176 
177     ASSERT_TRUE(mProvider.hasProperty("Some Reals"));
178     GesturesProp& prop = mProvider.getProperty("Some Reals");
179     EXPECT_EQ(prop.getName(), "Some Reals");
180     EXPECT_EQ(prop.getCount(), COUNT);
181     EXPECT_THAT(realData, ElementsAre(3.14, 0.7, -5.0));
182 }
183 
TEST_F(PropertyProviderTest,Real_Get)184 TEST_F(PropertyProviderTest, Real_Get) {
185     const size_t COUNT = 3;
186     double realData[COUNT] = {0.0, 0.0, 0.0};
187     double initialValues[COUNT] = {-1.0, -1.0, -1.0};
188     GesturesProp* propPtr = gesturePropProvider.create_real_fn(&mProvider, "Some Reals", realData,
189                                                                COUNT, initialValues);
190 
191     // Get handlers are supposed to be called before the property's data is accessed, so they can
192     // update it if necessary. This getter updates the values, so that the ordering can be checked.
193     GesturesPropGetHandler getter{[](void* handlerData) -> GesturesPropBool {
194         double* array = static_cast<double*>(handlerData);
195         array[0] = 3.14;
196         array[1] = 0.7;
197         array[2] = -5.0;
198         return true;
199     }};
200     gesturePropProvider.register_handlers_fn(&mProvider, propPtr, /* handler_data= */ realData,
201                                              getter, nullptr);
202 
203     ASSERT_TRUE(mProvider.hasProperty("Some Reals"));
204     GesturesProp& prop = mProvider.getProperty("Some Reals");
205     EXPECT_THAT(prop.getRealValues(), ElementsAre(3.14, 0.7, -5.0));
206 }
207 
TEST_F(PropertyProviderTest,Real_Set)208 TEST_F(PropertyProviderTest, Real_Set) {
209     const size_t COUNT = 3;
210     double realData[COUNT] = {0.0, 0.0, 0.0};
211     double initialValues[COUNT] = {-1.0, -1.0, -1.0};
212     GesturesProp* propPtr = gesturePropProvider.create_real_fn(&mProvider, "Some Reals", realData,
213                                                                COUNT, initialValues);
214 
215     struct SetterData {
216         bool setterCalled;
217         double* propertyData;
218     };
219     SetterData setterData = {false, realData};
220     GesturesPropSetHandler setter{[](void* handlerData) {
221         SetterData* data = static_cast<SetterData*>(handlerData);
222         // Set handlers should be called after the property's data has changed, so check the data.
223         EXPECT_EQ(data->propertyData[0], 3.14);
224         EXPECT_EQ(data->propertyData[1], 0.7);
225         EXPECT_EQ(data->propertyData[2], -5.0);
226         data->setterCalled = true;
227     }};
228     gesturePropProvider.register_handlers_fn(&mProvider, propPtr, /* handler_data= */ &setterData,
229                                              nullptr, setter);
230 
231     ASSERT_TRUE(mProvider.hasProperty("Some Reals"));
232     GesturesProp& prop = mProvider.getProperty("Some Reals");
233     prop.setRealValues({3.14, 0.7, -5.0});
234     EXPECT_THAT(realData, ElementsAre(3.14, 0.7, -5.0));
235     EXPECT_TRUE(setterData.setterCalled);
236     EXPECT_THAT(prop.getRealValues(), ElementsAre(3.14, 0.7, -5.0));
237 }
238 
TEST_F(PropertyProviderTest,String_Create)239 TEST_F(PropertyProviderTest, String_Create) {
240     const char* str = nullptr;
241     std::string initialValue = "Foo";
242     gesturePropProvider.create_string_fn(&mProvider, "A String", &str, initialValue.c_str());
243 
244     ASSERT_TRUE(mProvider.hasProperty("A String"));
245     GesturesProp& prop = mProvider.getProperty("A String");
246     EXPECT_EQ(prop.getName(), "A String");
247     EXPECT_EQ(prop.getCount(), 1u);
248     EXPECT_STREQ(str, "Foo");
249 }
250 
TEST_F(PropertyProviderTest,String_Get)251 TEST_F(PropertyProviderTest, String_Get) {
252     const char* str = nullptr;
253     std::string initialValue = "Foo";
254     GesturesProp* propPtr = gesturePropProvider.create_string_fn(&mProvider, "A String", &str,
255                                                                  initialValue.c_str());
256 
257     // Get handlers are supposed to be called before the property's data is accessed, so they can
258     // update it if necessary. This getter updates the values, so that the ordering can be checked.
259     struct GetterData {
260         const char** strPtr;
261         std::string newValue; // Have to store the new value outside getter so it stays allocated.
262     };
263     GetterData getterData = {&str, "Bar"};
264     GesturesPropGetHandler getter{[](void* handlerData) -> GesturesPropBool {
265         GetterData* data = static_cast<GetterData*>(handlerData);
266         *data->strPtr = data->newValue.c_str();
267         return true;
268     }};
269     gesturePropProvider.register_handlers_fn(&mProvider, propPtr, /* handler_data= */ &getterData,
270                                              getter, nullptr);
271 
272     ASSERT_TRUE(mProvider.hasProperty("A String"));
273     GesturesProp& prop = mProvider.getProperty("A String");
274     EXPECT_EQ(prop.getStringValue(), "Bar");
275 }
276 
TEST_F(PropertyProviderTest,Free)277 TEST_F(PropertyProviderTest, Free) {
278     int intData = 0;
279     int initialValue = 42;
280     GesturesProp* propPtr =
281             gesturePropProvider.create_int_fn(&mProvider, "Foo", &intData, 1, &initialValue);
282     gesturePropProvider.free_fn(&mProvider, propPtr);
283 
284     EXPECT_FALSE(mProvider.hasProperty("Foo"));
285 }
286 
287 class PropertyProviderIdcLoadingTest : public testing::Test {
288 protected:
SetUp()289     void SetUp() override {
290         int initialInt = 0;
291         GesturesPropBool initialBool = false;
292         double initialReal = 0.0;
293         gesturePropProvider.create_int_fn(&mProvider, "An Integer", &mIntData, 1, &initialInt);
294         gesturePropProvider.create_bool_fn(&mProvider, "A Boolean", &mBoolData, 1, &initialBool);
295         gesturePropProvider.create_real_fn(&mProvider, "A Real", &mRealData, 1, &initialReal);
296     }
297 
298     PropertyProvider mProvider;
299 
300     int mIntData;
301     GesturesPropBool mBoolData;
302     double mRealData;
303 };
304 
TEST_F(PropertyProviderIdcLoadingTest,AllCorrect)305 TEST_F(PropertyProviderIdcLoadingTest, AllCorrect) {
306     PropertyMap idcProps;
307     idcProps.addProperty("gestureProp.An_Integer", "42");
308     idcProps.addProperty("gestureProp.A_Boolean", "1");
309     idcProps.addProperty("gestureProp.A_Real", "3.14159");
310 
311     mProvider.loadPropertiesFromIdcFile(idcProps);
312     EXPECT_THAT(mProvider.getProperty("An Integer").getIntValues(), ElementsAre(42));
313     EXPECT_THAT(mProvider.getProperty("A Boolean").getBoolValues(), ElementsAre(true));
314     EXPECT_NEAR(mProvider.getProperty("A Real").getRealValues()[0], 3.14159, EPSILON);
315 }
316 
TEST_F(PropertyProviderIdcLoadingTest,InvalidPropsIgnored)317 TEST_F(PropertyProviderIdcLoadingTest, InvalidPropsIgnored) {
318     int intArrayData[2];
319     int initialInts[2] = {0, 1};
320     gesturePropProvider.create_int_fn(&mProvider, "Two Integers", intArrayData, 2, initialInts);
321 
322     PropertyMap idcProps;
323     // Wrong type
324     idcProps.addProperty("gestureProp.An_Integer", "37.25");
325     // Wrong size
326     idcProps.addProperty("gestureProp.Two_Integers", "42");
327     // Doesn't exist
328     idcProps.addProperty("gestureProp.Some_Nonexistent_Property", "1");
329     // A valid assignment that should still be applied despite the others being invalid
330     idcProps.addProperty("gestureProp.A_Real", "3.14159");
331 
332     mProvider.loadPropertiesFromIdcFile(idcProps);
333     EXPECT_THAT(mProvider.getProperty("An Integer").getIntValues(), ElementsAre(0));
334     EXPECT_THAT(mProvider.getProperty("Two Integers").getIntValues(), ElementsAre(0, 1));
335     EXPECT_FALSE(mProvider.hasProperty("Some Nonexistent Property"));
336     EXPECT_NEAR(mProvider.getProperty("A Real").getRealValues()[0], 3.14159, EPSILON);
337 }
338 
TEST_F(PropertyProviderIdcLoadingTest,FunkyName)339 TEST_F(PropertyProviderIdcLoadingTest, FunkyName) {
340     int data;
341     int initialData = 0;
342     gesturePropProvider.create_int_fn(&mProvider, "  I lOvE sNAKes ", &data, 1, &initialData);
343 
344     PropertyMap idcProps;
345     idcProps.addProperty("gestureProp.__I_lOvE_sNAKes_", "42");
346 
347     mProvider.loadPropertiesFromIdcFile(idcProps);
348     EXPECT_THAT(mProvider.getProperty("  I lOvE sNAKes ").getIntValues(), ElementsAre(42));
349 }
350 
351 } // namespace android
352