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 const char kExpectedHeaderOutput[] =
34 R"(#ifndef HEADER_INCLUDE_GUARD_H_
35 #define HEADER_INCLUDE_GUARD_H_
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 #endif // HEADER_INCLUDE_GUARD_H_)";
60
61 const char kExpectedEnumOutput[] =
62 R"(enum Foo {
63 BAR = 42,
64 BAZ,
65 };
66 )";
67
68 const char kExpectedSwitchOutput[] =
69 R"(switch (var) {
70 case 2:
71 {
72 baz;
73 }
74 break;
75 case 1:
76 {
77 foo;
78 bar;
79 }
80 break;
81 }
82 )";
83
84 const char kExpectedMethodImplOutput[] =
85 R"(return_type ClassName::MethodName(arg 1, arg 2, arg 3) const {
86 foo;
87 bar;
88 }
89 )";
90 } // namespace
91
92 class AstCppTests : public ::testing::Test {
93 protected:
CompareGeneratedCode(const AstNode & node,const string & expected_output)94 void CompareGeneratedCode(const AstNode& node,
95 const string& expected_output) {
96 string actual_output;
97 CodeWriterPtr writer = GetStringWriter(&actual_output);
98 node.Write(writer.get());
99 EXPECT_EQ(expected_output, actual_output);
100 }
101 }; // class AstCppTests
102
103
TEST_F(AstCppTests,GeneratesHeader)104 TEST_F(AstCppTests, GeneratesHeader) {
105 unique_ptr<MethodDecl> norm{new MethodDecl(
106 "void", "NormalMethod",
107 ArgList{vector<string>{"int normalarg", "float normal2"}})};
108 unique_ptr<MethodDecl> sub{
109 new MethodDecl("void", "SubMethod",
110 ArgList{ "int subarg" },
111 MethodDecl::IS_CONST | MethodDecl::IS_VIRTUAL)};
112 unique_ptr<MethodDecl> sub2{
113 new MethodDecl("void", "SubMethod",
114 ArgList{ "int subarg" },
115 MethodDecl::IS_CONST | MethodDecl::IS_VIRTUAL)};
116 vector<unique_ptr<Declaration>> test_methods;
117 test_methods.push_back(std::move(norm));
118 test_methods.push_back(std::move(sub));
119
120 vector<unique_ptr<Declaration>> test_sub_methods;
121 test_sub_methods.push_back(std::move(sub2));
122
123 unique_ptr<Declaration> test{new ClassDecl { "TestClass", "",
124 std::move(test_methods), {} }};
125
126 unique_ptr<Declaration> test_sub{new ClassDecl { "TestSubClass",
127 "TestClass", std::move(test_sub_methods), {} }};
128
129 vector<unique_ptr<Declaration>> classes;
130 classes.push_back(std::move(test));
131 classes.push_back(std::move(test_sub));
132
133 unique_ptr<CppNamespace> test_ns{new CppNamespace {"test",
134 std::move(classes)}};
135
136 vector<unique_ptr<Declaration>> test_ns_vec;
137 test_ns_vec.push_back(std::move(test_ns));
138
139 unique_ptr<CppNamespace> android_ns{new CppNamespace {"android",
140 std::move(test_ns_vec) }};
141
142 CppHeader cpp_header{"HEADER_INCLUDE_GUARD_H_", {"string", "memory"},
143 std::move(android_ns) };
144 CompareGeneratedCode(cpp_header, kExpectedHeaderOutput);
145 }
146
TEST_F(AstCppTests,GeneratesEnum)147 TEST_F(AstCppTests, GeneratesEnum) {
148 Enum e("Foo");
149 e.AddValue("BAR", "42");
150 e.AddValue("BAZ", "");
151 CompareGeneratedCode(e, kExpectedEnumOutput);
152 }
153
TEST_F(AstCppTests,GeneratesArgList)154 TEST_F(AstCppTests, GeneratesArgList) {
155 ArgList simple("foo");
156 CompareGeneratedCode(simple, "(foo)");
157 ArgList compound({"foo", "bar", "baz"});
158 CompareGeneratedCode(compound, "(foo, bar, baz)");
159 std::vector<unique_ptr<AstNode>> args;
160 args.emplace_back(new LiteralExpression("foo()"));
161 ArgList nested(std::move(args));
162 CompareGeneratedCode(nested, "(foo())");
163 }
164
TEST_F(AstCppTests,GeneratesStatement)165 TEST_F(AstCppTests, GeneratesStatement) {
166 Statement s(new LiteralExpression("foo"));
167 CompareGeneratedCode(s, "foo;\n");
168 }
169
TEST_F(AstCppTests,GeneratesComparison)170 TEST_F(AstCppTests, GeneratesComparison) {
171 Comparison c(
172 new LiteralExpression("lhs"), "&&", new LiteralExpression("rhs"));
173 CompareGeneratedCode(c, "((lhs) && (rhs))");
174 }
175
TEST_F(AstCppTests,GeneratesStatementBlock)176 TEST_F(AstCppTests, GeneratesStatementBlock) {
177 StatementBlock block;
178 block.AddStatement(unique_ptr<AstNode>(new Statement("foo")));
179 block.AddStatement(unique_ptr<AstNode>(new Statement("bar")));
180 CompareGeneratedCode(block, "{\nfoo;\nbar;\n}\n");
181 }
182
TEST_F(AstCppTests,GeneratesConstructorImpl)183 TEST_F(AstCppTests, GeneratesConstructorImpl) {
184 ConstructorImpl c("ClassName", ArgList({"a", "b", "c"}),
185 {"baz_(foo)", "bar_(blah)"});
186 string expected = R"(ClassName::ClassName(a, b, c)
187 : baz_(foo),
188 bar_(blah){
189 }
190 )";
191 CompareGeneratedCode(c, expected);
192 }
193
TEST_F(AstCppTests,GeneratesAssignment)194 TEST_F(AstCppTests, GeneratesAssignment) {
195 Assignment simple("foo", "8");
196 CompareGeneratedCode(simple, "foo = 8;\n");
197 Assignment less_simple("foo", new MethodCall("f", "8"));
198 CompareGeneratedCode(less_simple, "foo = f(8);\n");
199 }
200
TEST_F(AstCppTests,GeneratesMethodCall)201 TEST_F(AstCppTests, GeneratesMethodCall) {
202 MethodCall single("single", "arg");
203 CompareGeneratedCode(single, "single(arg)");
204 MethodCall multi(
205 "multi",
206 ArgList({"has", "some", "args"}));
207 CompareGeneratedCode(multi, "multi(has, some, args)");
208 }
209
TEST_F(AstCppTests,GeneratesIfStatement)210 TEST_F(AstCppTests, GeneratesIfStatement) {
211 IfStatement s(new LiteralExpression("foo"));
212 s.OnTrue()->AddLiteral("on true1");
213 s.OnFalse()->AddLiteral("on false");
214 CompareGeneratedCode(s, "if (foo) {\non true1;\n}\nelse {\non false;\n}\n");
215
216 IfStatement s2(new LiteralExpression("bar"));
217 s2.OnTrue()->AddLiteral("on true1");
218 CompareGeneratedCode(s2, "if (bar) {\non true1;\n}\n");
219 }
220
TEST_F(AstCppTests,GeneratesSwitchStatement)221 TEST_F(AstCppTests, GeneratesSwitchStatement) {
222 SwitchStatement s("var");
223 // These are intentionally out of alphanumeric order. We're testing
224 // that switch respects case addition order.
225 auto case2 = s.AddCase("2");
226 case2->AddStatement(unique_ptr<AstNode>{new Statement{"baz"}});
227 auto case1 = s.AddCase("1");
228 case1->AddStatement(unique_ptr<AstNode>{new Statement{"foo"}});
229 case1->AddStatement(unique_ptr<AstNode>{new Statement{"bar"}});
230 CompareGeneratedCode(s, kExpectedSwitchOutput);
231 }
232
TEST_F(AstCppTests,GeneratesMethodImpl)233 TEST_F(AstCppTests, GeneratesMethodImpl) {
234 MethodImpl m{"return_type", "ClassName", "MethodName",
235 ArgList{{"arg 1", "arg 2", "arg 3"}},
236 true};
237 auto b = m.GetStatementBlock();
238 b->AddLiteral("foo");
239 b->AddLiteral("bar");
240 CompareGeneratedCode(m, kExpectedMethodImplOutput);
241 }
242
243 } // namespace cpp
244 } // namespace aidl
245 } // namespace android
246