• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "google/protobuf/compiler/command_line_interface_tester.h"
9 
10 #include <cstddef>
11 #include <string>
12 #include <vector>
13 
14 #include "google/protobuf/testing/file.h"
15 #include "google/protobuf/testing/file.h"
16 #include "google/protobuf/testing/file.h"
17 #include <gmock/gmock.h>
18 #include "google/protobuf/testing/googletest.h"
19 #include <gtest/gtest.h>
20 #include "absl/log/absl_check.h"
21 #include "absl/status/status.h"
22 #include "absl/strings/str_cat.h"
23 #include "absl/strings/str_replace.h"
24 #include "absl/strings/str_split.h"
25 #include "absl/strings/string_view.h"
26 
27 namespace google {
28 namespace protobuf {
29 namespace compiler {
30 namespace {
31 
32 using ::testing::HasSubstr;
33 
FileExists(const std::string & path)34 bool FileExists(const std::string& path) {
35   return File::Exists(path);
36 }
37 
38 }  // namespace
39 
CommandLineInterfaceTester()40 CommandLineInterfaceTester::CommandLineInterfaceTester() {
41   temp_directory_ = absl::StrCat(TestTempDir(), "/proto2_cli_test_temp");
42 
43   // If the temp directory already exists, it must be left over from a
44   // previous run.  Delete it.
45   if (FileExists(temp_directory_)) {
46     File::DeleteRecursively(temp_directory_, NULL, NULL);
47   }
48 
49   // Create the temp directory.
50   ABSL_CHECK_OK(File::CreateDir(temp_directory_, 0777));
51 }
52 
~CommandLineInterfaceTester()53 CommandLineInterfaceTester::~CommandLineInterfaceTester() {
54   // Delete the temp directory.
55   if (FileExists(temp_directory_)) {
56     File::DeleteRecursively(temp_directory_, NULL, NULL);
57   }
58 }
59 
RunProtoc(absl::string_view command)60 void CommandLineInterfaceTester::RunProtoc(absl::string_view command) {
61   RunProtocWithArgs(absl::StrSplit(command, ' ', absl::SkipEmpty()));
62 }
63 
RunProtocWithArgs(std::vector<std::string> args)64 void CommandLineInterfaceTester::RunProtocWithArgs(
65     std::vector<std::string> args) {
66   std::vector<const char*> argv(args.size());
67 
68   for (size_t i = 0; i < args.size(); i++) {
69     args[i] = absl::StrReplaceAll(args[i], {{"$tmpdir", temp_directory_}});
70     argv[i] = args[i].c_str();
71   }
72 
73   // TODO: Cygwin doesn't work well if we try to capture stderr and
74   // stdout at the same time. Need to figure out why and add this capture back
75   // for Cygwin.
76 #if !defined(__CYGWIN__)
77   CaptureTestStdout();
78 #endif
79   CaptureTestStderr();
80 
81   return_code_ = cli_.Run(static_cast<int>(args.size()), argv.data());
82 
83   error_text_ = GetCapturedTestStderr();
84 #if !defined(__CYGWIN__)
85   captured_stdout_ = GetCapturedTestStdout();
86 #endif
87 }
88 
89 // -------------------------------------------------------------------
90 
CreateTempFile(absl::string_view name,absl::string_view contents)91 void CommandLineInterfaceTester::CreateTempFile(absl::string_view name,
92                                                 absl::string_view contents) {
93   // Create parent directory, if necessary.
94   std::string::size_type slash_pos = name.find_last_of('/');
95   if (slash_pos != std::string::npos) {
96     absl::string_view dir = name.substr(0, slash_pos);
97     if (!FileExists(absl::StrCat(temp_directory_, "/", dir))) {
98       ABSL_CHECK_OK(File::RecursivelyCreateDir(
99           absl::StrCat(temp_directory_, "/", dir), 0777));
100     }
101   }
102 
103   // Write file.
104   std::string full_name = absl::StrCat(temp_directory_, "/", name);
105   ABSL_CHECK_OK(File::SetContents(
106       full_name, absl::StrReplaceAll(contents, {{"$tmpdir", temp_directory_}}),
107       true));
108 }
109 
CreateTempDir(absl::string_view name)110 void CommandLineInterfaceTester::CreateTempDir(absl::string_view name) {
111   ABSL_CHECK_OK(File::RecursivelyCreateDir(
112       absl::StrCat(temp_directory_, "/", name), 0777));
113 }
114 
115 // -------------------------------------------------------------------
116 
ExpectNoErrors()117 void CommandLineInterfaceTester::ExpectNoErrors() {
118   EXPECT_EQ(0, return_code_);
119   EXPECT_EQ("", error_text_);
120 }
121 
ExpectErrorText(absl::string_view expected_text)122 void CommandLineInterfaceTester::ExpectErrorText(
123     absl::string_view expected_text) {
124   EXPECT_NE(0, return_code_);
125   EXPECT_EQ(absl::StrReplaceAll(expected_text, {{"$tmpdir", temp_directory_}}),
126             error_text_);
127 }
128 
ExpectErrorSubstring(absl::string_view expected_substring)129 void CommandLineInterfaceTester::ExpectErrorSubstring(
130     absl::string_view expected_substring) {
131   EXPECT_NE(0, return_code_);
132   EXPECT_THAT(error_text_, HasSubstr(expected_substring));
133 }
134 
ExpectWarningSubstring(absl::string_view expected_substring)135 void CommandLineInterfaceTester::ExpectWarningSubstring(
136     absl::string_view expected_substring) {
137   EXPECT_EQ(0, return_code_);
138   EXPECT_THAT(error_text_, HasSubstr(expected_substring));
139 }
140 
141 #if defined(_WIN32) && !defined(__CYGWIN__)
HasAlternateErrorSubstring(const std::string & expected_substring)142 bool CommandLineInterfaceTester::HasAlternateErrorSubstring(
143     const std::string& expected_substring) {
144   EXPECT_NE(0, return_code_);
145   return error_text_.find(expected_substring) != std::string::npos;
146 }
147 #endif  // _WIN32 && !__CYGWIN__
148 
ExpectCapturedStdout(absl::string_view expected_text)149 void CommandLineInterfaceTester::ExpectCapturedStdout(
150     absl::string_view expected_text) {
151   EXPECT_EQ(expected_text, captured_stdout_);
152 }
153 
154 void CommandLineInterfaceTester::
ExpectCapturedStdoutSubstringWithZeroReturnCode(absl::string_view expected_substring)155     ExpectCapturedStdoutSubstringWithZeroReturnCode(
156         absl::string_view expected_substring) {
157   EXPECT_EQ(0, return_code_);
158   EXPECT_THAT(captured_stdout_, HasSubstr(expected_substring));
159 }
160 
161 void CommandLineInterfaceTester::
ExpectCapturedStderrSubstringWithZeroReturnCode(absl::string_view expected_substring)162     ExpectCapturedStderrSubstringWithZeroReturnCode(
163         absl::string_view expected_substring) {
164   EXPECT_EQ(0, return_code_);
165   EXPECT_THAT(error_text_, HasSubstr(expected_substring));
166 }
167 
ExpectFileContent(absl::string_view filename,absl::string_view content)168 void CommandLineInterfaceTester::ExpectFileContent(absl::string_view filename,
169                                                    absl::string_view content) {
170   std::string path = absl::StrCat(temp_directory_, "/", filename);
171   std::string file_contents;
172   ABSL_CHECK_OK(File::GetContents(path, &file_contents, true));
173 
174   EXPECT_EQ(absl::StrReplaceAll(content, {{"$tmpdir", temp_directory_}}),
175             file_contents);
176 }
177 
178 }  // namespace compiler
179 }  // namespace protobuf
180 }  // namespace google
181