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