Ninja
build_log_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 "build_log.h"
00016 
00017 #include "util.h"
00018 #include "test.h"
00019 
00020 #ifdef _WIN32
00021 #include <fcntl.h>
00022 #include <share.h>
00023 #else
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <unistd.h>
00027 #endif
00028 
00029 namespace {
00030 
00031 const char kTestFilename[] = "BuildLogTest-tempfile";
00032 
00033 struct BuildLogTest : public StateTestWithBuiltinRules {
00034   virtual void SetUp() {
00035     // In case a crashing test left a stale file behind.
00036     unlink(kTestFilename);
00037   }
00038   virtual void TearDown() {
00039     unlink(kTestFilename);
00040   }
00041 };
00042 
00043 TEST_F(BuildLogTest, WriteRead) {
00044   AssertParse(&state_,
00045 "build out: cat mid\n"
00046 "build mid: cat in\n");
00047 
00048   BuildLog log1;
00049   string err;
00050   EXPECT_TRUE(log1.OpenForWrite(kTestFilename, &err));
00051   ASSERT_EQ("", err);
00052   log1.RecordCommand(state_.edges_[0], 15, 18);
00053   log1.RecordCommand(state_.edges_[1], 20, 25);
00054   log1.Close();
00055 
00056   BuildLog log2;
00057   EXPECT_TRUE(log2.Load(kTestFilename, &err));
00058   ASSERT_EQ("", err);
00059 
00060   ASSERT_EQ(2u, log1.entries().size());
00061   ASSERT_EQ(2u, log2.entries().size());
00062   BuildLog::LogEntry* e1 = log1.LookupByOutput("out");
00063   ASSERT_TRUE(e1);
00064   BuildLog::LogEntry* e2 = log2.LookupByOutput("out");
00065   ASSERT_TRUE(e2);
00066   ASSERT_TRUE(*e1 == *e2);
00067   ASSERT_EQ(15, e1->start_time);
00068   ASSERT_EQ("out", e1->output);
00069 }
00070 
00071 TEST_F(BuildLogTest, FirstWriteAddsSignature) {
00072   const char kExpectedVersion[] = "# ninja log vX\n";
00073   const size_t kVersionPos = strlen(kExpectedVersion) - 2;  // Points at 'X'.
00074 
00075   BuildLog log;
00076   string contents, err;
00077 
00078   EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err));
00079   ASSERT_EQ("", err);
00080   log.Close();
00081 
00082   ASSERT_EQ(0, ReadFile(kTestFilename, &contents, &err));
00083   ASSERT_EQ("", err);
00084   if (contents.size() >= kVersionPos)
00085     contents[kVersionPos] = 'X';
00086   EXPECT_EQ(kExpectedVersion, contents);
00087 
00088   // Opening the file anew shouldn't add a second version string.
00089   EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err));
00090   ASSERT_EQ("", err);
00091   log.Close();
00092 
00093   contents.clear();
00094   ASSERT_EQ(0, ReadFile(kTestFilename, &contents, &err));
00095   ASSERT_EQ("", err);
00096   if (contents.size() >= kVersionPos)
00097     contents[kVersionPos] = 'X';
00098   EXPECT_EQ(kExpectedVersion, contents);
00099 }
00100 
00101 TEST_F(BuildLogTest, DoubleEntry) {
00102   FILE* f = fopen(kTestFilename, "wb");
00103   fprintf(f, "# ninja log v4\n");
00104   fprintf(f, "0\t1\t2\tout\tcommand abc\n");
00105   fprintf(f, "3\t4\t5\tout\tcommand def\n");
00106   fclose(f);
00107 
00108   string err;
00109   BuildLog log;
00110   EXPECT_TRUE(log.Load(kTestFilename, &err));
00111   ASSERT_EQ("", err);
00112 
00113   BuildLog::LogEntry* e = log.LookupByOutput("out");
00114   ASSERT_TRUE(e);
00115   ASSERT_NO_FATAL_FAILURE(AssertHash("command def", e->command_hash));
00116 }
00117 
00118 TEST_F(BuildLogTest, Truncate) {
00119   AssertParse(&state_,
00120 "build out: cat mid\n"
00121 "build mid: cat in\n");
00122 
00123   BuildLog log1;
00124   string err;
00125   EXPECT_TRUE(log1.OpenForWrite(kTestFilename, &err));
00126   ASSERT_EQ("", err);
00127   log1.RecordCommand(state_.edges_[0], 15, 18);
00128   log1.RecordCommand(state_.edges_[1], 20, 25);
00129   log1.Close();
00130 
00131   struct stat statbuf;
00132   ASSERT_EQ(0, stat(kTestFilename, &statbuf));
00133   ASSERT_GT(statbuf.st_size, 0);
00134 
00135   // For all possible truncations of the input file, assert that we don't
00136   // crash when parsing.
00137   for (off_t size = statbuf.st_size; size > 0; --size) {
00138     BuildLog log2;
00139     string err;
00140     EXPECT_TRUE(log2.OpenForWrite(kTestFilename, &err));
00141     ASSERT_EQ("", err);
00142     log2.RecordCommand(state_.edges_[0], 15, 18);
00143     log2.RecordCommand(state_.edges_[1], 20, 25);
00144     log2.Close();
00145 
00146     ASSERT_TRUE(Truncate(kTestFilename, size, &err));
00147 
00148     BuildLog log3;
00149     err.clear();
00150     ASSERT_TRUE(log3.Load(kTestFilename, &err) || !err.empty());
00151   }
00152 }
00153 
00154 TEST_F(BuildLogTest, ObsoleteOldVersion) {
00155   FILE* f = fopen(kTestFilename, "wb");
00156   fprintf(f, "# ninja log v3\n");
00157   fprintf(f, "123 456 0 out command\n");
00158   fclose(f);
00159 
00160   string err;
00161   BuildLog log;
00162   EXPECT_TRUE(log.Load(kTestFilename, &err));
00163   ASSERT_NE(err.find("version"), string::npos);
00164 }
00165 
00166 TEST_F(BuildLogTest, SpacesInOutputV4) {
00167   FILE* f = fopen(kTestFilename, "wb");
00168   fprintf(f, "# ninja log v4\n");
00169   fprintf(f, "123\t456\t456\tout with space\tcommand\n");
00170   fclose(f);
00171 
00172   string err;
00173   BuildLog log;
00174   EXPECT_TRUE(log.Load(kTestFilename, &err));
00175   ASSERT_EQ("", err);
00176 
00177   BuildLog::LogEntry* e = log.LookupByOutput("out with space");
00178   ASSERT_TRUE(e);
00179   ASSERT_EQ(123, e->start_time);
00180   ASSERT_EQ(456, e->end_time);
00181   ASSERT_EQ(456, e->restat_mtime);
00182   ASSERT_NO_FATAL_FAILURE(AssertHash("command", e->command_hash));
00183 }
00184 
00185 TEST_F(BuildLogTest, DuplicateVersionHeader) {
00186   // Old versions of ninja accidentally wrote multiple version headers to the
00187   // build log on Windows. This shouldn't crash, and the second version header
00188   // should be ignored.
00189   FILE* f = fopen(kTestFilename, "wb");
00190   fprintf(f, "# ninja log v4\n");
00191   fprintf(f, "123\t456\t456\tout\tcommand\n");
00192   fprintf(f, "# ninja log v4\n");
00193   fprintf(f, "456\t789\t789\tout2\tcommand2\n");
00194   fclose(f);
00195 
00196   string err;
00197   BuildLog log;
00198   EXPECT_TRUE(log.Load(kTestFilename, &err));
00199   ASSERT_EQ("", err);
00200 
00201   BuildLog::LogEntry* e = log.LookupByOutput("out");
00202   ASSERT_TRUE(e);
00203   ASSERT_EQ(123, e->start_time);
00204   ASSERT_EQ(456, e->end_time);
00205   ASSERT_EQ(456, e->restat_mtime);
00206   ASSERT_NO_FATAL_FAILURE(AssertHash("command", e->command_hash));
00207 
00208   e = log.LookupByOutput("out2");
00209   ASSERT_TRUE(e);
00210   ASSERT_EQ(456, e->start_time);
00211   ASSERT_EQ(789, e->end_time);
00212   ASSERT_EQ(789, e->restat_mtime);
00213   ASSERT_NO_FATAL_FAILURE(AssertHash("command2", e->command_hash));
00214 }
00215 
00216 TEST_F(BuildLogTest, VeryLongInputLine) {
00217   // Ninja's build log buffer is currently 256kB. Lines longer than that are
00218   // silently ignored, but don't affect parsing of other lines.
00219   FILE* f = fopen(kTestFilename, "wb");
00220   fprintf(f, "# ninja log v4\n");
00221   fprintf(f, "123\t456\t456\tout\tcommand start");
00222   for (size_t i = 0; i < (512 << 10) / strlen(" more_command"); ++i)
00223     fputs(" more_command", f);
00224   fprintf(f, "\n");
00225   fprintf(f, "456\t789\t789\tout2\tcommand2\n");
00226   fclose(f);
00227 
00228   string err;
00229   BuildLog log;
00230   EXPECT_TRUE(log.Load(kTestFilename, &err));
00231   ASSERT_EQ("", err);
00232 
00233   BuildLog::LogEntry* e = log.LookupByOutput("out");
00234   ASSERT_EQ(NULL, e);
00235 
00236   e = log.LookupByOutput("out2");
00237   ASSERT_TRUE(e);
00238   ASSERT_EQ(456, e->start_time);
00239   ASSERT_EQ(789, e->end_time);
00240   ASSERT_EQ(789, e->restat_mtime);
00241   ASSERT_NO_FATAL_FAILURE(AssertHash("command2", e->command_hash));
00242 }
00243 
00244 TEST_F(BuildLogTest, MultiTargetEdge) {
00245   AssertParse(&state_,
00246 "build out out.d: cat\n");
00247 
00248   BuildLog log;
00249   log.RecordCommand(state_.edges_[0], 21, 22);
00250 
00251   ASSERT_EQ(2u, log.entries().size());
00252   BuildLog::LogEntry* e1 = log.LookupByOutput("out");
00253   ASSERT_TRUE(e1);
00254   BuildLog::LogEntry* e2 = log.LookupByOutput("out.d");
00255   ASSERT_TRUE(e2);
00256   ASSERT_EQ("out", e1->output);
00257   ASSERT_EQ("out.d", e2->output);
00258   ASSERT_EQ(21, e1->start_time);
00259   ASSERT_EQ(21, e2->start_time);
00260   ASSERT_EQ(22, e2->end_time);
00261   ASSERT_EQ(22, e2->end_time);
00262 }
00263 
00264 }  // anonymous namespace