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