1 /*
2  * Copyright (C) 2019 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 <android-base/file.h>
18 #include <cutils/fs.h>
19 #include <gtest/gtest.h>
20 
21 #include <cstdlib>
22 #include <fstream>
23 
24 #include "Hardware.h"
25 
26 namespace aidl {
27 namespace android {
28 namespace hardware {
29 namespace vibrator {
30 
31 using ::testing::Test;
32 using ::testing::TestParamInfo;
33 using ::testing::ValuesIn;
34 using ::testing::WithParamInterface;
35 
36 class HwApiTest : public Test {
37   protected:
38     static constexpr const char *FILE_NAMES[]{
39             "device/autocal",
40             "device/ol_lra_period",
41             "activate",
42             "duration",
43             "state",
44             "device/rtp_input",
45             "device/mode",
46             "device/set_sequencer",
47             "device/scale",
48             "device/ctrl_loop",
49             "device/lp_trigger_effect",
50             "device/lp_trigger_scale",
51             "device/lra_wave_shape",
52             "device/od_clamp",
53     };
54 
55     static constexpr const char *REQUIRED[]{
56             "activate",
57             "duration",
58             "state",
59     };
60 
61   public:
SetUp()62     void SetUp() override {
63         std::string prefix;
64         for (auto n : FILE_NAMES) {
65             auto name = std::filesystem::path(n);
66             auto path = std::filesystem::path(mFilesDir.path) / name;
67             fs_mkdirs(path.c_str(), S_IRWXU);
68             std::ofstream touch{path};
69             mFileMap[name] = path;
70         }
71         prefix = std::filesystem::path(mFilesDir.path) / "";
72         setenv("HWAPI_PATH_PREFIX", prefix.c_str(), true);
73         mHwApi = HwApi::Create();
74 
75         for (auto n : REQUIRED) {
76             auto name = std::filesystem::path(n);
77             auto path = std::filesystem::path(mEmptyDir.path) / name;
78             fs_mkdirs(path.c_str(), S_IRWXU);
79             std::ofstream touch{path};
80         }
81         prefix = std::filesystem::path(mEmptyDir.path) / "";
82         setenv("HWAPI_PATH_PREFIX", prefix.c_str(), true);
83         mNoApi = HwApi::Create();
84     }
85 
TearDown()86     void TearDown() override { verifyContents(); }
87 
88   protected:
89     // Set expected file content for a test.
90     template <typename T>
expectContent(const std::string & name,const T & value)91     void expectContent(const std::string &name, const T &value) {
92         mExpectedContent[name] << value << std::endl;
93     }
94 
95     // Set actual file content for an input test.
96     template <typename T>
updateContent(const std::string & name,const T & value)97     void updateContent(const std::string &name, const T &value) {
98         std::ofstream(mFileMap[name]) << value << std::endl;
99     }
100 
101     template <typename T>
expectAndUpdateContent(const std::string & name,const T & value)102     void expectAndUpdateContent(const std::string &name, const T &value) {
103         expectContent(name, value);
104         updateContent(name, value);
105     }
106 
107     // Compare all file contents against expected contents.
verifyContents()108     void verifyContents() {
109         for (auto &a : mFileMap) {
110             std::ifstream file{a.second};
111             std::string expect = mExpectedContent[a.first].str();
112             std::string actual = std::string(std::istreambuf_iterator<char>(file),
113                                              std::istreambuf_iterator<char>());
114             EXPECT_EQ(expect, actual) << a.first;
115         }
116     }
117 
118     // TODO(eliptus): Determine how to induce errors in required files
isRequired(const std::string & name)119     static bool isRequired(const std::string &name) {
120         for (auto n : REQUIRED) {
121             if (std::string(n) == name) {
122                 return true;
123             }
124         }
125         return false;
126     }
127 
ParamNameFixup(std::string str)128     static auto ParamNameFixup(std::string str) {
129         std::replace(str.begin(), str.end(), '/', '_');
130         return str;
131     }
132 
133   protected:
134     std::unique_ptr<Vibrator::HwApi> mHwApi;
135     std::unique_ptr<Vibrator::HwApi> mNoApi;
136     std::map<std::string, std::string> mFileMap;
137     TemporaryDir mFilesDir;
138     TemporaryDir mEmptyDir;
139     std::map<std::string, std::stringstream> mExpectedContent;
140 };
141 
142 class CreateTest : public HwApiTest, public WithParamInterface<const char *> {
143   public:
SetUp()144     void SetUp() override{};
TearDown()145     void TearDown() override{};
146 
PrintParam(const TestParamInfo<CreateTest::ParamType> & info)147     static auto PrintParam(const TestParamInfo<CreateTest::ParamType> &info) {
148         return ParamNameFixup(info.param);
149     }
AllParams()150     static auto &AllParams() { return FILE_NAMES; }
151 };
152 
TEST_P(CreateTest,file_missing)153 TEST_P(CreateTest, file_missing) {
154     auto skip = std::string(GetParam());
155     TemporaryDir dir;
156     std::unique_ptr<HwApi> hwapi;
157     std::string prefix;
158 
159     for (auto n : FILE_NAMES) {
160         auto name = std::string(n);
161         auto path = std::string(dir.path) + "/" + name;
162         if (name == skip) {
163             continue;
164         }
165         fs_mkdirs(path.c_str(), S_IRWXU);
166         std::ofstream touch{path};
167     }
168 
169     prefix = std::filesystem::path(dir.path) / "";
170     setenv("HWAPI_PATH_PREFIX", prefix.c_str(), true);
171     hwapi = HwApi::Create();
172     if (isRequired(skip)) {
173         EXPECT_EQ(nullptr, hwapi);
174     } else {
175         EXPECT_NE(nullptr, hwapi);
176     }
177 }
178 
179 INSTANTIATE_TEST_CASE_P(HwApiTests, CreateTest, ValuesIn(CreateTest::AllParams()),
180                         CreateTest::PrintParam);
181 
182 template <typename T>
183 class HwApiTypedTest : public HwApiTest,
184                        public WithParamInterface<std::tuple<std::string, std::function<T>>> {
185   public:
PrintParam(const TestParamInfo<typename HwApiTypedTest::ParamType> & info)186     static auto PrintParam(const TestParamInfo<typename HwApiTypedTest::ParamType> &info) {
187         return ParamNameFixup(std::get<0>(info.param));
188     }
MakeParam(std::string name,std::function<T> func)189     static auto MakeParam(std::string name, std::function<T> func) {
190         return std::make_tuple(name, func);
191     }
192 };
193 
194 using HasTest = HwApiTypedTest<bool(Vibrator::HwApi &)>;
195 
TEST_P(HasTest,success_returnsTrue)196 TEST_P(HasTest, success_returnsTrue) {
197     auto param = GetParam();
198     auto func = std::get<1>(param);
199 
200     EXPECT_TRUE(func(*mHwApi));
201 }
202 
TEST_P(HasTest,success_returnsFalse)203 TEST_P(HasTest, success_returnsFalse) {
204     auto param = GetParam();
205     auto func = std::get<1>(param);
206 
207     EXPECT_FALSE(func(*mNoApi));
208 }
209 
210 INSTANTIATE_TEST_CASE_P(HwApiTests, HasTest,
211                         ValuesIn({
212                                 HasTest::MakeParam("device/rtp_input",
213                                                    &Vibrator::HwApi::hasRtpInput),
214                         }),
215                         HasTest::PrintParam);
216 
217 using SetBoolTest = HwApiTypedTest<bool(Vibrator::HwApi &, bool)>;
218 
TEST_P(SetBoolTest,success_returnsTrue)219 TEST_P(SetBoolTest, success_returnsTrue) {
220     auto param = GetParam();
221     auto name = std::get<0>(param);
222     auto func = std::get<1>(param);
223 
224     expectContent(name, "1");
225 
226     EXPECT_TRUE(func(*mHwApi, true));
227 }
228 
TEST_P(SetBoolTest,success_returnsFalse)229 TEST_P(SetBoolTest, success_returnsFalse) {
230     auto param = GetParam();
231     auto name = std::get<0>(param);
232     auto func = std::get<1>(param);
233 
234     expectContent(name, "0");
235 
236     EXPECT_TRUE(func(*mHwApi, false));
237 }
238 
TEST_P(SetBoolTest,failure)239 TEST_P(SetBoolTest, failure) {
240     auto param = GetParam();
241     auto name = std::get<0>(param);
242     auto func = std::get<1>(param);
243 
244     if (isRequired(name)) {
245         GTEST_SKIP();
246     }
247 
248     EXPECT_FALSE(func(*mNoApi, true));
249     EXPECT_FALSE(func(*mNoApi, false));
250 }
251 
252 INSTANTIATE_TEST_CASE_P(HwApiTests, SetBoolTest,
253                         ValuesIn({
254                                 SetBoolTest::MakeParam("activate", &Vibrator::HwApi::setActivate),
255                                 SetBoolTest::MakeParam("state", &Vibrator::HwApi::setState),
256                                 SetBoolTest::MakeParam("device/ctrl_loop",
257                                                        &Vibrator::HwApi::setCtrlLoop),
258                         }),
259                         SetBoolTest::PrintParam);
260 
261 using SetInt8Test = HwApiTypedTest<bool(Vibrator::HwApi &, int8_t)>;
262 
TEST_P(SetInt8Test,success)263 TEST_P(SetInt8Test, success) {
264     auto param = GetParam();
265     auto name = std::get<0>(param);
266     auto func = std::get<1>(param);
267     int8_t value = std::rand();
268 
269     expectContent(name, +value);
270 
271     EXPECT_TRUE(func(*mHwApi, value));
272 }
273 
TEST_P(SetInt8Test,failure)274 TEST_P(SetInt8Test, failure) {
275     auto param = GetParam();
276     auto name = std::get<0>(param);
277     auto func = std::get<1>(param);
278     int8_t value = std::rand();
279 
280     if (isRequired(name)) {
281         GTEST_SKIP();
282     }
283 
284     EXPECT_FALSE(func(*mNoApi, value));
285 }
286 
287 INSTANTIATE_TEST_CASE_P(HwApiTests, SetInt8Test,
288                         ValuesIn({
289                                 SetInt8Test::MakeParam("device/rtp_input",
290                                                        &Vibrator::HwApi::setRtpInput),
291                         }),
292                         SetInt8Test::PrintParam);
293 
294 using SetUint8Test = HwApiTypedTest<bool(Vibrator::HwApi &, uint8_t)>;
295 
TEST_P(SetUint8Test,success)296 TEST_P(SetUint8Test, success) {
297     auto param = GetParam();
298     auto name = std::get<0>(param);
299     auto func = std::get<1>(param);
300     uint8_t value = std::rand();
301 
302     expectContent(name, +value);
303 
304     EXPECT_TRUE(func(*mHwApi, value));
305 }
306 
TEST_P(SetUint8Test,failure)307 TEST_P(SetUint8Test, failure) {
308     auto param = GetParam();
309     auto name = std::get<0>(param);
310     auto func = std::get<1>(param);
311     uint8_t value = std::rand();
312 
313     if (isRequired(name)) {
314         GTEST_SKIP();
315     }
316 
317     EXPECT_FALSE(func(*mNoApi, value));
318 }
319 
320 INSTANTIATE_TEST_CASE_P(HwApiTests, SetUint8Test,
321                         ValuesIn({
322                                 SetUint8Test::MakeParam("device/scale", &Vibrator::HwApi::setScale),
323                                 SetUint8Test::MakeParam("device/lp_trigger_scale",
324                                                         &Vibrator::HwApi::setLpTriggerScale),
325                         }),
326                         SetUint8Test::PrintParam);
327 
328 using SetUint32Test = HwApiTypedTest<bool(Vibrator::HwApi &, uint32_t)>;
329 
TEST_P(SetUint32Test,success)330 TEST_P(SetUint32Test, success) {
331     auto param = GetParam();
332     auto name = std::get<0>(param);
333     auto func = std::get<1>(param);
334     uint32_t value = std::rand();
335 
336     expectContent(name, value);
337 
338     EXPECT_TRUE(func(*mHwApi, value));
339 }
340 
TEST_P(SetUint32Test,failure)341 TEST_P(SetUint32Test, failure) {
342     auto param = GetParam();
343     auto name = std::get<0>(param);
344     auto func = std::get<1>(param);
345     uint32_t value = std::rand();
346 
347     if (isRequired(name)) {
348         GTEST_SKIP();
349     }
350 
351     EXPECT_FALSE(func(*mNoApi, value));
352 }
353 
354 INSTANTIATE_TEST_CASE_P(
355         HwApiTests, SetUint32Test,
356         ValuesIn({
357                 SetUint32Test::MakeParam("device/ol_lra_period", &Vibrator::HwApi::setOlLraPeriod),
358                 SetUint32Test::MakeParam("duration", &Vibrator::HwApi::setDuration),
359                 SetUint32Test::MakeParam("device/lp_trigger_effect",
360                                          &Vibrator::HwApi::setLpTriggerEffect),
361                 SetUint32Test::MakeParam("device/lra_wave_shape",
362                                          &Vibrator::HwApi::setLraWaveShape),
363                 SetUint32Test::MakeParam("device/od_clamp", &Vibrator::HwApi::setOdClamp),
364         }),
365         SetUint32Test::PrintParam);
366 
367 using SetStringTest = HwApiTypedTest<bool(Vibrator::HwApi &, std::string)>;
368 
TEST_P(SetStringTest,success)369 TEST_P(SetStringTest, success) {
370     auto param = GetParam();
371     auto name = std::get<0>(param);
372     auto func = std::get<1>(param);
373     std::string value = TemporaryFile().path;
374 
375     expectContent(name, value);
376 
377     EXPECT_TRUE(func(*mHwApi, value));
378 }
379 
TEST_P(SetStringTest,failure)380 TEST_P(SetStringTest, failure) {
381     auto param = GetParam();
382     auto name = std::get<0>(param);
383     auto func = std::get<1>(param);
384     std::string value = TemporaryFile().path;
385 
386     if (isRequired(name)) {
387         GTEST_SKIP();
388     }
389 
390     EXPECT_FALSE(func(*mNoApi, value));
391 }
392 
393 INSTANTIATE_TEST_CASE_P(
394         HwApiTests, SetStringTest,
395         ValuesIn({
396                 SetStringTest::MakeParam("device/autocal", &Vibrator::HwApi::setAutocal),
397                 SetStringTest::MakeParam("device/mode", &Vibrator::HwApi::setMode),
398                 SetStringTest::MakeParam("device/set_sequencer", &Vibrator::HwApi::setSequencer),
399         }),
400         SetStringTest::PrintParam);
401 
402 }  // namespace vibrator
403 }  // namespace hardware
404 }  // namespace android
405 }  // namespace aidl
406