• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 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 // Author: kenton@google.com (Kenton Varda)
9 // emulates google3/testing/base/public/googletest.cc
10 
11 #include "google/protobuf/testing/googletest.h"
12 
13 #include <errno.h>
14 #include <stdlib.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 
18 #include "absl/log/absl_check.h"
19 #include "absl/log/absl_log.h"
20 #include "absl/strings/match.h"
21 #include "absl/strings/str_cat.h"
22 #include "absl/strings/str_replace.h"
23 #include "google/protobuf/io/io_win32.h"
24 #include "google/protobuf/testing/file.h"
25 #include <gtest/gtest.h>
26 
27 #ifdef _MSC_VER
28 // #include <direct.h>
29 #else
30 #include <unistd.h>
31 #endif
32 #include <stdio.h>
33 #include <fcntl.h>
34 #include <iostream>
35 #include <fstream>
36 
37 namespace google {
38 namespace protobuf {
39 
40 #ifdef _WIN32
41 // DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
42 // them like we do below.
43 using google::protobuf::io::win32::close;
44 using google::protobuf::io::win32::dup2;
45 using google::protobuf::io::win32::dup;
46 using google::protobuf::io::win32::mkdir;
47 using google::protobuf::io::win32::open;
48 #endif
49 
50 #ifndef O_BINARY
51 #ifdef _O_BINARY
52 #define O_BINARY _O_BINARY
53 #else
54 #define O_BINARY 0     // If this isn't defined, the platform doesn't need it.
55 #endif
56 #endif
57 
TestSourceDir()58 std::string TestSourceDir() {
59 #ifndef GOOGLE_THIRD_PARTY_PROTOBUF
60 #ifdef GOOGLE_PROTOBUF_TEST_SOURCE_PATH
61   return GOOGLE_PROTOBUF_TEST_SOURCE_PATH;
62 #else
63 #ifndef _MSC_VER
64   // automake sets the "srcdir" environment variable.
65   char* result = getenv("srcdir");
66   if (result != nullptr) {
67     return result;
68   }
69 #endif  // _MSC_VER
70 
71   // Look for the "src" directory.
72   std::string prefix = ".";
73 
74   // Keep looking further up the directory tree until we find
75   // src/.../descriptor.cc. It is important to look for a particular file,
76   // keeping in mind that with Bazel builds the directory structure under
77   // bazel-bin/ looks similar to the main directory tree in the Git repo.
78   while (!File::Exists(
79       absl::StrCat(prefix, "/src/google/protobuf/descriptor.cc"))) {
80     if (!File::Exists(prefix)) {
81       ABSL_LOG(FATAL)
82           << "Could not find protobuf source code.  Please run tests from "
83              "somewhere within the protobuf source package.";
84     }
85     absl::StrAppend(&prefix, "/..");
86   }
87   absl::StrAppend(&prefix, "/src");
88   return prefix;
89 #endif  // GOOGLE_PROTOBUF_TEST_SOURCE_PATH
90 #else
91   return "third_party/protobuf/src";
92 #endif  // GOOGLE_THIRD_PARTY_PROTOBUF
93 }
94 
95 namespace {
96 
GetTemporaryDirectoryName()97 std::string GetTemporaryDirectoryName() {
98   std::string result = absl::StrCat(testing::TempDir(), "protobuf_tempdir");
99 #ifdef _WIN32
100   // The Win32 API accepts forward slashes as a path delimiter as long as the
101   // path doesn't use the "\\?\" prefix.
102   // Let's avoid confusion and use only forward slashes.
103   result = absl::StrReplaceAll(result, {{"\\", "/"}});
104 #endif  // _WIN32
105   return result;
106 }
107 
108 // Creates a temporary directory on demand and deletes it when the process
109 // quits.
110 class TempDirDeleter {
111  public:
TempDirDeleter()112   TempDirDeleter() {}
~TempDirDeleter()113   ~TempDirDeleter() {
114     if (!name_.empty()) {
115       File::DeleteRecursively(name_, nullptr, nullptr);
116     }
117   }
118 
GetTempDir()119   std::string GetTempDir() {
120     if (name_.empty()) {
121       name_ = GetTemporaryDirectoryName();
122       ABSL_CHECK(mkdir(name_.c_str(), 0777) == 0) << strerror(errno);
123 
124       // Stick a file in the directory that tells people what this is, in case
125       // we abort and don't get a chance to delete it.
126       File::WriteStringToFileOrDie(
127           "", absl::StrCat(name_, "/TEMP_DIR_FOR_PROTOBUF_TESTS"));
128     }
129     return name_;
130   }
131 
132  private:
133   std::string name_;
134 };
135 
136 TempDirDeleter temp_dir_deleter_;
137 
138 }  // namespace
139 
TestTempDir()140 std::string TestTempDir() { return temp_dir_deleter_.GetTempDir(); }
141 
142 // TODO:  Share duplicated code below.  Too busy/lazy for now.
143 
144 static std::string stdout_capture_filename_;
145 static std::string stderr_capture_filename_;
146 static int original_stdout_ = -1;
147 static int original_stderr_ = -1;
148 
CaptureTestStdout()149 void CaptureTestStdout() {
150   ABSL_CHECK_EQ(original_stdout_, -1) << "Already capturing.";
151 
152   stdout_capture_filename_ = absl::StrCat(TestTempDir(), "/captured_stdout");
153 
154   int fd = open(stdout_capture_filename_.c_str(),
155                 O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0777);
156   ABSL_CHECK(fd >= 0) << "open: " << strerror(errno);
157 
158   original_stdout_ = dup(1);
159   close(1);
160   dup2(fd, 1);
161   close(fd);
162 }
163 
CaptureTestStderr()164 void CaptureTestStderr() {
165   ABSL_CHECK_EQ(original_stderr_, -1) << "Already capturing.";
166 
167   stderr_capture_filename_ = absl::StrCat(TestTempDir(), "/captured_stderr");
168 
169   int fd = open(stderr_capture_filename_.c_str(),
170                 O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0777);
171   ABSL_CHECK(fd >= 0) << "open: " << strerror(errno);
172 
173   original_stderr_ = dup(2);
174   close(2);
175   dup2(fd, 2);
176   close(fd);
177 }
178 
GetCapturedTestStdout()179 std::string GetCapturedTestStdout() {
180   ABSL_CHECK_NE(original_stdout_, -1) << "Not capturing.";
181 
182   close(1);
183   dup2(original_stdout_, 1);
184   close(original_stdout_);
185   original_stdout_ = -1;
186 
187   std::string result;
188   File::ReadFileToStringOrDie(stdout_capture_filename_, &result);
189 
190   remove(stdout_capture_filename_.c_str());
191 
192   return result;
193 }
194 
GetCapturedTestStderr()195 std::string GetCapturedTestStderr() {
196   ABSL_CHECK_NE(original_stderr_, -1) << "Not capturing.";
197 
198   close(2);
199   dup2(original_stderr_, 2);
200   close(original_stderr_);
201   original_stderr_ = -1;
202 
203   std::string result;
204   File::ReadFileToStringOrDie(stderr_capture_filename_, &result);
205 
206   remove(stderr_capture_filename_.c_str());
207 
208   return result;
209 }
210 
211 namespace {
212 
213 // Force shutdown at process exit so that we can test for memory leaks.  To
214 // actually check for leaks, I suggest using the heap checker included with
215 // google-perftools.  Set it to "draconian" mode to ensure that every last
216 // call to malloc() has a corresponding free().
217 struct ForceShutdown {
~ForceShutdowngoogle::protobuf::__anon154c45850211::ForceShutdown218   ~ForceShutdown() {
219     ShutdownProtobufLibrary();
220     // Test to shutdown the library twice, which should succeed.
221     ShutdownProtobufLibrary();
222   }
223 } force_shutdown;
224 
225 }  // namespace
226 
227 }  // namespace protobuf
228 }  // namespace google
229