• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "clean.h"
16 #include "build.h"
17 
18 #include "util.h"
19 #include "test.h"
20 
21 #ifndef _WIN32
22 #include <unistd.h>
23 #endif
24 
25 using namespace std;
26 
27 namespace {
28 
29 const char kTestFilename[] = "CleanTest-tempfile";
30 
31 struct CleanTest : public StateTestWithBuiltinRules {
32   VirtualFileSystem fs_;
33   BuildConfig config_;
SetUp__anon61d4b1ad0111::CleanTest34   virtual void SetUp() {
35     config_.verbosity = BuildConfig::QUIET;
36   }
37 };
38 
TEST_F(CleanTest,CleanAll)39 TEST_F(CleanTest, CleanAll) {
40   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
41 "build in1: cat src1\n"
42 "build out1: cat in1\n"
43 "build in2: cat src2\n"
44 "build out2: cat in2\n"));
45   fs_.Create("in1", "");
46   fs_.Create("out1", "");
47   fs_.Create("in2", "");
48   fs_.Create("out2", "");
49 
50   Cleaner cleaner(&state_, config_, &fs_);
51 
52   ASSERT_EQ(0, cleaner.cleaned_files_count());
53   EXPECT_EQ(0, cleaner.CleanAll());
54   EXPECT_EQ(4, cleaner.cleaned_files_count());
55   EXPECT_EQ(4u, fs_.files_removed_.size());
56 
57   // Check they are removed.
58   string err;
59   EXPECT_EQ(0, fs_.Stat("in1", &err));
60   EXPECT_EQ(0, fs_.Stat("out1", &err));
61   EXPECT_EQ(0, fs_.Stat("in2", &err));
62   EXPECT_EQ(0, fs_.Stat("out2", &err));
63   fs_.files_removed_.clear();
64 
65   EXPECT_EQ(0, cleaner.CleanAll());
66   EXPECT_EQ(0, cleaner.cleaned_files_count());
67   EXPECT_EQ(0u, fs_.files_removed_.size());
68 }
69 
TEST_F(CleanTest,CleanAllDryRun)70 TEST_F(CleanTest, CleanAllDryRun) {
71   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
72 "build in1: cat src1\n"
73 "build out1: cat in1\n"
74 "build in2: cat src2\n"
75 "build out2: cat in2\n"));
76   fs_.Create("in1", "");
77   fs_.Create("out1", "");
78   fs_.Create("in2", "");
79   fs_.Create("out2", "");
80 
81   config_.dry_run = true;
82   Cleaner cleaner(&state_, config_, &fs_);
83 
84   ASSERT_EQ(0, cleaner.cleaned_files_count());
85   EXPECT_EQ(0, cleaner.CleanAll());
86   EXPECT_EQ(4, cleaner.cleaned_files_count());
87   EXPECT_EQ(0u, fs_.files_removed_.size());
88 
89   // Check they are not removed.
90   string err;
91   EXPECT_LT(0, fs_.Stat("in1", &err));
92   EXPECT_LT(0, fs_.Stat("out1", &err));
93   EXPECT_LT(0, fs_.Stat("in2", &err));
94   EXPECT_LT(0, fs_.Stat("out2", &err));
95   fs_.files_removed_.clear();
96 
97   EXPECT_EQ(0, cleaner.CleanAll());
98   EXPECT_EQ(4, cleaner.cleaned_files_count());
99   EXPECT_EQ(0u, fs_.files_removed_.size());
100 }
101 
TEST_F(CleanTest,CleanTarget)102 TEST_F(CleanTest, CleanTarget) {
103   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
104 "build in1: cat src1\n"
105 "build out1: cat in1\n"
106 "build in2: cat src2\n"
107 "build out2: cat in2\n"));
108   fs_.Create("in1", "");
109   fs_.Create("out1", "");
110   fs_.Create("in2", "");
111   fs_.Create("out2", "");
112 
113   Cleaner cleaner(&state_, config_, &fs_);
114 
115   ASSERT_EQ(0, cleaner.cleaned_files_count());
116   ASSERT_EQ(0, cleaner.CleanTarget("out1"));
117   EXPECT_EQ(2, cleaner.cleaned_files_count());
118   EXPECT_EQ(2u, fs_.files_removed_.size());
119 
120   // Check they are removed.
121   string err;
122   EXPECT_EQ(0, fs_.Stat("in1", &err));
123   EXPECT_EQ(0, fs_.Stat("out1", &err));
124   EXPECT_LT(0, fs_.Stat("in2", &err));
125   EXPECT_LT(0, fs_.Stat("out2", &err));
126   fs_.files_removed_.clear();
127 
128   ASSERT_EQ(0, cleaner.CleanTarget("out1"));
129   EXPECT_EQ(0, cleaner.cleaned_files_count());
130   EXPECT_EQ(0u, fs_.files_removed_.size());
131 }
132 
TEST_F(CleanTest,CleanTargetDryRun)133 TEST_F(CleanTest, CleanTargetDryRun) {
134   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
135 "build in1: cat src1\n"
136 "build out1: cat in1\n"
137 "build in2: cat src2\n"
138 "build out2: cat in2\n"));
139   fs_.Create("in1", "");
140   fs_.Create("out1", "");
141   fs_.Create("in2", "");
142   fs_.Create("out2", "");
143 
144   config_.dry_run = true;
145   Cleaner cleaner(&state_, config_, &fs_);
146 
147   ASSERT_EQ(0, cleaner.cleaned_files_count());
148   ASSERT_EQ(0, cleaner.CleanTarget("out1"));
149   EXPECT_EQ(2, cleaner.cleaned_files_count());
150   EXPECT_EQ(0u, fs_.files_removed_.size());
151 
152   // Check they are not removed.
153   string err;
154   EXPECT_LT(0, fs_.Stat("in1", &err));
155   EXPECT_LT(0, fs_.Stat("out1", &err));
156   EXPECT_LT(0, fs_.Stat("in2", &err));
157   EXPECT_LT(0, fs_.Stat("out2", &err));
158   fs_.files_removed_.clear();
159 
160   ASSERT_EQ(0, cleaner.CleanTarget("out1"));
161   EXPECT_EQ(2, cleaner.cleaned_files_count());
162   EXPECT_EQ(0u, fs_.files_removed_.size());
163 }
164 
TEST_F(CleanTest,CleanRule)165 TEST_F(CleanTest, CleanRule) {
166   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
167 "rule cat_e\n"
168 "  command = cat -e $in > $out\n"
169 "build in1: cat_e src1\n"
170 "build out1: cat in1\n"
171 "build in2: cat_e src2\n"
172 "build out2: cat in2\n"));
173   fs_.Create("in1", "");
174   fs_.Create("out1", "");
175   fs_.Create("in2", "");
176   fs_.Create("out2", "");
177 
178   Cleaner cleaner(&state_, config_, &fs_);
179 
180   ASSERT_EQ(0, cleaner.cleaned_files_count());
181   ASSERT_EQ(0, cleaner.CleanRule("cat_e"));
182   EXPECT_EQ(2, cleaner.cleaned_files_count());
183   EXPECT_EQ(2u, fs_.files_removed_.size());
184 
185   // Check they are removed.
186   string err;
187   EXPECT_EQ(0, fs_.Stat("in1", &err));
188   EXPECT_LT(0, fs_.Stat("out1", &err));
189   EXPECT_EQ(0, fs_.Stat("in2", &err));
190   EXPECT_LT(0, fs_.Stat("out2", &err));
191   fs_.files_removed_.clear();
192 
193   ASSERT_EQ(0, cleaner.CleanRule("cat_e"));
194   EXPECT_EQ(0, cleaner.cleaned_files_count());
195   EXPECT_EQ(0u, fs_.files_removed_.size());
196 }
197 
TEST_F(CleanTest,CleanRuleDryRun)198 TEST_F(CleanTest, CleanRuleDryRun) {
199   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
200 "rule cat_e\n"
201 "  command = cat -e $in > $out\n"
202 "build in1: cat_e src1\n"
203 "build out1: cat in1\n"
204 "build in2: cat_e src2\n"
205 "build out2: cat in2\n"));
206   fs_.Create("in1", "");
207   fs_.Create("out1", "");
208   fs_.Create("in2", "");
209   fs_.Create("out2", "");
210 
211   config_.dry_run = true;
212   Cleaner cleaner(&state_, config_, &fs_);
213 
214   ASSERT_EQ(0, cleaner.cleaned_files_count());
215   ASSERT_EQ(0, cleaner.CleanRule("cat_e"));
216   EXPECT_EQ(2, cleaner.cleaned_files_count());
217   EXPECT_EQ(0u, fs_.files_removed_.size());
218 
219   // Check they are not removed.
220   string err;
221   EXPECT_LT(0, fs_.Stat("in1", &err));
222   EXPECT_LT(0, fs_.Stat("out1", &err));
223   EXPECT_LT(0, fs_.Stat("in2", &err));
224   EXPECT_LT(0, fs_.Stat("out2", &err));
225   fs_.files_removed_.clear();
226 
227   ASSERT_EQ(0, cleaner.CleanRule("cat_e"));
228   EXPECT_EQ(2, cleaner.cleaned_files_count());
229   EXPECT_EQ(0u, fs_.files_removed_.size());
230 }
231 
TEST_F(CleanTest,CleanRuleGenerator)232 TEST_F(CleanTest, CleanRuleGenerator) {
233   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
234 "rule regen\n"
235 "  command = cat $in > $out\n"
236 "  generator = 1\n"
237 "build out1: cat in1\n"
238 "build out2: regen in2\n"));
239   fs_.Create("out1", "");
240   fs_.Create("out2", "");
241 
242   Cleaner cleaner(&state_, config_, &fs_);
243   EXPECT_EQ(0, cleaner.CleanAll());
244   EXPECT_EQ(1, cleaner.cleaned_files_count());
245   EXPECT_EQ(1u, fs_.files_removed_.size());
246 
247   fs_.Create("out1", "");
248 
249   EXPECT_EQ(0, cleaner.CleanAll(/*generator=*/true));
250   EXPECT_EQ(2, cleaner.cleaned_files_count());
251   EXPECT_EQ(2u, fs_.files_removed_.size());
252 }
253 
TEST_F(CleanTest,CleanDepFile)254 TEST_F(CleanTest, CleanDepFile) {
255   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
256 "rule cc\n"
257 "  command = cc $in > $out\n"
258 "  depfile = $out.d\n"
259 "build out1: cc in1\n"));
260   fs_.Create("out1", "");
261   fs_.Create("out1.d", "");
262 
263   Cleaner cleaner(&state_, config_, &fs_);
264   EXPECT_EQ(0, cleaner.CleanAll());
265   EXPECT_EQ(2, cleaner.cleaned_files_count());
266   EXPECT_EQ(2u, fs_.files_removed_.size());
267 }
268 
TEST_F(CleanTest,CleanDepFileOnCleanTarget)269 TEST_F(CleanTest, CleanDepFileOnCleanTarget) {
270   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
271 "rule cc\n"
272 "  command = cc $in > $out\n"
273 "  depfile = $out.d\n"
274 "build out1: cc in1\n"));
275   fs_.Create("out1", "");
276   fs_.Create("out1.d", "");
277 
278   Cleaner cleaner(&state_, config_, &fs_);
279   EXPECT_EQ(0, cleaner.CleanTarget("out1"));
280   EXPECT_EQ(2, cleaner.cleaned_files_count());
281   EXPECT_EQ(2u, fs_.files_removed_.size());
282 }
283 
TEST_F(CleanTest,CleanDepFileOnCleanRule)284 TEST_F(CleanTest, CleanDepFileOnCleanRule) {
285   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
286 "rule cc\n"
287 "  command = cc $in > $out\n"
288 "  depfile = $out.d\n"
289 "build out1: cc in1\n"));
290   fs_.Create("out1", "");
291   fs_.Create("out1.d", "");
292 
293   Cleaner cleaner(&state_, config_, &fs_);
294   EXPECT_EQ(0, cleaner.CleanRule("cc"));
295   EXPECT_EQ(2, cleaner.cleaned_files_count());
296   EXPECT_EQ(2u, fs_.files_removed_.size());
297 }
298 
TEST_F(CleanTest,CleanDyndep)299 TEST_F(CleanTest, CleanDyndep) {
300   // Verify that a dyndep file can be loaded to discover a new output
301   // to be cleaned.
302   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
303 "build out: cat in || dd\n"
304 "  dyndep = dd\n"
305   ));
306   fs_.Create("in", "");
307   fs_.Create("dd",
308 "ninja_dyndep_version = 1\n"
309 "build out | out.imp: dyndep\n"
310 );
311   fs_.Create("out", "");
312   fs_.Create("out.imp", "");
313 
314   Cleaner cleaner(&state_, config_, &fs_);
315 
316   ASSERT_EQ(0, cleaner.cleaned_files_count());
317   EXPECT_EQ(0, cleaner.CleanAll());
318   EXPECT_EQ(2, cleaner.cleaned_files_count());
319   EXPECT_EQ(2u, fs_.files_removed_.size());
320 
321   string err;
322   EXPECT_EQ(0, fs_.Stat("out", &err));
323   EXPECT_EQ(0, fs_.Stat("out.imp", &err));
324 }
325 
TEST_F(CleanTest,CleanDyndepMissing)326 TEST_F(CleanTest, CleanDyndepMissing) {
327   // Verify that a missing dyndep file is tolerated.
328   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
329 "build out: cat in || dd\n"
330 "  dyndep = dd\n"
331   ));
332   fs_.Create("in", "");
333   fs_.Create("out", "");
334   fs_.Create("out.imp", "");
335 
336   Cleaner cleaner(&state_, config_, &fs_);
337 
338   ASSERT_EQ(0, cleaner.cleaned_files_count());
339   EXPECT_EQ(0, cleaner.CleanAll());
340   EXPECT_EQ(1, cleaner.cleaned_files_count());
341   EXPECT_EQ(1u, fs_.files_removed_.size());
342 
343   string err;
344   EXPECT_EQ(0, fs_.Stat("out", &err));
345   EXPECT_EQ(1, fs_.Stat("out.imp", &err));
346 }
347 
TEST_F(CleanTest,CleanRspFile)348 TEST_F(CleanTest, CleanRspFile) {
349   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
350 "rule cc\n"
351 "  command = cc $in > $out\n"
352 "  rspfile = $rspfile\n"
353 "  rspfile_content=$in\n"
354 "build out1: cc in1\n"
355 "  rspfile = cc1.rsp\n"));
356   fs_.Create("out1", "");
357   fs_.Create("cc1.rsp", "");
358 
359   Cleaner cleaner(&state_, config_, &fs_);
360   EXPECT_EQ(0, cleaner.CleanAll());
361   EXPECT_EQ(2, cleaner.cleaned_files_count());
362   EXPECT_EQ(2u, fs_.files_removed_.size());
363 }
364 
TEST_F(CleanTest,CleanRsp)365 TEST_F(CleanTest, CleanRsp) {
366   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
367 "rule cat_rsp \n"
368 "  command = cat $rspfile > $out\n"
369 "  rspfile = $rspfile\n"
370 "  rspfile_content = $in\n"
371 "build in1: cat src1\n"
372 "build out1: cat in1\n"
373 "build in2: cat_rsp src2\n"
374 "  rspfile=in2.rsp\n"
375 "build out2: cat_rsp in2\n"
376 "  rspfile=out2.rsp\n"
377 ));
378   fs_.Create("in1", "");
379   fs_.Create("out1", "");
380   fs_.Create("in2.rsp", "");
381   fs_.Create("out2.rsp", "");
382   fs_.Create("in2", "");
383   fs_.Create("out2", "");
384 
385   Cleaner cleaner(&state_, config_, &fs_);
386   ASSERT_EQ(0, cleaner.cleaned_files_count());
387   ASSERT_EQ(0, cleaner.CleanTarget("out1"));
388   EXPECT_EQ(2, cleaner.cleaned_files_count());
389   ASSERT_EQ(0, cleaner.CleanTarget("in2"));
390   EXPECT_EQ(2, cleaner.cleaned_files_count());
391   ASSERT_EQ(0, cleaner.CleanRule("cat_rsp"));
392   EXPECT_EQ(2, cleaner.cleaned_files_count());
393 
394   EXPECT_EQ(6u, fs_.files_removed_.size());
395 
396   // Check they are removed.
397   string err;
398   EXPECT_EQ(0, fs_.Stat("in1", &err));
399   EXPECT_EQ(0, fs_.Stat("out1", &err));
400   EXPECT_EQ(0, fs_.Stat("in2", &err));
401   EXPECT_EQ(0, fs_.Stat("out2", &err));
402   EXPECT_EQ(0, fs_.Stat("in2.rsp", &err));
403   EXPECT_EQ(0, fs_.Stat("out2.rsp", &err));
404 }
405 
TEST_F(CleanTest,CleanFailure)406 TEST_F(CleanTest, CleanFailure) {
407   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
408                                       "build dir: cat src1\n"));
409   fs_.MakeDir("dir");
410   Cleaner cleaner(&state_, config_, &fs_);
411   EXPECT_NE(0, cleaner.CleanAll());
412 }
413 
TEST_F(CleanTest,CleanPhony)414 TEST_F(CleanTest, CleanPhony) {
415   string err;
416   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
417 "build phony: phony t1 t2\n"
418 "build t1: cat\n"
419 "build t2: cat\n"));
420 
421   fs_.Create("phony", "");
422   fs_.Create("t1", "");
423   fs_.Create("t2", "");
424 
425   // Check that CleanAll does not remove "phony".
426   Cleaner cleaner(&state_, config_, &fs_);
427   EXPECT_EQ(0, cleaner.CleanAll());
428   EXPECT_EQ(2, cleaner.cleaned_files_count());
429   EXPECT_LT(0, fs_.Stat("phony", &err));
430 
431   fs_.Create("t1", "");
432   fs_.Create("t2", "");
433 
434   // Check that CleanTarget does not remove "phony".
435   EXPECT_EQ(0, cleaner.CleanTarget("phony"));
436   EXPECT_EQ(2, cleaner.cleaned_files_count());
437   EXPECT_LT(0, fs_.Stat("phony", &err));
438 }
439 
TEST_F(CleanTest,CleanDepFileAndRspFileWithSpaces)440 TEST_F(CleanTest, CleanDepFileAndRspFileWithSpaces) {
441   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
442 "rule cc_dep\n"
443 "  command = cc $in > $out\n"
444 "  depfile = $out.d\n"
445 "rule cc_rsp\n"
446 "  command = cc $in > $out\n"
447 "  rspfile = $out.rsp\n"
448 "  rspfile_content = $in\n"
449 "build out$ 1: cc_dep in$ 1\n"
450 "build out$ 2: cc_rsp in$ 1\n"
451 ));
452   fs_.Create("out 1", "");
453   fs_.Create("out 2", "");
454   fs_.Create("out 1.d", "");
455   fs_.Create("out 2.rsp", "");
456 
457   Cleaner cleaner(&state_, config_, &fs_);
458   EXPECT_EQ(0, cleaner.CleanAll());
459   EXPECT_EQ(4, cleaner.cleaned_files_count());
460   EXPECT_EQ(4u, fs_.files_removed_.size());
461 
462   string err;
463   EXPECT_EQ(0, fs_.Stat("out 1", &err));
464   EXPECT_EQ(0, fs_.Stat("out 2", &err));
465   EXPECT_EQ(0, fs_.Stat("out 1.d", &err));
466   EXPECT_EQ(0, fs_.Stat("out 2.rsp", &err));
467 }
468 
469 struct CleanDeadTest : public CleanTest, public BuildLogUser{
SetUp__anon61d4b1ad0111::CleanDeadTest470   virtual void SetUp() {
471     // In case a crashing test left a stale file behind.
472     unlink(kTestFilename);
473     CleanTest::SetUp();
474   }
TearDown__anon61d4b1ad0111::CleanDeadTest475   virtual void TearDown() {
476     unlink(kTestFilename);
477   }
IsPathDead__anon61d4b1ad0111::CleanDeadTest478   virtual bool IsPathDead(StringPiece) const { return false; }
479 };
480 
TEST_F(CleanDeadTest,CleanDead)481 TEST_F(CleanDeadTest, CleanDead) {
482   State state;
483   ASSERT_NO_FATAL_FAILURE(AssertParse(&state,
484 "rule cat\n"
485 "  command = cat $in > $out\n"
486 "build out1: cat in\n"
487 "build out2: cat in\n"
488 ));
489   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
490 "build out2: cat in\n"
491 ));
492   fs_.Create("in", "");
493   fs_.Create("out1", "");
494   fs_.Create("out2", "");
495 
496   BuildLog log1;
497   string err;
498   EXPECT_TRUE(log1.OpenForWrite(kTestFilename, *this, &err));
499   ASSERT_EQ("", err);
500   log1.RecordCommand(state.edges_[0], 15, 18);
501   log1.RecordCommand(state.edges_[1], 20, 25);
502   log1.Close();
503 
504   BuildLog log2;
505   EXPECT_TRUE(log2.Load(kTestFilename, &err));
506   ASSERT_EQ("", err);
507   ASSERT_EQ(2u, log2.entries().size());
508   ASSERT_TRUE(log2.LookupByOutput("out1"));
509   ASSERT_TRUE(log2.LookupByOutput("out2"));
510 
511   // First use the manifest that describe how to build out1.
512   Cleaner cleaner1(&state, config_, &fs_);
513   EXPECT_EQ(0, cleaner1.CleanDead(log2.entries()));
514   EXPECT_EQ(0, cleaner1.cleaned_files_count());
515   EXPECT_EQ(0u, fs_.files_removed_.size());
516   EXPECT_NE(0, fs_.Stat("in", &err));
517   EXPECT_NE(0, fs_.Stat("out1", &err));
518   EXPECT_NE(0, fs_.Stat("out2", &err));
519 
520   // Then use the manifest that does not build out1 anymore.
521   Cleaner cleaner2(&state_, config_, &fs_);
522   EXPECT_EQ(0, cleaner2.CleanDead(log2.entries()));
523   EXPECT_EQ(1, cleaner2.cleaned_files_count());
524   EXPECT_EQ(1u, fs_.files_removed_.size());
525   EXPECT_EQ("out1", *(fs_.files_removed_.begin()));
526   EXPECT_NE(0, fs_.Stat("in", &err));
527   EXPECT_EQ(0, fs_.Stat("out1", &err));
528   EXPECT_NE(0, fs_.Stat("out2", &err));
529 
530   // Nothing to do now.
531   EXPECT_EQ(0, cleaner2.CleanDead(log2.entries()));
532   EXPECT_EQ(0, cleaner2.cleaned_files_count());
533   EXPECT_EQ(1u, fs_.files_removed_.size());
534   EXPECT_EQ("out1", *(fs_.files_removed_.begin()));
535   EXPECT_NE(0, fs_.Stat("in", &err));
536   EXPECT_EQ(0, fs_.Stat("out1", &err));
537   EXPECT_NE(0, fs_.Stat("out2", &err));
538   log2.Close();
539 }
540 
TEST_F(CleanDeadTest,CleanDeadPreservesInputs)541 TEST_F(CleanDeadTest, CleanDeadPreservesInputs) {
542   State state;
543   ASSERT_NO_FATAL_FAILURE(AssertParse(&state,
544 "rule cat\n"
545 "  command = cat $in > $out\n"
546 "build out1: cat in\n"
547 "build out2: cat in\n"
548 ));
549   // This manifest does not build out1 anymore, but makes
550   // it an implicit input. CleanDead should detect this
551   // and preserve it.
552   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
553 "build out2: cat in | out1\n"
554 ));
555   fs_.Create("in", "");
556   fs_.Create("out1", "");
557   fs_.Create("out2", "");
558 
559   BuildLog log1;
560   string err;
561   EXPECT_TRUE(log1.OpenForWrite(kTestFilename, *this, &err));
562   ASSERT_EQ("", err);
563   log1.RecordCommand(state.edges_[0], 15, 18);
564   log1.RecordCommand(state.edges_[1], 20, 25);
565   log1.Close();
566 
567   BuildLog log2;
568   EXPECT_TRUE(log2.Load(kTestFilename, &err));
569   ASSERT_EQ("", err);
570   ASSERT_EQ(2u, log2.entries().size());
571   ASSERT_TRUE(log2.LookupByOutput("out1"));
572   ASSERT_TRUE(log2.LookupByOutput("out2"));
573 
574   // First use the manifest that describe how to build out1.
575   Cleaner cleaner1(&state, config_, &fs_);
576   EXPECT_EQ(0, cleaner1.CleanDead(log2.entries()));
577   EXPECT_EQ(0, cleaner1.cleaned_files_count());
578   EXPECT_EQ(0u, fs_.files_removed_.size());
579   EXPECT_NE(0, fs_.Stat("in", &err));
580   EXPECT_NE(0, fs_.Stat("out1", &err));
581   EXPECT_NE(0, fs_.Stat("out2", &err));
582 
583   // Then use the manifest that does not build out1 anymore.
584   Cleaner cleaner2(&state_, config_, &fs_);
585   EXPECT_EQ(0, cleaner2.CleanDead(log2.entries()));
586   EXPECT_EQ(0, cleaner2.cleaned_files_count());
587   EXPECT_EQ(0u, fs_.files_removed_.size());
588   EXPECT_NE(0, fs_.Stat("in", &err));
589   EXPECT_NE(0, fs_.Stat("out1", &err));
590   EXPECT_NE(0, fs_.Stat("out2", &err));
591 
592   // Nothing to do now.
593   EXPECT_EQ(0, cleaner2.CleanDead(log2.entries()));
594   EXPECT_EQ(0, cleaner2.cleaned_files_count());
595   EXPECT_EQ(0u, fs_.files_removed_.size());
596   EXPECT_NE(0, fs_.Stat("in", &err));
597   EXPECT_NE(0, fs_.Stat("out1", &err));
598   EXPECT_NE(0, fs_.Stat("out2", &err));
599   log2.Close();
600 }
601 }  // anonymous namespace
602