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_; |
34 | virtual void SetUp() { |
35 | config_.verbosity = BuildConfig::QUIET; |
36 | } |
37 | }; |
38 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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{ |
470 | virtual void SetUp() { |
471 | // In case a crashing test left a stale file behind. |
472 | unlink(kTestFilename); |
473 | CleanTest::SetUp(); |
474 | } |
475 | virtual void TearDown() { |
476 | unlink(kTestFilename); |
477 | } |
478 | virtual bool IsPathDead(StringPiece) const { return false; } |
479 | }; |
480 | |
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 | |
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 | |