1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // http://code.google.com/p/protobuf/ 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 (at) 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 67 string 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 93 namespace { 94 95 string 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. 113 class 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 138 TempDirDeleter temp_dir_deleter_; 139 140 } // namespace 141 142 string TestTempDir() { 143 return temp_dir_deleter_.GetTempDir(); 144 } 145 146 // TODO(kenton): Share duplicated code below. Too busy/lazy for now. 147 148 static string stdout_capture_filename_; 149 static string stderr_capture_filename_; 150 static int original_stdout_ = -1; 151 static int original_stderr_ = -1; 152 153 void 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 168 void 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 183 string 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 198 string 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 213 ScopedMemoryLog* ScopedMemoryLog::active_log_ = NULL; 214 215 ScopedMemoryLog::ScopedMemoryLog() { 216 GOOGLE_CHECK(active_log_ == NULL); 217 active_log_ = this; 218 old_handler_ = SetLogHandler(&HandleLog); 219 } 220 221 ScopedMemoryLog::~ScopedMemoryLog() { 222 SetLogHandler(old_handler_); 223 active_log_ = NULL; 224 } 225 226 const vector<string>& ScopedMemoryLog::GetMessages(LogLevel dummy) const { 227 GOOGLE_CHECK_EQ(dummy, ERROR); 228 return messages_; 229 } 230 231 void ScopedMemoryLog::HandleLog(LogLevel level, const char* filename, 232 int line, const string& message) { 233 GOOGLE_CHECK(active_log_ != NULL); 234 if (level == ERROR) { 235 active_log_->messages_.push_back(message); 236 } 237 } 238 239 namespace { 240 241 // Force shutdown at process exit so that we can test for memory leaks. To 242 // actually check for leaks, I suggest using the heap checker included with 243 // google-perftools. Set it to "draconian" mode to ensure that every last 244 // call to malloc() has a corresponding free(). 245 struct ForceShutdown { 246 ~ForceShutdown() { 247 ShutdownProtobufLibrary(); 248 } 249 } force_shutdown; 250 251 } // namespace 252 253 } // namespace protobuf 254 } // namespace google 255