Home | History | Annotate | Download | only in aidl
      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