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 52namespace google { 53namespace 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 67string TestSourceDir() { 68#ifdef _MSC_VER 69 // Look for the "src" directory. 70 string prefix = "."; 71 72 while (!File::Exists(prefix + "/src/google/protobuf")) { 73 if (!File::Exists(prefix)) { 74 GOOGLE_LOG(FATAL) 75 << "Could not find protobuf source code. Please run tests from " 76 "somewhere within the protobuf source package."; 77 } 78 prefix += "/.."; 79 } 80 return prefix + "/src"; 81#else 82 // automake sets the "srcdir" environment variable. 83 char* result = getenv("srcdir"); 84 if (result == NULL) { 85 // Otherwise, the test must be run from the source directory. 86 return "."; 87 } else { 88 return result; 89 } 90#endif 91} 92 93namespace { 94 95string GetTemporaryDirectoryName() { 96 // tmpnam() is generally not considered safe but we're only using it for 97 // testing. We cannot use tmpfile() or mkstemp() since we're creating a 98 // directory. 99 char b[L_tmpnam + 1]; // HPUX multithread return 0 if s is 0 100 string result = tmpnam(b); 101#ifdef _WIN32 102 // On Win32, tmpnam() returns a file prefixed with '\', but which is supposed 103 // to be used in the current working directory. WTF? 104 if (HasPrefixString(result, "\\")) { 105 result.erase(0, 1); 106 } 107#endif // _WIN32 108 return result; 109} 110 111// Creates a temporary directory on demand and deletes it when the process 112// quits. 113class TempDirDeleter { 114 public: 115 TempDirDeleter() {} 116 ~TempDirDeleter() { 117 if (!name_.empty()) { 118 File::DeleteRecursively(name_, NULL, NULL); 119 } 120 } 121 122 string GetTempDir() { 123 if (name_.empty()) { 124 name_ = GetTemporaryDirectoryName(); 125 GOOGLE_CHECK(mkdir(name_.c_str(), 0777) == 0) << strerror(errno); 126 127 // Stick a file in the directory that tells people what this is, in case 128 // we abort and don't get a chance to delete it. 129 File::WriteStringToFileOrDie("", name_ + "/TEMP_DIR_FOR_PROTOBUF_TESTS"); 130 } 131 return name_; 132 } 133 134 private: 135 string name_; 136}; 137 138TempDirDeleter temp_dir_deleter_; 139 140} // namespace 141 142string TestTempDir() { 143 return temp_dir_deleter_.GetTempDir(); 144} 145 146// TODO(kenton): Share duplicated code below. Too busy/lazy for now. 147 148static string stdout_capture_filename_; 149static string stderr_capture_filename_; 150static int original_stdout_ = -1; 151static int original_stderr_ = -1; 152 153void CaptureTestStdout() { 154 GOOGLE_CHECK_EQ(original_stdout_, -1) << "Already capturing."; 155 156 stdout_capture_filename_ = TestTempDir() + "/captured_stdout"; 157 158 int fd = open(stdout_capture_filename_.c_str(), 159 O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0777); 160 GOOGLE_CHECK(fd >= 0) << "open: " << strerror(errno); 161 162 original_stdout_ = dup(1); 163 close(1); 164 dup2(fd, 1); 165 close(fd); 166} 167 168void CaptureTestStderr() { 169 GOOGLE_CHECK_EQ(original_stderr_, -1) << "Already capturing."; 170 171 stderr_capture_filename_ = TestTempDir() + "/captured_stderr"; 172 173 int fd = open(stderr_capture_filename_.c_str(), 174 O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0777); 175 GOOGLE_CHECK(fd >= 0) << "open: " << strerror(errno); 176 177 original_stderr_ = dup(2); 178 close(2); 179 dup2(fd, 2); 180 close(fd); 181} 182 183string GetCapturedTestStdout() { 184 GOOGLE_CHECK_NE(original_stdout_, -1) << "Not capturing."; 185 186 close(1); 187 dup2(original_stdout_, 1); 188 original_stdout_ = -1; 189 190 string result; 191 File::ReadFileToStringOrDie(stdout_capture_filename_, &result); 192 193 remove(stdout_capture_filename_.c_str()); 194 195 return result; 196} 197 198string GetCapturedTestStderr() { 199 GOOGLE_CHECK_NE(original_stderr_, -1) << "Not capturing."; 200 201 close(2); 202 dup2(original_stderr_, 2); 203 original_stderr_ = -1; 204 205 string result; 206 File::ReadFileToStringOrDie(stderr_capture_filename_, &result); 207 208 remove(stderr_capture_filename_.c_str()); 209 210 return result; 211} 212 213ScopedMemoryLog* ScopedMemoryLog::active_log_ = NULL; 214 215ScopedMemoryLog::ScopedMemoryLog() { 216 GOOGLE_CHECK(active_log_ == NULL); 217 active_log_ = this; 218 old_handler_ = SetLogHandler(&HandleLog); 219} 220 221ScopedMemoryLog::~ScopedMemoryLog() { 222 SetLogHandler(old_handler_); 223 active_log_ = NULL; 224} 225 226const vector<string>& ScopedMemoryLog::GetMessages(LogLevel level) { 227 GOOGLE_CHECK(level == ERROR || 228 level == WARNING); 229 return messages_[level]; 230} 231 232void ScopedMemoryLog::HandleLog(LogLevel level, const char* filename, 233 int line, const string& message) { 234 GOOGLE_CHECK(active_log_ != NULL); 235 if (level == ERROR || level == WARNING) { 236 active_log_->messages_[level].push_back(message); 237 } 238} 239 240namespace { 241 242// Force shutdown at process exit so that we can test for memory leaks. To 243// actually check for leaks, I suggest using the heap checker included with 244// google-perftools. Set it to "draconian" mode to ensure that every last 245// call to malloc() has a corresponding free(). 246struct ForceShutdown { 247 ~ForceShutdown() { 248 ShutdownProtobufLibrary(); 249 } 250} force_shutdown; 251 252} // namespace 253 254} // namespace protobuf 255} // namespace google 256