• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  // Protocol Buffers - Google's data interchange format
2  // Copyright 2008 Google Inc.  All rights reserved.
3  // https://developers.google.com/protocol-buffers/
4  //
5  // Redistribution and use in source and binary forms, with or without
6  // modification, are permitted provided that the following conditions are
7  // met:
8  //
9  //     * Redistributions of source code must retain the above copyright
10  // notice, this list of conditions and the following disclaimer.
11  //     * Redistributions in binary form must reproduce the above
12  // copyright notice, this list of conditions and the following disclaimer
13  // in the documentation and/or other materials provided with the
14  // distribution.
15  //     * Neither the name of Google Inc. nor the names of its
16  // contributors may be used to endorse or promote products derived from
17  // this software without specific prior written permission.
18  //
19  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  
31  // Author: kenton@google.com (Kenton Varda)
32  // emulates google3/testing/base/public/googletest.cc
33  
34  #include <google/protobuf/testing/googletest.h>
35  #include <google/protobuf/testing/file.h>
36  #include <google/protobuf/stubs/strutil.h>
37  #include <sys/stat.h>
38  #include <sys/types.h>
39  #include <errno.h>
40  #include <stdlib.h>
41  #ifdef _MSC_VER
42  #include <io.h>
43  #include <direct.h>
44  #else
45  #include <unistd.h>
46  #endif
47  #include <stdio.h>
48  #include <fcntl.h>
49  #include <iostream>
50  #include <fstream>
51  
52  namespace google {
53  namespace protobuf {
54  
55  #ifdef _WIN32
56  #define mkdir(name, mode) mkdir(name)
57  #endif
58  
59  #ifndef O_BINARY
60  #ifdef _O_BINARY
61  #define O_BINARY _O_BINARY
62  #else
63  #define O_BINARY 0     // If this isn't defined, the platform doesn't need it.
64  #endif
65  #endif
66  
TestSourceDir()67  string TestSourceDir() {
68  #ifndef GOOGLE_THIRD_PARTY_PROTOBUF
69  #ifdef GOOGLE_PROTOBUF_TEST_SOURCE_PATH
70    return GOOGLE_PROTOBUF_TEST_SOURCE_PATH;
71  #else
72  #ifndef _MSC_VER
73    // automake sets the "srcdir" environment variable.
74    char* result = getenv("srcdir");
75    if (result != NULL) {
76      return result;
77    }
78  #endif  // _MSC_VER
79  
80    // Look for the "src" directory.
81    string prefix = ".";
82  
83    while (!File::Exists(prefix + "/src/google/protobuf")) {
84      if (!File::Exists(prefix)) {
85        GOOGLE_LOG(FATAL)
86          << "Could not find protobuf source code.  Please run tests from "
87             "somewhere within the protobuf source package.";
88      }
89      prefix += "/..";
90    }
91    return prefix + "/src";
92  #endif  // GOOGLE_PROTOBUF_TEST_SOURCE_PATH
93  #else
94    return "third_party/protobuf/src";
95  #endif  // GOOGLE_THIRD_PARTY_PROTOBUF
96  }
97  
98  namespace {
99  
GetTemporaryDirectoryName()100  string GetTemporaryDirectoryName() {
101    // Tests run under Bazel "should not" use /tmp. Bazel sets this environment
102    // variable for tests to use instead.
103    char *from_environment = getenv("TEST_TMPDIR");
104    if (from_environment != NULL && from_environment[0] != '\0') {
105      return string(from_environment) + "/protobuf_tmpdir";
106    }
107  
108    // tmpnam() is generally not considered safe but we're only using it for
109    // testing.  We cannot use tmpfile() or mkstemp() since we're creating a
110    // directory.
111    char b[L_tmpnam + 1];     // HPUX multithread return 0 if s is 0
112    string result = tmpnam(b);
113  #ifdef _WIN32
114    // On Win32, tmpnam() returns a file prefixed with '\', but which is supposed
115    // to be used in the current working directory.  WTF?
116    if (HasPrefixString(result, "\\")) {
117      result.erase(0, 1);
118    }
119    // The Win32 API accepts forward slashes as a path delimiter even though
120    // backslashes are standard.  Let's avoid confusion and use only forward
121    // slashes.
122    result = StringReplace(result, "\\", "/", true);
123  #endif  // _WIN32
124    return result;
125  }
126  
127  // Creates a temporary directory on demand and deletes it when the process
128  // quits.
129  class TempDirDeleter {
130   public:
TempDirDeleter()131    TempDirDeleter() {}
~TempDirDeleter()132    ~TempDirDeleter() {
133      if (!name_.empty()) {
134        File::DeleteRecursively(name_, NULL, NULL);
135      }
136    }
137  
GetTempDir()138    string GetTempDir() {
139      if (name_.empty()) {
140        name_ = GetTemporaryDirectoryName();
141        GOOGLE_CHECK(mkdir(name_.c_str(), 0777) == 0) << strerror(errno);
142  
143        // Stick a file in the directory that tells people what this is, in case
144        // we abort and don't get a chance to delete it.
145        File::WriteStringToFileOrDie("", name_ + "/TEMP_DIR_FOR_PROTOBUF_TESTS");
146      }
147      return name_;
148    }
149  
150   private:
151    string name_;
152  };
153  
154  TempDirDeleter temp_dir_deleter_;
155  
156  }  // namespace
157  
TestTempDir()158  string TestTempDir() {
159    return temp_dir_deleter_.GetTempDir();
160  }
161  
162  // TODO(kenton):  Share duplicated code below.  Too busy/lazy for now.
163  
164  static string stdout_capture_filename_;
165  static string stderr_capture_filename_;
166  static int original_stdout_ = -1;
167  static int original_stderr_ = -1;
168  
CaptureTestStdout()169  void CaptureTestStdout() {
170    GOOGLE_CHECK_EQ(original_stdout_, -1) << "Already capturing.";
171  
172    stdout_capture_filename_ = TestTempDir() + "/captured_stdout";
173  
174    int fd = open(stdout_capture_filename_.c_str(),
175                  O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0777);
176    GOOGLE_CHECK(fd >= 0) << "open: " << strerror(errno);
177  
178    original_stdout_ = dup(1);
179    close(1);
180    dup2(fd, 1);
181    close(fd);
182  }
183  
CaptureTestStderr()184  void CaptureTestStderr() {
185    GOOGLE_CHECK_EQ(original_stderr_, -1) << "Already capturing.";
186  
187    stderr_capture_filename_ = TestTempDir() + "/captured_stderr";
188  
189    int fd = open(stderr_capture_filename_.c_str(),
190                  O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0777);
191    GOOGLE_CHECK(fd >= 0) << "open: " << strerror(errno);
192  
193    original_stderr_ = dup(2);
194    close(2);
195    dup2(fd, 2);
196    close(fd);
197  }
198  
GetCapturedTestStdout()199  string GetCapturedTestStdout() {
200    GOOGLE_CHECK_NE(original_stdout_, -1) << "Not capturing.";
201  
202    close(1);
203    dup2(original_stdout_, 1);
204    original_stdout_ = -1;
205  
206    string result;
207    File::ReadFileToStringOrDie(stdout_capture_filename_, &result);
208  
209    remove(stdout_capture_filename_.c_str());
210  
211    return result;
212  }
213  
GetCapturedTestStderr()214  string GetCapturedTestStderr() {
215    GOOGLE_CHECK_NE(original_stderr_, -1) << "Not capturing.";
216  
217    close(2);
218    dup2(original_stderr_, 2);
219    original_stderr_ = -1;
220  
221    string result;
222    File::ReadFileToStringOrDie(stderr_capture_filename_, &result);
223  
224    remove(stderr_capture_filename_.c_str());
225  
226    return result;
227  }
228  
229  ScopedMemoryLog* ScopedMemoryLog::active_log_ = NULL;
230  
ScopedMemoryLog()231  ScopedMemoryLog::ScopedMemoryLog() {
232    GOOGLE_CHECK(active_log_ == NULL);
233    active_log_ = this;
234    old_handler_ = SetLogHandler(&HandleLog);
235  }
236  
~ScopedMemoryLog()237  ScopedMemoryLog::~ScopedMemoryLog() {
238    SetLogHandler(old_handler_);
239    active_log_ = NULL;
240  }
241  
GetMessages(LogLevel level)242  const vector<string>& ScopedMemoryLog::GetMessages(LogLevel level) {
243    GOOGLE_CHECK(level == ERROR ||
244                 level == WARNING);
245    return messages_[level];
246  }
247  
HandleLog(LogLevel level,const char * filename,int line,const string & message)248  void ScopedMemoryLog::HandleLog(LogLevel level, const char* filename,
249                                  int line, const string& message) {
250    GOOGLE_CHECK(active_log_ != NULL);
251    if (level == ERROR || level == WARNING) {
252      active_log_->messages_[level].push_back(message);
253    }
254  }
255  
256  namespace {
257  
258  // Force shutdown at process exit so that we can test for memory leaks.  To
259  // actually check for leaks, I suggest using the heap checker included with
260  // google-perftools.  Set it to "draconian" mode to ensure that every last
261  // call to malloc() has a corresponding free().
262  struct ForceShutdown {
~ForceShutdowngoogle::protobuf::__anoncde038520211::ForceShutdown263    ~ForceShutdown() {
264      ShutdownProtobufLibrary();
265    }
266  } force_shutdown;
267  
268  }  // namespace
269  
270  }  // namespace protobuf
271  }  // namespace google
272