1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef ZIRCON_SYSTEM_UTEST_FIDL_COMPILER_TEST_LIBRARY_H_
6 #define ZIRCON_SYSTEM_UTEST_FIDL_COMPILER_TEST_LIBRARY_H_
7 
8 #include <fidl/flat_ast.h>
9 #include <fidl/json_generator.h>
10 #include <fidl/lexer.h>
11 #include <fidl/parser.h>
12 #include <fidl/source_file.h>
13 
MakeSourceFile(const std::string & filename,const std::string & raw_source_code)14 static fidl::SourceFile MakeSourceFile(const std::string& filename, const std::string& raw_source_code) {
15     std::string source_code(raw_source_code);
16     // NUL terminate the string.
17     source_code.resize(source_code.size() + 1);
18     return fidl::SourceFile(filename, source_code);
19 }
20 
21 class TestLibrary {
22 public:
TestLibrary(const std::string & raw_source_code)23     TestLibrary(const std::string& raw_source_code)
24         : TestLibrary("example.fidl", raw_source_code) {}
25 
TestLibrary(const std::string & filename,const std::string & raw_source_code)26     TestLibrary(const std::string& filename, const std::string& raw_source_code)
27         : source_file_(MakeSourceFile(filename, raw_source_code)),
28           lexer_(source_file_, &error_reporter_),
29           parser_(&lexer_, &error_reporter_),
30           library_(std::make_unique<fidl::flat::Library>(
31               &all_libraries_, &error_reporter_, &typespace_)) {}
32 
AddDependentLibrary(TestLibrary & dependent_library)33     bool AddDependentLibrary(TestLibrary& dependent_library) {
34         // For testing, we have conveniences to construct compiled test
35         // libraries, which we usurp here to move it into the current library
36         // under test. This would be made clearer with a helper object which
37         // owned all libraries under test.
38         if (!all_libraries_.Insert(std::unique_ptr<fidl::flat::Library>(dependent_library.library_.get()))) {
39             return false;
40         }
41         dependent_library.library_.release();
42         return true;
43     }
44 
AddAttributeSchema(const std::string & name,fidl::flat::AttributeSchema schema)45     void AddAttributeSchema(const std::string& name, fidl::flat::AttributeSchema schema) {
46         all_libraries_.AddAttributeSchema(name, std::move(schema));
47     }
48 
Parse(std::unique_ptr<fidl::raw::File> & ast_ptr)49     bool Parse(std::unique_ptr<fidl::raw::File>& ast_ptr) {
50         ast_ptr.reset(parser_.Parse().release());
51         return parser_.Ok();
52     }
53 
Compile()54     bool Compile() {
55         auto ast = parser_.Parse();
56         return parser_.Ok() &&
57                library_->ConsumeFile(std::move(ast)) &&
58                library_->Compile();
59     }
60 
GenerateJSON()61     std::string GenerateJSON() {
62         auto json_generator = fidl::JSONGenerator(library_.get());
63         auto out = json_generator.Produce();
64         return out.str();
65     }
66 
AddSourceFile(const std::string & filename,const std::string & raw_source_code)67     bool AddSourceFile(const std::string& filename, const std::string& raw_source_code) {
68         auto source_file = MakeSourceFile(filename, raw_source_code);
69         fidl::Lexer lexer(source_file, &error_reporter_);
70         fidl::Parser parser(&lexer, &error_reporter_);
71         auto ast = parser.Parse();
72         return parser.Ok() &&
73                library_->ConsumeFile(std::move(ast)) &&
74                library_->Compile();
75     }
76 
LookupStruct(const std::string & name)77     const fidl::flat::Struct* LookupStruct(const std::string& name) {
78         for (const auto& struct_decl : library_->struct_declarations_) {
79             if (struct_decl->GetName() == name) {
80                 return struct_decl.get();
81             }
82         }
83         return nullptr;
84     }
85 
LookupTable(const std::string & name)86     const fidl::flat::Table* LookupTable(const std::string& name) {
87         for (const auto& table_decl : library_->table_declarations_) {
88             if (table_decl->GetName() == name) {
89                 return table_decl.get();
90             }
91         }
92         return nullptr;
93     }
94 
LookupUnion(const std::string & name)95     const fidl::flat::Union* LookupUnion(const std::string& name) {
96         for (const auto& union_decl : library_->union_declarations_) {
97             if (union_decl->GetName() == name) {
98                 return union_decl.get();
99             }
100         }
101         return nullptr;
102     }
103 
LookupInterface(const std::string & name)104     const fidl::flat::Interface* LookupInterface(const std::string& name) {
105         for (const auto& interface_decl : library_->interface_declarations_) {
106             if (interface_decl->GetName() == name) {
107                 return interface_decl.get();
108             }
109         }
110         return nullptr;
111     }
112 
library()113     const fidl::flat::Library* library() const {
114         return library_.get();
115     }
116 
source_file()117     fidl::SourceFile source_file() {
118         return source_file_;
119     }
120 
errors()121     const std::vector<std::string>& errors() const {
122         return error_reporter_.errors();
123     }
124 
warnings()125     const std::vector<std::string>& warnings() const {
126         return error_reporter_.warnings();
127     }
128 
129 protected:
130     fidl::SourceFile source_file_;
131     fidl::ErrorReporter error_reporter_;
132     fidl::flat::Typespace typespace_ = fidl::flat::Typespace::RootTypes();
133     fidl::Lexer lexer_;
134     fidl::Parser parser_;
135     fidl::flat::Libraries all_libraries_;
136     std::unique_ptr<fidl::flat::Library> library_;
137 };
138 
139 #endif // ZIRCON_SYSTEM_UTEST_FIDL_COMPILER_TEST_LIBRARY_H_
140