1 // Copyright 2020 google llc
2 //
3 // licensed under the apache license, version 2.0 (the "license");
4 // you may not use this file except in compliance with the license.
5 // you may obtain a copy of the license at
6 //
7 //     http://www.apache.org/licenses/license-2.0
8 //
9 // unless required by applicable law or agreed to in writing, software
10 // distributed under the license is distributed on an "as is" basis,
11 // without warranties or conditions of any kind, either express or implied.
12 // see the license for the specific language governing permissions and
13 // limitations under the license.
14 
15 #ifndef SANDBOXED_API_TOOLS_CLANG_GENERATOR_FRONTEND_ACTION_TEST_UTIL_H_
16 #define SANDBOXED_API_TOOLS_CLANG_GENERATOR_FRONTEND_ACTION_TEST_UTIL_H_
17 
18 #include <memory>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "absl/container/flat_hash_map.h"
26 #include "absl/memory/memory.h"
27 #include "absl/status/status.h"
28 #include "absl/strings/str_cat.h"
29 #include "absl/strings/string_view.h"
30 #include "clang/Frontend/FrontendAction.h"
31 #include "sandboxed_api/util/status_matchers.h"
32 
33 namespace sapi {
34 namespace internal {
35 
36 absl::Status RunClangTool(
37     const std::vector<std::string> command_line,
38     const absl::flat_hash_map<std::string, std::string> file_contents,
39     std::unique_ptr<clang::FrontendAction> action);
40 
41 }  // namespace internal
42 
43 class FrontendActionTest : public ::testing::Test {
44  protected:
45   // Adds code to a virtual filesystem with the given filename.
AddCode(const std::string & filename,absl::string_view code)46   void AddCode(const std::string& filename, absl::string_view code) {
47     absl::StrAppend(&file_contents_[filename], code);
48   }
49 
50   // Changes the name of the virtual input file. Useful for special cases where
51   // the filenames of compiled sources matter.
set_input_file(absl::string_view value)52   void set_input_file(absl::string_view value) {
53     input_file_ = std::string(value);
54   }
55 
56   virtual std::vector<std::string> GetCommandLineFlagsForTesting(
57       absl::string_view input_file);
58 
59   // Runs the specified frontend action on in-memory source code.
RunFrontendAction(absl::string_view code,std::unique_ptr<clang::FrontendAction> action)60   absl::Status RunFrontendAction(
61       absl::string_view code, std::unique_ptr<clang::FrontendAction> action) {
62     std::vector<std::string> command_line =
63         GetCommandLineFlagsForTesting(input_file_);
64     AddCode(input_file_, code);
65     return internal::RunClangTool(command_line, file_contents_,
66                                   std::move(action));
67   }
68 
69   // Runs the specified frontend action. Provided for compatibility with LLVM <
70   // 10. Takes ownership.
RunFrontendAction(absl::string_view code,clang::FrontendAction * action)71   absl::Status RunFrontendAction(absl::string_view code,
72                                  clang::FrontendAction* action) {
73     return RunFrontendAction(code, absl::WrapUnique(action));
74   }
75 
76  private:
77   std::string input_file_ = "input.cc";
78   absl::flat_hash_map<std::string, std::string> file_contents_;
79 };
80 
81 // Flattens a piece of C++ code into one line and removes consecutive runs of
82 // whitespace. This makes it easier to compare code snippets for testing.
83 // Note: This is not syntax-aware and will replace characters within strings as
84 // well.
85 std::string Uglify(absl::string_view code);
86 
87 std::vector<std::string> UglifyAll(const std::vector<std::string>& snippets);
88 
89 }  // namespace sapi
90 
91 #endif  // SANDBOXED_API_TOOLS_CLANG_GENERATOR_FRONTEND_ACTION_TEST_UTIL_H_
92