1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2023 Google Inc. All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file or at 6 // https://developers.google.com/open-source/licenses/bsd 7 8 #ifndef GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_TESTER_H__ 9 #define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_TESTER_H__ 10 11 #include <fcntl.h> 12 #include <sys/stat.h> 13 #include <sys/types.h> 14 15 #include <memory> 16 #include <string> 17 #include <utility> 18 #include <vector> 19 20 #ifndef _MSC_VER 21 #include <unistd.h> 22 #endif 23 24 #include <gtest/gtest.h> 25 #include "absl/strings/string_view.h" 26 #include "google/protobuf/compiler/code_generator.h" 27 #include "google/protobuf/compiler/command_line_interface.h" 28 29 // Must be included last. 30 #include "google/protobuf/port_def.inc" 31 32 namespace google { 33 namespace protobuf { 34 namespace compiler { 35 36 // Provide a base class for testing the protoc CLI and plugins. 37 class CommandLineInterfaceTester : public testing::Test { 38 protected: 39 CommandLineInterfaceTester(); 40 ~CommandLineInterfaceTester() override; 41 42 // Runs the CommandLineInterface with the given command line. The 43 // command is automatically split on spaces, and the string "$tmpdir" 44 // is replaced with TestTempDir(). 45 void RunProtoc(absl::string_view command); 46 void RunProtocWithArgs(std::vector<std::string> args); 47 48 // ----------------------------------------------------------------- 49 // Methods to set up the test (called before Run()). 50 51 // Returns the temporary directory created for testing. temp_directory()52 std::string temp_directory() { return temp_directory_; } 53 AllowPlugins(const std::string & prefix)54 void AllowPlugins(const std::string& prefix) { cli_.AllowPlugins(prefix); } 55 RegisterGenerator(const std::string & flag_name,std::unique_ptr<CodeGenerator> generator,const std::string & help_text)56 void RegisterGenerator(const std::string& flag_name, 57 std::unique_ptr<CodeGenerator> generator, 58 const std::string& help_text) { 59 generators_.emplace_back(std::move(generator)); 60 cli_.RegisterGenerator(flag_name, generators_.back().get(), help_text); 61 } 62 RegisterGenerator(const std::string & flag_name,const std::string & option_flag_name,std::unique_ptr<CodeGenerator> generator,const std::string & help_text)63 void RegisterGenerator(const std::string& flag_name, 64 const std::string& option_flag_name, 65 std::unique_ptr<CodeGenerator> generator, 66 const std::string& help_text) { 67 generators_.emplace_back(std::move(generator)); 68 cli_.RegisterGenerator(flag_name, option_flag_name, 69 generators_.back().get(), help_text); 70 } 71 72 // Creates a temp file within temp_directory_ with the given name. 73 // The containing directory is also created if necessary. 74 void CreateTempFile(absl::string_view name, absl::string_view contents); 75 76 // Creates a subdirectory within temp_directory_. 77 void CreateTempDir(absl::string_view name); 78 79 #ifdef PROTOBUF_OPENSOURCE 80 // Changes working directory to temp directory. SwitchToTempDirectory()81 void SwitchToTempDirectory() { 82 File::ChangeWorkingDirectory(temp_directory_); 83 } 84 #endif // !PROTOBUF_OPENSOURCE 85 86 // ----------------------------------------------------------------- 87 // Methods to check the test results (called after Run()). 88 89 // Checks that no text was written to stderr during Run(), and Run() 90 // returned 0. 91 void ExpectNoErrors(); 92 93 // Checks that Run() returned non-zero and the stderr output is exactly 94 // the text given. expected_test may contain references to "$tmpdir", 95 // which will be replaced by the temporary directory path. 96 void ExpectErrorText(absl::string_view expected_text); 97 98 // Checks that Run() returned non-zero and the stderr contains the given 99 // substring. 100 void ExpectErrorSubstring(absl::string_view expected_substring); 101 102 // Checks that Run() returned zero and the stderr contains the given 103 // substring. 104 void ExpectWarningSubstring(absl::string_view expected_substring); 105 106 // Checks that the captured stdout is the same as the expected_text. 107 void ExpectCapturedStdout(absl::string_view expected_text); 108 109 // Checks that Run() returned zero and the stdout contains the given 110 // substring. 111 void ExpectCapturedStdoutSubstringWithZeroReturnCode( 112 absl::string_view expected_substring); 113 114 // Checks that Run() returned zero and the stderr contains the given 115 // substring. 116 void ExpectCapturedStderrSubstringWithZeroReturnCode( 117 absl::string_view expected_substring); 118 119 #if defined(_WIN32) && !defined(__CYGWIN__) 120 // Returns true if ExpectErrorSubstring(expected_substring) would pass, but 121 // does not fail otherwise. 122 bool HasAlternateErrorSubstring(const std::string& expected_substring); 123 #endif // _WIN32 && !__CYGWIN__ 124 125 void ExpectFileContent(absl::string_view filename, absl::string_view content); 126 127 private: 128 // The object we are testing. 129 CommandLineInterface cli_; 130 131 // We create a directory within TestTempDir() in order to add extra 132 // protection against accidentally deleting user files (since we recursively 133 // delete this directory during the test). This is the full path of that 134 // directory. 135 std::string temp_directory_; 136 137 // The result of Run(). 138 int return_code_; 139 140 // The captured stderr output. 141 std::string error_text_; 142 143 // The captured stdout. 144 std::string captured_stdout_; 145 146 std::vector<std::unique_ptr<CodeGenerator>> generators_; 147 }; 148 149 } // namespace compiler 150 } // namespace protobuf 151 } // namespace google 152 153 #include "google/protobuf/port_undef.inc" 154 155 #endif // GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_TEST_UTIL_H__ 156