Ninja
test.cc
Go to the documentation of this file.
00001 // Copyright 2011 Google Inc. All Rights Reserved.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //     http://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include "test.h"
00016 
00017 #include <algorithm>
00018 
00019 #include <errno.h>
00020 
00021 #include "build_log.h"
00022 #include "manifest_parser.h"
00023 #include "util.h"
00024 
00025 #ifdef _WIN32
00026 #include <windows.h>
00027 #endif
00028 
00029 namespace {
00030 
00031 #ifdef _WIN32
00032 #ifndef _mktemp_s
00033 /// mingw has no mktemp.  Implement one with the same type as the one
00034 /// found in the Windows API.
00035 int _mktemp_s(char* templ) {
00036   char* ofs = strchr(templ, 'X');
00037   sprintf(ofs, "%d", rand() % 1000000);
00038   return 0;
00039 }
00040 #endif
00041 
00042 /// Windows has no mkdtemp.  Implement it in terms of _mktemp_s.
00043 char* mkdtemp(char* name_template) {
00044   int err = _mktemp_s(name_template);
00045   if (err < 0) {
00046     perror("_mktemp_s");
00047     return NULL;
00048   }
00049 
00050   err = _mkdir(name_template);
00051   if (err < 0) {
00052     perror("mkdir");
00053     return NULL;
00054   }
00055 
00056   return name_template;
00057 }
00058 #endif  // _WIN32
00059 
00060 string GetSystemTempDir() {
00061 #ifdef _WIN32
00062   char buf[1024];
00063   if (!GetTempPath(sizeof(buf), buf))
00064     return "";
00065   return buf;
00066 #else
00067   const char* tempdir = getenv("TMPDIR");
00068   if (tempdir)
00069     return tempdir;
00070   return "/tmp";
00071 #endif
00072 }
00073 
00074 }  // anonymous namespace
00075 
00076 StateTestWithBuiltinRules::StateTestWithBuiltinRules() {
00077   AddCatRule(&state_);
00078 }
00079 
00080 void StateTestWithBuiltinRules::AddCatRule(State* state) {
00081   AssertParse(state,
00082 "rule cat\n"
00083 "  command = cat $in > $out\n");
00084 }
00085 
00086 Node* StateTestWithBuiltinRules::GetNode(const string& path) {
00087   return state_.GetNode(path);
00088 }
00089 
00090 void AssertParse(State* state, const char* input) {
00091   ManifestParser parser(state, NULL);
00092   string err;
00093   ASSERT_TRUE(parser.ParseTest(input, &err)) << err;
00094   ASSERT_EQ("", err);
00095 }
00096 
00097 void AssertHash(const char* expected, uint64_t actual) {
00098   ASSERT_EQ(BuildLog::LogEntry::HashCommand(expected), actual);
00099 }
00100 
00101 void VirtualFileSystem::Create(const string& path,
00102                                const string& contents) {
00103   files_[path].mtime = now_;
00104   files_[path].contents = contents;
00105   files_created_.insert(path);
00106 }
00107 
00108 TimeStamp VirtualFileSystem::Stat(const string& path) {
00109   FileMap::iterator i = files_.find(path);
00110   if (i != files_.end())
00111     return i->second.mtime;
00112   return 0;
00113 }
00114 
00115 bool VirtualFileSystem::WriteFile(const string& path, const string& contents) {
00116   Create(path, contents);
00117   return true;
00118 }
00119 
00120 bool VirtualFileSystem::MakeDir(const string& path) {
00121   directories_made_.push_back(path);
00122   return true;  // success
00123 }
00124 
00125 string VirtualFileSystem::ReadFile(const string& path, string* err) {
00126   files_read_.push_back(path);
00127   FileMap::iterator i = files_.find(path);
00128   if (i != files_.end())
00129     return i->second.contents;
00130   return "";
00131 }
00132 
00133 int VirtualFileSystem::RemoveFile(const string& path) {
00134   if (find(directories_made_.begin(), directories_made_.end(), path)
00135       != directories_made_.end())
00136     return -1;
00137   FileMap::iterator i = files_.find(path);
00138   if (i != files_.end()) {
00139     files_.erase(i);
00140     files_removed_.insert(path);
00141     return 0;
00142   } else {
00143     return 1;
00144   }
00145 }
00146 
00147 void ScopedTempDir::CreateAndEnter(const string& name) {
00148   // First change into the system temp dir and save it for cleanup.
00149   start_dir_ = GetSystemTempDir();
00150   if (start_dir_.empty())
00151     Fatal("couldn't get system temp dir");
00152   if (chdir(start_dir_.c_str()) < 0)
00153     Fatal("chdir: %s", strerror(errno));
00154 
00155   // Create a temporary subdirectory of that.
00156   char name_template[1024];
00157   strcpy(name_template, name.c_str());
00158   strcat(name_template, "-XXXXXX");
00159   char* tempname = mkdtemp(name_template);
00160   if (!tempname)
00161     Fatal("mkdtemp: %s", strerror(errno));
00162   temp_dir_name_ = tempname;
00163 
00164   // chdir into the new temporary directory.
00165   if (chdir(temp_dir_name_.c_str()) < 0)
00166     Fatal("chdir: %s", strerror(errno));
00167 }
00168 
00169 void ScopedTempDir::Cleanup() {
00170   if (temp_dir_name_.empty())
00171     return;  // Something went wrong earlier.
00172 
00173   // Move out of the directory we're about to clobber.
00174   if (chdir(start_dir_.c_str()) < 0)
00175     Fatal("chdir: %s", strerror(errno));
00176 
00177 #ifdef _WIN32
00178   string command = "rmdir /s /q " + temp_dir_name_;
00179 #else
00180   string command = "rm -rf " + temp_dir_name_;
00181 #endif
00182   if (system(command.c_str()) < 0)
00183     Fatal("system: %s", strerror(errno));
00184 
00185   temp_dir_name_.clear();
00186 }