1 /*
2  * Copyright (C) 2016 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 "libhidl-gen-utils"
18 
19 #include <vector>
20 
21 #include <gtest/gtest.h>
22 
23 #include <ConstantExpression.h>
24 #include <Coordinator.h>
25 #include <hidl-util/FQName.h>
26 
27 #define EXPECT_EQ_OK(expectResult, call, ...)        \
28     do {                                             \
29         std::string result;                          \
30         status_t err = (call)(__VA_ARGS__, &result); \
31         EXPECT_EQ(err, ::android::OK);               \
32         EXPECT_EQ(expectResult, result);             \
33     } while (false)
34 
35 namespace android {
36 
37 class HidlGenHostTest : public ::testing::Test {};
38 
39 class HidlGenHostDeathTest : public ::testing::Test {};
40 
TEST_F(HidlGenHostTest,CoordinatorTest)41 TEST_F(HidlGenHostTest, CoordinatorTest) {
42     Coordinator coordinator;
43 
44     std::string error;
45     EXPECT_EQ(OK, coordinator.addPackagePath("a.b", "a1/b1", &error));
46     EXPECT_TRUE(error.empty());
47     EXPECT_NE(OK, coordinator.addPackagePath("a.b", "a2/b2/", &error));
48     EXPECT_FALSE(error.empty());
49 
50     coordinator.addDefaultPackagePath("a.b", "a3/b3/"); // should take path above
51     coordinator.addDefaultPackagePath("a.c", "a4/b4/"); // should succeed
52 
53     EXPECT_EQ_OK("a.b", coordinator.getPackageRoot, FQName("a.b.foo", "1.0"));
54     EXPECT_EQ_OK("a.c", coordinator.getPackageRoot, FQName("a.c.foo.bar", "1.0", "IFoo"));
55 
56     // getPackagePath(fqname, relative, sanitized, ...)
57     EXPECT_EQ_OK("a1/b1/foo/1.0/", coordinator.getPackagePath, FQName("a.b.foo", "1.0"), false,
58                  false);
59     EXPECT_EQ_OK("a4/b4/foo/bar/1.0/", coordinator.getPackagePath,
60                  FQName("a.c.foo.bar", "1.0", "IFoo"), false, false);
61     EXPECT_EQ_OK("a1/b1/foo/V1_0/", coordinator.getPackagePath, FQName("a.b.foo", "1.0"), false,
62                  true);
63     EXPECT_EQ_OK("a4/b4/foo/bar/V1_0/", coordinator.getPackagePath,
64                  FQName("a.c.foo.bar", "1.0", "IFoo"), false, true);
65     EXPECT_EQ_OK("foo/1.0/", coordinator.getPackagePath, FQName("a.b.foo", "1.0"), true, false);
66     EXPECT_EQ_OK("foo/bar/1.0/", coordinator.getPackagePath, FQName("a.c.foo.bar", "1.0", "IFoo"),
67                  true, false);
68     EXPECT_EQ_OK("foo/V1_0/", coordinator.getPackagePath, FQName("a.b.foo", "1.0"), true, true);
69     EXPECT_EQ_OK("foo/bar/V1_0/", coordinator.getPackagePath, FQName("a.c.foo.bar", "1.0", "IFoo"),
70                  true, true);
71 }
72 
TEST_F(HidlGenHostTest,CoordinatorFilepathTest)73 TEST_F(HidlGenHostTest, CoordinatorFilepathTest) {
74     using Location = Coordinator::Location;
75 
76     Coordinator coordinator;
77     coordinator.setOutputPath("foo/");
78     coordinator.setRootPath("bar/");
79 
80     std::string error;
81     EXPECT_EQ(OK, coordinator.addPackagePath("a.b", "a1/b1", &error));
82     EXPECT_TRUE(error.empty());
83 
84     const static FQName kName = FQName("a.b.c", "1.2");
85 
86     // get file names
87     EXPECT_EQ_OK("foo/x.y", coordinator.getFilepath, kName, Location::DIRECT, "x.y");
88     EXPECT_EQ_OK("foo/a1/b1/c/1.2/x.y", coordinator.getFilepath, kName, Location::PACKAGE_ROOT,
89                  "x.y");
90     EXPECT_EQ_OK("foo/a/b/c/1.2/x.y", coordinator.getFilepath, kName, Location::GEN_OUTPUT, "x.y");
91     EXPECT_EQ_OK("foo/a/b/c/V1_2/x.y", coordinator.getFilepath, kName, Location::GEN_SANITIZED,
92                  "x.y");
93 
94     // get directories
95     EXPECT_EQ_OK("foo/", coordinator.getFilepath, kName, Location::DIRECT, "");
96     EXPECT_EQ_OK("foo/a1/b1/c/1.2/", coordinator.getFilepath, kName, Location::PACKAGE_ROOT, "");
97     EXPECT_EQ_OK("foo/a/b/c/1.2/", coordinator.getFilepath, kName, Location::GEN_OUTPUT, "");
98     EXPECT_EQ_OK("foo/a/b/c/V1_2/", coordinator.getFilepath, kName, Location::GEN_SANITIZED, "");
99 }
100 
TEST_F(HidlGenHostTest,LocationTest)101 TEST_F(HidlGenHostTest, LocationTest) {
102     Location a{{"file", 3, 4}, {"file", 3, 5}};
103     Location b{{"file", 3, 6}, {"file", 3, 7}};
104     Location c{{"file", 4, 4}, {"file", 4, 5}};
105 
106     Location other{{"other", 0, 0}, {"other", 0, 1}};
107 
108     EXPECT_LT(a, b);
109     EXPECT_LT(b, c);
110     EXPECT_LT(a, c);
111     EXPECT_FALSE(Location::inSameFile(a, other));
112 }
113 
populateArgv(std::vector<const char * > options,char ** argv)114 void populateArgv(std::vector<const char*> options, char** argv) {
115     for (int i = 0; i < options.size(); i++) {
116         argv[i] = const_cast<char*>(options.at(i));
117     }
118 }
119 
TEST_F(HidlGenHostTest,CoordinatorRootPathTest)120 TEST_F(HidlGenHostTest, CoordinatorRootPathTest) {
121     // Test that rootPath is set correctly
122     Coordinator coordinator;
123 
124     std::vector<const char*> options = {"hidl-gen", "-p", "~/"};
125     char* argv[options.size()];
126 
127     populateArgv(options, argv);
128     coordinator.parseOptions(options.size(), argv, "", [&](int /* res */, char* /* arg */) {
129         // Coordinator should always handle -p
130         FAIL() << "Coordinator should handle -p";
131     });
132 
133     EXPECT_EQ("~/", coordinator.getRootPath());
134 }
135 
TEST_F(HidlGenHostDeathTest,CoordinatorTooManyRootPathsTest)136 TEST_F(HidlGenHostDeathTest, CoordinatorTooManyRootPathsTest) {
137     // Test that cannot set multiple rootPaths
138     Coordinator coordinator;
139 
140     std::vector<const char*> options = {"hidl-gen", "-p", "~/", "-p", "."};
141     char* argv[options.size()];
142 
143     populateArgv(options, argv);
144     EXPECT_DEATH(coordinator.parseOptions(options.size(), argv, "",
145                                           [&](int /* res */, char* /* arg */) {
146                                               // Coordinator should always handle -p
147                                               FAIL() << "Coordinator should handle -p";
148                                           }),
149                  "ERROR: -p <root path> can only be specified once.");
150 }
151 
TEST_F(HidlGenHostTest,CoordinatorNoDefaultRootTest)152 TEST_F(HidlGenHostTest, CoordinatorNoDefaultRootTest) {
153     // Test that overrides default root paths without specifying new roots
154     Coordinator coordinator;
155 
156     std::vector<const char*> options = {"hidl-gen", "-R"};
157     char* argv[options.size()];
158 
159     populateArgv(options, argv);
160     coordinator.parseOptions(options.size(), argv, "", [&](int /* res */, char* /* arg */) {
161         // Coordinator should always handle -R
162         FAIL() << "Coordinator should handle -R";
163     });
164 
165     // android.hardware is a default path. with -R specified it should not be set
166     std::string root;
167     EXPECT_NE(::android::OK,
168               coordinator.getPackageRoot(FQName("android.hardware.tests.Baz", "1.0"), &root));
169     EXPECT_EQ("", root);
170 }
171 
TEST_F(HidlGenHostTest,CoordinatorCustomArgParseTest)172 TEST_F(HidlGenHostTest, CoordinatorCustomArgParseTest) {
173     // Test custom args are sent to the function
174     Coordinator coordinator;
175 
176     std::string optstring = "xy:";
177     std::vector<const char*> options = {"hidl-gen", "-y", "yvalue", "-x"};
178     char* argv[options.size()];
179 
180     populateArgv(options, argv);
181 
182     bool xCalled = false;
183     bool yCalled = false;
184     coordinator.parseOptions(options.size(), argv, optstring, [&](int res, char* arg) {
185         switch (res) {
186             case 'x': {
187                 EXPECT_STREQ(nullptr, arg);
188                 xCalled = true;
189                 break;
190             }
191             case 'y': {
192                 EXPECT_STREQ(argv[2] /* "yvalue" */, arg);
193                 yCalled = true;
194                 break;
195             }
196             default: { FAIL() << "Coordinator sent invalid param " << (char)res; }
197         }
198     });
199 
200     // Ensure the function was called with both x and y
201     EXPECT_TRUE(xCalled);
202     EXPECT_TRUE(yCalled);
203 }
204 
main(int argc,char ** argv)205 int main(int argc, char **argv) {
206     ::testing::InitGoogleTest(&argc, argv);
207     return RUN_ALL_TESTS();
208 }
209 
210 }  // namespace android