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