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