1 /*
2 * Copyright (C) 2015, 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 <string>
18
19 #include <gtest/gtest.h>
20
21 #include "ast_cpp.h"
22 #include "code_writer.h"
23
24 using std::string;
25 using std::vector;
26 using std::unique_ptr;
27
28 namespace android {
29 namespace aidl {
30 namespace cpp {
31 namespace {
32
33 // clang-format off
34 const char kExpectedHeaderOutput[] =
35 R"(#pragma once
36
37 #include <string>
38 #include <memory>
39
40 namespace android {
41
42 namespace test {
43
44 class TestClass {
45 public:
46 void NormalMethod(int normalarg, float normal2);
47 virtual void SubMethod(int subarg) const;
48 }; // class TestClass
49
50 class TestSubClass : public TestClass {
51 public:
52 virtual void SubMethod(int subarg) const;
53 }; // class TestSubClass
54
55 } // namespace test
56
57 } // namespace android
58 )";
59
60 const char kExpectedGenericHeaderOutput[] =
61 R"(#pragma once
62
63 #include <string>
64 #include <memory>
65
66 namespace android {
67
68 namespace test {
69
70 template <typename A, typename B>
71 class TestParcelable : public ::android::Parcelable {
72 public:
73 int a;
74 }; // class TestParcelable
75
76 } // namespace test
77
78 } // namespace android
79 )";
80 // clang-format on
81
82 const char kExpectedSwitchOutput[] =
83 R"(switch (var) {
84 case 2:
85 {
86 baz;
87 }
88 break;
89 case 1:
90 {
91 foo;
92 bar;
93 }
94 break;
95 }
96 )";
97
98 const char kExpectedMethodImplOutput[] =
99 R"(return_type ClassName::MethodName(int32_t a, int32_t b, int32_t* c) const {
100 foo;
101 bar;
102 }
103 )";
104 const char kExpectedGenericMethodImplOutput[] =
105 R"(template <typename T>
106 return_type ClassName<T>::MethodName(int32_t a, int32_t b, int32_t* c) const {
107 foo;
108 bar;
109 }
110 )";
111 } // namespace
112
113 class AstCppTests : public ::testing::Test {
114 protected:
CompareGeneratedCode(const AstNode & node,const string & expected_output)115 void CompareGeneratedCode(const AstNode& node,
116 const string& expected_output) {
117 string actual_output;
118 node.Write(CodeWriter::ForString(&actual_output).get());
119 EXPECT_EQ(expected_output, actual_output);
120 }
121 }; // class AstCppTests
122
123
TEST_F(AstCppTests,GeneratesHeader)124 TEST_F(AstCppTests, GeneratesHeader) {
125 unique_ptr<MethodDecl> norm{new MethodDecl(
126 "void", "NormalMethod",
127 ArgList{vector<string>{"int normalarg", "float normal2"}})};
128 unique_ptr<MethodDecl> sub{
129 new MethodDecl("void", "SubMethod",
130 ArgList{ "int subarg" },
131 MethodDecl::IS_CONST | MethodDecl::IS_VIRTUAL)};
132 unique_ptr<MethodDecl> sub2{
133 new MethodDecl("void", "SubMethod",
134 ArgList{ "int subarg" },
135 MethodDecl::IS_CONST | MethodDecl::IS_VIRTUAL)};
136 vector<unique_ptr<Declaration>> test_methods;
137 test_methods.push_back(std::move(norm));
138 test_methods.push_back(std::move(sub));
139
140 vector<unique_ptr<Declaration>> test_sub_methods;
141 test_sub_methods.push_back(std::move(sub2));
142
143 unique_ptr<Declaration> test{new ClassDecl{"TestClass", "", {}, std::move(test_methods), {}}};
144
145 unique_ptr<Declaration> test_sub{
146 new ClassDecl{"TestSubClass", "TestClass", {}, std::move(test_sub_methods), {}}};
147
148 vector<unique_ptr<Declaration>> classes;
149 classes.push_back(std::move(test));
150 classes.push_back(std::move(test_sub));
151
152 unique_ptr<CppNamespace> test_ns{new CppNamespace {"test",
153 std::move(classes)}};
154
155 vector<unique_ptr<Declaration>> test_ns_vec;
156 test_ns_vec.push_back(std::move(test_ns));
157
158 unique_ptr<CppNamespace> android_ns{new CppNamespace {"android",
159 std::move(test_ns_vec) }};
160
161 vector<unique_ptr<Declaration>> test_ns_globals;
162 test_ns_globals.push_back(std::move(android_ns));
163
164 CppHeader cpp_header{{"string", "memory"}, std::move(test_ns_globals)};
165 CompareGeneratedCode(cpp_header, kExpectedHeaderOutput);
166 }
167
TEST_F(AstCppTests,GeneratesGenericHeader)168 TEST_F(AstCppTests, GeneratesGenericHeader) {
169 const std::vector<std::string> type_params = {"A", "B"};
170 std::vector<std::unique_ptr<Declaration>> publics;
171 publics.emplace_back(new LiteralDecl("int a;\n"));
172 unique_ptr<Declaration> test{new ClassDecl{
173 "TestParcelable", "::android::Parcelable", type_params, std::move(publics), {}}};
174
175 vector<unique_ptr<Declaration>> classes;
176 classes.push_back(std::move(test));
177
178 unique_ptr<CppNamespace> test_ns{new CppNamespace{"test", std::move(classes)}};
179
180 vector<unique_ptr<Declaration>> test_ns_vec;
181 test_ns_vec.push_back(std::move(test_ns));
182
183 unique_ptr<CppNamespace> android_ns{new CppNamespace{"android", std::move(test_ns_vec)}};
184
185 vector<unique_ptr<Declaration>> test_ns_globals;
186 test_ns_globals.push_back(std::move(android_ns));
187
188 CppHeader cpp_header{{"string", "memory"}, std::move(test_ns_globals)};
189 CompareGeneratedCode(cpp_header, kExpectedGenericHeaderOutput);
190 }
191
TEST_F(AstCppTests,GeneratesUnscopedEnum)192 TEST_F(AstCppTests, GeneratesUnscopedEnum) {
193 Enum e("Foo", "", false);
194 e.AddValue("BAR", "42");
195 e.AddValue("BAZ", "");
196
197 string expected =
198 R"(enum Foo {
199 BAR = 42,
200 BAZ,
201 };
202 )";
203
204 CompareGeneratedCode(e, expected);
205 }
206
TEST_F(AstCppTests,GeneratesScopedEnum)207 TEST_F(AstCppTests, GeneratesScopedEnum) {
208 Enum e("Foo", "int32_t", true);
209 e.AddValue("BAR", "42");
210 e.AddValue("BAZ", "");
211
212 string expected =
213 R"(enum class Foo : int32_t {
214 BAR = 42,
215 BAZ,
216 };
217 )";
218
219 CompareGeneratedCode(e, expected);
220 }
221
TEST_F(AstCppTests,GeneratesArgList)222 TEST_F(AstCppTests, GeneratesArgList) {
223 ArgList simple("foo");
224 CompareGeneratedCode(simple, "(foo)");
225 ArgList compound({"foo", "bar", "baz"});
226 CompareGeneratedCode(compound, "(foo, bar, baz)");
227 std::vector<unique_ptr<AstNode>> args;
228 args.emplace_back(new LiteralExpression("foo()"));
229 ArgList nested(std::move(args));
230 CompareGeneratedCode(nested, "(foo())");
231 }
232
TEST_F(AstCppTests,GeneratesStatement)233 TEST_F(AstCppTests, GeneratesStatement) {
234 Statement s(new LiteralExpression("foo"));
235 CompareGeneratedCode(s, "foo;\n");
236 }
237
TEST_F(AstCppTests,GeneratesComparison)238 TEST_F(AstCppTests, GeneratesComparison) {
239 Comparison c(
240 new LiteralExpression("lhs"), "&&", new LiteralExpression("rhs"));
241 CompareGeneratedCode(c, "((lhs) && (rhs))");
242 }
243
TEST_F(AstCppTests,GeneratesStatementBlock)244 TEST_F(AstCppTests, GeneratesStatementBlock) {
245 StatementBlock block;
246 block.AddStatement(unique_ptr<AstNode>(new Statement("foo")));
247 block.AddStatement(unique_ptr<AstNode>(new Statement("bar")));
248 CompareGeneratedCode(block, "{\n foo;\n bar;\n}\n");
249 }
250
TEST_F(AstCppTests,GeneratesConstructorImpl)251 TEST_F(AstCppTests, GeneratesConstructorImpl) {
252 ConstructorImpl c("ClassName", ArgList({"a", "b", "c"}),
253 {"baz_(foo)", "bar_(blah)"});
254 string expected = R"(ClassName::ClassName(a, b, c)
255 : baz_(foo),
256 bar_(blah){
257 }
258 )";
259 CompareGeneratedCode(c, expected);
260 }
261
TEST_F(AstCppTests,GeneratesAssignment)262 TEST_F(AstCppTests, GeneratesAssignment) {
263 Assignment simple("foo", "8");
264 CompareGeneratedCode(simple, "foo = 8;\n");
265 Assignment less_simple("foo", new MethodCall("f", "8"));
266 CompareGeneratedCode(less_simple, "foo = f(8);\n");
267 }
268
TEST_F(AstCppTests,GeneratesMethodCall)269 TEST_F(AstCppTests, GeneratesMethodCall) {
270 MethodCall single("single", "arg");
271 CompareGeneratedCode(single, "single(arg)");
272 MethodCall multi(
273 "multi",
274 ArgList({"has", "some", "args"}));
275 CompareGeneratedCode(multi, "multi(has, some, args)");
276 }
277
TEST_F(AstCppTests,GeneratesIfStatement)278 TEST_F(AstCppTests, GeneratesIfStatement) {
279 IfStatement s(new LiteralExpression("foo"));
280 s.OnTrue()->AddLiteral("on true1");
281 s.OnFalse()->AddLiteral("on false");
282 CompareGeneratedCode(s, "if (foo) {\n on true1;\n}\nelse {\n on false;\n}\n");
283
284 IfStatement s2(new LiteralExpression("bar"));
285 s2.OnTrue()->AddLiteral("on true1");
286 CompareGeneratedCode(s2, "if (bar) {\n on true1;\n}\n");
287 }
288
TEST_F(AstCppTests,GeneratesSwitchStatement)289 TEST_F(AstCppTests, GeneratesSwitchStatement) {
290 SwitchStatement s("var");
291 // These are intentionally out of alphanumeric order. We're testing
292 // that switch respects case addition order.
293 auto case2 = s.AddCase("2");
294 case2->AddStatement(unique_ptr<AstNode>{new Statement{"baz"}});
295 auto case1 = s.AddCase("1");
296 case1->AddStatement(unique_ptr<AstNode>{new Statement{"foo"}});
297 case1->AddStatement(unique_ptr<AstNode>{new Statement{"bar"}});
298 CompareGeneratedCode(s, kExpectedSwitchOutput);
299 }
300
TEST_F(AstCppTests,GeneratesMethodImpl)301 TEST_F(AstCppTests, GeneratesMethodImpl) {
302 MethodImpl m{"return_type",
303 "ClassName",
304 "MethodName",
305 {},
306 ArgList{{"int32_t a", "int32_t b", "int32_t* c"}},
307 true};
308 auto b = m.GetStatementBlock();
309 b->AddLiteral("foo");
310 b->AddLiteral("bar");
311 CompareGeneratedCode(m, kExpectedMethodImplOutput);
312 }
313
TEST_F(AstCppTests,GeneratesGenericMethodImpl)314 TEST_F(AstCppTests, GeneratesGenericMethodImpl) {
315 MethodImpl m{"return_type",
316 "ClassName",
317 "MethodName",
318 {"T"},
319 ArgList{{"int32_t a", "int32_t b", "int32_t* c"}},
320 true};
321 auto b = m.GetStatementBlock();
322 b->AddLiteral("foo");
323 b->AddLiteral("bar");
324 CompareGeneratedCode(m, kExpectedGenericMethodImplOutput);
325 }
326
TEST_F(AstCppTests,ToString)327 TEST_F(AstCppTests, ToString) {
328 std::string literal = "void foo() {}";
329 LiteralDecl decl(literal);
330 std::string actual = decl.ToString();
331 EXPECT_EQ(literal, actual);
332 std::string written;
333 decl.Write(CodeWriter::ForString(&written).get());
334 EXPECT_EQ(literal, written);
335 }
336
337 } // namespace cpp
338 } // namespace aidl
339 } // namespace android
340