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: 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 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 148 TEST_F(AstCppTests, GeneratesEnum) { 149 Enum e("Foo"); 150 e.AddValue("BAR", "42"); 151 e.AddValue("BAZ", ""); 152 CompareGeneratedCode(e, kExpectedEnumOutput); 153 } 154 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 166 TEST_F(AstCppTests, GeneratesStatement) { 167 Statement s(new LiteralExpression("foo")); 168 CompareGeneratedCode(s, "foo;\n"); 169 } 170 171 TEST_F(AstCppTests, GeneratesComparison) { 172 Comparison c( 173 new LiteralExpression("lhs"), "&&", new LiteralExpression("rhs")); 174 CompareGeneratedCode(c, "((lhs) && (rhs))"); 175 } 176 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 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 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 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 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 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 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