// Copyright 2011 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "test.h" #include #include #include "build_log.h" #include "manifest_parser.h" #include "util.h" #ifdef _WIN32 #include #endif namespace { #ifdef _WIN32 #ifndef _mktemp_s /// mingw has no mktemp. Implement one with the same type as the one /// found in the Windows API. int _mktemp_s(char* templ) { char* ofs = strchr(templ, 'X'); sprintf(ofs, "%d", rand() % 1000000); return 0; } #endif /// Windows has no mkdtemp. Implement it in terms of _mktemp_s. char* mkdtemp(char* name_template) { int err = _mktemp_s(name_template); if (err < 0) { perror("_mktemp_s"); return NULL; } err = _mkdir(name_template); if (err < 0) { perror("mkdir"); return NULL; } return name_template; } #endif // _WIN32 string GetSystemTempDir() { #ifdef _WIN32 char buf[1024]; if (!GetTempPath(sizeof(buf), buf)) return ""; return buf; #else const char* tempdir = getenv("TMPDIR"); if (tempdir) return tempdir; return "/tmp"; #endif } } // anonymous namespace StateTestWithBuiltinRules::StateTestWithBuiltinRules() { AssertParse(&state_, "rule cat\n" " command = cat $in > $out\n"); } Node* StateTestWithBuiltinRules::GetNode(const string& path) { return state_.GetNode(path); } void AssertParse(State* state, const char* input) { ManifestParser parser(state, NULL); string err; ASSERT_TRUE(parser.ParseTest(input, &err)) << err; ASSERT_EQ("", err); } void AssertHash(const char* expected, uint64_t actual) { ASSERT_EQ(BuildLog::LogEntry::HashCommand(expected), actual); } void VirtualFileSystem::Create(const string& path, const string& contents) { files_[path].mtime = now_; files_[path].contents = contents; files_created_.insert(path); } TimeStamp VirtualFileSystem::Stat(const string& path) { FileMap::iterator i = files_.find(path); if (i != files_.end()) return i->second.mtime; return 0; } bool VirtualFileSystem::WriteFile(const string& path, const string& contents) { Create(path, contents); return true; } bool VirtualFileSystem::MakeDir(const string& path) { directories_made_.push_back(path); return true; // success } string VirtualFileSystem::ReadFile(const string& path, string* err) { files_read_.push_back(path); FileMap::iterator i = files_.find(path); if (i != files_.end()) return i->second.contents; return ""; } int VirtualFileSystem::RemoveFile(const string& path) { if (find(directories_made_.begin(), directories_made_.end(), path) != directories_made_.end()) return -1; FileMap::iterator i = files_.find(path); if (i != files_.end()) { files_.erase(i); files_removed_.insert(path); return 0; } else { return 1; } } void ScopedTempDir::CreateAndEnter(const string& name) { // First change into the system temp dir and save it for cleanup. start_dir_ = GetSystemTempDir(); if (start_dir_.empty()) Fatal("couldn't get system temp dir"); if (chdir(start_dir_.c_str()) < 0) Fatal("chdir: %s", strerror(errno)); // Create a temporary subdirectory of that. char name_template[1024]; strcpy(name_template, name.c_str()); strcat(name_template, "-XXXXXX"); char* tempname = mkdtemp(name_template); if (!tempname) Fatal("mkdtemp: %s", strerror(errno)); temp_dir_name_ = tempname; // chdir into the new temporary directory. if (chdir(temp_dir_name_.c_str()) < 0) Fatal("chdir: %s", strerror(errno)); } void ScopedTempDir::Cleanup() { if (temp_dir_name_.empty()) return; // Something went wrong earlier. // Move out of the directory we're about to clobber. if (chdir(start_dir_.c_str()) < 0) Fatal("chdir: %s", strerror(errno)); #ifdef _WIN32 string command = "rmdir /s /q " + temp_dir_name_; #else string command = "rm -rf " + temp_dir_name_; #endif if (system(command.c_str()) < 0) Fatal("system: %s", strerror(errno)); temp_dir_name_.clear(); }