33 struct DepsLogTest :
public testing::Test {
34 virtual void SetUp() {
41 TEST_F(DepsLogTest, WriteRead) {
50 deps.push_back(state1.
GetNode(
"foo.h", 0));
51 deps.push_back(state1.
GetNode(
"bar.h", 0));
55 deps.push_back(state1.
GetNode(
"foo.h", 0));
56 deps.push_back(state1.
GetNode(
"bar2.h", 0));
60 ASSERT_TRUE(log_deps);
61 ASSERT_EQ(1, log_deps->
mtime);
63 ASSERT_EQ(
"foo.h", log_deps->
nodes[0]->
path());
64 ASSERT_EQ(
"bar.h", log_deps->
nodes[1]->
path());
74 ASSERT_EQ(log1.
nodes().size(), log2.
nodes().size());
75 for (
int i = 0; i < (int)log1.
nodes().size(); ++i) {
78 ASSERT_EQ(i, node1->
id());
79 ASSERT_EQ(node1->
id(), node2->
id());
84 ASSERT_TRUE(log_deps);
85 ASSERT_EQ(2, log_deps->
mtime);
87 ASSERT_EQ(
"foo.h", log_deps->
nodes[0]->
path());
88 ASSERT_EQ(
"bar2.h", log_deps->
nodes[1]->
path());
91 TEST_F(DepsLogTest, LotsOfDeps) {
92 const int kNumDeps = 100000;
102 for (
int i = 0; i < kNumDeps; ++i) {
104 sprintf(buf,
"file%d.h", i);
105 deps.push_back(state1.
GetNode(buf, 0));
125 TEST_F(DepsLogTest, DoubleEntry) {
136 deps.push_back(state.
GetNode(
"foo.h", 0));
137 deps.push_back(state.
GetNode(
"bar.h", 0));
140 #ifdef __USE_LARGEFILE64
147 file_size = (int)st.st_size;
148 ASSERT_GT(file_size, 0);
162 deps.push_back(state.
GetNode(
"foo.h", 0));
163 deps.push_back(state.
GetNode(
"bar.h", 0));
166 #ifdef __USE_LARGEFILE64
173 int file_size_2 = (int)st.st_size;
174 ASSERT_EQ(file_size, file_size_2);
179 TEST_F(DepsLogTest, Recompact) {
180 const char kManifest[] =
185 "build other_out.o: cc\n";
191 ASSERT_NO_FATAL_FAILURE(
AssertParse(&state, kManifest));
198 deps.push_back(state.
GetNode(
"foo.h", 0));
199 deps.push_back(state.
GetNode(
"bar.h", 0));
203 deps.push_back(state.
GetNode(
"foo.h", 0));
204 deps.push_back(state.
GetNode(
"baz.h", 0));
208 #ifdef __USE_LARGEFILE64
215 file_size = (int)st.st_size;
216 ASSERT_GT(file_size, 0);
223 ASSERT_NO_FATAL_FAILURE(
AssertParse(&state, kManifest));
232 deps.push_back(state.
GetNode(
"foo.h", 0));
236 #ifdef __USE_LARGEFILE64
243 file_size_2 = (int)st.st_size;
245 ASSERT_GT(file_size_2, file_size);
253 ASSERT_NO_FATAL_FAILURE(
AssertParse(&state, kManifest));
261 ASSERT_EQ(1, deps->
mtime);
263 ASSERT_EQ(
"foo.h", deps->
nodes[0]->
path());
268 ASSERT_EQ(1, deps->
mtime);
270 ASSERT_EQ(
"foo.h", deps->
nodes[0]->
path());
271 ASSERT_EQ(
"baz.h", deps->
nodes[1]->
path());
278 ASSERT_EQ(1, deps->
mtime);
280 ASSERT_EQ(
"foo.h", deps->
nodes[0]->
path());
281 ASSERT_EQ(out, log.
nodes()[out->
id()]);
285 ASSERT_EQ(1, deps->
mtime);
287 ASSERT_EQ(
"foo.h", deps->
nodes[0]->
path());
288 ASSERT_EQ(
"baz.h", deps->
nodes[1]->
path());
289 ASSERT_EQ(other_out, log.
nodes()[other_out->
id()]);
292 #ifdef __USE_LARGEFILE64
299 file_size_3 = (int)st.st_size;
300 ASSERT_LT(file_size_3, file_size_2);
315 ASSERT_EQ(1, deps->
mtime);
317 ASSERT_EQ(
"foo.h", deps->
nodes[0]->
path());
322 ASSERT_EQ(1, deps->
mtime);
324 ASSERT_EQ(
"foo.h", deps->
nodes[0]->
path());
325 ASSERT_EQ(
"baz.h", deps->
nodes[1]->
path());
341 #ifdef __USE_LARGEFILE64
348 int file_size_4 = (int)st.st_size;
349 ASSERT_LT(file_size_4, file_size_3);
354 TEST_F(DepsLogTest, InvalidHeader) {
355 const char *kInvalidHeaders[] = {
359 "# ninjadeps\n\001\002",
360 "# ninjadeps\n\001\002\003\004"
362 for (
size_t i = 0; i <
sizeof(kInvalidHeaders) /
sizeof(kInvalidHeaders[0]);
365 ASSERT_TRUE(deps_log != NULL);
367 strlen(kInvalidHeaders[i]),
368 fwrite(kInvalidHeaders[i], 1, strlen(kInvalidHeaders[i]), deps_log));
369 ASSERT_EQ(0 ,fclose(deps_log));
375 EXPECT_EQ(
"bad deps log signature or version; starting over", err);
380 TEST_F(DepsLogTest, Truncated) {
390 deps.push_back(state.
GetNode(
"foo.h", 0));
391 deps.push_back(state.
GetNode(
"bar.h", 0));
395 deps.push_back(state.
GetNode(
"foo.h", 0));
396 deps.push_back(state.
GetNode(
"bar2.h", 0));
403 #ifdef __USE_LARGEFILE64
416 for (
int size = (
int)st.st_size; size > 0; --size) {
428 ASSERT_GE(node_count, (
int)log.
nodes().size());
429 node_count =
static_cast<int>(log.
nodes().size());
432 int new_deps_count = 0;
433 for (vector<DepsLog::Deps*>::const_iterator i = log.
deps().begin();
434 i != log.
deps().end(); ++i) {
438 ASSERT_GE(deps_count, new_deps_count);
439 deps_count = new_deps_count;
444 TEST_F(DepsLogTest, TruncatedRecovery) {
454 deps.push_back(state.
GetNode(
"foo.h", 0));
455 deps.push_back(state.
GetNode(
"bar.h", 0));
459 deps.push_back(state.
GetNode(
"foo.h", 0));
460 deps.push_back(state.
GetNode(
"bar2.h", 0));
468 #ifdef __USE_LARGEFILE64
485 ASSERT_EQ(
"premature end of file; recovering", err);
496 deps.push_back(state.
GetNode(
"foo.h", 0));
497 deps.push_back(state.
GetNode(
"bar2.h", 0));
517 TEST_F(DepsLogTest, ReverseDepsNodes) {
525 deps.push_back(state.
GetNode(
"foo.h", 0));
526 deps.push_back(state.
GetNode(
"bar.h", 0));
530 deps.push_back(state.
GetNode(
"foo.h", 0));
531 deps.push_back(state.
GetNode(
"bar2.h", 0));
537 EXPECT_TRUE(rev_deps == state.
GetNode(
"out.o", 0) ||
538 rev_deps == state.
GetNode(
"out2.o", 0));
541 EXPECT_TRUE(rev_deps == state.
GetNode(
"out.o", 0));
544 TEST_F(DepsLogTest, MalformedDepsLog) {
553 std::vector<Node*> deps;
554 deps.push_back(state.
GetNode(
"foo.hh", 0));
555 deps.push_back(state.
GetNode(
"bar.hpp", 0));
563 std::string original_contents;
565 &original_contents, &err));
567 const size_t version_offset = 12;
568 ASSERT_EQ(
"# ninjadeps\n", original_contents.substr(0, version_offset));
569 ASSERT_EQ(
'\x04', original_contents[version_offset + 0]);
570 ASSERT_EQ(
'\x00', original_contents[version_offset + 1]);
571 ASSERT_EQ(
'\x00', original_contents[version_offset + 2]);
572 ASSERT_EQ(
'\x00', original_contents[version_offset + 3]);
575 static const uint8_t kFirstRecord[] = {
577 0x0c, 0x00, 0x00, 0x00,
579 'o',
'u',
't',
'.',
'o', 0x00, 0x00, 0x00,
581 0xff, 0xff, 0xff, 0xff,
584 const size_t kFirstRecordLen =
sizeof(kFirstRecord);
585 const size_t first_offset = version_offset + 4;
587 #define COMPARE_RECORD(start_pos, reference, len) \
588 ASSERT_EQ(original_contents.substr(start_pos, len), std::string(reinterpret_cast<const char*>(reference), len))
592 const size_t second_offset = first_offset + kFirstRecordLen;
594 static const uint8_t kSecondRecord[] = {
596 0x0c, 0x00, 0x00, 0x00,
598 'f',
'o',
'o',
'.',
'h',
'h', 0x00, 0x00,
600 0xfe, 0xff, 0xff, 0xff,
603 const size_t kSecondRecordLen =
sizeof(kSecondRecord);
607 const char kBadLogFile[] =
"DepsLogTest-corrupted.tempfile";
610 auto write_bad_log_file =
611 [&disk, &kBadLogFile](
const std::string& bad_contents) ->
bool {
613 return disk.
WriteFile(kBadLogFile, bad_contents,
false);
617 std::string bad_contents = original_contents;
618 bad_contents[0] =
'@';
620 ASSERT_TRUE(write_bad_log_file(bad_contents)) << strerror(errno);
626 ASSERT_EQ(
"bad deps log signature or version; starting over", err);
630 bad_contents = original_contents.substr(0, version_offset + 3);
631 ASSERT_TRUE(write_bad_log_file(bad_contents)) << strerror(errno);
637 ASSERT_EQ(
"bad deps log signature or version; starting over", err);
641 bad_contents = original_contents.substr(0, version_offset + 4 + 3);
642 ASSERT_TRUE(write_bad_log_file(bad_contents)) << strerror(errno);
652 bad_contents = original_contents;
653 bad_contents[first_offset + 0] =
'\x55';
654 bad_contents[first_offset + 1] =
'\xaa';
655 bad_contents[first_offset + 2] =
'\xff';
656 bad_contents[first_offset + 3] =
'\xff';
657 ASSERT_TRUE(write_bad_log_file(bad_contents)) << strerror(errno);
663 ASSERT_EQ(
"premature end of file; recovering", err);
667 bad_contents = original_contents;
668 bad_contents[first_offset] =
'\x01';
669 ASSERT_TRUE(write_bad_log_file(bad_contents)) << strerror(errno);
675 ASSERT_EQ(
"premature end of file; recovering", err);
const char kTestFilename[]
#define COMPARE_RECORD(start_pos, reference, len)
As build commands run they can output extra dependency information (e.g.
Deps * GetDeps(Node *node)
const std::vector< Node * > & nodes() const
Used for tests.
Node * GetFirstReverseDepsNode(Node *node)
bool Recompact(const std::string &path, std::string *err)
Rewrite the known log entries, throwing away old data.
bool OpenForWrite(const std::string &path, std::string *err)
bool RecordDeps(Node *node, TimeStamp mtime, const std::vector< Node * > &nodes)
const std::vector< Deps * > & deps() const
LoadStatus Load(const std::string &path, State *state, std::string *err)
Information about a node in the dependency graph: the file, whether it's dirty, mtime,...
const std::string & path() const
Implementation of DiskInterface that actually hits the disk.
Status ReadFile(const std::string &path, std::string *contents, std::string *err) override
Read and store in given string.
bool WriteFile(const std::string &path, const std::string &contents, bool crlf_on_windows) override
Create a file, with the specified name and contents If crlf_on_windows is true, will be converted t...
int RemoveFile(const std::string &path) override
Remove the file named path.
Global state (file status) for a single run.
Node * GetNode(StringPiece path, uint64_t slash_bits)
Node * LookupNode(StringPiece path) const
void AssertParse(State *state, const char *input, ManifestParserOptions opts)
int platformAwareUnlink(const char *filename)
bool Truncate(const string &path, size_t size, string *err)