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