github.com/maruel/nin@v0.0.0-20220112143044-f35891e3ce7e/build_test.go (about)

     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  package nin
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"os"
    21  	"path/filepath"
    22  	"runtime"
    23  	"sort"
    24  	"strconv"
    25  	"strings"
    26  	"testing"
    27  
    28  	"github.com/google/go-cmp/cmp"
    29  )
    30  
    31  // Fixture for tests involving Plan.
    32  // Though Plan doesn't use State, it's useful to have one around
    33  // to create Nodes and Edges.
    34  type PlanTest struct {
    35  	StateTestWithBuiltinRules
    36  	plan plan
    37  }
    38  
    39  func NewPlanTest(t *testing.T) *PlanTest {
    40  	return &PlanTest{
    41  		StateTestWithBuiltinRules: NewStateTestWithBuiltinRules(t),
    42  		plan:                      newPlan(nil),
    43  	}
    44  }
    45  
    46  // Because FindWork does not return Edges in any sort of predictable order,
    47  // provide a means to get available Edges in order and in a format which is
    48  // easy to write tests around.
    49  func (p *PlanTest) FindWorkSorted(count int) []*Edge {
    50  	var out []*Edge
    51  	for i := 0; i < count; i++ {
    52  		if !p.plan.moreToDo() {
    53  			p.t.Fatal("expected true")
    54  		}
    55  		edge := p.plan.findWork()
    56  		if edge == nil {
    57  			p.t.Fatal("expected true")
    58  		}
    59  		out = append(out, edge)
    60  	}
    61  	if p.plan.findWork() != nil {
    62  		p.t.Fatal("expected false")
    63  	}
    64  	sort.Slice(out, func(i, j int) bool {
    65  		return out[i].Outputs[0].Path < out[j].Outputs[0].Path
    66  	})
    67  	return out
    68  }
    69  
    70  func TestPlanTest_Basic(t *testing.T) {
    71  	p := NewPlanTest(t)
    72  	p.AssertParse(&p.state, "build out: cat mid\nbuild mid: cat in\n", ParseManifestOpts{})
    73  	p.GetNode("mid").Dirty = true
    74  	p.GetNode("out").Dirty = true
    75  	if do, err := p.plan.addTarget(p.GetNode("out")); !do || err != nil {
    76  		t.Fatal(do, err)
    77  	}
    78  	if !p.plan.moreToDo() {
    79  		t.Fatal("expected true")
    80  	}
    81  
    82  	edge := p.plan.findWork()
    83  	if edge == nil {
    84  		t.Fatalf("plan is inconsistent: %#v", p.plan)
    85  	}
    86  	if "in" != edge.Inputs[0].Path {
    87  		t.Fatal("expected equal")
    88  	}
    89  	if "mid" != edge.Outputs[0].Path {
    90  		t.Fatal("expected equal")
    91  	}
    92  
    93  	if e := p.plan.findWork(); e != nil {
    94  		t.Fatalf("%#v", e)
    95  	}
    96  
    97  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
    98  		t.Fatal(err)
    99  	}
   100  
   101  	edge = p.plan.findWork()
   102  	if edge == nil {
   103  		t.Fatal("expected true")
   104  	}
   105  	if "mid" != edge.Inputs[0].Path {
   106  		t.Fatal("expected equal")
   107  	}
   108  	if "out" != edge.Outputs[0].Path {
   109  		t.Fatal("expected equal")
   110  	}
   111  
   112  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   113  		t.Fatal(err)
   114  	}
   115  
   116  	if p.plan.moreToDo() {
   117  		t.Fatal("expected false")
   118  	}
   119  	edge = p.plan.findWork()
   120  	if edge != nil {
   121  		t.Fatal("expected equal")
   122  	}
   123  }
   124  
   125  // Test that two outputs from one rule can be handled as inputs to the next.
   126  func TestPlanTest_DoubleOutputDirect(t *testing.T) {
   127  	p := NewPlanTest(t)
   128  	p.AssertParse(&p.state, "build out: cat mid1 mid2\nbuild mid1 mid2: cat in\n", ParseManifestOpts{})
   129  	p.GetNode("mid1").Dirty = true
   130  	p.GetNode("mid2").Dirty = true
   131  	p.GetNode("out").Dirty = true
   132  
   133  	if do, err := p.plan.addTarget(p.GetNode("out")); !do || err != nil {
   134  		t.Fatal(do, err)
   135  	}
   136  	if !p.plan.moreToDo() {
   137  		t.Fatal("expected true")
   138  	}
   139  
   140  	edge := p.plan.findWork()
   141  	if edge == nil {
   142  		t.Fatal("expected true")
   143  	} // cat in
   144  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   145  		t.Fatal(err)
   146  	}
   147  
   148  	edge = p.plan.findWork()
   149  	if edge == nil {
   150  		t.Fatal("expected true")
   151  	} // cat mid1 mid2
   152  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   153  		t.Fatal(err)
   154  	}
   155  
   156  	edge = p.plan.findWork()
   157  	if edge != nil {
   158  		t.Fatal("expected false")
   159  	} // done
   160  }
   161  
   162  // Test that two outputs from one rule can eventually be routed to another.
   163  func TestPlanTest_DoubleOutputIndirect(t *testing.T) {
   164  	p := NewPlanTest(t)
   165  	p.AssertParse(&p.state, "build out: cat b1 b2\nbuild b1: cat a1\nbuild b2: cat a2\nbuild a1 a2: cat in\n", ParseManifestOpts{})
   166  	p.GetNode("a1").Dirty = true
   167  	p.GetNode("a2").Dirty = true
   168  	p.GetNode("b1").Dirty = true
   169  	p.GetNode("b2").Dirty = true
   170  	p.GetNode("out").Dirty = true
   171  	if do, err := p.plan.addTarget(p.GetNode("out")); !do || err != nil {
   172  		t.Fatal(do, err)
   173  	}
   174  	if !p.plan.moreToDo() {
   175  		t.Fatal("expected true")
   176  	}
   177  
   178  	edge := p.plan.findWork()
   179  	if edge == nil {
   180  		t.Fatal("expected true")
   181  	} // cat in
   182  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   183  		t.Fatal(err)
   184  	}
   185  
   186  	edge = p.plan.findWork()
   187  	if edge == nil {
   188  		t.Fatal("expected true")
   189  	} // cat a1
   190  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   191  		t.Fatal(err)
   192  	}
   193  
   194  	edge = p.plan.findWork()
   195  	if edge == nil {
   196  		t.Fatal("expected true")
   197  	} // cat a2
   198  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   199  		t.Fatal(err)
   200  	}
   201  
   202  	edge = p.plan.findWork()
   203  	if edge == nil {
   204  		t.Fatal("expected true")
   205  	} // cat b1 b2
   206  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   207  		t.Fatal(err)
   208  	}
   209  
   210  	edge = p.plan.findWork()
   211  	if edge != nil {
   212  		t.Fatal("expected false")
   213  	} // done
   214  }
   215  
   216  // Test that two edges from one output can both execute.
   217  func TestPlanTest_DoubleDependent(t *testing.T) {
   218  	p := NewPlanTest(t)
   219  	p.AssertParse(&p.state, "build out: cat a1 a2\nbuild a1: cat mid\nbuild a2: cat mid\nbuild mid: cat in\n", ParseManifestOpts{})
   220  	p.GetNode("mid").Dirty = true
   221  	p.GetNode("a1").Dirty = true
   222  	p.GetNode("a2").Dirty = true
   223  	p.GetNode("out").Dirty = true
   224  
   225  	if do, err := p.plan.addTarget(p.GetNode("out")); !do || err != nil {
   226  		t.Fatal(do, err)
   227  	}
   228  	if !p.plan.moreToDo() {
   229  		t.Fatal("expected true")
   230  	}
   231  
   232  	edge := p.plan.findWork()
   233  	if edge == nil {
   234  		t.Fatal("expected true")
   235  	} // cat in
   236  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   237  		t.Fatal(err)
   238  	}
   239  
   240  	edge = p.plan.findWork()
   241  	if edge == nil {
   242  		t.Fatal("expected true")
   243  	} // cat mid
   244  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   245  		t.Fatal(err)
   246  	}
   247  
   248  	edge = p.plan.findWork()
   249  	if edge == nil {
   250  		t.Fatal("expected true")
   251  	} // cat mid
   252  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   253  		t.Fatal(err)
   254  	}
   255  
   256  	edge = p.plan.findWork()
   257  	if edge == nil {
   258  		t.Fatal("expected true")
   259  	} // cat a1 a2
   260  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   261  		t.Fatal(err)
   262  	}
   263  
   264  	edge = p.plan.findWork()
   265  	if edge != nil {
   266  		t.Fatal("expected false")
   267  	} // done
   268  }
   269  
   270  func (p *PlanTest) TestPoolWithDepthOne(testCase string) {
   271  	p.AssertParse(&p.state, testCase, ParseManifestOpts{})
   272  	p.GetNode("out1").Dirty = true
   273  	p.GetNode("out2").Dirty = true
   274  	if do, err := p.plan.addTarget(p.GetNode("out1")); !do || err != nil {
   275  		p.t.Fatal(do, err)
   276  	}
   277  	if do, err := p.plan.addTarget(p.GetNode("out2")); !do || err != nil {
   278  		p.t.Fatal(do, err)
   279  	}
   280  	if !p.plan.moreToDo() {
   281  		p.t.Fatal("expected true")
   282  	}
   283  
   284  	edge := p.plan.findWork()
   285  	if edge == nil {
   286  		p.t.Fatal("expected true")
   287  	}
   288  	if "in" != edge.Inputs[0].Path {
   289  		p.t.Fatal("expected equal")
   290  	}
   291  	if "out1" != edge.Outputs[0].Path {
   292  		p.t.Fatal("expected equal")
   293  	}
   294  
   295  	// This will be false since poolcat is serialized
   296  	if p.plan.findWork() != nil {
   297  		p.t.Fatal("expected false")
   298  	}
   299  
   300  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   301  		p.t.Fatal(err)
   302  	}
   303  
   304  	edge = p.plan.findWork()
   305  	if edge == nil {
   306  		p.t.Fatal("expected true")
   307  	}
   308  	if "in" != edge.Inputs[0].Path {
   309  		p.t.Fatal("expected equal")
   310  	}
   311  	if "out2" != edge.Outputs[0].Path {
   312  		p.t.Fatal("expected equal")
   313  	}
   314  
   315  	if p.plan.findWork() != nil {
   316  		p.t.Fatal("expected false")
   317  	}
   318  
   319  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   320  		p.t.Fatal(err)
   321  	}
   322  
   323  	if p.plan.moreToDo() {
   324  		p.t.Fatal("expected false")
   325  	}
   326  	edge = p.plan.findWork()
   327  	if edge != nil {
   328  		p.t.Fatal("expected equal")
   329  	}
   330  }
   331  
   332  func TestPlanTest_PoolWithDepthOne(t *testing.T) {
   333  	p := NewPlanTest(t)
   334  	p.TestPoolWithDepthOne("pool foobar\n  depth = 1\nrule poolcat\n  command = cat $in > $out\n  pool = foobar\nbuild out1: poolcat in\nbuild out2: poolcat in\n")
   335  }
   336  
   337  func TestPlanTest_ConsolePool(t *testing.T) {
   338  	p := NewPlanTest(t)
   339  	p.TestPoolWithDepthOne("rule poolcat\n  command = cat $in > $out\n  pool = console\nbuild out1: poolcat in\nbuild out2: poolcat in\n")
   340  }
   341  
   342  func TestPlanTest_PoolsWithDepthTwo(t *testing.T) {
   343  	p := NewPlanTest(t)
   344  	p.AssertParse(&p.state, "pool foobar\n  depth = 2\npool bazbin\n  depth = 2\nrule foocat\n  command = cat $in > $out\n  pool = foobar\nrule bazcat\n  command = cat $in > $out\n  pool = bazbin\nbuild out1: foocat in\nbuild out2: foocat in\nbuild out3: foocat in\nbuild outb1: bazcat in\nbuild outb2: bazcat in\nbuild outb3: bazcat in\n  pool =\nbuild allTheThings: cat out1 out2 out3 outb1 outb2 outb3\n", ParseManifestOpts{})
   345  	// Mark all the out* nodes dirty
   346  	for i := 0; i < 3; i++ {
   347  		p.GetNode(fmt.Sprintf("out%d", i+1)).Dirty = true
   348  		p.GetNode(fmt.Sprintf("outb%d", i+1)).Dirty = true
   349  	}
   350  	p.GetNode("allTheThings").Dirty = true
   351  
   352  	if do, err := p.plan.addTarget(p.GetNode("allTheThings")); !do || err != nil {
   353  		t.Fatal(do, err)
   354  	}
   355  
   356  	edges := p.FindWorkSorted(5)
   357  
   358  	for i := 0; i < 4; i++ {
   359  		edge := edges[i]
   360  		if "in" != edge.Inputs[0].Path {
   361  			t.Fatal("expected equal")
   362  		}
   363  		baseName := "outb"
   364  		if i < 2 {
   365  			baseName = "out"
   366  		}
   367  		if want := fmt.Sprintf("%s%d", baseName, 1+(i%2)); want != edge.Outputs[0].Path {
   368  			t.Fatal(want)
   369  		}
   370  	}
   371  
   372  	// outb3 is exempt because it has an empty pool
   373  	edge := edges[4]
   374  	if edge == nil {
   375  		t.Fatal("expected true")
   376  	}
   377  	if "in" != edge.Inputs[0].Path {
   378  		t.Fatal("expected equal")
   379  	}
   380  	if "outb3" != edge.Outputs[0].Path {
   381  		t.Fatal("expected equal")
   382  	}
   383  
   384  	// finish out1
   385  	if err := p.plan.edgeFinished(edges[0], edgeSucceeded); err != nil {
   386  		t.Fatal(err)
   387  	}
   388  	edges = edges[1:]
   389  
   390  	// out3 should be available
   391  	out3 := p.plan.findWork()
   392  	if out3 == nil {
   393  		t.Fatal("expected true")
   394  	}
   395  	if "in" != out3.Inputs[0].Path {
   396  		t.Fatal("expected equal")
   397  	}
   398  	if "out3" != out3.Outputs[0].Path {
   399  		t.Fatal("expected equal")
   400  	}
   401  
   402  	if p.plan.findWork() != nil {
   403  		t.Fatal("expected false")
   404  	}
   405  
   406  	if err := p.plan.edgeFinished(out3, edgeSucceeded); err != nil {
   407  		t.Fatal(err)
   408  	}
   409  
   410  	if p.plan.findWork() != nil {
   411  		t.Fatal("expected false")
   412  	}
   413  
   414  	for _, it := range edges {
   415  		if err := p.plan.edgeFinished(it, edgeSucceeded); err != nil {
   416  			t.Fatal(err)
   417  		}
   418  	}
   419  
   420  	last := p.plan.findWork()
   421  	if last == nil {
   422  		t.Fatal("expected true")
   423  	}
   424  	if "allTheThings" != last.Outputs[0].Path {
   425  		t.Fatal("expected equal")
   426  	}
   427  
   428  	if err := p.plan.edgeFinished(last, edgeSucceeded); err != nil {
   429  		t.Fatal(err)
   430  	}
   431  
   432  	if p.plan.moreToDo() {
   433  		t.Fatal("expected false")
   434  	}
   435  	if p.plan.findWork() != nil {
   436  		t.Fatal("expected false")
   437  	}
   438  }
   439  
   440  func TestPlanTest_PoolWithRedundantEdges(t *testing.T) {
   441  	p := NewPlanTest(t)
   442  	p.AssertParse(&p.state, "pool compile\n  depth = 1\nrule gen_foo\n  command = touch foo.cpp\nrule gen_bar\n  command = touch bar.cpp\nrule echo\n  command = echo $out > $out\nbuild foo.cpp.obj: echo foo.cpp || foo.cpp\n  pool = compile\nbuild bar.cpp.obj: echo bar.cpp || bar.cpp\n  pool = compile\nbuild libfoo.a: echo foo.cpp.obj bar.cpp.obj\nbuild foo.cpp: gen_foo\nbuild bar.cpp: gen_bar\nbuild all: phony libfoo.a\n", ParseManifestOpts{})
   443  	p.GetNode("foo.cpp").Dirty = true
   444  	p.GetNode("foo.cpp.obj").Dirty = true
   445  	p.GetNode("bar.cpp").Dirty = true
   446  	p.GetNode("bar.cpp.obj").Dirty = true
   447  	p.GetNode("libfoo.a").Dirty = true
   448  	p.GetNode("all").Dirty = true
   449  	if do, err := p.plan.addTarget(p.GetNode("all")); !do || err != nil {
   450  		t.Fatal(do, err)
   451  	}
   452  	if !p.plan.moreToDo() {
   453  		t.Fatal("expected true")
   454  	}
   455  
   456  	initialEdges := p.FindWorkSorted(2)
   457  
   458  	edge := initialEdges[1] // Foo first
   459  	if "foo.cpp" != edge.Outputs[0].Path {
   460  		t.Fatal("expected equal")
   461  	}
   462  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   463  		t.Fatal(err)
   464  	}
   465  
   466  	edge = p.plan.findWork()
   467  	if edge == nil {
   468  		t.Fatal("expected true")
   469  	}
   470  	if p.plan.findWork() != nil {
   471  		t.Fatal("expected false")
   472  	}
   473  	if "foo.cpp" != edge.Inputs[0].Path {
   474  		t.Fatal("expected equal")
   475  	}
   476  	if "foo.cpp" != edge.Inputs[1].Path {
   477  		t.Fatal("expected equal")
   478  	}
   479  	if "foo.cpp.obj" != edge.Outputs[0].Path {
   480  		t.Fatal("expected equal")
   481  	}
   482  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   483  		t.Fatal(err)
   484  	}
   485  
   486  	edge = initialEdges[0] // Now for bar
   487  	if "bar.cpp" != edge.Outputs[0].Path {
   488  		t.Fatal("expected equal")
   489  	}
   490  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   491  		t.Fatal(err)
   492  	}
   493  
   494  	edge = p.plan.findWork()
   495  	if edge == nil {
   496  		t.Fatal("expected true")
   497  	}
   498  	if p.plan.findWork() != nil {
   499  		t.Fatal("expected false")
   500  	}
   501  	if "bar.cpp" != edge.Inputs[0].Path {
   502  		t.Fatal(edge.Inputs[0].Path)
   503  	}
   504  	if "bar.cpp" != edge.Inputs[1].Path {
   505  		t.Fatal("expected equal")
   506  	}
   507  	if "bar.cpp.obj" != edge.Outputs[0].Path {
   508  		t.Fatal("expected equal")
   509  	}
   510  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   511  		t.Fatal(err)
   512  	}
   513  
   514  	edge = p.plan.findWork()
   515  	if edge == nil {
   516  		t.Fatal("expected true")
   517  	}
   518  	if p.plan.findWork() != nil {
   519  		t.Fatal("expected false")
   520  	}
   521  	if "foo.cpp.obj" != edge.Inputs[0].Path {
   522  		t.Fatal("expected equal")
   523  	}
   524  	if "bar.cpp.obj" != edge.Inputs[1].Path {
   525  		t.Fatal("expected equal")
   526  	}
   527  	if "libfoo.a" != edge.Outputs[0].Path {
   528  		t.Fatal("expected equal")
   529  	}
   530  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   531  		t.Fatal(err)
   532  	}
   533  
   534  	edge = p.plan.findWork()
   535  	if edge == nil {
   536  		t.Fatal("expected true")
   537  	}
   538  	if p.plan.findWork() != nil {
   539  		t.Fatal("expected false")
   540  	}
   541  	if "libfoo.a" != edge.Inputs[0].Path {
   542  		t.Fatal("expected equal")
   543  	}
   544  	if "all" != edge.Outputs[0].Path {
   545  		t.Fatal("expected equal")
   546  	}
   547  	if err := p.plan.edgeFinished(edge, edgeSucceeded); err != nil {
   548  		t.Fatal(err)
   549  	}
   550  
   551  	edge = p.plan.findWork()
   552  	if edge != nil {
   553  		t.Fatal("expected false")
   554  	}
   555  	if p.plan.moreToDo() {
   556  		t.Fatal("expected false")
   557  	}
   558  }
   559  
   560  func TestPlanTest_PoolWithFailingEdge(t *testing.T) {
   561  	p := NewPlanTest(t)
   562  	p.AssertParse(&p.state, "pool foobar\n  depth = 1\nrule poolcat\n  command = cat $in > $out\n  pool = foobar\nbuild out1: poolcat in\nbuild out2: poolcat in\n", ParseManifestOpts{})
   563  	p.GetNode("out1").Dirty = true
   564  	p.GetNode("out2").Dirty = true
   565  	if do, err := p.plan.addTarget(p.GetNode("out1")); !do || err != nil {
   566  		t.Fatal(do, err)
   567  	}
   568  	if do, err := p.plan.addTarget(p.GetNode("out2")); !do || err != nil {
   569  		t.Fatal(do, err)
   570  	}
   571  	if !p.plan.moreToDo() {
   572  		t.Fatal("expected true")
   573  	}
   574  
   575  	edge := p.plan.findWork()
   576  	if edge == nil {
   577  		t.Fatal("expected true")
   578  	}
   579  	if "in" != edge.Inputs[0].Path {
   580  		t.Fatal("expected equal")
   581  	}
   582  	if "out1" != edge.Outputs[0].Path {
   583  		t.Fatal("expected equal")
   584  	}
   585  
   586  	// This will be false since poolcat is serialized
   587  	if p.plan.findWork() != nil {
   588  		t.Fatal("expected false")
   589  	}
   590  
   591  	if err := p.plan.edgeFinished(edge, edgeFailed); err != nil {
   592  		t.Fatal(err)
   593  	}
   594  
   595  	edge = p.plan.findWork()
   596  	if edge == nil {
   597  		t.Fatal("expected true")
   598  	}
   599  	if "in" != edge.Inputs[0].Path {
   600  		t.Fatal("expected equal")
   601  	}
   602  	if "out2" != edge.Outputs[0].Path {
   603  		t.Fatal("expected equal")
   604  	}
   605  
   606  	if p.plan.findWork() != nil {
   607  		t.Fatal("expected false")
   608  	}
   609  
   610  	if err := p.plan.edgeFinished(edge, edgeFailed); err != nil {
   611  		t.Fatal(err)
   612  	}
   613  
   614  	if !p.plan.moreToDo() {
   615  		t.Fatal("expected true")
   616  	} // Jobs have failed
   617  	edge = p.plan.findWork()
   618  	if edge != nil {
   619  		t.Fatal("expected equal")
   620  	}
   621  }
   622  
   623  type statusFake struct{}
   624  
   625  func (s *statusFake) PlanHasTotalEdges(total int)                        {}
   626  func (s *statusFake) BuildEdgeStarted(edge *Edge, startTimeMillis int32) {}
   627  func (s *statusFake) BuildEdgeFinished(edge *Edge, endTimeMillis int32, success bool, output string) {
   628  }
   629  func (s *statusFake) BuildLoadDyndeps()                    {}
   630  func (s *statusFake) BuildStarted()                        {}
   631  func (s *statusFake) BuildFinished()                       {}
   632  func (s *statusFake) Info(msg string, i ...interface{})    {}
   633  func (s *statusFake) Warning(msg string, i ...interface{}) {}
   634  func (s *statusFake) Error(msg string, i ...interface{})   {}
   635  
   636  type BuildTestBase struct {
   637  	StateTestWithBuiltinRules
   638  	config        BuildConfig
   639  	commandRunner FakeCommandRunner
   640  	fs            VirtualFileSystem
   641  	status        Status
   642  }
   643  
   644  func NewBuildTestBase(t *testing.T) *BuildTestBase {
   645  	b := &BuildTestBase{
   646  		StateTestWithBuiltinRules: NewStateTestWithBuiltinRules(t),
   647  		config:                    NewBuildConfig(),
   648  		fs:                        NewVirtualFileSystem(),
   649  		status:                    &statusFake{},
   650  	}
   651  	b.config.Verbosity = Quiet
   652  	b.commandRunner = NewFakeCommandRunner(t, &b.fs)
   653  	b.AssertParse(&b.state, "build cat1: cat in1\nbuild cat2: cat in1 in2\nbuild cat12: cat cat1 cat2\n", ParseManifestOpts{})
   654  	b.fs.Create("in1", "")
   655  	b.fs.Create("in2", "")
   656  	return b
   657  }
   658  
   659  func (b *BuildTestBase) IsPathDead(s string) bool {
   660  	return false
   661  }
   662  
   663  // Rebuild target in the 'working tree' (fs).
   664  // State of commandRunner and logs contents (if specified) ARE MODIFIED.
   665  // Handy to check for NOOP builds, and higher-level rebuild tests.
   666  func (b *BuildTestBase) RebuildTarget(target, manifest, logPath, depsPath string, state *State) {
   667  	pstate := state
   668  	if pstate == nil {
   669  		localState := NewState()
   670  		pstate = &localState
   671  	}
   672  	b.AddCatRule(pstate)
   673  	b.AssertParse(pstate, manifest, ParseManifestOpts{})
   674  
   675  	var pbuildLog *BuildLog
   676  	if logPath != "" {
   677  		buildLog := NewBuildLog()
   678  		defer buildLog.Close()
   679  		if s, err := buildLog.Load(logPath); !((s == LoadSuccess && err == nil) || (s == LoadNotFound && os.IsNotExist(err))) {
   680  			b.t.Fatalf("%s = %d: %s", logPath, s, err)
   681  		}
   682  		if err := buildLog.OpenForWrite(logPath, b); err != nil {
   683  			b.t.Fatal(err)
   684  		}
   685  		pbuildLog = &buildLog
   686  	}
   687  
   688  	var pdepsLog *DepsLog
   689  	if depsPath != "" {
   690  		pdepsLog = &DepsLog{}
   691  		defer pdepsLog.Close()
   692  		if s, err := pdepsLog.Load(depsPath, pstate); !((s == LoadSuccess && err == nil) || (s == LoadNotFound && os.IsNotExist(err))) {
   693  			b.t.Fatalf("%s = %d: %s", depsPath, s, err)
   694  		}
   695  		if err := pdepsLog.OpenForWrite(depsPath); err != nil {
   696  			b.t.Fatal(err)
   697  		}
   698  	}
   699  
   700  	builder := NewBuilder(pstate, &b.config, pbuildLog, pdepsLog, &b.fs, b.status, 0)
   701  	if _, err := builder.addTargetName(target); err != nil {
   702  		b.t.Fatal(err)
   703  	}
   704  
   705  	b.commandRunner.commandsRan = nil
   706  	builder.commandRunner = &b.commandRunner
   707  	if !builder.AlreadyUpToDate() {
   708  		if err := builder.Build(); err != nil {
   709  			b.t.Fatal(err)
   710  		}
   711  	}
   712  }
   713  
   714  // Fake implementation of CommandRunner, useful for tests.
   715  type FakeCommandRunner struct {
   716  	t              *testing.T
   717  	commandsRan    []string
   718  	activeEdges    []*Edge
   719  	maxActiveEdges uint
   720  	fs             *VirtualFileSystem
   721  }
   722  
   723  func NewFakeCommandRunner(t *testing.T, fs *VirtualFileSystem) FakeCommandRunner {
   724  	return FakeCommandRunner{
   725  		t:              t,
   726  		maxActiveEdges: 1,
   727  		fs:             fs,
   728  	}
   729  }
   730  
   731  // CommandRunner impl
   732  func (f *FakeCommandRunner) CanRunMore() bool {
   733  	return len(f.activeEdges) < int(f.maxActiveEdges)
   734  }
   735  
   736  func (f *FakeCommandRunner) StartCommand(edge *Edge) bool {
   737  	cmd := edge.EvaluateCommand(false)
   738  	//f.t.Logf("StartCommand(%s)", cmd)
   739  	if len(f.activeEdges) > int(f.maxActiveEdges) {
   740  		f.t.Fatal("oops")
   741  	}
   742  	found := false
   743  	for _, a := range f.activeEdges {
   744  		if a == edge {
   745  			found = true
   746  			break
   747  		}
   748  	}
   749  	if found {
   750  		f.t.Fatalf("running same edge twice")
   751  	}
   752  	f.commandsRan = append(f.commandsRan, cmd)
   753  	if edge.Rule.Name == "cat" || edge.Rule.Name == "cat_rsp" || edge.Rule.Name == "cat_rsp_out" || edge.Rule.Name == "cc" || edge.Rule.Name == "cp_multi_msvc" || edge.Rule.Name == "cp_multi_gcc" || edge.Rule.Name == "touch" || edge.Rule.Name == "touch-interrupt" || edge.Rule.Name == "touch-fail-tick2" {
   754  		for _, out := range edge.Outputs {
   755  			f.fs.Create(out.Path, "")
   756  		}
   757  	} else if edge.Rule.Name == "true" || edge.Rule.Name == "fail" || edge.Rule.Name == "interrupt" || edge.Rule.Name == "console" {
   758  		// Don't do anything.
   759  	} else if edge.Rule.Name == "cp" {
   760  		if len(edge.Inputs) == 0 {
   761  			f.t.Fatal("oops")
   762  		}
   763  		if len(edge.Outputs) != 1 {
   764  			f.t.Fatalf("%#v", edge.Outputs)
   765  		}
   766  		content, err := f.fs.ReadFile(edge.Inputs[0].Path)
   767  		if err == nil {
   768  			// ReadFile append a zero byte, strip it when writing back.
   769  			c := content
   770  			if len(c) != 0 {
   771  				c = c[:len(c)-1]
   772  			}
   773  			f.fs.WriteFile(edge.Outputs[0].Path, string(c))
   774  		}
   775  	} else if edge.Rule.Name == "touch-implicit-dep-out" {
   776  		dep := edge.GetBinding("test_dependency")
   777  		f.fs.Create(dep, "")
   778  		f.fs.Tick()
   779  		for _, out := range edge.Outputs {
   780  			f.fs.Create(out.Path, "")
   781  		}
   782  	} else if edge.Rule.Name == "touch-out-implicit-dep" {
   783  		dep := edge.GetBinding("test_dependency")
   784  		for _, out := range edge.Outputs {
   785  			f.fs.Create(out.Path, "")
   786  		}
   787  		f.fs.Tick()
   788  		f.fs.Create(dep, "")
   789  	} else if edge.Rule.Name == "generate-depfile" {
   790  		dep := edge.GetBinding("test_dependency")
   791  		depfile := edge.GetUnescapedDepfile()
   792  		contents := ""
   793  		for _, out := range edge.Outputs {
   794  			contents += out.Path + ": " + dep + "\n"
   795  			f.fs.Create(out.Path, "")
   796  		}
   797  		f.fs.Create(depfile, contents)
   798  	} else {
   799  		fmt.Printf("unknown command\n")
   800  		return false
   801  	}
   802  
   803  	f.activeEdges = append(f.activeEdges, edge)
   804  
   805  	// Allow tests to control the order by the name of the first output.
   806  	sort.Slice(f.activeEdges, func(i, j int) bool {
   807  		return f.activeEdges[i].Outputs[0].Path < f.activeEdges[j].Outputs[0].Path
   808  	})
   809  	return true
   810  }
   811  
   812  func (f *FakeCommandRunner) WaitForCommand(result *Result) bool {
   813  	if len(f.activeEdges) == 0 {
   814  		return false
   815  	}
   816  
   817  	// All active edges were already completed immediately when started,
   818  	// so we can pick any edge here.  Pick the last edge.  Tests can
   819  	// control the order of edges by the name of the first output.
   820  	edgeIter := len(f.activeEdges) - 1
   821  
   822  	edge := f.activeEdges[edgeIter]
   823  	result.Edge = edge
   824  
   825  	if edge.Rule.Name == "interrupt" || edge.Rule.Name == "touch-interrupt" {
   826  		result.ExitCode = ExitInterrupted
   827  		return true
   828  	}
   829  
   830  	if edge.Rule.Name == "console" {
   831  		if edge.Pool == ConsolePool {
   832  			result.ExitCode = ExitSuccess
   833  		} else {
   834  			result.ExitCode = ExitFailure
   835  		}
   836  		copy(f.activeEdges[edgeIter:], f.activeEdges[edgeIter+1:])
   837  		f.activeEdges = f.activeEdges[:len(f.activeEdges)-1]
   838  		return true
   839  	}
   840  
   841  	if edge.Rule.Name == "cp_multi_msvc" {
   842  		prefix := edge.GetBinding("msvc_deps_prefix")
   843  		for _, in := range edge.Inputs {
   844  			result.Output += prefix + in.Path + "\n"
   845  		}
   846  	}
   847  
   848  	if edge.Rule.Name == "fail" || (edge.Rule.Name == "touch-fail-tick2" && f.fs.now == 2) {
   849  		result.ExitCode = ExitFailure
   850  	} else {
   851  		result.ExitCode = ExitSuccess
   852  	}
   853  
   854  	// Provide a way for test cases to verify when an edge finishes that
   855  	// some other edge is still active.  This is useful for test cases
   856  	// covering behavior involving multiple active edges.
   857  	verifyActiveEdge := edge.GetBinding("verify_active_edge")
   858  	if verifyActiveEdge != "" {
   859  		verifyActiveEdgeFound := false
   860  		for _, i := range f.activeEdges {
   861  			if len(i.Outputs) != 0 && i.Outputs[0].Path == verifyActiveEdge {
   862  				verifyActiveEdgeFound = true
   863  			}
   864  		}
   865  		if !verifyActiveEdgeFound {
   866  			f.t.Fatal("expected true")
   867  		}
   868  	}
   869  
   870  	copy(f.activeEdges[edgeIter:], f.activeEdges[edgeIter+1:])
   871  	f.activeEdges = f.activeEdges[:len(f.activeEdges)-1]
   872  	return true
   873  }
   874  
   875  func (f *FakeCommandRunner) GetActiveEdges() []*Edge {
   876  	return f.activeEdges
   877  }
   878  
   879  func (f *FakeCommandRunner) Abort() {
   880  	f.activeEdges = nil
   881  }
   882  
   883  type BuildTest struct {
   884  	*BuildTestBase
   885  	builder *Builder
   886  }
   887  
   888  func NewBuildTest(t *testing.T) *BuildTest {
   889  	b := &BuildTest{
   890  		BuildTestBase: NewBuildTestBase(t),
   891  	}
   892  	b.builder = NewBuilder(&b.state, &b.config, nil, nil, &b.fs, b.status, 0)
   893  	b.builder.commandRunner = &b.commandRunner
   894  	// TODO(maruel): Only do it for tests that write to disk.
   895  	CreateTempDirAndEnter(t)
   896  	return b
   897  }
   898  
   899  // Mark a path dirty.
   900  func (b *BuildTest) Dirty(path string) {
   901  	node := b.GetNode(path)
   902  	node.Dirty = true
   903  
   904  	// If it's an input file, mark that we've already stat()ed it and
   905  	// it's missing.
   906  	if node.InEdge == nil {
   907  		if node.MTime == -1 {
   908  			node.MTime = 0
   909  		}
   910  		node.Exists = ExistenceStatusMissing
   911  	}
   912  }
   913  
   914  func TestBuildTest_NoWork(t *testing.T) {
   915  	b := NewBuildTest(t)
   916  	if !b.builder.AlreadyUpToDate() {
   917  		t.Fatal("expected true")
   918  	}
   919  }
   920  
   921  func TestBuildTest_OneStep(t *testing.T) {
   922  	b := NewBuildTest(t)
   923  	// Given a dirty target with one ready input,
   924  	// we should rebuild the target.
   925  	b.Dirty("cat1")
   926  	if _, err := b.builder.addTargetName("cat1"); err != nil {
   927  		t.Fatal(err)
   928  	}
   929  	if err := b.builder.Build(); err != nil {
   930  		t.Fatal()
   931  	}
   932  
   933  	wantCommands := []string{"cat in1 > cat1"}
   934  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
   935  		t.Fatal(diff)
   936  	}
   937  }
   938  
   939  func TestBuildTest_OneStep2(t *testing.T) {
   940  	b := NewBuildTest(t)
   941  	// Given a target with one dirty input,
   942  	// we should rebuild the target.
   943  	b.Dirty("cat1")
   944  	if _, err := b.builder.addTargetName("cat1"); err != nil {
   945  		t.Fatal(err)
   946  	}
   947  	if err := b.builder.Build(); err != nil {
   948  		t.Fatal(err)
   949  	}
   950  
   951  	wantCommands := []string{"cat in1 > cat1"}
   952  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
   953  		t.Fatal(diff)
   954  	}
   955  }
   956  
   957  func TestBuildTest_TwoStep(t *testing.T) {
   958  	b := NewBuildTest(t)
   959  	if _, err := b.builder.addTargetName("cat12"); err != nil {
   960  		t.Fatal(err)
   961  	}
   962  	if err := b.builder.Build(); err != nil {
   963  		t.Fatal(err)
   964  	}
   965  	if 3 != len(b.commandRunner.commandsRan) {
   966  		t.Fatal("expected equal")
   967  	}
   968  	// Depending on how the pointers work out, we could've ran
   969  	// the first two commands in either order.
   970  	if !(b.commandRunner.commandsRan[0] == "cat in1 > cat1" && b.commandRunner.commandsRan[1] == "cat in1 in2 > cat2") || (b.commandRunner.commandsRan[1] == "cat in1 > cat1" && b.commandRunner.commandsRan[0] == "cat in1 in2 > cat2") {
   971  		t.Fatal("expected true")
   972  	}
   973  
   974  	if "cat cat1 cat2 > cat12" != b.commandRunner.commandsRan[2] {
   975  		t.Fatal("expected equal")
   976  	}
   977  
   978  	b.fs.Tick()
   979  
   980  	// Modifying in2 requires rebuilding one intermediate file
   981  	// and the final file.
   982  	b.fs.Create("in2", "")
   983  	b.state.Reset()
   984  	if _, err := b.builder.addTargetName("cat12"); err != nil {
   985  		t.Fatal(err)
   986  	}
   987  	if err := b.builder.Build(); err != nil {
   988  		t.Fatal()
   989  	}
   990  	if 5 != len(b.commandRunner.commandsRan) {
   991  		t.Fatal("expected equal")
   992  	}
   993  	if "cat in1 in2 > cat2" != b.commandRunner.commandsRan[3] {
   994  		t.Fatal("expected equal")
   995  	}
   996  	if "cat cat1 cat2 > cat12" != b.commandRunner.commandsRan[4] {
   997  		t.Fatal("expected equal")
   998  	}
   999  }
  1000  
  1001  func TestBuildTest_TwoOutputs(t *testing.T) {
  1002  	b := NewBuildTest(t)
  1003  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\nbuild out1 out2: touch in.txt\n", ParseManifestOpts{})
  1004  
  1005  	b.fs.Create("in.txt", "")
  1006  
  1007  	if _, err := b.builder.addTargetName("out1"); err != nil {
  1008  		t.Fatal(err)
  1009  	}
  1010  	if err := b.builder.Build(); err != nil {
  1011  		t.Fatal(err)
  1012  	}
  1013  	wantCommands := []string{"touch out1 out2"}
  1014  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  1015  		t.Fatal(diff)
  1016  	}
  1017  }
  1018  
  1019  func TestBuildTest_ImplicitOutput(t *testing.T) {
  1020  	b := NewBuildTest(t)
  1021  	b.AssertParse(&b.state, "rule touch\n  command = touch $out $out.imp\nbuild out | out.imp: touch in.txt\n", ParseManifestOpts{})
  1022  	b.fs.Create("in.txt", "")
  1023  
  1024  	if _, err := b.builder.addTargetName("out.imp"); err != nil {
  1025  		t.Fatal(err)
  1026  	}
  1027  	if err := b.builder.Build(); err != nil {
  1028  		t.Fatal(err)
  1029  	}
  1030  	wantCommands := []string{"touch out out.imp"}
  1031  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  1032  		t.Fatal(diff)
  1033  	}
  1034  }
  1035  
  1036  // Test case from
  1037  //   https://github.com/ninja-build/ninja/issues/148
  1038  func TestBuildTest_MultiOutIn(t *testing.T) {
  1039  	b := NewBuildTest(t)
  1040  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\nbuild in1 otherfile: touch in\nbuild out: touch in | in1\n", ParseManifestOpts{})
  1041  
  1042  	b.fs.Create("in", "")
  1043  	b.fs.Tick()
  1044  	b.fs.Create("in1", "")
  1045  
  1046  	if _, err := b.builder.addTargetName("out"); err != nil {
  1047  		t.Fatal(err)
  1048  	}
  1049  	if err := b.builder.Build(); err != nil {
  1050  		t.Fatal(err)
  1051  	}
  1052  }
  1053  
  1054  func TestBuildTest_Chain(t *testing.T) {
  1055  	b := NewBuildTest(t)
  1056  	b.AssertParse(&b.state, "build c2: cat c1\nbuild c3: cat c2\nbuild c4: cat c3\nbuild c5: cat c4\n", ParseManifestOpts{})
  1057  
  1058  	b.fs.Create("c1", "")
  1059  
  1060  	if _, err := b.builder.addTargetName("c5"); err != nil {
  1061  		t.Fatal(err)
  1062  	}
  1063  	if err := b.builder.Build(); err != nil {
  1064  		t.Fatal(err)
  1065  	}
  1066  	if 4 != len(b.commandRunner.commandsRan) {
  1067  		t.Fatal("expected equal")
  1068  	}
  1069  
  1070  	b.commandRunner.commandsRan = nil
  1071  	b.state.Reset()
  1072  	if _, err := b.builder.addTargetName("c5"); err != nil {
  1073  		t.Fatal(err)
  1074  	}
  1075  	if !b.builder.AlreadyUpToDate() {
  1076  		t.Fatal("expected true")
  1077  	}
  1078  
  1079  	b.fs.Tick()
  1080  
  1081  	b.fs.Create("c3", "")
  1082  	b.commandRunner.commandsRan = nil
  1083  	b.state.Reset()
  1084  	if _, err := b.builder.addTargetName("c5"); err != nil {
  1085  		t.Fatal(err)
  1086  	}
  1087  	if b.builder.AlreadyUpToDate() {
  1088  		t.Fatal("expected false")
  1089  	}
  1090  	if err := b.builder.Build(); err != nil {
  1091  		t.Fatal(err)
  1092  	}
  1093  	if 2 != len(b.commandRunner.commandsRan) {
  1094  		t.Fatal("expected equal")
  1095  	} // 3->4, 4->5
  1096  }
  1097  
  1098  func TestBuildTest_MissingInput(t *testing.T) {
  1099  	b := NewBuildTest(t)
  1100  	// Input is referenced by build file, but no rule for it.
  1101  	b.Dirty("in1")
  1102  	if n, err := b.builder.addTargetName("cat1"); n != nil || err == nil {
  1103  		t.Fatal("expected failure")
  1104  	} else if err.Error() != "'in1', needed by 'cat1', missing and no known rule to make it" {
  1105  		t.Fatal(err)
  1106  	}
  1107  }
  1108  
  1109  func TestBuildTest_MissingTarget(t *testing.T) {
  1110  	b := NewBuildTest(t)
  1111  	// Target is not referenced by build file.
  1112  	if _, err := b.builder.addTargetName("meow"); err == nil {
  1113  		t.Fatal("expected false")
  1114  	} else if err.Error() != "unknown target: 'meow'" {
  1115  		t.Fatal(err)
  1116  	}
  1117  }
  1118  
  1119  func TestBuildTest_MissingInputTarget(t *testing.T) {
  1120  	b := NewBuildTest(t)
  1121  	// Target is a missing input file
  1122  	b.Dirty("in1")
  1123  	if _, err := b.builder.addTargetName("in1"); err == nil {
  1124  		t.Fatal("unexpected success")
  1125  	} else if err.Error() != "'in1' missing and no known rule to make it" {
  1126  		t.Fatal(err)
  1127  	}
  1128  }
  1129  
  1130  func TestBuildTest_MakeDirs(t *testing.T) {
  1131  	b := NewBuildTest(t)
  1132  
  1133  	p := filepath.Join("subdir", "dir2", "file")
  1134  	b.AssertParse(&b.state, "build "+p+": cat in1\n", ParseManifestOpts{})
  1135  	if _, err := b.builder.addTargetName("subdir/dir2/file"); err != nil {
  1136  		t.Fatal(err)
  1137  	}
  1138  
  1139  	if err := b.builder.Build(); err != nil {
  1140  		t.Fatal(err)
  1141  	}
  1142  	wantMade := map[string]struct{}{
  1143  		"subdir":                        {},
  1144  		filepath.Join("subdir", "dir2"): {},
  1145  	}
  1146  	if diff := cmp.Diff(wantMade, b.fs.directoriesMade); diff != "" {
  1147  		t.Fatal(diff)
  1148  	}
  1149  }
  1150  
  1151  func TestBuildTest_DepFileMissing(t *testing.T) {
  1152  	b := NewBuildTest(t)
  1153  	b.AssertParse(&b.state, "rule cc\n  command = cc $in\n  depfile = $out.d\nbuild fo$ o.o: cc foo.c\n", ParseManifestOpts{})
  1154  	b.fs.Create("foo.c", "")
  1155  
  1156  	if _, err := b.builder.addTargetName("fo o.o"); err != nil {
  1157  		t.Fatal(err)
  1158  	}
  1159  	if 1 != len(b.fs.filesRead) {
  1160  		t.Fatal("expected equal")
  1161  	}
  1162  	if "fo o.o.d" != b.fs.filesRead[0] {
  1163  		t.Fatal("expected equal")
  1164  	}
  1165  }
  1166  
  1167  func TestBuildTest_DepFileOK(t *testing.T) {
  1168  	b := NewBuildTest(t)
  1169  	origEdges := len(b.state.Edges)
  1170  	b.AssertParse(&b.state, "rule cc\n  command = cc $in\n  depfile = $out.d\nbuild foo.o: cc foo.c\n", ParseManifestOpts{})
  1171  	edge := b.state.Edges[len(b.state.Edges)-1]
  1172  
  1173  	b.fs.Create("foo.c", "")
  1174  	b.GetNode("bar.h").Dirty = true // Mark bar.h as missing.
  1175  	b.fs.Create("foo.o.d", "foo.o: blah.h bar.h\n")
  1176  	if _, err := b.builder.addTargetName("foo.o"); err != nil {
  1177  		t.Fatal("expected true")
  1178  	}
  1179  	if 1 != len(b.fs.filesRead) {
  1180  		t.Fatal("expected equal")
  1181  	}
  1182  	if "foo.o.d" != b.fs.filesRead[0] {
  1183  		t.Fatal("expected equal")
  1184  	}
  1185  
  1186  	// Expect three new edges: one generating foo.o, and two more from
  1187  	// loading the depfile.
  1188  	if origEdges+3 != len(b.state.Edges) {
  1189  		t.Fatal("expected equal")
  1190  	}
  1191  	// Expect our edge to now have three inputs: foo.c and two headers.
  1192  	if 3 != len(edge.Inputs) {
  1193  		t.Fatalf("%#v", edge.Inputs)
  1194  	}
  1195  
  1196  	// Expect the command line we generate to only use the original input.
  1197  	if "cc foo.c" != edge.EvaluateCommand(false) {
  1198  		t.Fatal("expected equal")
  1199  	}
  1200  }
  1201  
  1202  func TestBuildTest_DepFileParseError(t *testing.T) {
  1203  	b := NewBuildTest(t)
  1204  	b.AssertParse(&b.state, "rule cc\n  command = cc $in\n  depfile = $out.d\nbuild foo.o: cc foo.c\n", ParseManifestOpts{})
  1205  	b.fs.Create("foo.c", "")
  1206  	b.fs.Create("foo.o.d", "randomtext\n")
  1207  	if _, err := b.builder.addTargetName("foo.o"); err == nil {
  1208  		t.Fatal("expected false")
  1209  	} else if err.Error() != "foo.o.d: expected ':' in depfile" {
  1210  		t.Fatal(err)
  1211  	}
  1212  }
  1213  
  1214  func TestBuildTest_EncounterReadyTwice(t *testing.T) {
  1215  	b := NewBuildTest(t)
  1216  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\nbuild c: touch\nbuild b: touch || c\nbuild a: touch | b || c\n", ParseManifestOpts{})
  1217  
  1218  	cOut := b.GetNode("c").OutEdges
  1219  	if 2 != len(cOut) {
  1220  		t.Fatal("expected equal")
  1221  	}
  1222  	if "b" != cOut[0].Outputs[0].Path {
  1223  		t.Fatal("expected equal")
  1224  	}
  1225  	if "a" != cOut[1].Outputs[0].Path {
  1226  		t.Fatal("expected equal")
  1227  	}
  1228  
  1229  	b.fs.Create("b", "")
  1230  	if _, err := b.builder.addTargetName("a"); err != nil {
  1231  		t.Fatal("expected true")
  1232  	}
  1233  
  1234  	if err := b.builder.Build(); err != nil {
  1235  		t.Fatal(err)
  1236  	}
  1237  	if 2 != len(b.commandRunner.commandsRan) {
  1238  		t.Fatal("expected equal")
  1239  	}
  1240  }
  1241  
  1242  func TestBuildTest_OrderOnlyDeps(t *testing.T) {
  1243  	b := NewBuildTest(t)
  1244  	b.AssertParse(&b.state, "rule cc\n  command = cc $in\n  depfile = $out.d\nbuild foo.o: cc foo.c || otherfile\n", ParseManifestOpts{})
  1245  	edge := b.state.Edges[len(b.state.Edges)-1]
  1246  
  1247  	b.fs.Create("foo.c", "")
  1248  	b.fs.Create("otherfile", "")
  1249  	b.fs.Create("foo.o.d", "foo.o: blah.h bar.h\n")
  1250  	if _, err := b.builder.addTargetName("foo.o"); err != nil {
  1251  		t.Fatal(err)
  1252  	}
  1253  
  1254  	// One explicit, two implicit, one order only.
  1255  	if 4 != len(edge.Inputs) {
  1256  		t.Fatal("expected equal")
  1257  	}
  1258  	if 2 != edge.ImplicitDeps {
  1259  		t.Fatal("expected equal")
  1260  	}
  1261  	if 1 != edge.OrderOnlyDeps {
  1262  		t.Fatal("expected equal")
  1263  	}
  1264  	// Verify the inputs are in the order we expect
  1265  	// (explicit then implicit then orderonly).
  1266  	if "foo.c" != edge.Inputs[0].Path {
  1267  		t.Fatal("expected equal")
  1268  	}
  1269  	if "blah.h" != edge.Inputs[1].Path {
  1270  		t.Fatal("expected equal")
  1271  	}
  1272  	if "bar.h" != edge.Inputs[2].Path {
  1273  		t.Fatal("expected equal")
  1274  	}
  1275  	if "otherfile" != edge.Inputs[3].Path {
  1276  		t.Fatal("expected equal")
  1277  	}
  1278  
  1279  	// Expect the command line we generate to only use the original input.
  1280  	if "cc foo.c" != edge.EvaluateCommand(false) {
  1281  		t.Fatal("expected equal")
  1282  	}
  1283  
  1284  	// explicit dep dirty, expect a rebuild.
  1285  	if err := b.builder.Build(); err != nil {
  1286  		t.Fatal(err)
  1287  	}
  1288  	if 1 != len(b.commandRunner.commandsRan) {
  1289  		t.Fatal("expected equal")
  1290  	}
  1291  
  1292  	b.fs.Tick()
  1293  
  1294  	// Recreate the depfile, as it should have been deleted by the build.
  1295  	b.fs.Create("foo.o.d", "foo.o: blah.h bar.h\n")
  1296  
  1297  	// implicit dep dirty, expect a rebuild.
  1298  	b.fs.Create("blah.h", "")
  1299  	b.fs.Create("bar.h", "")
  1300  	b.commandRunner.commandsRan = nil
  1301  	b.state.Reset()
  1302  	if _, err := b.builder.addTargetName("foo.o"); err != nil {
  1303  		t.Fatal(err)
  1304  	}
  1305  	if err := b.builder.Build(); err != nil {
  1306  		t.Fatal(err)
  1307  	}
  1308  	if 1 != len(b.commandRunner.commandsRan) {
  1309  		t.Fatal("expected equal")
  1310  	}
  1311  
  1312  	b.fs.Tick()
  1313  
  1314  	// Recreate the depfile, as it should have been deleted by the build.
  1315  	b.fs.Create("foo.o.d", "foo.o: blah.h bar.h\n")
  1316  
  1317  	// order only dep dirty, no rebuild.
  1318  	b.fs.Create("otherfile", "")
  1319  	b.commandRunner.commandsRan = nil
  1320  	b.state.Reset()
  1321  	if _, err := b.builder.addTargetName("foo.o"); err != nil {
  1322  		t.Fatal(err)
  1323  	}
  1324  	if !b.builder.AlreadyUpToDate() {
  1325  		t.Fatal("expected true")
  1326  	}
  1327  
  1328  	// implicit dep missing, expect rebuild.
  1329  	b.fs.RemoveFile("bar.h")
  1330  	b.commandRunner.commandsRan = nil
  1331  	b.state.Reset()
  1332  	if _, err := b.builder.addTargetName("foo.o"); err != nil {
  1333  		t.Fatal(err)
  1334  	}
  1335  	if err := b.builder.Build(); err != nil {
  1336  		t.Fatal(err)
  1337  	}
  1338  	if 1 != len(b.commandRunner.commandsRan) {
  1339  		t.Fatal("expected equal")
  1340  	}
  1341  }
  1342  
  1343  func TestBuildTest_RebuildOrderOnlyDeps(t *testing.T) {
  1344  	b := NewBuildTest(t)
  1345  	b.AssertParse(&b.state, "rule cc\n  command = cc $in\nrule true\n  command = true\nbuild oo.h: cc oo.h.in\nbuild foo.o: cc foo.c || oo.h\n", ParseManifestOpts{})
  1346  
  1347  	b.fs.Create("foo.c", "")
  1348  	b.fs.Create("oo.h.in", "")
  1349  
  1350  	// foo.o and order-only dep dirty, build both.
  1351  	if _, err := b.builder.addTargetName("foo.o"); err != nil {
  1352  		t.Fatal(err)
  1353  	}
  1354  	if err := b.builder.Build(); err != nil {
  1355  		t.Fatal(err)
  1356  	}
  1357  	if 2 != len(b.commandRunner.commandsRan) {
  1358  		t.Fatal("expected equal")
  1359  	}
  1360  
  1361  	// all clean, no rebuild.
  1362  	b.commandRunner.commandsRan = nil
  1363  	b.state.Reset()
  1364  	if _, err := b.builder.addTargetName("foo.o"); err != nil {
  1365  		t.Fatal(err)
  1366  	}
  1367  	if !b.builder.AlreadyUpToDate() {
  1368  		t.Fatal("expected true")
  1369  	}
  1370  
  1371  	// order-only dep missing, build it only.
  1372  	b.fs.RemoveFile("oo.h")
  1373  	b.commandRunner.commandsRan = nil
  1374  	b.state.Reset()
  1375  	if _, err := b.builder.addTargetName("foo.o"); err != nil {
  1376  		t.Fatal(err)
  1377  	}
  1378  	if err := b.builder.Build(); err != nil {
  1379  		t.Fatal(err)
  1380  	}
  1381  	wantCommands := []string{"cc oo.h.in"}
  1382  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  1383  		t.Fatal(diff)
  1384  	}
  1385  
  1386  	b.fs.Tick()
  1387  
  1388  	// order-only dep dirty, build it only.
  1389  	b.fs.Create("oo.h.in", "")
  1390  	b.commandRunner.commandsRan = nil
  1391  	b.state.Reset()
  1392  	if _, err := b.builder.addTargetName("foo.o"); err != nil {
  1393  		t.Fatal(err)
  1394  	}
  1395  	if err := b.builder.Build(); err != nil {
  1396  		t.Fatal(err)
  1397  	}
  1398  	wantCommands = []string{"cc oo.h.in"}
  1399  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  1400  		t.Fatal(diff)
  1401  	}
  1402  }
  1403  
  1404  func TestBuildTest_DepFileCanonicalize(t *testing.T) {
  1405  	if runtime.GOOS != "windows" {
  1406  		t.Skip("windows only")
  1407  	}
  1408  	t.Skip("TODO")
  1409  	b := NewBuildTest(t)
  1410  	origEdges := len(b.state.Edges)
  1411  	if origEdges != 3 {
  1412  		t.Fatal(origEdges)
  1413  	}
  1414  	b.AssertParse(&b.state, "rule cc\n  command = cc $in\n  depfile = $out.d\nbuild gen/stuff\\things/foo.o: cc x\\y/z\\foo.c\n", ParseManifestOpts{})
  1415  	edge := b.state.Edges[len(b.state.Edges)-1]
  1416  
  1417  	b.fs.Create("x/y/z/foo.c", "")
  1418  	b.GetNode("bar.h").Dirty = true // Mark bar.h as missing.
  1419  	// Note, different slashes from manifest.
  1420  	b.fs.Create("gen/stuff\\things/foo.o.d", "gen\\stuff\\things\\foo.o: blah.h bar.h\n")
  1421  	if _, err := b.builder.addTargetName("gen/stuff/things/foo.o"); err != nil {
  1422  		t.Fatal(err)
  1423  	}
  1424  	// The depfile path does not get Canonicalize as it seems unnecessary.
  1425  	wantReads := []string{"gen/stuff\\things/foo.o.d"}
  1426  	if diff := cmp.Diff(wantReads, b.fs.filesRead); diff != "" {
  1427  		t.Fatal(diff)
  1428  	}
  1429  
  1430  	// Expect three new edges: one generating foo.o, and two more from
  1431  	// loading the depfile.
  1432  	if origEdges+3 != len(b.state.Edges) {
  1433  		t.Fatal(len(b.state.Edges))
  1434  	}
  1435  	// Expect our edge to now have three inputs: foo.c and two headers.
  1436  	if 3 != len(edge.Inputs) {
  1437  		t.Fatal(len(edge.Inputs))
  1438  	}
  1439  
  1440  	// Expect the command line we generate to only use the original input, and
  1441  	// using the slashes from the manifest.
  1442  	if got := edge.EvaluateCommand(false); got != "cc x\\y/z\\foo.c" {
  1443  		t.Fatalf("%q", got)
  1444  	}
  1445  }
  1446  
  1447  func TestBuildTest_Phony(t *testing.T) {
  1448  	b := NewBuildTest(t)
  1449  	b.AssertParse(&b.state, "build out: cat bar.cc\nbuild all: phony out\n", ParseManifestOpts{})
  1450  	b.fs.Create("bar.cc", "")
  1451  
  1452  	if _, err := b.builder.addTargetName("all"); err != nil {
  1453  		t.Fatal(err)
  1454  	}
  1455  
  1456  	// Only one command to run, because phony runs no command.
  1457  	if b.builder.AlreadyUpToDate() {
  1458  		t.Fatal("expected false")
  1459  	}
  1460  	if err := b.builder.Build(); err != nil {
  1461  		t.Fatal(err)
  1462  	}
  1463  	if 1 != len(b.commandRunner.commandsRan) {
  1464  		t.Fatal("expected equal")
  1465  	}
  1466  }
  1467  
  1468  func TestBuildTest_PhonyNoWork(t *testing.T) {
  1469  	b := NewBuildTest(t)
  1470  	b.AssertParse(&b.state, "build out: cat bar.cc\nbuild all: phony out\n", ParseManifestOpts{})
  1471  	b.fs.Create("bar.cc", "")
  1472  	b.fs.Create("out", "")
  1473  
  1474  	if _, err := b.builder.addTargetName("all"); err != nil {
  1475  		t.Fatal(err)
  1476  	}
  1477  	if !b.builder.AlreadyUpToDate() {
  1478  		t.Fatal("expected true")
  1479  	}
  1480  }
  1481  
  1482  // Test a self-referencing phony.  Ideally this should not work, but
  1483  // ninja 1.7 and below tolerated and CMake 2.8.12.x and 3.0.x both
  1484  // incorrectly produce it.  We tolerate it for compatibility.
  1485  func TestBuildTest_PhonySelfReference(t *testing.T) {
  1486  	b := NewBuildTest(t)
  1487  	b.AssertParse(&b.state, "build a: phony a\n", ParseManifestOpts{Quiet: true})
  1488  
  1489  	if _, err := b.builder.addTargetName("a"); err != nil {
  1490  		t.Fatal(err)
  1491  	}
  1492  	if !b.builder.AlreadyUpToDate() {
  1493  		t.Fatal("expected true")
  1494  	}
  1495  }
  1496  
  1497  // There are 6 different cases for phony rules:
  1498  //
  1499  // 1. output edge does not exist, inputs are not real
  1500  // 2. output edge does not exist, no inputs
  1501  // 3. output edge does not exist, inputs are real, newest mtime is M
  1502  // 4. output edge is real, inputs are not real
  1503  // 5. output edge is real, no inputs
  1504  // 6. output edge is real, inputs are real, newest mtime is M
  1505  //
  1506  // Expected results :
  1507  // 1. Edge is marked as clean, mtime is newest mtime of dependents.
  1508  //     Touching inputs will cause dependents to rebuild.
  1509  // 2. Edge is marked as dirty, causing dependent edges to always rebuild
  1510  // 3. Edge is marked as clean, mtime is newest mtime of dependents.
  1511  //     Touching inputs will cause dependents to rebuild.
  1512  // 4. Edge is marked as clean, mtime is newest mtime of dependents.
  1513  //     Touching inputs will cause dependents to rebuild.
  1514  // 5. Edge is marked as dirty, causing dependent edges to always rebuild
  1515  // 6. Edge is marked as clean, mtime is newest mtime of dependents.
  1516  //     Touching inputs will cause dependents to rebuild.
  1517  func PhonyUseCase(t *testing.T, i int) {
  1518  	b := NewBuildTest(t)
  1519  	b.AssertParse(&b.state, "rule touch\n command = touch $out\nbuild notreal: phony blank\nbuild phony1: phony notreal\nbuild phony2: phony\nbuild phony3: phony blank\nbuild phony4: phony notreal\nbuild phony5: phony\nbuild phony6: phony blank\n\nbuild test1: touch phony1\nbuild test2: touch phony2\nbuild test3: touch phony3\nbuild test4: touch phony4\nbuild test5: touch phony5\nbuild test6: touch phony6\n", ParseManifestOpts{})
  1520  
  1521  	// Set up test.
  1522  	b.builder.commandRunner = nil // BuildTest owns the CommandRunner
  1523  	b.builder.commandRunner = &b.commandRunner
  1524  
  1525  	b.fs.Create("blank", "") // a "real" file
  1526  	if _, err := b.builder.addTargetName("test1"); err != nil {
  1527  		t.Fatal(err)
  1528  	}
  1529  	if _, err := b.builder.addTargetName("test2"); err != nil {
  1530  		t.Fatal(err)
  1531  	}
  1532  	if _, err := b.builder.addTargetName("test3"); err != nil {
  1533  		t.Fatal(err)
  1534  	}
  1535  	if _, err := b.builder.addTargetName("test4"); err != nil {
  1536  		t.Fatal(err)
  1537  	}
  1538  	if _, err := b.builder.addTargetName("test5"); err != nil {
  1539  		t.Fatal(err)
  1540  	}
  1541  	if _, err := b.builder.addTargetName("test6"); err != nil {
  1542  		t.Fatal(err)
  1543  	}
  1544  	if err := b.builder.Build(); err != nil {
  1545  		t.Fatal(err)
  1546  	}
  1547  
  1548  	ci := strconv.Itoa(i)
  1549  
  1550  	// Tests 1, 3, 4, and 6 should rebuild when the input is updated.
  1551  	if i != 2 && i != 5 {
  1552  		testNode := b.GetNode("test" + ci)
  1553  		phonyNode := b.GetNode("phony" + ci)
  1554  		inputNode := b.GetNode("blank")
  1555  
  1556  		b.state.Reset()
  1557  		startTime := b.fs.now
  1558  
  1559  		// Build number 1
  1560  		if _, err := b.builder.addTargetName("test" + ci); err != nil {
  1561  			t.Fatal(err)
  1562  		}
  1563  		if !b.builder.AlreadyUpToDate() {
  1564  			if err := b.builder.Build(); err != nil {
  1565  				t.Fatal(err)
  1566  			}
  1567  		}
  1568  
  1569  		// Touch the input file
  1570  		b.state.Reset()
  1571  		b.commandRunner.commandsRan = nil
  1572  		b.fs.Tick()
  1573  		b.fs.Create("blank", "") // a "real" file
  1574  		if _, err := b.builder.addTargetName("test" + ci); err != nil {
  1575  			t.Fatal(err)
  1576  		}
  1577  
  1578  		// Second build, expect testN edge to be rebuilt
  1579  		// and phonyN node's mtime to be updated.
  1580  		if b.builder.AlreadyUpToDate() {
  1581  			t.Fatal("expected false")
  1582  		}
  1583  		if err := b.builder.Build(); err != nil {
  1584  			t.Fatal(err)
  1585  		}
  1586  		wantCommands := []string{"touch test" + ci}
  1587  		if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  1588  			t.Fatal(diff)
  1589  		}
  1590  		if !b.builder.AlreadyUpToDate() {
  1591  			t.Fatal("expected true")
  1592  		}
  1593  
  1594  		inputTime := inputNode.MTime
  1595  
  1596  		if phonyNode.Exists == ExistenceStatusExists {
  1597  			t.Fatal("expected false")
  1598  		}
  1599  		if phonyNode.Dirty {
  1600  			t.Fatal("expected false")
  1601  		}
  1602  
  1603  		if phonyNode.MTime <= startTime {
  1604  			t.Fatal("expected greater")
  1605  		}
  1606  		if phonyNode.MTime != inputTime {
  1607  			t.Fatal("expected equal")
  1608  		}
  1609  		if err := testNode.Stat(&b.fs); err != nil {
  1610  			t.Fatal(err)
  1611  		}
  1612  		if testNode.Exists != ExistenceStatusExists {
  1613  			t.Fatal("expected true")
  1614  		}
  1615  		if testNode.MTime <= startTime {
  1616  			t.Fatal("expected greater")
  1617  		}
  1618  	} else {
  1619  		// Tests 2 and 5: Expect dependents to always rebuild.
  1620  
  1621  		b.state.Reset()
  1622  		b.commandRunner.commandsRan = nil
  1623  		b.fs.Tick()
  1624  		b.commandRunner.commandsRan = nil
  1625  		if _, err := b.builder.addTargetName("test" + ci); err != nil {
  1626  			t.Fatal(err)
  1627  		}
  1628  		if b.builder.AlreadyUpToDate() {
  1629  			t.Fatal("expected false")
  1630  		}
  1631  		if err := b.builder.Build(); err != nil {
  1632  			t.Fatal(err)
  1633  		}
  1634  		wantCommands := []string{"touch test" + ci}
  1635  		if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  1636  			t.Fatal(diff)
  1637  		}
  1638  
  1639  		b.state.Reset()
  1640  		b.commandRunner.commandsRan = nil
  1641  		if _, err := b.builder.addTargetName("test" + ci); err != nil {
  1642  			t.Fatal(err)
  1643  		}
  1644  		if b.builder.AlreadyUpToDate() {
  1645  			t.Fatal("expected false")
  1646  		}
  1647  		if err := b.builder.Build(); err != nil {
  1648  			t.Fatal(err)
  1649  		}
  1650  		wantCommands = []string{"touch test" + ci}
  1651  		if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  1652  			t.Fatal(diff)
  1653  		}
  1654  	}
  1655  }
  1656  
  1657  func TestBuildTest_PhonyUseCase(t *testing.T) {
  1658  	for i := 1; i < 7; i++ {
  1659  		t.Run(strconv.Itoa(i), func(t *testing.T) { PhonyUseCase(t, i) })
  1660  	}
  1661  }
  1662  
  1663  func TestBuildTest_Fail(t *testing.T) {
  1664  	b := NewBuildTest(t)
  1665  	b.AssertParse(&b.state, "rule fail\n  command = fail\nbuild out1: fail\n", ParseManifestOpts{})
  1666  
  1667  	if _, err := b.builder.addTargetName("out1"); err != nil {
  1668  		t.Fatal(err)
  1669  	}
  1670  
  1671  	if err := b.builder.Build(); err == nil {
  1672  		t.Fatal("expected false")
  1673  	} else if err.Error() != "subcommand failed" {
  1674  		t.Fatal(err)
  1675  	}
  1676  	if 1 != len(b.commandRunner.commandsRan) {
  1677  		t.Fatal("expected equal")
  1678  	}
  1679  }
  1680  
  1681  func TestBuildTest_SwallowFailures(t *testing.T) {
  1682  	b := NewBuildTest(t)
  1683  	b.AssertParse(&b.state, "rule fail\n  command = fail\nbuild out1: fail\nbuild out2: fail\nbuild out3: fail\nbuild all: phony out1 out2 out3\n", ParseManifestOpts{})
  1684  
  1685  	// Swallow two failures, die on the third.
  1686  	b.config.FailuresAllowed = 3
  1687  
  1688  	if _, err := b.builder.addTargetName("all"); err != nil {
  1689  		t.Fatal(err)
  1690  	}
  1691  
  1692  	err := b.builder.Build()
  1693  	if err == nil {
  1694  		t.Fatal("expected error")
  1695  	} else if err.Error() != "subcommands failed" {
  1696  		t.Fatal(err)
  1697  	}
  1698  	if 3 != len(b.commandRunner.commandsRan) {
  1699  		t.Fatal("expected equal")
  1700  	}
  1701  }
  1702  
  1703  func TestBuildTest_SwallowFailuresLimit(t *testing.T) {
  1704  	b := NewBuildTest(t)
  1705  	b.AssertParse(&b.state, "rule fail\n  command = fail\nbuild out1: fail\nbuild out2: fail\nbuild out3: fail\nbuild final: cat out1 out2 out3\n", ParseManifestOpts{})
  1706  
  1707  	// Swallow ten failures; we should stop before building final.
  1708  	b.config.FailuresAllowed = 11
  1709  
  1710  	if _, err := b.builder.addTargetName("final"); err != nil {
  1711  		t.Fatal(err)
  1712  	}
  1713  
  1714  	if err := b.builder.Build(); err == nil {
  1715  		t.Fatal("expected false")
  1716  	} else if err.Error() != "cannot make progress due to previous errors" {
  1717  		t.Fatal(err)
  1718  	}
  1719  	if 3 != len(b.commandRunner.commandsRan) {
  1720  		t.Fatal("expected equal")
  1721  	}
  1722  }
  1723  
  1724  func TestBuildTest_SwallowFailuresPool(t *testing.T) {
  1725  	b := NewBuildTest(t)
  1726  	b.AssertParse(&b.state, "pool failpool\n  depth = 1\nrule fail\n  command = fail\n  pool = failpool\nbuild out1: fail\nbuild out2: fail\nbuild out3: fail\nbuild final: cat out1 out2 out3\n", ParseManifestOpts{})
  1727  
  1728  	// Swallow ten failures; we should stop before building final.
  1729  	b.config.FailuresAllowed = 11
  1730  
  1731  	if _, err := b.builder.addTargetName("final"); err != nil {
  1732  		t.Fatal(err)
  1733  	}
  1734  
  1735  	if err := b.builder.Build(); err == nil {
  1736  		t.Fatal("expected false")
  1737  	} else if err.Error() != "cannot make progress due to previous errors" {
  1738  		t.Fatal(err)
  1739  	}
  1740  	if 3 != len(b.commandRunner.commandsRan) {
  1741  		t.Fatal("expected equal")
  1742  	}
  1743  }
  1744  
  1745  func TestBuildTest_PoolEdgesReadyButNotWanted(t *testing.T) {
  1746  	b := NewBuildTest(t)
  1747  	b.fs.Create("x", "")
  1748  
  1749  	manifest := "pool some_pool\n  depth = 4\nrule touch\n  command = touch $out\n  pool = some_pool\nrule cc\n  command = touch grit\n\nbuild B.d.stamp: cc | x\nbuild C.stamp: touch B.d.stamp\nbuild final.stamp: touch || C.stamp\n"
  1750  
  1751  	b.RebuildTarget("final.stamp", manifest, "", "", nil)
  1752  
  1753  	b.fs.RemoveFile("B.d.stamp")
  1754  
  1755  	saveState := NewState()
  1756  	b.RebuildTarget("final.stamp", manifest, "", "", &saveState)
  1757  	if saveState.Pools["some_pool"].currentUse < 0 {
  1758  		t.Fatal("expected greater or equal")
  1759  	}
  1760  }
  1761  
  1762  type BuildWithLogTest struct {
  1763  	*BuildTest
  1764  	buildLog BuildLog
  1765  }
  1766  
  1767  func NewBuildWithLogTest(t *testing.T) *BuildWithLogTest {
  1768  	b := &BuildWithLogTest{
  1769  		BuildTest: NewBuildTest(t),
  1770  		buildLog:  NewBuildLog(),
  1771  	}
  1772  	t.Cleanup(func() {
  1773  		b.buildLog.Close()
  1774  	})
  1775  	b.builder.scan.buildLog = &b.buildLog
  1776  	return b
  1777  }
  1778  
  1779  func TestBuildWithLogTest_ImplicitGeneratedOutOfDate(t *testing.T) {
  1780  	b := NewBuildWithLogTest(t)
  1781  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\n  generator = 1\nbuild out.imp: touch | in\n", ParseManifestOpts{})
  1782  	b.fs.Create("out.imp", "")
  1783  	b.fs.Tick()
  1784  	b.fs.Create("in", "")
  1785  
  1786  	if _, err := b.builder.addTargetName("out.imp"); err != nil {
  1787  		t.Fatal(err)
  1788  	}
  1789  	if b.builder.AlreadyUpToDate() {
  1790  		t.Fatal("expected false")
  1791  	}
  1792  
  1793  	if !b.GetNode("out.imp").Dirty {
  1794  		t.Fatal("expected true")
  1795  	}
  1796  }
  1797  
  1798  func TestBuildWithLogTest_ImplicitGeneratedOutOfDate2(t *testing.T) {
  1799  	b := NewBuildWithLogTest(t)
  1800  	b.AssertParse(&b.state, "rule touch-implicit-dep-out\n  command = touch $test_dependency ; sleep 1 ; touch $out\n  generator = 1\nbuild out.imp: touch-implicit-dep-out | inimp inimp2\n  test_dependency = inimp\n", ParseManifestOpts{})
  1801  	b.fs.Create("inimp", "")
  1802  	b.fs.Create("out.imp", "")
  1803  	b.fs.Tick()
  1804  	b.fs.Create("inimp2", "")
  1805  	b.fs.Tick()
  1806  
  1807  	if _, err := b.builder.addTargetName("out.imp"); err != nil {
  1808  		t.Fatal(err)
  1809  	}
  1810  	if b.builder.AlreadyUpToDate() {
  1811  		t.Fatal("expected false")
  1812  	}
  1813  
  1814  	if err := b.builder.Build(); err != nil {
  1815  		t.Fatal(err)
  1816  	}
  1817  	if !b.builder.AlreadyUpToDate() {
  1818  		t.Fatal("expected true")
  1819  	}
  1820  
  1821  	b.commandRunner.commandsRan = nil
  1822  	b.state.Reset()
  1823  	b.builder.cleanup()
  1824  	b.builder.plan.Reset()
  1825  
  1826  	if _, err := b.builder.addTargetName("out.imp"); err != nil {
  1827  		t.Fatal(err)
  1828  	}
  1829  	if !b.builder.AlreadyUpToDate() {
  1830  		t.Fatal("expected true")
  1831  	}
  1832  	if b.GetNode("out.imp").Dirty {
  1833  		t.Fatal("expected false")
  1834  	}
  1835  }
  1836  
  1837  func TestBuildWithLogTest_NotInLogButOnDisk(t *testing.T) {
  1838  	b := NewBuildWithLogTest(t)
  1839  	b.AssertParse(&b.state, "rule cc\n  command = cc\nbuild out1: cc in\n", ParseManifestOpts{})
  1840  
  1841  	// Create input/output that would be considered up to date when
  1842  	// not considering the command line hash.
  1843  	b.fs.Create("in", "")
  1844  	b.fs.Create("out1", "")
  1845  
  1846  	// Because it's not in the log, it should not be up-to-date until
  1847  	// we build again.
  1848  	if _, err := b.builder.addTargetName("out1"); err != nil {
  1849  		t.Fatal(err)
  1850  	}
  1851  	if b.builder.AlreadyUpToDate() {
  1852  		t.Fatal("expected false")
  1853  	}
  1854  
  1855  	b.commandRunner.commandsRan = nil
  1856  	b.state.Reset()
  1857  
  1858  	if _, err := b.builder.addTargetName("out1"); err != nil {
  1859  		t.Fatal(err)
  1860  	}
  1861  	if err := b.builder.Build(); err != nil {
  1862  		t.Fatal(err)
  1863  	}
  1864  	if !b.builder.AlreadyUpToDate() {
  1865  		t.Fatal("expected true")
  1866  	}
  1867  }
  1868  
  1869  func TestBuildWithLogTest_RebuildAfterFailure(t *testing.T) {
  1870  	b := NewBuildWithLogTest(t)
  1871  	b.AssertParse(&b.state, "rule touch-fail-tick2\n  command = touch-fail-tick2\nbuild out1: touch-fail-tick2 in\n", ParseManifestOpts{})
  1872  
  1873  	b.fs.Create("in", "")
  1874  
  1875  	// Run once successfully to get out1 in the log
  1876  	if _, err := b.builder.addTargetName("out1"); err != nil {
  1877  		t.Fatal(err)
  1878  	}
  1879  	if err := b.builder.Build(); err != nil {
  1880  		t.Fatal(err)
  1881  	}
  1882  	if 1 != len(b.commandRunner.commandsRan) {
  1883  		t.Fatal("expected equal")
  1884  	}
  1885  
  1886  	b.commandRunner.commandsRan = nil
  1887  	b.state.Reset()
  1888  	b.builder.cleanup()
  1889  	b.builder.plan.Reset()
  1890  
  1891  	b.fs.Tick()
  1892  	b.fs.Create("in", "")
  1893  
  1894  	// Run again with a failure that updates the output file timestamp
  1895  	if _, err := b.builder.addTargetName("out1"); err != nil {
  1896  		t.Fatal(err)
  1897  	}
  1898  	if err := b.builder.Build(); err == nil {
  1899  		t.Fatal("expected false")
  1900  	} else if err.Error() != "subcommand failed" {
  1901  		t.Fatal(err)
  1902  	}
  1903  	if 1 != len(b.commandRunner.commandsRan) {
  1904  		t.Fatal("expected equal")
  1905  	}
  1906  
  1907  	b.commandRunner.commandsRan = nil
  1908  	b.state.Reset()
  1909  	b.builder.cleanup()
  1910  	b.builder.plan.Reset()
  1911  
  1912  	b.fs.Tick()
  1913  
  1914  	// Run again, should rerun even though the output file is up to date on disk
  1915  	if _, err := b.builder.addTargetName("out1"); err != nil {
  1916  		t.Fatal(err)
  1917  	}
  1918  	if b.builder.AlreadyUpToDate() {
  1919  		t.Fatal("expected false")
  1920  	}
  1921  	if err := b.builder.Build(); err != nil {
  1922  		t.Fatal(err)
  1923  	}
  1924  	if 1 != len(b.commandRunner.commandsRan) {
  1925  		t.Fatal("expected equal")
  1926  	}
  1927  }
  1928  
  1929  func TestBuildWithLogTest_RebuildWithNoInputs(t *testing.T) {
  1930  	b := NewBuildWithLogTest(t)
  1931  	b.AssertParse(&b.state, "rule touch\n  command = touch\nbuild out1: touch\nbuild out2: touch in\n", ParseManifestOpts{})
  1932  
  1933  	b.fs.Create("in", "")
  1934  
  1935  	if _, err := b.builder.addTargetName("out1"); err != nil {
  1936  		t.Fatal(err)
  1937  	}
  1938  	if _, err := b.builder.addTargetName("out2"); err != nil {
  1939  		t.Fatal(err)
  1940  	}
  1941  	if err := b.builder.Build(); err != nil {
  1942  		t.Fatal(err)
  1943  	}
  1944  	if 2 != len(b.commandRunner.commandsRan) {
  1945  		t.Fatal("expected equal")
  1946  	}
  1947  
  1948  	b.commandRunner.commandsRan = nil
  1949  	b.state.Reset()
  1950  
  1951  	b.fs.Tick()
  1952  
  1953  	b.fs.Create("in", "")
  1954  
  1955  	if _, err := b.builder.addTargetName("out1"); err != nil {
  1956  		t.Fatal(err)
  1957  	}
  1958  	if _, err := b.builder.addTargetName("out2"); err != nil {
  1959  		t.Fatal(err)
  1960  	}
  1961  	if err := b.builder.Build(); err != nil {
  1962  		t.Fatal(err)
  1963  	}
  1964  	if 1 != len(b.commandRunner.commandsRan) {
  1965  		t.Fatal("expected equal")
  1966  	}
  1967  }
  1968  
  1969  func TestBuildWithLogTest_RestatTest(t *testing.T) {
  1970  	b := NewBuildWithLogTest(t)
  1971  	b.AssertParse(&b.state, "rule true\n  command = true\n  restat = 1\nrule cc\n  command = cc\n  restat = 1\nbuild out1: cc in\nbuild out2: true out1\nbuild out3: cat out2\n", ParseManifestOpts{})
  1972  
  1973  	b.fs.Create("out1", "")
  1974  	b.fs.Create("out2", "")
  1975  	b.fs.Create("out3", "")
  1976  
  1977  	b.fs.Tick()
  1978  
  1979  	b.fs.Create("in", "")
  1980  
  1981  	// Do a pre-build so that there's commands in the log for the outputs,
  1982  	// otherwise, the lack of an entry in the build log will cause out3 to rebuild
  1983  	// regardless of restat.
  1984  	if _, err := b.builder.addTargetName("out3"); err != nil {
  1985  		t.Fatal(err)
  1986  	}
  1987  	if err := b.builder.Build(); err != nil {
  1988  		t.Fatal(err)
  1989  	}
  1990  	if 3 != len(b.commandRunner.commandsRan) {
  1991  		t.Fatal("expected equal")
  1992  	}
  1993  	if 3 != b.builder.plan.commandEdges {
  1994  		t.Fatal("expected equal")
  1995  	}
  1996  	b.commandRunner.commandsRan = nil
  1997  	b.state.Reset()
  1998  
  1999  	b.fs.Tick()
  2000  
  2001  	b.fs.Create("in", "")
  2002  	// "cc" touches out1, so we should build out2.  But because "true" does not
  2003  	// touch out2, we should cancel the build of out3.
  2004  	if _, err := b.builder.addTargetName("out3"); err != nil {
  2005  		t.Fatal(err)
  2006  	}
  2007  	if err := b.builder.Build(); err != nil {
  2008  		t.Fatal(err)
  2009  	}
  2010  	if 2 != len(b.commandRunner.commandsRan) {
  2011  		t.Fatal("expected equal")
  2012  	}
  2013  
  2014  	// If we run again, it should be a no-op, because the build log has recorded
  2015  	// that we've already built out2 with an input timestamp of 2 (from out1).
  2016  	b.commandRunner.commandsRan = nil
  2017  	b.state.Reset()
  2018  	if _, err := b.builder.addTargetName("out3"); err != nil {
  2019  		t.Fatal(err)
  2020  	}
  2021  	if !b.builder.AlreadyUpToDate() {
  2022  		t.Fatal("expected true")
  2023  	}
  2024  
  2025  	b.fs.Tick()
  2026  
  2027  	b.fs.Create("in", "")
  2028  
  2029  	// The build log entry should not, however, prevent us from rebuilding out2
  2030  	// if out1 changes.
  2031  	b.commandRunner.commandsRan = nil
  2032  	b.state.Reset()
  2033  	if _, err := b.builder.addTargetName("out3"); err != nil {
  2034  		t.Fatal(err)
  2035  	}
  2036  	if err := b.builder.Build(); err != nil {
  2037  		t.Fatal(err)
  2038  	}
  2039  	if 2 != len(b.commandRunner.commandsRan) {
  2040  		t.Fatal("expected equal")
  2041  	}
  2042  }
  2043  
  2044  func TestBuildWithLogTest_RestatMissingFile(t *testing.T) {
  2045  	b := NewBuildWithLogTest(t)
  2046  	// If a restat rule doesn't create its output, and the output didn't
  2047  	// exist before the rule was run, consider that behavior equivalent
  2048  	// to a rule that doesn't modify its existent output file.
  2049  
  2050  	b.AssertParse(&b.state, "rule true\n  command = true\n  restat = 1\nrule cc\n  command = cc\nbuild out1: true in\nbuild out2: cc out1\n", ParseManifestOpts{})
  2051  
  2052  	b.fs.Create("in", "")
  2053  	b.fs.Create("out2", "")
  2054  
  2055  	// Do a pre-build so that there's commands in the log for the outputs,
  2056  	// otherwise, the lack of an entry in the build log will cause out2 to rebuild
  2057  	// regardless of restat.
  2058  	if _, err := b.builder.addTargetName("out2"); err != nil {
  2059  		t.Fatal(err)
  2060  	}
  2061  	if err := b.builder.Build(); err != nil {
  2062  		t.Fatal(err)
  2063  	}
  2064  	b.commandRunner.commandsRan = nil
  2065  	b.state.Reset()
  2066  
  2067  	b.fs.Tick()
  2068  	b.fs.Create("in", "")
  2069  	b.fs.Create("out2", "")
  2070  
  2071  	// Run a build, expect only the first command to run.
  2072  	// It doesn't touch its output (due to being the "true" command), so
  2073  	// we shouldn't run the dependent build.
  2074  	if _, err := b.builder.addTargetName("out2"); err != nil {
  2075  		t.Fatal(err)
  2076  	}
  2077  	if err := b.builder.Build(); err != nil {
  2078  		t.Fatal(err)
  2079  	}
  2080  	if 1 != len(b.commandRunner.commandsRan) {
  2081  		t.Fatal("expected equal")
  2082  	}
  2083  }
  2084  
  2085  func TestBuildWithLogTest_RestatSingleDependentOutputDirty(t *testing.T) {
  2086  	b := NewBuildWithLogTest(t)
  2087  	b.AssertParse(&b.state, "rule true\n  command = true\n  restat = 1\nrule touch\n  command = touch\nbuild out1: true in\nbuild out2 out3: touch out1\nbuild out4: touch out2\n", ParseManifestOpts{})
  2088  
  2089  	// Create the necessary files
  2090  	b.fs.Create("in", "")
  2091  
  2092  	if _, err := b.builder.addTargetName("out4"); err != nil {
  2093  		t.Fatal(err)
  2094  	}
  2095  	if err := b.builder.Build(); err != nil {
  2096  		t.Fatal(err)
  2097  	}
  2098  	if 3 != len(b.commandRunner.commandsRan) {
  2099  		t.Fatal("expected equal")
  2100  	}
  2101  
  2102  	b.fs.Tick()
  2103  	b.fs.Create("in", "")
  2104  	b.fs.RemoveFile("out3")
  2105  
  2106  	// Since "in" is missing, out1 will be built. Since "out3" is missing,
  2107  	// out2 and out3 will be built even though "in" is not touched when built.
  2108  	// Then, since out2 is rebuilt, out4 should be rebuilt -- the restat on the
  2109  	// "true" rule should not lead to the "touch" edge writing out2 and out3 being
  2110  	// cleard.
  2111  	b.commandRunner.commandsRan = nil
  2112  	b.state.Reset()
  2113  	if _, err := b.builder.addTargetName("out4"); err != nil {
  2114  		t.Fatal(err)
  2115  	}
  2116  	if err := b.builder.Build(); err != nil {
  2117  		t.Fatal(err)
  2118  	}
  2119  	if 3 != len(b.commandRunner.commandsRan) {
  2120  		t.Fatal("expected equal")
  2121  	}
  2122  }
  2123  
  2124  // Test scenario, in which an input file is removed, but output isn't changed
  2125  // https://github.com/ninja-build/ninja/issues/295
  2126  func TestBuildWithLogTest_RestatMissingInput(t *testing.T) {
  2127  	b := NewBuildWithLogTest(t)
  2128  	b.AssertParse(&b.state, "rule true\n  command = true\n  depfile = $out.d\n  restat = 1\nrule cc\n  command = cc\nbuild out1: true in\nbuild out2: cc out1\n", ParseManifestOpts{})
  2129  
  2130  	// Create all necessary files
  2131  	b.fs.Create("in", "")
  2132  
  2133  	// The implicit dependencies and the depfile itself
  2134  	// are newer than the output
  2135  	restatMtime := b.fs.Tick()
  2136  	b.fs.Create("out1.d", "out1: will.be.deleted restat.file\n")
  2137  	b.fs.Create("will.be.deleted", "")
  2138  	b.fs.Create("restat.file", "")
  2139  
  2140  	// Run the build, out1 and out2 get built
  2141  	if _, err := b.builder.addTargetName("out2"); err != nil {
  2142  		t.Fatal(err)
  2143  	}
  2144  	if err := b.builder.Build(); err != nil {
  2145  		t.Fatal(err)
  2146  	}
  2147  	if 2 != len(b.commandRunner.commandsRan) {
  2148  		t.Fatal("expected equal")
  2149  	}
  2150  
  2151  	// See that an entry in the logfile is created, capturing
  2152  	// the right mtime
  2153  	logEntry := b.buildLog.Entries["out1"]
  2154  	if nil == logEntry {
  2155  		t.Fatal("expected true")
  2156  	}
  2157  	if restatMtime != logEntry.mtime {
  2158  		t.Fatal("expected equal")
  2159  	}
  2160  
  2161  	// Now remove a file, referenced from depfile, so that target becomes
  2162  	// dirty, but the output does not change
  2163  	b.fs.RemoveFile("will.be.deleted")
  2164  
  2165  	// Trigger the build again - only out1 gets built
  2166  	b.commandRunner.commandsRan = nil
  2167  	b.state.Reset()
  2168  	if _, err := b.builder.addTargetName("out2"); err != nil {
  2169  		t.Fatal(err)
  2170  	}
  2171  	if err := b.builder.Build(); err != nil {
  2172  		t.Fatal(err)
  2173  	}
  2174  	if 1 != len(b.commandRunner.commandsRan) {
  2175  		t.Fatal("expected equal")
  2176  	}
  2177  
  2178  	// Check that the logfile entry remains correctly set
  2179  	logEntry = b.buildLog.Entries["out1"]
  2180  	if nil == logEntry {
  2181  		t.Fatal("expected true")
  2182  	}
  2183  	if restatMtime != logEntry.mtime {
  2184  		t.Fatal("expected equal")
  2185  	}
  2186  }
  2187  
  2188  func TestBuildWithLogTest_GeneratedPlainDepfileMtime(t *testing.T) {
  2189  	b := NewBuildWithLogTest(t)
  2190  	b.AssertParse(&b.state, "rule generate-depfile\n  command = touch $out ; echo \"$out: $test_dependency\" > $depfile\nbuild out: generate-depfile\n  test_dependency = inimp\n  depfile = out.d\n", ParseManifestOpts{})
  2191  	b.fs.Create("inimp", "")
  2192  	b.fs.Tick()
  2193  
  2194  	if _, err := b.builder.addTargetName("out"); err != nil {
  2195  		t.Fatal(err)
  2196  	}
  2197  	if b.builder.AlreadyUpToDate() {
  2198  		t.Fatal("expected false")
  2199  	}
  2200  
  2201  	if err := b.builder.Build(); err != nil {
  2202  		t.Fatal(err)
  2203  	}
  2204  	if !b.builder.AlreadyUpToDate() {
  2205  		t.Fatal("expected true")
  2206  	}
  2207  
  2208  	b.commandRunner.commandsRan = nil
  2209  	b.state.Reset()
  2210  	b.builder.cleanup()
  2211  	b.builder.plan.Reset()
  2212  
  2213  	if _, err := b.builder.addTargetName("out"); err != nil {
  2214  		t.Fatal(err)
  2215  	}
  2216  	if !b.builder.AlreadyUpToDate() {
  2217  		t.Fatal("expected true")
  2218  	}
  2219  }
  2220  
  2221  func NewBuildDryRunTest(t *testing.T) *BuildWithLogTest {
  2222  	b := NewBuildWithLogTest(t)
  2223  	b.config.DryRun = true
  2224  	return b
  2225  }
  2226  
  2227  func TestBuildDryRun_AllCommandsShown(t *testing.T) {
  2228  	b := NewBuildDryRunTest(t)
  2229  	b.AssertParse(&b.state, "rule true\n  command = true\n  restat = 1\nrule cc\n  command = cc\n  restat = 1\nbuild out1: cc in\nbuild out2: true out1\nbuild out3: cat out2\n", ParseManifestOpts{})
  2230  
  2231  	b.fs.Create("out1", "")
  2232  	b.fs.Create("out2", "")
  2233  	b.fs.Create("out3", "")
  2234  
  2235  	b.fs.Tick()
  2236  
  2237  	b.fs.Create("in", "")
  2238  
  2239  	// "cc" touches out1, so we should build out2.  But because "true" does not
  2240  	// touch out2, we should cancel the build of out3.
  2241  	if _, err := b.builder.addTargetName("out3"); err != nil {
  2242  		t.Fatal(err)
  2243  	}
  2244  	if err := b.builder.Build(); err != nil {
  2245  		t.Fatal(err)
  2246  	}
  2247  	if 3 != len(b.commandRunner.commandsRan) {
  2248  		t.Fatal("expected equal")
  2249  	}
  2250  }
  2251  
  2252  // Test that RSP files are created when & where appropriate and deleted after
  2253  // successful execution.
  2254  func TestBuildTest_RspFileSuccess(t *testing.T) {
  2255  	b := NewBuildTest(t)
  2256  	b.AssertParse(&b.state, "rule cat_rsp\n  command = cat $rspfile > $out\n  rspfile = $rspfile\n  rspfile_content = $long_command\nrule cat_rsp_out\n  command = cat $rspfile > $out\n  rspfile = $out.rsp\n  rspfile_content = $long_command\nbuild out1: cat in\nbuild out2: cat_rsp in\n  rspfile = out 2.rsp\n  long_command = Some very long command\nbuild out$ 3: cat_rsp_out in\n  long_command = Some very long command\n", ParseManifestOpts{})
  2257  
  2258  	b.fs.Create("out1", "")
  2259  	b.fs.Create("out2", "")
  2260  	b.fs.Create("out 3", "")
  2261  
  2262  	b.fs.Tick()
  2263  
  2264  	b.fs.Create("in", "")
  2265  
  2266  	if _, err := b.builder.addTargetName("out1"); err != nil {
  2267  		t.Fatal(err)
  2268  	}
  2269  	if _, err := b.builder.addTargetName("out2"); err != nil {
  2270  		t.Fatal(err)
  2271  	}
  2272  	if _, err := b.builder.addTargetName("out 3"); err != nil {
  2273  		t.Fatal(err)
  2274  	}
  2275  
  2276  	wantCreated := map[string]struct{}{
  2277  		"in":    {},
  2278  		"in1":   {},
  2279  		"in2":   {},
  2280  		"out 3": {},
  2281  		"out1":  {},
  2282  		"out2":  {},
  2283  	}
  2284  	if diff := cmp.Diff(wantCreated, b.fs.filesCreated); diff != "" {
  2285  		t.Fatal(diff)
  2286  	}
  2287  	wantRemoved := map[string]struct{}{}
  2288  	if diff := cmp.Diff(wantRemoved, b.fs.filesRemoved); diff != "" {
  2289  		t.Fatal(diff)
  2290  	}
  2291  
  2292  	if err := b.builder.Build(); err != nil {
  2293  		t.Fatal(err)
  2294  	}
  2295  	if 3 != len(b.commandRunner.commandsRan) {
  2296  		t.Fatal(b.commandRunner.commandsRan)
  2297  	}
  2298  
  2299  	// The RSP files were created
  2300  	wantCreated["out 2.rsp"] = struct{}{}
  2301  	wantCreated["out 3.rsp"] = struct{}{}
  2302  	if diff := cmp.Diff(wantCreated, b.fs.filesCreated); diff != "" {
  2303  		t.Fatal(diff)
  2304  	}
  2305  
  2306  	// The RSP files were removed
  2307  	wantRemoved["out 2.rsp"] = struct{}{}
  2308  	wantRemoved["out 3.rsp"] = struct{}{}
  2309  	if diff := cmp.Diff(wantRemoved, b.fs.filesRemoved); diff != "" {
  2310  		t.Fatal(diff)
  2311  	}
  2312  }
  2313  
  2314  // Test that RSP file is created but not removed for commands, which fail
  2315  func TestBuildTest_RspFileFailure(t *testing.T) {
  2316  	b := NewBuildTest(t)
  2317  	b.AssertParse(&b.state, "rule fail\n  command = fail\n  rspfile = $rspfile\n  rspfile_content = $long_command\nbuild out: fail in\n  rspfile = out.rsp\n  long_command = Another very long command\n", ParseManifestOpts{})
  2318  
  2319  	b.fs.Create("out", "")
  2320  	b.fs.Tick()
  2321  	b.fs.Create("in", "")
  2322  
  2323  	if _, err := b.builder.addTargetName("out"); err != nil {
  2324  		t.Fatal(err)
  2325  	}
  2326  
  2327  	wantCreated := map[string]struct{}{
  2328  		"in":  {},
  2329  		"in1": {},
  2330  		"in2": {},
  2331  		"out": {},
  2332  	}
  2333  	if diff := cmp.Diff(wantCreated, b.fs.filesCreated); diff != "" {
  2334  		t.Fatal(diff)
  2335  	}
  2336  	wantRemoved := map[string]struct{}{}
  2337  	if diff := cmp.Diff(wantRemoved, b.fs.filesRemoved); diff != "" {
  2338  		t.Fatal(diff)
  2339  	}
  2340  
  2341  	if err := b.builder.Build(); err == nil {
  2342  		t.Fatal("expected false")
  2343  	} else if err.Error() != "subcommand failed" {
  2344  		t.Fatal(err)
  2345  	}
  2346  	wantCommand := []string{"fail"}
  2347  	if diff := cmp.Diff(wantCommand, b.commandRunner.commandsRan); diff != "" {
  2348  		t.Fatal(diff)
  2349  	}
  2350  
  2351  	// The RSP file was created
  2352  	wantCreated["out.rsp"] = struct{}{}
  2353  	if diff := cmp.Diff(wantCreated, b.fs.filesCreated); diff != "" {
  2354  		t.Fatal(diff)
  2355  	}
  2356  
  2357  	// The RSP file was NOT removed
  2358  	if diff := cmp.Diff(wantRemoved, b.fs.filesRemoved); diff != "" {
  2359  		t.Fatal(diff)
  2360  	}
  2361  
  2362  	// The RSP file contains what it should
  2363  	if c, err := b.fs.ReadFile("out.rsp"); err != nil || string(c) != "Another very long command\x00" {
  2364  		t.Fatal(c, err)
  2365  	}
  2366  }
  2367  
  2368  // Test that contents of the RSP file behaves like a regular part of
  2369  // command line, i.e. triggers a rebuild if changed
  2370  func TestBuildWithLogTest_RspFileCmdLineChange(t *testing.T) {
  2371  	b := NewBuildWithLogTest(t)
  2372  	b.AssertParse(&b.state, "rule cat_rsp\n  command = cat $rspfile > $out\n  rspfile = $rspfile\n  rspfile_content = $long_command\nbuild out: cat_rsp in\n  rspfile = out.rsp\n  long_command = Original very long command\n", ParseManifestOpts{})
  2373  
  2374  	b.fs.Create("out", "")
  2375  	b.fs.Tick()
  2376  	b.fs.Create("in", "")
  2377  
  2378  	if _, err := b.builder.addTargetName("out"); err != nil {
  2379  		t.Fatal(err)
  2380  	}
  2381  
  2382  	// 1. Build for the 1st time (-> populate log)
  2383  	if err := b.builder.Build(); err != nil {
  2384  		t.Fatal(err)
  2385  	}
  2386  	wantCommand := []string{"cat out.rsp > out"}
  2387  	if diff := cmp.Diff(wantCommand, b.commandRunner.commandsRan); diff != "" {
  2388  		t.Fatal(diff)
  2389  	}
  2390  
  2391  	// 2. Build again (no change)
  2392  	b.commandRunner.commandsRan = nil
  2393  	b.state.Reset()
  2394  	if _, err := b.builder.addTargetName("out"); err != nil {
  2395  		t.Fatal(err)
  2396  	}
  2397  	if !b.builder.AlreadyUpToDate() {
  2398  		t.Fatal("expected true")
  2399  	}
  2400  
  2401  	// 3. Alter the entry in the logfile
  2402  	// (to simulate a change in the command line between 2 builds)
  2403  	logEntry := b.buildLog.Entries["out"]
  2404  	if nil == logEntry {
  2405  		t.Fatal("expected true")
  2406  	}
  2407  	b.AssertHash("cat out.rsp > out;rspfile=Original very long command", logEntry.commandHash)
  2408  	logEntry.commandHash++ // Change the command hash to something else.
  2409  	// Now expect the target to be rebuilt
  2410  	b.commandRunner.commandsRan = nil
  2411  	b.state.Reset()
  2412  	if _, err := b.builder.addTargetName("out"); err != nil {
  2413  		t.Fatal(err)
  2414  	}
  2415  	if err := b.builder.Build(); err != nil {
  2416  		t.Fatal(err)
  2417  	}
  2418  	if diff := cmp.Diff(wantCommand, b.commandRunner.commandsRan); diff != "" {
  2419  		t.Fatal(diff)
  2420  	}
  2421  }
  2422  
  2423  func TestBuildTest_InterruptCleanup(t *testing.T) {
  2424  	b := NewBuildTest(t)
  2425  	b.AssertParse(&b.state, "rule interrupt\n  command = interrupt\nrule touch-interrupt\n  command = touch-interrupt\nbuild out1: interrupt in1\nbuild out2: touch-interrupt in2\n", ParseManifestOpts{})
  2426  
  2427  	b.fs.Create("out1", "")
  2428  	b.fs.Create("out2", "")
  2429  	b.fs.Tick()
  2430  	b.fs.Create("in1", "")
  2431  	b.fs.Create("in2", "")
  2432  
  2433  	// An untouched output of an interrupted command should be retained.
  2434  	if _, err := b.builder.addTargetName("out1"); err != nil {
  2435  		t.Fatal(err)
  2436  	}
  2437  	if err := b.builder.Build(); err == nil {
  2438  		t.Fatal("expected false")
  2439  	} else if err.Error() != "interrupted by user" {
  2440  		t.Fatal(err)
  2441  	}
  2442  	b.builder.cleanup()
  2443  	if mtime, err := b.fs.Stat("out1"); mtime <= 0 || err != nil {
  2444  		t.Fatal(mtime, err)
  2445  	}
  2446  
  2447  	// A touched output of an interrupted command should be deleted.
  2448  	if _, err := b.builder.addTargetName("out2"); err != nil {
  2449  		t.Fatal(err)
  2450  	}
  2451  	if err := b.builder.Build(); err == nil {
  2452  		t.Fatal("expected false")
  2453  	} else if err.Error() != "interrupted by user" {
  2454  		t.Fatal(err)
  2455  	}
  2456  	b.builder.cleanup()
  2457  	if mtime, err := b.fs.Stat("out2"); mtime != 0 || err != nil {
  2458  		t.Fatal(mtime, err)
  2459  	}
  2460  }
  2461  
  2462  func TestBuildTest_StatFailureAbortsBuild(t *testing.T) {
  2463  	b := NewBuildTest(t)
  2464  	tooLongToStat := strings.Repeat("i", 400)
  2465  	b.AssertParse(&b.state, ("build " + tooLongToStat + ": cat in\n"), ParseManifestOpts{})
  2466  	b.fs.Create("in", "")
  2467  
  2468  	// This simulates a stat failure:
  2469  	b.fs.files[tooLongToStat] = Entry{
  2470  		mtime:     -1,
  2471  		statError: errors.New("stat failed"),
  2472  	}
  2473  
  2474  	if _, err := b.builder.addTargetName(tooLongToStat); err == nil {
  2475  		t.Fatal("expected false")
  2476  	} else if err.Error() != "stat failed" {
  2477  		t.Fatal(err)
  2478  	}
  2479  }
  2480  
  2481  func TestBuildTest_PhonyWithNoInputs(t *testing.T) {
  2482  	b := NewBuildTest(t)
  2483  	b.AssertParse(&b.state, "build nonexistent: phony\nbuild out1: cat || nonexistent\nbuild out2: cat nonexistent\n", ParseManifestOpts{})
  2484  	b.fs.Create("out1", "")
  2485  	b.fs.Create("out2", "")
  2486  
  2487  	// out1 should be up to date even though its input is dirty, because its
  2488  	// order-only dependency has nothing to do.
  2489  	if _, err := b.builder.addTargetName("out1"); err != nil {
  2490  		t.Fatal(err)
  2491  	}
  2492  	if !b.builder.AlreadyUpToDate() {
  2493  		t.Fatal("expected true")
  2494  	}
  2495  
  2496  	// out2 should still be out of date though, because its input is dirty.
  2497  	b.commandRunner.commandsRan = nil
  2498  	b.state.Reset()
  2499  	if _, err := b.builder.addTargetName("out2"); err != nil {
  2500  		t.Fatal(err)
  2501  	}
  2502  	if err := b.builder.Build(); err != nil {
  2503  		t.Fatal(err)
  2504  	}
  2505  	if 1 != len(b.commandRunner.commandsRan) {
  2506  		t.Fatal("expected equal")
  2507  	}
  2508  }
  2509  
  2510  func TestBuildTest_DepsGccWithEmptyDepfileErrorsOut(t *testing.T) {
  2511  	b := NewBuildTest(t)
  2512  	b.AssertParse(&b.state, "rule cc\n  command = cc\n  deps = gcc\nbuild out: cc\n", ParseManifestOpts{})
  2513  	b.Dirty("out")
  2514  
  2515  	if _, err := b.builder.addTargetName("out"); err != nil {
  2516  		t.Fatal(err)
  2517  	}
  2518  	if b.builder.AlreadyUpToDate() {
  2519  		t.Fatal("expected false")
  2520  	}
  2521  
  2522  	if err := b.builder.Build(); err == nil {
  2523  		t.Fatal("expected false")
  2524  	} else if err.Error() != "subcommand failed" {
  2525  		t.Fatal(err)
  2526  	}
  2527  	if 1 != len(b.commandRunner.commandsRan) {
  2528  		t.Fatal("expected equal")
  2529  	}
  2530  }
  2531  
  2532  func TestBuildTest_FailedDepsParse(t *testing.T) {
  2533  	b := NewBuildTest(t)
  2534  	b.AssertParse(&b.state, "build bad_deps.o: cat in1\n  deps = gcc\n  depfile = in1.d\n", ParseManifestOpts{})
  2535  
  2536  	if _, err := b.builder.addTargetName("bad_deps.o"); err != nil {
  2537  		t.Fatal(err)
  2538  	}
  2539  
  2540  	// These deps will fail to parse, as they should only have one
  2541  	// path to the left of the colon.
  2542  	b.fs.Create("in1.d", "AAA BBB")
  2543  
  2544  	if err := b.builder.Build(); err == nil {
  2545  		t.Fatal("expected false")
  2546  	} else if err.Error() != "subcommand failed" {
  2547  		t.Fatal(err)
  2548  	}
  2549  }
  2550  
  2551  type BuildWithQueryDepsLogTest struct {
  2552  	*BuildTestBase
  2553  	log     DepsLog
  2554  	builder *Builder
  2555  }
  2556  
  2557  func NewBuildWithQueryDepsLogTest(t *testing.T) *BuildWithQueryDepsLogTest {
  2558  	b := &BuildWithQueryDepsLogTest{
  2559  		BuildTestBase: NewBuildTestBase(t),
  2560  	}
  2561  	CreateTempDirAndEnter(t)
  2562  	if err := b.log.OpenForWrite("ninja_deps"); err != nil {
  2563  		t.Fatal(err)
  2564  	}
  2565  	t.Cleanup(func() {
  2566  		if err2 := b.log.Close(); err2 != nil {
  2567  			t.Error(err2)
  2568  		}
  2569  	})
  2570  	b.builder = NewBuilder(&b.state, &b.config, nil, &b.log, &b.fs, b.status, 0)
  2571  	b.builder.commandRunner = &b.commandRunner
  2572  	return b
  2573  }
  2574  
  2575  // Test a MSVC-style deps log with multiple outputs.
  2576  func TestBuildWithQueryDepsLogTest_TwoOutputsDepFileMSVC(t *testing.T) {
  2577  	b := NewBuildWithQueryDepsLogTest(t)
  2578  	b.AssertParse(&b.state, "rule cp_multi_msvc\n    command = echo 'using $in' && for file in $out; do cp $in $$file; done\n    deps = msvc\n    msvc_deps_prefix = using \nbuild out1 out2: cp_multi_msvc in1\n", ParseManifestOpts{})
  2579  
  2580  	if _, err := b.builder.addTargetName("out1"); err != nil {
  2581  		t.Fatal(err)
  2582  	}
  2583  	if err := b.builder.Build(); err != nil {
  2584  		t.Fatal(err)
  2585  	}
  2586  	wantCommands := []string{"echo 'using in1' && for file in out1 out2; do cp in1 $file; done"}
  2587  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  2588  		t.Fatal(diff)
  2589  	}
  2590  
  2591  	out1Node := b.state.Paths["out1"]
  2592  	out1Deps := b.log.GetDeps(out1Node)
  2593  	if 1 != len(out1Deps.Nodes) {
  2594  		t.Fatal("expected equal")
  2595  	}
  2596  	if "in1" != out1Deps.Nodes[0].Path {
  2597  		t.Fatal("expected equal")
  2598  	}
  2599  
  2600  	out2Node := b.state.Paths["out2"]
  2601  	out2Deps := b.log.GetDeps(out2Node)
  2602  	if 1 != len(out2Deps.Nodes) {
  2603  		t.Fatal("expected equal")
  2604  	}
  2605  	if "in1" != out2Deps.Nodes[0].Path {
  2606  		t.Fatal("expected equal")
  2607  	}
  2608  }
  2609  
  2610  // Test a GCC-style deps log with multiple outputs.
  2611  func TestBuildWithQueryDepsLogTest_TwoOutputsDepFileGCCOneLine(t *testing.T) {
  2612  	b := NewBuildWithQueryDepsLogTest(t)
  2613  	b.AssertParse(&b.state, "rule cp_multi_gcc\n    command = echo '$out: $in' > in.d && for file in $out; do cp in1 $$file; done\n    deps = gcc\n    depfile = in.d\nbuild out1 out2: cp_multi_gcc in1 in2\n", ParseManifestOpts{})
  2614  
  2615  	if _, err := b.builder.addTargetName("out1"); err != nil {
  2616  		t.Fatal(err)
  2617  	}
  2618  	b.fs.Create("in.d", "out1 out2: in1 in2")
  2619  	if err := b.builder.Build(); err != nil {
  2620  		t.Fatal(err)
  2621  	}
  2622  	wantCommands := []string{"echo 'out1 out2: in1 in2' > in.d && for file in out1 out2; do cp in1 $file; done"}
  2623  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  2624  		t.Fatal(diff)
  2625  	}
  2626  
  2627  	out1Node := b.state.Paths["out1"]
  2628  	out1Deps := b.log.GetDeps(out1Node)
  2629  	if 2 != len(out1Deps.Nodes) {
  2630  		t.Fatal("expected equal")
  2631  	}
  2632  	if "in1" != out1Deps.Nodes[0].Path {
  2633  		t.Fatal("expected equal")
  2634  	}
  2635  	if "in2" != out1Deps.Nodes[1].Path {
  2636  		t.Fatal("expected equal")
  2637  	}
  2638  
  2639  	out2Node := b.state.Paths["out2"]
  2640  	out2Deps := b.log.GetDeps(out2Node)
  2641  	if 2 != len(out2Deps.Nodes) {
  2642  		t.Fatal("expected equal")
  2643  	}
  2644  	if "in1" != out2Deps.Nodes[0].Path {
  2645  		t.Fatal("expected equal")
  2646  	}
  2647  	if "in2" != out2Deps.Nodes[1].Path {
  2648  		t.Fatal("expected equal")
  2649  	}
  2650  }
  2651  
  2652  // Test a GCC-style deps log with multiple outputs using a line per input.
  2653  func TestBuildWithQueryDepsLogTest_TwoOutputsDepFileGCCMultiLineInput(t *testing.T) {
  2654  	b := NewBuildWithQueryDepsLogTest(t)
  2655  	b.AssertParse(&b.state, "rule cp_multi_gcc\n    command = echo '$out: in1\\n$out: in2' > in.d && for file in $out; do cp in1 $$file; done\n    deps = gcc\n    depfile = in.d\nbuild out1 out2: cp_multi_gcc in1 in2\n", ParseManifestOpts{})
  2656  
  2657  	if _, err := b.builder.addTargetName("out1"); err != nil {
  2658  		t.Fatal(err)
  2659  	}
  2660  	b.fs.Create("in.d", "out1 out2: in1\nout1 out2: in2")
  2661  	if err := b.builder.Build(); err != nil {
  2662  		t.Fatal(err)
  2663  	}
  2664  	wantCommands := []string{"echo 'out1 out2: in1\\nout1 out2: in2' > in.d && for file in out1 out2; do cp in1 $file; done"}
  2665  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  2666  		t.Fatal(diff)
  2667  	}
  2668  
  2669  	out1Node := b.state.Paths["out1"]
  2670  	out1Deps := b.log.GetDeps(out1Node)
  2671  	if 2 != len(out1Deps.Nodes) {
  2672  		t.Fatal("expected equal")
  2673  	}
  2674  	if "in1" != out1Deps.Nodes[0].Path {
  2675  		t.Fatal("expected equal")
  2676  	}
  2677  	if "in2" != out1Deps.Nodes[1].Path {
  2678  		t.Fatal("expected equal")
  2679  	}
  2680  
  2681  	out2Node := b.state.Paths["out2"]
  2682  	out2Deps := b.log.GetDeps(out2Node)
  2683  	if 2 != len(out2Deps.Nodes) {
  2684  		t.Fatal("expected equal")
  2685  	}
  2686  	if "in1" != out2Deps.Nodes[0].Path {
  2687  		t.Fatal("expected equal")
  2688  	}
  2689  	if "in2" != out2Deps.Nodes[1].Path {
  2690  		t.Fatal("expected equal")
  2691  	}
  2692  }
  2693  
  2694  // Test a GCC-style deps log with multiple outputs using a line per output.
  2695  func TestBuildWithQueryDepsLogTest_TwoOutputsDepFileGCCMultiLineOutput(t *testing.T) {
  2696  	b := NewBuildWithQueryDepsLogTest(t)
  2697  	b.AssertParse(&b.state, "rule cp_multi_gcc\n    command = echo 'out1: $in\\nout2: $in' > in.d && for file in $out; do cp in1 $$file; done\n    deps = gcc\n    depfile = in.d\nbuild out1 out2: cp_multi_gcc in1 in2\n", ParseManifestOpts{})
  2698  
  2699  	if _, err := b.builder.addTargetName("out1"); err != nil {
  2700  		t.Fatal(err)
  2701  	}
  2702  	b.fs.Create("in.d", "out1: in1 in2\nout2: in1 in2")
  2703  	if err := b.builder.Build(); err != nil {
  2704  		t.Fatal(err)
  2705  	}
  2706  	wantCommands := []string{"echo 'out1: in1 in2\\nout2: in1 in2' > in.d && for file in out1 out2; do cp in1 $file; done"}
  2707  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  2708  		t.Fatal(diff)
  2709  	}
  2710  
  2711  	out1Node := b.state.Paths["out1"]
  2712  	out1Deps := b.log.GetDeps(out1Node)
  2713  	if 2 != len(out1Deps.Nodes) {
  2714  		t.Fatal("expected equal")
  2715  	}
  2716  	if "in1" != out1Deps.Nodes[0].Path {
  2717  		t.Fatal("expected equal")
  2718  	}
  2719  	if "in2" != out1Deps.Nodes[1].Path {
  2720  		t.Fatal("expected equal")
  2721  	}
  2722  
  2723  	out2Node := b.state.Paths["out2"]
  2724  	out2Deps := b.log.GetDeps(out2Node)
  2725  	if 2 != len(out2Deps.Nodes) {
  2726  		t.Fatal("expected equal")
  2727  	}
  2728  	if "in1" != out2Deps.Nodes[0].Path {
  2729  		t.Fatal("expected equal")
  2730  	}
  2731  	if "in2" != out2Deps.Nodes[1].Path {
  2732  		t.Fatal("expected equal")
  2733  	}
  2734  }
  2735  
  2736  // Test a GCC-style deps log with multiple outputs mentioning only the main output.
  2737  func TestBuildWithQueryDepsLogTest_TwoOutputsDepFileGCCOnlyMainOutput(t *testing.T) {
  2738  	b := NewBuildWithQueryDepsLogTest(t)
  2739  	b.AssertParse(&b.state, "rule cp_multi_gcc\n    command = echo 'out1: $in' > in.d && for file in $out; do cp in1 $$file; done\n    deps = gcc\n    depfile = in.d\nbuild out1 out2: cp_multi_gcc in1 in2\n", ParseManifestOpts{})
  2740  
  2741  	if _, err := b.builder.addTargetName("out1"); err != nil {
  2742  		t.Fatal(err)
  2743  	}
  2744  	b.fs.Create("in.d", "out1: in1 in2")
  2745  	if err := b.builder.Build(); err != nil {
  2746  		t.Fatal(err)
  2747  	}
  2748  	wantCommand := []string{"echo 'out1: in1 in2' > in.d && for file in out1 out2; do cp in1 $file; done"}
  2749  	if diff := cmp.Diff(wantCommand, b.commandRunner.commandsRan); diff != "" {
  2750  		t.Fatal(diff)
  2751  	}
  2752  
  2753  	out1Node := b.state.Paths["out1"]
  2754  	out1Deps := b.log.GetDeps(out1Node)
  2755  	if 2 != len(out1Deps.Nodes) {
  2756  		t.Fatal("expected equal")
  2757  	}
  2758  	if "in1" != out1Deps.Nodes[0].Path {
  2759  		t.Fatal("expected equal")
  2760  	}
  2761  	if "in2" != out1Deps.Nodes[1].Path {
  2762  		t.Fatal("expected equal")
  2763  	}
  2764  
  2765  	out2Node := b.state.Paths["out2"]
  2766  	out2Deps := b.log.GetDeps(out2Node)
  2767  	if 2 != len(out2Deps.Nodes) {
  2768  		t.Fatal("expected equal")
  2769  	}
  2770  	if "in1" != out2Deps.Nodes[0].Path {
  2771  		t.Fatal("expected equal")
  2772  	}
  2773  	if "in2" != out2Deps.Nodes[1].Path {
  2774  		t.Fatal("expected equal")
  2775  	}
  2776  }
  2777  
  2778  // Test a GCC-style deps log with multiple outputs mentioning only the secondary output.
  2779  func TestBuildWithQueryDepsLogTest_TwoOutputsDepFileGCCOnlySecondaryOutput(t *testing.T) {
  2780  	b := NewBuildWithQueryDepsLogTest(t)
  2781  	// Note: This ends up short-circuiting the node creation due to the primary
  2782  	// output not being present, but it should still work.
  2783  	b.AssertParse(&b.state, "rule cp_multi_gcc\n    command = echo 'out2: $in' > in.d && for file in $out; do cp in1 $$file; done\n    deps = gcc\n    depfile = in.d\nbuild out1 out2: cp_multi_gcc in1 in2\n", ParseManifestOpts{})
  2784  
  2785  	if _, err := b.builder.addTargetName("out1"); err != nil {
  2786  		t.Fatal(err)
  2787  	}
  2788  	b.fs.Create("in.d", "out2: in1 in2")
  2789  	if err := b.builder.Build(); err != nil {
  2790  		t.Fatal(err)
  2791  	}
  2792  	wantCommand := []string{"echo 'out2: in1 in2' > in.d && for file in out1 out2; do cp in1 $file; done"}
  2793  	if diff := cmp.Diff(wantCommand, b.commandRunner.commandsRan); diff != "" {
  2794  		t.Fatal(diff)
  2795  	}
  2796  
  2797  	out1Node := b.state.Paths["out1"]
  2798  	out1Deps := b.log.GetDeps(out1Node)
  2799  	if 2 != len(out1Deps.Nodes) {
  2800  		t.Fatal("expected equal")
  2801  	}
  2802  	if "in1" != out1Deps.Nodes[0].Path {
  2803  		t.Fatal("expected equal")
  2804  	}
  2805  	if "in2" != out1Deps.Nodes[1].Path {
  2806  		t.Fatal("expected equal")
  2807  	}
  2808  
  2809  	out2Node := b.state.Paths["out2"]
  2810  	out2Deps := b.log.GetDeps(out2Node)
  2811  	if 2 != len(out2Deps.Nodes) {
  2812  		t.Fatal("expected equal")
  2813  	}
  2814  	if "in1" != out2Deps.Nodes[0].Path {
  2815  		t.Fatal("expected equal")
  2816  	}
  2817  	if "in2" != out2Deps.Nodes[1].Path {
  2818  		t.Fatal("expected equal")
  2819  	}
  2820  }
  2821  
  2822  // Tests of builds involving deps logs necessarily must span
  2823  // multiple builds.  We reuse methods on BuildTest but not the
  2824  // b.builder it sets up, because we want pristine objects for
  2825  // each build.
  2826  func NewBuildWithDepsLogTest(t *testing.T) *BuildTest {
  2827  	b := NewBuildTest(t)
  2828  	CreateTempDirAndEnter(t)
  2829  	return b
  2830  }
  2831  
  2832  // Run a straightforward build where the deps log is used.
  2833  func TestBuildWithDepsLogTest_Straightforward(t *testing.T) {
  2834  	b := NewBuildWithDepsLogTest(t)
  2835  	// Note: in1 was created by the superclass SetUp().
  2836  	manifest := "build out: cat in1\n  deps = gcc\n  depfile = in1.d\n"
  2837  	{
  2838  		state := NewState()
  2839  		b.AddCatRule(&state)
  2840  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  2841  
  2842  		// Run the build once, everything should be ok.
  2843  		depsLog := DepsLog{}
  2844  		defer depsLog.Close()
  2845  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  2846  			t.Fatal(err)
  2847  		}
  2848  
  2849  		builder := NewBuilder(&state, &b.config, nil, &depsLog, &b.fs, b.status, 0)
  2850  		builder.commandRunner = &b.commandRunner
  2851  		if _, err := builder.addTargetName("out"); err != nil {
  2852  			t.Fatal(err)
  2853  		}
  2854  		b.fs.Create("in1.d", "out: in2")
  2855  		if err := builder.Build(); err != nil {
  2856  			t.Fatal(err)
  2857  		}
  2858  
  2859  		// The deps file should have been removed.
  2860  		if mtime, err := b.fs.Stat("in1.d"); mtime != 0 || err != nil {
  2861  			t.Fatal(mtime, err)
  2862  		}
  2863  		// Recreate it for the next step.
  2864  		b.fs.Create("in1.d", "out: in2")
  2865  		depsLog.Close()
  2866  		builder.commandRunner = nil
  2867  	}
  2868  
  2869  	{
  2870  		state := NewState()
  2871  		b.AddCatRule(&state)
  2872  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  2873  
  2874  		// Touch the file only mentioned in the deps.
  2875  		b.fs.Tick()
  2876  		b.fs.Create("in2", "")
  2877  
  2878  		// Run the build again.
  2879  		depsLog := DepsLog{}
  2880  		defer depsLog.Close()
  2881  		if s, err := depsLog.Load("ninja_deps", &state); s != LoadSuccess || err != nil {
  2882  			t.Fatal(s, err)
  2883  		}
  2884  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  2885  			t.Fatal(err)
  2886  		}
  2887  
  2888  		builder := NewBuilder(&state, &b.config, nil, &depsLog, &b.fs, b.status, 0)
  2889  		builder.commandRunner = &b.commandRunner
  2890  		b.commandRunner.commandsRan = nil
  2891  		if _, err := builder.addTargetName("out"); err != nil {
  2892  			t.Fatal(err)
  2893  		}
  2894  		if err := builder.Build(); err != nil {
  2895  			t.Fatal(err)
  2896  		}
  2897  
  2898  		// We should have rebuilt the output due to in2 being
  2899  		// out of date.
  2900  		if 1 != len(b.commandRunner.commandsRan) {
  2901  			t.Fatal("expected equal")
  2902  		}
  2903  
  2904  		builder.commandRunner = nil
  2905  	}
  2906  }
  2907  
  2908  // Verify that obsolete dependency info causes a rebuild.
  2909  // 1) Run a successful build where everything has time t, record deps.
  2910  // 2) Move input/output to time t+1 -- despite files in alignment,
  2911  //    should still need to rebuild due to deps at older time.
  2912  func TestBuildWithDepsLogTest_ObsoleteDeps(t *testing.T) {
  2913  	b := NewBuildWithDepsLogTest(t)
  2914  	// Note: in1 was created by the superclass SetUp().
  2915  	manifest := "build out: cat in1\n  deps = gcc\n  depfile = in1.d\n"
  2916  	{
  2917  		// Run an ordinary build that gathers dependencies.
  2918  		b.fs.Create("in1", "")
  2919  		b.fs.Create("in1.d", "out: ")
  2920  
  2921  		state := NewState()
  2922  		b.AddCatRule(&state)
  2923  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  2924  
  2925  		// Run the build once, everything should be ok.
  2926  		depsLog := DepsLog{}
  2927  		defer depsLog.Close()
  2928  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  2929  			t.Fatal(err)
  2930  		}
  2931  
  2932  		builder := NewBuilder(&state, &b.config, nil, &depsLog, &b.fs, b.status, 0)
  2933  		builder.commandRunner = &b.commandRunner
  2934  		if _, err := builder.addTargetName("out"); err != nil {
  2935  			t.Fatal(err)
  2936  		}
  2937  		if err := builder.Build(); err != nil {
  2938  			t.Fatal(err)
  2939  		}
  2940  
  2941  		builder.commandRunner = nil
  2942  	}
  2943  
  2944  	// Push all files one tick forward so that only the deps are out
  2945  	// of date.
  2946  	b.fs.Tick()
  2947  	b.fs.Create("in1", "")
  2948  	b.fs.Create("out", "")
  2949  
  2950  	// The deps file should have been removed, so no need to timestamp it.
  2951  	if mtime, err := b.fs.Stat("in1.d"); mtime != 0 || err != nil {
  2952  		t.Fatal(mtime, err)
  2953  	}
  2954  
  2955  	{
  2956  		state := NewState()
  2957  		b.AddCatRule(&state)
  2958  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  2959  
  2960  		depsLog := DepsLog{}
  2961  		defer depsLog.Close()
  2962  		if s, err := depsLog.Load("ninja_deps", &state); s != LoadSuccess || err != nil {
  2963  			t.Fatal(s, err)
  2964  		}
  2965  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  2966  			t.Fatal(err)
  2967  		}
  2968  
  2969  		builder := NewBuilder(&state, &b.config, nil, &depsLog, &b.fs, b.status, 0)
  2970  		builder.commandRunner = &b.commandRunner
  2971  		b.commandRunner.commandsRan = nil
  2972  		if _, err := builder.addTargetName("out"); err != nil {
  2973  			t.Fatal(err)
  2974  		}
  2975  
  2976  		// Recreate the deps file here because the build expects them to exist.
  2977  		b.fs.Create("in1.d", "out: ")
  2978  
  2979  		if err := builder.Build(); err != nil {
  2980  			t.Fatal(err)
  2981  		}
  2982  
  2983  		// We should have rebuilt the output due to the deps being
  2984  		// out of date.
  2985  		if 1 != len(b.commandRunner.commandsRan) {
  2986  			t.Fatal("expected equal")
  2987  		}
  2988  
  2989  		builder.commandRunner = nil
  2990  	}
  2991  }
  2992  
  2993  func TestBuildWithDepsLogTest_DepsIgnoredInDryRun(t *testing.T) {
  2994  	b := NewBuildWithDepsLogTest(t)
  2995  	manifest := "build out: cat in1\n  deps = gcc\n  depfile = in1.d\n"
  2996  
  2997  	b.fs.Create("out", "")
  2998  	b.fs.Tick()
  2999  	b.fs.Create("in1", "")
  3000  
  3001  	state := NewState()
  3002  	b.AddCatRule(&state)
  3003  	b.AssertParse(&state, manifest, ParseManifestOpts{})
  3004  
  3005  	// The deps log is NULL in dry runs.
  3006  	b.config.DryRun = true
  3007  	builder := NewBuilder(&state, &b.config, nil, nil, &b.fs, b.status, 0)
  3008  	builder.commandRunner = &b.commandRunner
  3009  	b.commandRunner.commandsRan = nil
  3010  
  3011  	if _, err := builder.addTargetName("out"); err != nil {
  3012  		t.Fatal(err)
  3013  	}
  3014  	if err := builder.Build(); err != nil {
  3015  		t.Fatal(err)
  3016  	}
  3017  	if 1 != len(b.commandRunner.commandsRan) {
  3018  		t.Fatal("expected equal")
  3019  	}
  3020  
  3021  	builder.commandRunner = nil
  3022  }
  3023  
  3024  // Check that a restat rule generating a header cancels compilations correctly.
  3025  func TestBuildTest_RestatDepfileDependency(t *testing.T) {
  3026  	b := NewBuildTest(t)
  3027  	b.AssertParse(&b.state, "rule true\n  command = true\n  restat = 1\nbuild header.h: true header.in\nbuild out: cat in1\n  depfile = in1.d\n", ParseManifestOpts{}) // Would be "write if out-of-date" in reality
  3028  
  3029  	b.fs.Create("header.h", "")
  3030  	b.fs.Create("in1.d", "out: header.h")
  3031  	b.fs.Tick()
  3032  	b.fs.Create("header.in", "")
  3033  
  3034  	if _, err := b.builder.addTargetName("out"); err != nil {
  3035  		t.Fatal(err)
  3036  	}
  3037  	if err := b.builder.Build(); err != nil {
  3038  		t.Fatal(err)
  3039  	}
  3040  }
  3041  
  3042  // Check that a restat rule generating a header cancels compilations correctly,
  3043  // depslog case.
  3044  func TestBuildWithDepsLogTest_RestatDepfileDependencyDepsLog(t *testing.T) {
  3045  	b := NewBuildWithDepsLogTest(t)
  3046  	// Note: in1 was created by the superclass SetUp().
  3047  	manifest := "rule true\n  command = true\n  restat = 1\nbuild header.h: true header.in\nbuild out: cat in1\n  deps = gcc\n  depfile = in1.d\n" // Would be "write if out-of-date" in reality.
  3048  	{
  3049  		state := NewState()
  3050  		b.AddCatRule(&state)
  3051  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  3052  
  3053  		// Run the build once, everything should be ok.
  3054  		depsLog := DepsLog{}
  3055  		defer depsLog.Close()
  3056  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  3057  			t.Fatal(err)
  3058  		}
  3059  
  3060  		builder := NewBuilder(&state, &b.config, nil, &depsLog, &b.fs, b.status, 0)
  3061  		builder.commandRunner = &b.commandRunner
  3062  		if _, err := builder.addTargetName("out"); err != nil {
  3063  			t.Fatal(err)
  3064  		}
  3065  		b.fs.Create("in1.d", "out: header.h")
  3066  		if err := builder.Build(); err != nil {
  3067  			t.Fatal(err)
  3068  		}
  3069  
  3070  		depsLog.Close()
  3071  		builder.commandRunner = nil
  3072  	}
  3073  
  3074  	{
  3075  		state := NewState()
  3076  		b.AddCatRule(&state)
  3077  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  3078  
  3079  		// Touch the input of the restat rule.
  3080  		b.fs.Tick()
  3081  		b.fs.Create("header.in", "")
  3082  
  3083  		// Run the build again.
  3084  		depsLog := DepsLog{}
  3085  		defer depsLog.Close()
  3086  		if s, err := depsLog.Load("ninja_deps", &state); s != LoadSuccess || err != nil {
  3087  			t.Fatal(s, err)
  3088  		}
  3089  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  3090  			t.Fatal(err)
  3091  		}
  3092  
  3093  		builder := NewBuilder(&state, &b.config, nil, &depsLog, &b.fs, b.status, 0)
  3094  		builder.commandRunner = &b.commandRunner
  3095  		b.commandRunner.commandsRan = nil
  3096  		if _, err := builder.addTargetName("out"); err != nil {
  3097  			t.Fatal(err)
  3098  		}
  3099  		if err := builder.Build(); err != nil {
  3100  			t.Fatal(err)
  3101  		}
  3102  
  3103  		// Rule "true" should have run again, but the build of "out" should have
  3104  		// been cancelled due to restat propagating through the depfile header.
  3105  		if 1 != len(b.commandRunner.commandsRan) {
  3106  			t.Fatal("expected equal")
  3107  		}
  3108  
  3109  		builder.commandRunner = nil
  3110  	}
  3111  }
  3112  
  3113  func TestBuildWithDepsLogTest_DepFileOKDepsLog(t *testing.T) {
  3114  	b := NewBuildWithDepsLogTest(t)
  3115  	manifest := "rule cc\n  command = cc $in\n  depfile = $out.d\n  deps = gcc\nbuild fo$ o.o: cc foo.c\n"
  3116  
  3117  	b.fs.Create("foo.c", "")
  3118  
  3119  	{
  3120  		state := NewState()
  3121  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  3122  
  3123  		// Run the build once, everything should be ok.
  3124  		depsLog := DepsLog{}
  3125  		defer depsLog.Close()
  3126  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  3127  			t.Fatal(err)
  3128  		}
  3129  
  3130  		builder := NewBuilder(&state, &b.config, nil, &depsLog, &b.fs, b.status, 0)
  3131  		builder.commandRunner = &b.commandRunner
  3132  		if _, err := builder.addTargetName("fo o.o"); err != nil {
  3133  			t.Fatal(err)
  3134  		}
  3135  		b.fs.Create("fo o.o.d", "fo\\ o.o: blah.h bar.h\n")
  3136  		if err := builder.Build(); err != nil {
  3137  			t.Fatal(err)
  3138  		}
  3139  
  3140  		depsLog.Close()
  3141  		builder.commandRunner = nil
  3142  	}
  3143  
  3144  	{
  3145  		state := NewState()
  3146  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  3147  
  3148  		depsLog := DepsLog{}
  3149  		defer depsLog.Close()
  3150  		if s, err := depsLog.Load("ninja_deps", &state); s != LoadSuccess || err != nil {
  3151  			t.Fatal(s, err)
  3152  		}
  3153  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  3154  			t.Fatal(err)
  3155  		}
  3156  
  3157  		builder := NewBuilder(&state, &b.config, nil, &depsLog, &b.fs, b.status, 0)
  3158  		builder.commandRunner = &b.commandRunner
  3159  
  3160  		edge := state.Edges[len(state.Edges)-1]
  3161  
  3162  		state.GetNode("bar.h", 0).Dirty = true // Mark bar.h as missing.
  3163  		if _, err := builder.addTargetName("fo o.o"); err != nil {
  3164  			t.Fatal(err)
  3165  		}
  3166  
  3167  		// Expect three new edges: one generating fo o.o, and two more from
  3168  		// loading the depfile.
  3169  		if 3 != len(state.Edges) {
  3170  			t.Fatal("expected equal")
  3171  		}
  3172  		// Expect our edge to now have three inputs: foo.c and two headers.
  3173  		if 3 != len(edge.Inputs) {
  3174  			t.Fatal("expected equal")
  3175  		}
  3176  
  3177  		// Expect the command line we generate to only use the original input.
  3178  		if "cc foo.c" != edge.EvaluateCommand(false) {
  3179  			t.Fatal("expected equal")
  3180  		}
  3181  
  3182  		depsLog.Close()
  3183  		builder.commandRunner = nil
  3184  	}
  3185  }
  3186  
  3187  func TestBuildWithDepsLogTest_DiscoveredDepDuringBuildChanged(t *testing.T) {
  3188  	b := NewBuildWithDepsLogTest(t)
  3189  	manifest := "rule touch-out-implicit-dep\n  command = touch $out ; sleep 1 ; touch $test_dependency\nrule generate-depfile\n  command = touch $out ; echo \"$out: $test_dependency\" > $depfile\nbuild out1: touch-out-implicit-dep in1\n  test_dependency = inimp\nbuild out2: generate-depfile in1 || out1\n  test_dependency = inimp\n  depfile = out2.d\n  deps = gcc\n"
  3190  
  3191  	b.fs.Create("in1", "")
  3192  	b.fs.Tick()
  3193  
  3194  	buildLog := NewBuildLog()
  3195  	defer buildLog.Close()
  3196  
  3197  	{
  3198  		state := NewState()
  3199  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  3200  
  3201  		depsLog := DepsLog{}
  3202  		defer depsLog.Close()
  3203  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  3204  			t.Fatal(err)
  3205  		}
  3206  
  3207  		builder := NewBuilder(&state, &b.config, &buildLog, &depsLog, &b.fs, b.status, 0)
  3208  		builder.commandRunner = &b.commandRunner
  3209  		if _, err := builder.addTargetName("out2"); err != nil {
  3210  			t.Fatal(err)
  3211  		}
  3212  		if builder.AlreadyUpToDate() {
  3213  			t.Fatal("expected false")
  3214  		}
  3215  
  3216  		if err := builder.Build(); err != nil {
  3217  			t.Fatal(err)
  3218  		}
  3219  		if !builder.AlreadyUpToDate() {
  3220  			t.Fatal("expected true")
  3221  		}
  3222  
  3223  		depsLog.Close()
  3224  		builder.commandRunner = nil
  3225  	}
  3226  
  3227  	b.fs.Tick()
  3228  	b.fs.Create("in1", "")
  3229  
  3230  	{
  3231  		state := NewState()
  3232  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  3233  
  3234  		depsLog := DepsLog{}
  3235  		defer depsLog.Close()
  3236  		if s, err := depsLog.Load("ninja_deps", &state); s != LoadSuccess || err != nil {
  3237  			t.Fatal(s, err)
  3238  		}
  3239  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  3240  			t.Fatal(err)
  3241  		}
  3242  
  3243  		builder := NewBuilder(&state, &b.config, &buildLog, &depsLog, &b.fs, b.status, 0)
  3244  		builder.commandRunner = &b.commandRunner
  3245  		if _, err := builder.addTargetName("out2"); err != nil {
  3246  			t.Fatal(err)
  3247  		}
  3248  		if builder.AlreadyUpToDate() {
  3249  			t.Fatal("expected false")
  3250  		}
  3251  
  3252  		if err := builder.Build(); err != nil {
  3253  			t.Fatal(err)
  3254  		}
  3255  		if !builder.AlreadyUpToDate() {
  3256  			t.Fatal("expected true")
  3257  		}
  3258  
  3259  		depsLog.Close()
  3260  		builder.commandRunner = nil
  3261  	}
  3262  
  3263  	b.fs.Tick()
  3264  
  3265  	{
  3266  		state := NewState()
  3267  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  3268  
  3269  		depsLog := DepsLog{}
  3270  		defer depsLog.Close()
  3271  		if s, err := depsLog.Load("ninja_deps", &state); s != LoadSuccess || err != nil {
  3272  			t.Fatal(s, err)
  3273  		}
  3274  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  3275  			t.Fatal(err)
  3276  		}
  3277  
  3278  		builder := NewBuilder(&state, &b.config, &buildLog, &depsLog, &b.fs, b.status, 0)
  3279  		builder.commandRunner = &b.commandRunner
  3280  		if _, err := builder.addTargetName("out2"); err != nil {
  3281  			t.Fatal(err)
  3282  		}
  3283  		if !builder.AlreadyUpToDate() {
  3284  			t.Fatal("expected true")
  3285  		}
  3286  
  3287  		depsLog.Close()
  3288  		builder.commandRunner = nil
  3289  	}
  3290  }
  3291  
  3292  func TestBuildWithDepsLogTest_DepFileDepsLogCanonicalize(t *testing.T) {
  3293  	if runtime.GOOS != "windows" {
  3294  		t.Skip("windows only")
  3295  	}
  3296  	b := NewBuildWithDepsLogTest(t)
  3297  	manifest := "rule cc\n  command = cc $in\n  depfile = $out.d\n  deps = gcc\nbuild a/b\\c\\d/e/fo$ o.o: cc x\\y/z\\foo.c\n"
  3298  
  3299  	b.fs.Create("x/y/z/foo.c", "")
  3300  
  3301  	{
  3302  		state := NewState()
  3303  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  3304  
  3305  		// Run the build once, everything should be ok.
  3306  		depsLog := DepsLog{}
  3307  		defer depsLog.Close()
  3308  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  3309  			t.Fatal(err)
  3310  		}
  3311  
  3312  		builder := NewBuilder(&state, &b.config, nil, &depsLog, &b.fs, b.status, 0)
  3313  		builder.commandRunner = &b.commandRunner
  3314  		if _, err := builder.addTargetName("a/b/c/d/e/fo o.o"); err != nil {
  3315  			t.Fatal(err)
  3316  		}
  3317  		// Note, different slashes from manifest.
  3318  		b.fs.Create("a/b\\c\\d/e/fo o.o.d", "a\\b\\c\\d\\e\\fo\\ o.o: blah.h bar.h\n")
  3319  		if err := builder.Build(); err != nil {
  3320  			t.Fatal(err)
  3321  		}
  3322  
  3323  		depsLog.Close()
  3324  		builder.commandRunner = nil
  3325  	}
  3326  
  3327  	{
  3328  		state := NewState()
  3329  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  3330  
  3331  		depsLog := DepsLog{}
  3332  		defer depsLog.Close()
  3333  		if s, err := depsLog.Load("ninja_deps", &state); s != LoadSuccess || err != nil {
  3334  			t.Fatal(s, err)
  3335  		}
  3336  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  3337  			t.Fatal(err)
  3338  		}
  3339  
  3340  		builder := NewBuilder(&state, &b.config, nil, &depsLog, &b.fs, b.status, 0)
  3341  		builder.commandRunner = &b.commandRunner
  3342  
  3343  		edge := state.Edges[len(state.Edges)-1]
  3344  
  3345  		state.GetNode("bar.h", 0).Dirty = true // Mark bar.h as missing.
  3346  		if _, err := builder.addTargetName("a/b/c/d/e/fo o.o"); err != nil {
  3347  			t.Fatal(err)
  3348  		}
  3349  
  3350  		// Expect three new edges: one generating fo o.o, and two more from
  3351  		// loading the depfile.
  3352  		if 3 != len(state.Edges) {
  3353  			t.Fatal("expected equal")
  3354  		}
  3355  		// Expect our edge to now have three inputs: foo.c and two headers.
  3356  		if 3 != len(edge.Inputs) {
  3357  			t.Fatal("expected equal")
  3358  		}
  3359  
  3360  		// Expect the command line we generate to only use the original input.
  3361  		// Note, slashes from manifest, not .d.
  3362  		if "cc x\\y/z\\foo.c" != edge.EvaluateCommand(false) {
  3363  			t.Fatal("expected equal")
  3364  		}
  3365  
  3366  		depsLog.Close()
  3367  		builder.commandRunner = nil
  3368  	}
  3369  }
  3370  
  3371  // Check that a restat rule doesn't clear an edge if the depfile is missing.
  3372  // Follows from: https://github.com/ninja-build/ninja/issues/603
  3373  func TestBuildTest_RestatMissingDepfile(t *testing.T) {
  3374  	b := NewBuildTest(t)
  3375  	manifest := "rule true\n  command = true\n  restat = 1\nbuild header.h: true header.in\nbuild out: cat header.h\n  depfile = out.d\n" // Would be "write if out-of-date" in reality.
  3376  
  3377  	b.fs.Create("header.h", "")
  3378  	b.fs.Tick()
  3379  	b.fs.Create("out", "")
  3380  	b.fs.Create("header.in", "")
  3381  
  3382  	// Normally, only 'header.h' would be rebuilt, as
  3383  	// its rule doesn't touch the output and has 'restat=1' set.
  3384  	// But we are also missing the depfile for 'out',
  3385  	// which should force its command to run anyway!
  3386  	b.RebuildTarget("out", manifest, "", "", nil)
  3387  	if 2 != len(b.commandRunner.commandsRan) {
  3388  		t.Fatal("expected equal")
  3389  	}
  3390  }
  3391  
  3392  // Check that a restat rule doesn't clear an edge if the deps are missing.
  3393  // https://github.com/ninja-build/ninja/issues/603
  3394  func TestBuildWithDepsLogTest_RestatMissingDepfileDepslog(t *testing.T) {
  3395  	b := NewBuildWithDepsLogTest(t)
  3396  	manifest := "rule true\n  command = true\n  restat = 1\nbuild header.h: true header.in\nbuild out: cat header.h\n  deps = gcc\n  depfile = out.d\n" // Would be "write if out-of-date" in reality.
  3397  
  3398  	// Build once to populate ninja deps logs from out.d
  3399  	b.fs.Create("header.in", "")
  3400  	b.fs.Create("out.d", "out: header.h")
  3401  	b.fs.Create("header.h", "")
  3402  
  3403  	b.RebuildTarget("out", manifest, "build_log", "ninja_deps", nil)
  3404  	if 2 != len(b.commandRunner.commandsRan) {
  3405  		t.Fatal("expected equal")
  3406  	}
  3407  
  3408  	// Sanity: this rebuild should be NOOP
  3409  	b.RebuildTarget("out", manifest, "build_log", "ninja_deps", nil)
  3410  	if 0 != len(b.commandRunner.commandsRan) {
  3411  		t.Fatalf("Expected no command; %#v", b.commandRunner.commandsRan)
  3412  	}
  3413  
  3414  	// Touch 'header.in', blank dependencies log (create a different one).
  3415  	// Building header.h triggers 'restat' outputs cleanup.
  3416  	// Validate that out is rebuilt netherless, as deps are missing.
  3417  	b.fs.Tick()
  3418  	b.fs.Create("header.in", "")
  3419  
  3420  	// (switch to a new blank depsLog "ninja_deps2")
  3421  	b.RebuildTarget("out", manifest, "build_log", "ninja_deps2", nil)
  3422  	if 2 != len(b.commandRunner.commandsRan) {
  3423  		t.Fatal("expected equal")
  3424  	}
  3425  
  3426  	// Sanity: this build should be NOOP
  3427  	b.RebuildTarget("out", manifest, "build_log", "ninja_deps2", nil)
  3428  	if 0 != len(b.commandRunner.commandsRan) {
  3429  		t.Fatal("expected equal")
  3430  	}
  3431  
  3432  	// Check that invalidating deps by target timestamp also works here
  3433  	// Repeat the test but touch target instead of blanking the log.
  3434  	b.fs.Tick()
  3435  	b.fs.Create("header.in", "")
  3436  	b.fs.Create("out", "")
  3437  	b.RebuildTarget("out", manifest, "build_log", "ninja_deps2", nil)
  3438  	if 2 != len(b.commandRunner.commandsRan) {
  3439  		t.Fatal("expected equal")
  3440  	}
  3441  
  3442  	// And this build should be NOOP again
  3443  	b.RebuildTarget("out", manifest, "build_log", "ninja_deps2", nil)
  3444  	if 0 != len(b.commandRunner.commandsRan) {
  3445  		t.Fatal("expected equal")
  3446  	}
  3447  }
  3448  
  3449  func TestBuildTest_WrongOutputInDepfileCausesRebuild(t *testing.T) {
  3450  	b := NewBuildTest(t)
  3451  	manifest := "rule cc\n  command = cc $in\n  depfile = $out.d\nbuild foo.o: cc foo.c\n"
  3452  
  3453  	b.fs.Create("foo.c", "")
  3454  	b.fs.Create("foo.o", "")
  3455  	b.fs.Create("header.h", "")
  3456  	b.fs.Create("foo.o.d", "bar.o.d: header.h\n")
  3457  
  3458  	b.RebuildTarget("foo.o", manifest, "build_log", "ninja_deps", nil)
  3459  	if 1 != len(b.commandRunner.commandsRan) {
  3460  		t.Fatal("expected equal")
  3461  	}
  3462  }
  3463  
  3464  func TestBuildTest_Console(t *testing.T) {
  3465  	b := NewBuildTest(t)
  3466  	b.AssertParse(&b.state, "rule console\n  command = console\n  pool = console\nbuild cons: console in.txt\n", ParseManifestOpts{})
  3467  
  3468  	b.fs.Create("in.txt", "")
  3469  
  3470  	if _, err := b.builder.addTargetName("cons"); err != nil {
  3471  		t.Fatal(err)
  3472  	}
  3473  	if err := b.builder.Build(); err != nil {
  3474  		t.Fatal(err)
  3475  	}
  3476  	if 1 != len(b.commandRunner.commandsRan) {
  3477  		t.Fatal("expected equal")
  3478  	}
  3479  }
  3480  
  3481  func TestBuildTest_DyndepMissingAndNoRule(t *testing.T) {
  3482  	b := NewBuildTest(t)
  3483  	// Verify that we can diagnose when a dyndep file is missing and
  3484  	// has no rule to build it.
  3485  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\nbuild out: touch || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3486  
  3487  	if _, err := b.builder.addTargetName("out"); err == nil {
  3488  		t.Fatal("expected false")
  3489  	} else if err.Error() != "loading 'dd': file does not exist" {
  3490  		t.Fatal(err)
  3491  	}
  3492  }
  3493  
  3494  func TestBuildTest_DyndepReadyImplicitConnection(t *testing.T) {
  3495  	b := NewBuildTest(t)
  3496  	// Verify that a dyndep file can be loaded immediately to discover
  3497  	// that one edge has an implicit output that is also an implicit
  3498  	// input of another edge.
  3499  	b.AssertParse(&b.state, "rule touch\n  command = touch $out $out.imp\nbuild tmp: touch || dd\n  dyndep = dd\nbuild out: touch || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3500  	b.fs.Create("dd", "ninja_dyndep_version = 1\nbuild out | out.imp: dyndep | tmp.imp\nbuild tmp | tmp.imp: dyndep\n")
  3501  
  3502  	if _, err := b.builder.addTargetName("out"); err != nil {
  3503  		t.Fatal(err)
  3504  	}
  3505  	if err := b.builder.Build(); err != nil {
  3506  		t.Fatal(err)
  3507  	}
  3508  	wantCommands := []string{"touch tmp tmp.imp", "touch out out.imp"}
  3509  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  3510  		t.Fatal(diff)
  3511  	}
  3512  }
  3513  
  3514  func TestBuildTest_DyndepReadySyntaxError(t *testing.T) {
  3515  	b := NewBuildTest(t)
  3516  	// Verify that a dyndep file can be loaded immediately to discover
  3517  	// and reject a syntax error in it.
  3518  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\nbuild out: touch || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3519  	b.fs.Create("dd", "build out: dyndep\n")
  3520  
  3521  	if _, err := b.builder.addTargetName("out"); err == nil {
  3522  		t.Fatal("expected false")
  3523  	} else if err.Error() != "dd:1: expected 'ninja_dyndep_version = ...'\n" {
  3524  		t.Fatal(err)
  3525  	}
  3526  }
  3527  
  3528  func TestBuildTest_DyndepReadyCircular(t *testing.T) {
  3529  	b := NewBuildTest(t)
  3530  	// Verify that a dyndep file can be loaded immediately to discover
  3531  	// and reject a circular dependency.
  3532  	b.AssertParse(&b.state, "rule r\n  command = unused\nbuild out: r in || dd\n  dyndep = dd\nbuild in: r circ\n", ParseManifestOpts{})
  3533  	b.fs.Create("dd", "ninja_dyndep_version = 1\nbuild out | circ: dyndep\n")
  3534  	b.fs.Create("out", "")
  3535  
  3536  	if _, err := b.builder.addTargetName("out"); err == nil {
  3537  		t.Fatal("expected false")
  3538  	} else if err.Error() != "dependency cycle: circ -> in -> circ" {
  3539  		t.Fatal(err)
  3540  	}
  3541  }
  3542  
  3543  func TestBuildTest_DyndepBuild(t *testing.T) {
  3544  	b := NewBuildTest(t)
  3545  	// Verify that a dyndep file can be built and loaded to discover nothing.
  3546  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild out: touch || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3547  	b.fs.Create("dd-in", "ninja_dyndep_version = 1\nbuild out: dyndep\n")
  3548  
  3549  	if _, err := b.builder.addTargetName("out"); err != nil {
  3550  		t.Fatal(err)
  3551  	}
  3552  
  3553  	wantCreated := map[string]struct{}{"dd-in": {}, "in1": {}, "in2": {}}
  3554  	if diff := cmp.Diff(wantCreated, b.fs.filesCreated); diff != "" {
  3555  		t.Fatal(diff)
  3556  	}
  3557  
  3558  	if err := b.builder.Build(); err != nil {
  3559  		t.Fatal(err)
  3560  	}
  3561  
  3562  	wantCommand := []string{"cp dd-in dd", "touch out"}
  3563  	if diff := cmp.Diff(wantCommand, b.commandRunner.commandsRan); diff != "" {
  3564  		t.Fatal(diff)
  3565  	}
  3566  	wantFilesRead := []string{"dd-in", "dd"}
  3567  	if diff := cmp.Diff(wantFilesRead, b.fs.filesRead); diff != "" {
  3568  		t.Fatal(diff)
  3569  	}
  3570  	wantCreated["dd"] = struct{}{}
  3571  	wantCreated["out"] = struct{}{}
  3572  	if diff := cmp.Diff(wantCreated, b.fs.filesCreated); diff != "" {
  3573  		t.Fatal(diff)
  3574  	}
  3575  }
  3576  
  3577  func TestBuildTest_DyndepBuildSyntaxError(t *testing.T) {
  3578  	b := NewBuildTest(t)
  3579  	// Verify that a dyndep file can be built and loaded to discover
  3580  	// and reject a syntax error in it.
  3581  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild out: touch || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3582  	b.fs.Create("dd-in", "build out: dyndep\n")
  3583  
  3584  	if _, err := b.builder.addTargetName("out"); err != nil {
  3585  		t.Fatal(err)
  3586  	}
  3587  
  3588  	if err := b.builder.Build(); err == nil {
  3589  		t.Fatal("expected false")
  3590  	} else if err.Error() != "dd:1: expected 'ninja_dyndep_version = ...'\n" {
  3591  		t.Fatal(err)
  3592  	}
  3593  }
  3594  
  3595  func TestBuildTest_DyndepBuildUnrelatedOutput(t *testing.T) {
  3596  	b := NewBuildTest(t)
  3597  	// Verify that a dyndep file can have dependents that do not specify
  3598  	// it as their dyndep binding.
  3599  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild unrelated: touch || dd\nbuild out: touch unrelated || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3600  	b.fs.Create("dd-in", "ninja_dyndep_version = 1\nbuild out: dyndep\n")
  3601  	b.fs.Tick()
  3602  	b.fs.Create("out", "")
  3603  
  3604  	if _, err := b.builder.addTargetName("out"); err != nil {
  3605  		t.Fatal(err)
  3606  	}
  3607  
  3608  	if err := b.builder.Build(); err != nil {
  3609  		t.Fatal(err)
  3610  	}
  3611  	wantCommands := []string{"cp dd-in dd", "touch unrelated", "touch out"}
  3612  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  3613  		t.Fatal(diff)
  3614  	}
  3615  }
  3616  
  3617  func TestBuildTest_DyndepBuildDiscoverNewOutput(t *testing.T) {
  3618  	b := NewBuildTest(t)
  3619  	// Verify that a dyndep file can be built and loaded to discover
  3620  	// a new output of an edge.
  3621  	b.AssertParse(&b.state, "rule touch\n  command = touch $out $out.imp\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild out: touch in || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3622  	b.fs.Create("in", "")
  3623  	b.fs.Create("dd-in", "ninja_dyndep_version = 1\nbuild out | out.imp: dyndep\n")
  3624  	b.fs.Tick()
  3625  	b.fs.Create("out", "")
  3626  
  3627  	if _, err := b.builder.addTargetName("out"); err != nil {
  3628  		t.Fatal(err)
  3629  	}
  3630  
  3631  	if err := b.builder.Build(); err != nil {
  3632  		t.Fatal(err)
  3633  	}
  3634  	wantCommands := []string{"cp dd-in dd", "touch out out.imp"}
  3635  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  3636  		t.Fatal(diff)
  3637  	}
  3638  }
  3639  
  3640  func TestBuildTest_DyndepBuildDiscoverNewOutputWithMultipleRules1(t *testing.T) {
  3641  	b := NewBuildTest(t)
  3642  	// Verify that a dyndep file can be built and loaded to discover
  3643  	// a new output of an edge that is already the output of another edge.
  3644  	b.AssertParse(&b.state, "rule touch\n  command = touch $out $out.imp\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild out1 | out-twice.imp: touch in\nbuild out2: touch in || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3645  	b.fs.Create("in", "")
  3646  	b.fs.Create("dd-in", "ninja_dyndep_version = 1\nbuild out2 | out-twice.imp: dyndep\n")
  3647  	b.fs.Tick()
  3648  	b.fs.Create("out1", "")
  3649  	b.fs.Create("out2", "")
  3650  
  3651  	if _, err := b.builder.addTargetName("out1"); err != nil {
  3652  		t.Fatal(err)
  3653  	}
  3654  	if _, err := b.builder.addTargetName("out2"); err != nil {
  3655  		t.Fatal(err)
  3656  	}
  3657  
  3658  	if err := b.builder.Build(); err == nil {
  3659  		t.Fatal("expected false")
  3660  	} else if err.Error() != "multiple rules generate out-twice.imp" {
  3661  		t.Fatal(err)
  3662  	}
  3663  }
  3664  
  3665  func TestBuildTest_DyndepBuildDiscoverNewOutputWithMultipleRules2(t *testing.T) {
  3666  	b := NewBuildTest(t)
  3667  	// Verify that a dyndep file can be built and loaded to discover
  3668  	// a new output of an edge that is already the output of another
  3669  	// edge also discovered by dyndep.
  3670  	b.AssertParse(&b.state, "rule touch\n  command = touch $out $out.imp\nrule cp\n  command = cp $in $out\nbuild dd1: cp dd1-in\nbuild out1: touch || dd1\n  dyndep = dd1\nbuild dd2: cp dd2-in || dd1\nbuild out2: touch || dd2\n  dyndep = dd2\n", ParseManifestOpts{}) // make order predictable for test
  3671  	b.fs.Create("out1", "")
  3672  	b.fs.Create("out2", "")
  3673  	b.fs.Create("dd1-in", "ninja_dyndep_version = 1\nbuild out1 | out-twice.imp: dyndep\n")
  3674  	b.fs.Create("dd2-in", "")
  3675  	b.fs.Create("dd2", "ninja_dyndep_version = 1\nbuild out2 | out-twice.imp: dyndep\n")
  3676  	b.fs.Tick()
  3677  	b.fs.Create("out1", "")
  3678  	b.fs.Create("out2", "")
  3679  
  3680  	if _, err := b.builder.addTargetName("out1"); err != nil {
  3681  		t.Fatal(err)
  3682  	}
  3683  	if _, err := b.builder.addTargetName("out2"); err != nil {
  3684  		t.Fatal(err)
  3685  	}
  3686  
  3687  	if err := b.builder.Build(); err == nil {
  3688  		t.Fatal("expected false")
  3689  	} else if err.Error() != "multiple rules generate out-twice.imp" {
  3690  		t.Fatal(err)
  3691  	}
  3692  }
  3693  
  3694  func TestBuildTest_DyndepBuildDiscoverNewInput(t *testing.T) {
  3695  	b := NewBuildTest(t)
  3696  	// Verify that a dyndep file can be built and loaded to discover
  3697  	// a new input to an edge.
  3698  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild in: touch\nbuild out: touch || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3699  	b.fs.Create("dd-in", "ninja_dyndep_version = 1\nbuild out: dyndep | in\n")
  3700  	b.fs.Tick()
  3701  	b.fs.Create("out", "")
  3702  
  3703  	if _, err := b.builder.addTargetName("out"); err != nil {
  3704  		t.Fatal(err)
  3705  	}
  3706  
  3707  	if err := b.builder.Build(); err != nil {
  3708  		t.Fatal(err)
  3709  	}
  3710  	wantCommands := []string{"cp dd-in dd", "touch in", "touch out"}
  3711  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  3712  		t.Fatal(diff)
  3713  	}
  3714  }
  3715  
  3716  func TestBuildTest_DyndepBuildDiscoverNewInputWithValidation(t *testing.T) {
  3717  	b := NewBuildTest(t)
  3718  	// Verify that a dyndep file cannot contain the |@ validation
  3719  	// syntax.
  3720  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild out: touch || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3721  	b.fs.Create("dd-in", "ninja_dyndep_version = 1\nbuild out: dyndep |@ validation\n")
  3722  
  3723  	if _, err := b.builder.addTargetName("out"); err != nil {
  3724  		t.Fatal(err)
  3725  	}
  3726  
  3727  	err := b.builder.Build()
  3728  	if err == nil {
  3729  		t.Fatal("expected false")
  3730  	}
  3731  	errFirstLine := strings.SplitN(err.Error(), "\n", 2)[0]
  3732  	if "dd:2: expected newline, got '|@'" != errFirstLine {
  3733  		t.Fatal(errFirstLine)
  3734  	}
  3735  }
  3736  
  3737  func TestBuildTest_DyndepBuildDiscoverNewInputWithTransitiveValidation(t *testing.T) {
  3738  	b := NewBuildTest(t)
  3739  	// Verify that a dyndep file can be built and loaded to discover
  3740  	// a new input to an edge that has a validation edge.
  3741  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild in: touch |@ validation\nbuild validation: touch in out\nbuild out: touch || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3742  	b.fs.Create("dd-in", "ninja_dyndep_version = 1\nbuild out: dyndep | in\n")
  3743  	b.fs.Tick()
  3744  	b.fs.Create("out", "")
  3745  
  3746  	if _, err := b.builder.addTargetName("out"); err != nil {
  3747  		t.Fatal(err)
  3748  	}
  3749  
  3750  	if err := b.builder.Build(); err != nil {
  3751  		t.Fatal(err)
  3752  	}
  3753  	wantCommands := []string{"cp dd-in dd", "touch in", "touch out", "touch validation"}
  3754  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  3755  		t.Fatal(diff)
  3756  	}
  3757  }
  3758  
  3759  func TestBuildTest_DyndepBuildDiscoverImplicitConnection(t *testing.T) {
  3760  	b := NewBuildTest(t)
  3761  	// Verify that a dyndep file can be built and loaded to discover
  3762  	// that one edge has an implicit output that is also an implicit
  3763  	// input of another edge.
  3764  	b.AssertParse(&b.state, "rule touch\n  command = touch $out $out.imp\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild tmp: touch || dd\n  dyndep = dd\nbuild out: touch || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3765  	b.fs.Create("dd-in", "ninja_dyndep_version = 1\nbuild out | out.imp: dyndep | tmp.imp\nbuild tmp | tmp.imp: dyndep\n")
  3766  
  3767  	if _, err := b.builder.addTargetName("out"); err != nil {
  3768  		t.Fatal(err)
  3769  	}
  3770  	if err := b.builder.Build(); err != nil {
  3771  		t.Fatal(err)
  3772  	}
  3773  	wantCommands := []string{"cp dd-in dd", "touch tmp tmp.imp", "touch out out.imp"}
  3774  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  3775  		t.Fatal(diff)
  3776  	}
  3777  }
  3778  
  3779  func TestBuildTest_DyndepBuildDiscoverOutputAndDepfileInput(t *testing.T) {
  3780  	// WARNING: I (maruel) am not 100% sure about this test case.
  3781  	b := NewBuildTest(t)
  3782  	// Verify that a dyndep file can be built and loaded to discover
  3783  	// that one edge has an implicit output that is also reported by
  3784  	// a depfile as an input of another edge.
  3785  	b.AssertParse(&b.state, "rule touch\n  command = touch $out $out.imp\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild tmp: touch || dd\n  dyndep = dd\nbuild out: cp tmp\n  depfile = out.d\n", ParseManifestOpts{})
  3786  	b.fs.Create("out.d", "out: tmp.imp\n")
  3787  	b.fs.Create("dd-in", "ninja_dyndep_version = 1\nbuild tmp | tmp.imp: dyndep\n")
  3788  
  3789  	if _, err := b.builder.addTargetName("out"); err != nil {
  3790  		t.Fatal(err)
  3791  	}
  3792  
  3793  	// Loading the depfile gave tmp.imp a phony input edge.
  3794  	if b.GetNode("tmp.imp").InEdge.Rule != PhonyRule {
  3795  		t.Fatal("expected true")
  3796  	}
  3797  
  3798  	wantCreated := map[string]struct{}{
  3799  		"dd-in": {},
  3800  		"in1":   {},
  3801  		"in2":   {},
  3802  		"out.d": {},
  3803  	}
  3804  	if diff := cmp.Diff(wantCreated, b.fs.filesCreated); diff != "" {
  3805  		t.Fatal(diff)
  3806  	}
  3807  
  3808  	if err := b.builder.Build(); err != nil {
  3809  		t.Fatal(err)
  3810  	}
  3811  
  3812  	// Loading the dyndep file gave tmp.imp a real input edge.
  3813  	if b.GetNode("tmp.imp").InEdge.Rule == PhonyRule {
  3814  		t.Fatal("expected false")
  3815  	}
  3816  
  3817  	wantCommands := []string{"cp dd-in dd", "touch tmp tmp.imp", "cp tmp out"}
  3818  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  3819  		t.Fatal(diff)
  3820  	}
  3821  	wantCreated["dd"] = struct{}{}
  3822  	wantCreated["out"] = struct{}{}
  3823  	wantCreated["tmp"] = struct{}{}
  3824  	wantCreated["tmp.imp"] = struct{}{}
  3825  	if diff := cmp.Diff(wantCreated, b.fs.filesCreated); diff != "" {
  3826  		t.Fatal(diff)
  3827  	}
  3828  	if !b.builder.AlreadyUpToDate() {
  3829  		t.Fatal("expected true")
  3830  	}
  3831  }
  3832  
  3833  func TestBuildTest_DyndepBuildDiscoverNowWantEdge(t *testing.T) {
  3834  	b := NewBuildTest(t)
  3835  	// Verify that a dyndep file can be built and loaded to discover
  3836  	// that an edge is actually wanted due to a missing implicit output.
  3837  	b.AssertParse(&b.state, "rule touch\n  command = touch $out $out.imp\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild tmp: touch || dd\n  dyndep = dd\nbuild out: touch tmp || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3838  	b.fs.Create("tmp", "")
  3839  	b.fs.Create("out", "")
  3840  	b.fs.Create("dd-in", "ninja_dyndep_version = 1\nbuild out: dyndep\nbuild tmp | tmp.imp: dyndep\n")
  3841  
  3842  	if _, err := b.builder.addTargetName("out"); err != nil {
  3843  		t.Fatal(err)
  3844  	}
  3845  	if err := b.builder.Build(); err != nil {
  3846  		t.Fatal(err)
  3847  	}
  3848  	wantCommands := []string{"cp dd-in dd", "touch tmp tmp.imp", "touch out out.imp"}
  3849  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  3850  		t.Fatal(diff)
  3851  	}
  3852  }
  3853  
  3854  func TestBuildTest_DyndepBuildDiscoverNowWantEdgeAndDependent(t *testing.T) {
  3855  	t.Skip("TODO")
  3856  	b := NewBuildTest(t)
  3857  	// Verify that a dyndep file can be built and loaded to discover
  3858  	// that an edge and a dependent are actually wanted.
  3859  	b.AssertParse(&b.state, "rule touch\n  command = touch $out $out.imp\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild tmp: touch || dd\n  dyndep = dd\nbuild out: touch tmp\n", ParseManifestOpts{})
  3860  	b.fs.Create("tmp", "")
  3861  	b.fs.Create("out", "")
  3862  	b.fs.Create("dd-in", "ninja_dyndep_version = 1\nbuild tmp | tmp.imp: dyndep\n")
  3863  
  3864  	if _, err := b.builder.addTargetName("out"); err != nil {
  3865  		t.Fatal(err)
  3866  	}
  3867  
  3868  	// fmt.Printf("State:\n")
  3869  	// b.state.Dump()
  3870  	// fmt.Printf("Plan:\n")
  3871  	// b.builder.plan.Dump()
  3872  
  3873  	if err := b.builder.Build(); err != nil {
  3874  		t.Fatal(err)
  3875  	}
  3876  
  3877  	// fmt.Printf("After:\n")
  3878  	// fmt.Printf("State:\n")
  3879  	// b.state.Dump()
  3880  	// fmt.Printf("Plan:\n")
  3881  	// b.builder.plan.Dump()
  3882  
  3883  	wantCommands := []string{"cp dd-in dd", "touch tmp tmp.imp", "touch out out.imp"}
  3884  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  3885  		t.Fatal(diff)
  3886  	}
  3887  }
  3888  
  3889  func TestBuildTest_DyndepBuildDiscoverCircular(t *testing.T) {
  3890  	b := NewBuildTest(t)
  3891  	// Verify that a dyndep file can be built and loaded to discover
  3892  	// and reject a circular dependency.
  3893  	b.AssertParse(&b.state, "rule r\n  command = unused\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild out: r in || dd\n  depfile = out.d\n  dyndep = dd\nbuild in: r || dd\n  dyndep = dd\n", ParseManifestOpts{})
  3894  	b.fs.Create("out.d", "out: inimp\n")
  3895  	b.fs.Create("dd-in", "ninja_dyndep_version = 1\nbuild out | circ: dyndep\nbuild in: dyndep | circ\n")
  3896  	b.fs.Create("out", "")
  3897  
  3898  	if _, err := b.builder.addTargetName("out"); err != nil {
  3899  		t.Fatal(err)
  3900  	}
  3901  
  3902  	if err := b.builder.Build(); err == nil {
  3903  		t.Fatal("expected false")
  3904  	} else if err.Error() != "dependency cycle: circ -> in -> circ" && err.Error() != "dependency cycle: in -> circ -> in" {
  3905  		// Depending on how the pointers in ready work out, we could have
  3906  		// discovered the cycle from either starting point.
  3907  		t.Fatal(err)
  3908  	}
  3909  }
  3910  
  3911  func TestBuildWithLogTest_DyndepBuildDiscoverRestat(t *testing.T) {
  3912  	b := NewBuildWithLogTest(t)
  3913  	// Verify that a dyndep file can be built and loaded to discover
  3914  	// that an edge has a restat binding.
  3915  	b.AssertParse(&b.state, "rule true\n  command = true\nrule cp\n  command = cp $in $out\nbuild dd: cp dd-in\nbuild out1: true in || dd\n  dyndep = dd\nbuild out2: cat out1\n", ParseManifestOpts{})
  3916  
  3917  	b.fs.Create("out1", "")
  3918  	b.fs.Create("out2", "")
  3919  	b.fs.Create("dd-in", "ninja_dyndep_version = 1\nbuild out1: dyndep\n  restat = 1\n")
  3920  	b.fs.Tick()
  3921  	b.fs.Create("in", "")
  3922  
  3923  	// Do a pre-build so that there's commands in the log for the outputs,
  3924  	// otherwise, the lack of an entry in the build log will cause "out2" to
  3925  	// rebuild regardless of restat.
  3926  	if _, err := b.builder.addTargetName("out2"); err != nil {
  3927  		t.Fatal(err)
  3928  	}
  3929  	if err := b.builder.Build(); err != nil {
  3930  		t.Fatal(err)
  3931  	}
  3932  	wantCommands := []string{"cp dd-in dd", "true", "cat out1 > out2"}
  3933  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  3934  		t.Fatal(diff)
  3935  	}
  3936  
  3937  	b.commandRunner.commandsRan = nil
  3938  	b.state.Reset()
  3939  	b.fs.Tick()
  3940  	b.fs.Create("in", "")
  3941  
  3942  	// We touched "in", so we should build "out1".  But because "true" does not
  3943  	// touch "out1", we should cancel the build of "out2".
  3944  	if _, err := b.builder.addTargetName("out2"); err != nil {
  3945  		t.Fatal(err)
  3946  	}
  3947  	if err := b.builder.Build(); err != nil {
  3948  		t.Fatal(err)
  3949  	}
  3950  	wantCommands = []string{"true"}
  3951  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  3952  		t.Fatal(diff)
  3953  	}
  3954  }
  3955  
  3956  func TestBuildTest_DyndepBuildDiscoverScheduledEdge(t *testing.T) {
  3957  	b := NewBuildTest(t)
  3958  	// Verify that a dyndep file can be built and loaded to discover a
  3959  	// new input that itself is an output from an edge that has already
  3960  	// been scheduled but not finished.  We should not re-schedule it.
  3961  	b.AssertParse(&b.state, "rule touch\n  command = touch $out $out.imp\nrule cp\n  command = cp $in $out\nbuild out1 | out1.imp: touch\nbuild zdd: cp zdd-in\n  verify_active_edge = out1\nbuild out2: cp out1 || zdd\n  dyndep = zdd\n", ParseManifestOpts{}) // verify out1 is active when zdd is finished
  3962  	b.fs.Create("zdd-in", "ninja_dyndep_version = 1\nbuild out2: dyndep | out1.imp\n")
  3963  
  3964  	// Enable concurrent builds so that we can load the dyndep file
  3965  	// while another edge is still active.
  3966  	b.commandRunner.maxActiveEdges = 2
  3967  
  3968  	// During the build "out1" and "zdd" should be built concurrently.
  3969  	// The fake command runner will finish these in reverse order
  3970  	// of the names of the first outputs, so "zdd" will finish first
  3971  	// and we will load the dyndep file while the edge for "out1" is
  3972  	// still active.  This will add a new dependency on "out1.imp",
  3973  	// also produced by the active edge.  The builder should not
  3974  	// re-schedule the already-active edge.
  3975  
  3976  	if _, err := b.builder.addTargetName("out1"); err != nil {
  3977  		t.Fatal(err)
  3978  	}
  3979  	if _, err := b.builder.addTargetName("out2"); err != nil {
  3980  		t.Fatal(err)
  3981  	}
  3982  	if err := b.builder.Build(); err != nil {
  3983  		t.Fatal(err)
  3984  	}
  3985  	if 3 != len(b.commandRunner.commandsRan) {
  3986  		t.Fatal("expected equal")
  3987  	}
  3988  	// Depending on how the pointers in ready work out, the first
  3989  	// two commands may have run in either order.
  3990  	if !(b.commandRunner.commandsRan[0] == "touch out1 out1.imp" && b.commandRunner.commandsRan[1] == "cp zdd-in zdd") || (b.commandRunner.commandsRan[1] == "touch out1 out1.imp" && b.commandRunner.commandsRan[0] == "cp zdd-in zdd") {
  3991  		t.Fatal("expected true")
  3992  	}
  3993  	if "cp out1 out2" != b.commandRunner.commandsRan[2] {
  3994  		t.Fatal("expected equal")
  3995  	}
  3996  }
  3997  
  3998  func TestBuildTest_DyndepTwoLevelDirect(t *testing.T) {
  3999  	b := NewBuildTest(t)
  4000  	// Verify that a clean dyndep file can depend on a dirty dyndep file
  4001  	// and be loaded properly after the dirty one is built and loaded.
  4002  	b.AssertParse(&b.state, "rule touch\n  command = touch $out $out.imp\nrule cp\n  command = cp $in $out\nbuild dd1: cp dd1-in\nbuild out1 | out1.imp: touch || dd1\n  dyndep = dd1\nbuild dd2: cp dd2-in || dd1\nbuild out2: touch || dd2\n  dyndep = dd2\n", ParseManifestOpts{}) // direct order-only dep on dd1
  4003  	b.fs.Create("out1.imp", "")
  4004  	b.fs.Create("out2", "")
  4005  	b.fs.Create("out2.imp", "")
  4006  	b.fs.Create("dd1-in", "ninja_dyndep_version = 1\nbuild out1: dyndep\n")
  4007  	b.fs.Create("dd2-in", "")
  4008  	b.fs.Create("dd2", "ninja_dyndep_version = 1\nbuild out2 | out2.imp: dyndep | out1.imp\n")
  4009  
  4010  	// During the build dd1 should be built and loaded.  The RecomputeDirty
  4011  	// called as a result of loading dd1 should not cause dd2 to be loaded
  4012  	// because the builder will never get a chance to update the build plan
  4013  	// to account for dd2.  Instead dd2 should only be later loaded once the
  4014  	// builder recognizes that it is now ready (as its order-only dependency
  4015  	// on dd1 has been satisfied).  This test case verifies that each dyndep
  4016  	// file is loaded to update the build graph independently.
  4017  
  4018  	if _, err := b.builder.addTargetName("out2"); err != nil {
  4019  		t.Fatal(err)
  4020  	}
  4021  	if err := b.builder.Build(); err != nil {
  4022  		t.Fatal(err)
  4023  	}
  4024  	wantCommands := []string{"cp dd1-in dd1", "touch out1 out1.imp", "touch out2 out2.imp"}
  4025  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  4026  		t.Fatal(diff)
  4027  	}
  4028  }
  4029  
  4030  func TestBuildTest_DyndepTwoLevelIndirect(t *testing.T) {
  4031  	b := NewBuildTest(t)
  4032  	// Verify that dyndep files can add to an edge new implicit inputs that
  4033  	// correspond to implicit outputs added to other edges by other dyndep
  4034  	// files on which they (order-only) depend.
  4035  	b.AssertParse(&b.state, "rule touch\n  command = touch $out $out.imp\nrule cp\n  command = cp $in $out\nbuild dd1: cp dd1-in\nbuild out1: touch || dd1\n  dyndep = dd1\nbuild dd2: cp dd2-in || out1\nbuild out2: touch || dd2\n  dyndep = dd2\n", ParseManifestOpts{}) // indirect order-only dep on dd1
  4036  	b.fs.Create("out1.imp", "")
  4037  	b.fs.Create("out2", "")
  4038  	b.fs.Create("out2.imp", "")
  4039  	b.fs.Create("dd1-in", "ninja_dyndep_version = 1\nbuild out1 | out1.imp: dyndep\n")
  4040  	b.fs.Create("dd2-in", "")
  4041  	b.fs.Create("dd2", "ninja_dyndep_version = 1\nbuild out2 | out2.imp: dyndep | out1.imp\n")
  4042  
  4043  	// During the build dd1 should be built and loaded.  Then dd2 should
  4044  	// be built and loaded.  Loading dd2 should cause the builder to
  4045  	// recognize that out2 needs to be built even though it was originally
  4046  	// clean without dyndep info.
  4047  
  4048  	if _, err := b.builder.addTargetName("out2"); err != nil {
  4049  		t.Fatal(err)
  4050  	}
  4051  	if err := b.builder.Build(); err != nil {
  4052  		t.Fatal(err)
  4053  	}
  4054  	wantCommands := []string{"cp dd1-in dd1", "touch out1 out1.imp", "touch out2 out2.imp"}
  4055  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  4056  		t.Fatal(diff)
  4057  	}
  4058  }
  4059  
  4060  func TestBuildTest_DyndepTwoLevelDiscoveredReady(t *testing.T) {
  4061  	b := NewBuildTest(t)
  4062  	// Verify that a dyndep file can discover a new input whose
  4063  	// edge also has a dyndep file that is ready to load immediately.
  4064  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\nrule cp\n  command = cp $in $out\nbuild dd0: cp dd0-in\nbuild dd1: cp dd1-in\nbuild in: touch\nbuild tmp: touch || dd0\n  dyndep = dd0\nbuild out: touch || dd1\n  dyndep = dd1\n", ParseManifestOpts{})
  4065  	b.fs.Create("dd1-in", "ninja_dyndep_version = 1\nbuild out: dyndep | tmp\n")
  4066  	b.fs.Create("dd0-in", "")
  4067  	b.fs.Create("dd0", "ninja_dyndep_version = 1\nbuild tmp: dyndep | in\n")
  4068  	b.fs.Tick()
  4069  	b.fs.Create("out", "")
  4070  
  4071  	if _, err := b.builder.addTargetName("out"); err != nil {
  4072  		t.Fatal(err)
  4073  	}
  4074  
  4075  	if err := b.builder.Build(); err != nil {
  4076  		t.Fatal(err)
  4077  	}
  4078  	wantCommands := []string{"cp dd1-in dd1", "touch in", "touch tmp", "touch out"}
  4079  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  4080  		t.Fatal(diff)
  4081  	}
  4082  }
  4083  
  4084  func TestBuildTest_DyndepTwoLevelDiscoveredDirty(t *testing.T) {
  4085  	b := NewBuildTest(t)
  4086  	// Verify that a dyndep file can discover a new input whose
  4087  	// edge also has a dyndep file that needs to be built.
  4088  	b.AssertParse(&b.state, "rule touch\n  command = touch $out\nrule cp\n  command = cp $in $out\nbuild dd0: cp dd0-in\nbuild dd1: cp dd1-in\nbuild in: touch\nbuild tmp: touch || dd0\n  dyndep = dd0\nbuild out: touch || dd1\n  dyndep = dd1\n", ParseManifestOpts{})
  4089  	b.fs.Create("dd1-in", "ninja_dyndep_version = 1\nbuild out: dyndep | tmp\n")
  4090  	b.fs.Create("dd0-in", "ninja_dyndep_version = 1\nbuild tmp: dyndep | in\n")
  4091  	b.fs.Tick()
  4092  	b.fs.Create("out", "")
  4093  
  4094  	if _, err := b.builder.addTargetName("out"); err != nil {
  4095  		t.Fatal(err)
  4096  	}
  4097  
  4098  	if err := b.builder.Build(); err != nil {
  4099  		t.Fatal(err)
  4100  	}
  4101  	wantCommands := []string{"cp dd1-in dd1", "cp dd0-in dd0", "touch in", "touch tmp", "touch out"}
  4102  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  4103  		t.Fatal(diff)
  4104  	}
  4105  }
  4106  
  4107  func TestBuildTest_Validation(t *testing.T) {
  4108  	b := NewBuildTest(t)
  4109  	b.AssertParse(&b.state, "build out: cat in |@ validate\nbuild validate: cat in2\n", ParseManifestOpts{})
  4110  
  4111  	b.fs.Create("in", "")
  4112  	b.fs.Create("in2", "")
  4113  
  4114  	if _, err := b.builder.addTargetName("out"); err != nil {
  4115  		t.Fatal(err)
  4116  	}
  4117  
  4118  	if err := b.builder.Build(); err != nil {
  4119  		t.Fatal(err)
  4120  	}
  4121  
  4122  	if len(b.commandRunner.commandsRan) != 2 {
  4123  		t.Fatal("size")
  4124  	}
  4125  
  4126  	// Test touching "in" only rebuilds "out" ("validate" doesn't depend on
  4127  	// "out").
  4128  	b.fs.Tick()
  4129  	b.fs.Create("in", "")
  4130  
  4131  	b.commandRunner.commandsRan = nil
  4132  	b.state.Reset()
  4133  	if _, err := b.builder.addTargetName("out"); err != nil {
  4134  		t.Fatal(err)
  4135  	}
  4136  
  4137  	if err := b.builder.Build(); err != nil {
  4138  		t.Fatal(err)
  4139  	}
  4140  
  4141  	wantCommands := []string{"cat in > out"}
  4142  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  4143  		t.Fatal(diff)
  4144  	}
  4145  
  4146  	// Test touching "in2" only rebuilds "validate" ("out" doesn't depend on
  4147  	// "validate").
  4148  	b.fs.Tick()
  4149  	b.fs.Create("in2", "")
  4150  
  4151  	b.commandRunner.commandsRan = nil
  4152  	b.state.Reset()
  4153  	if _, err := b.builder.addTargetName("out"); err != nil {
  4154  		t.Fatal(err)
  4155  	}
  4156  
  4157  	if err := b.builder.Build(); err != nil {
  4158  		t.Fatal(err)
  4159  	}
  4160  
  4161  	wantCommands = []string{"cat in2 > validate"}
  4162  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  4163  		t.Fatal(diff)
  4164  	}
  4165  }
  4166  
  4167  func TestBuildTest_ValidationDependsOnOutput(t *testing.T) {
  4168  	b := NewBuildTest(t)
  4169  	b.AssertParse(&b.state, "build out: cat in |@ validate\nbuild validate: cat in2 | out\n", ParseManifestOpts{})
  4170  
  4171  	b.fs.Create("in", "")
  4172  	b.fs.Create("in2", "")
  4173  	if _, err := b.builder.addTargetName("out"); err != nil {
  4174  		t.Fatal(err)
  4175  	}
  4176  
  4177  	if err := b.builder.Build(); err != nil {
  4178  		t.Fatal(err)
  4179  	}
  4180  
  4181  	if len(b.commandRunner.commandsRan) != 2 {
  4182  		t.Fatal(b.commandRunner.commandsRan)
  4183  	}
  4184  
  4185  	// Test touching "in" rebuilds "out" and "validate".
  4186  	b.fs.Tick()
  4187  	b.fs.Create("in", "")
  4188  
  4189  	b.commandRunner.commandsRan = nil
  4190  	b.state.Reset()
  4191  	if _, err := b.builder.addTargetName("out"); err != nil {
  4192  		t.Fatal(err)
  4193  	}
  4194  
  4195  	if err := b.builder.Build(); err != nil {
  4196  		t.Fatal(err)
  4197  	}
  4198  
  4199  	if len(b.commandRunner.commandsRan) != 2 {
  4200  		t.Fatal(b.commandRunner.commandsRan)
  4201  	}
  4202  
  4203  	// Test touching "in2" only rebuilds "validate" ("out" doesn't depend on
  4204  	// "validate").
  4205  	b.fs.Tick()
  4206  	b.fs.Create("in2", "")
  4207  
  4208  	b.commandRunner.commandsRan = nil
  4209  	b.state.Reset()
  4210  	if _, err := b.builder.addTargetName("out"); err != nil {
  4211  		t.Fatal(err)
  4212  	}
  4213  
  4214  	if err := b.builder.Build(); err != nil {
  4215  		t.Fatal(err)
  4216  	}
  4217  
  4218  	wantCommands := []string{"cat in2 > validate"}
  4219  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  4220  		t.Fatal(diff)
  4221  	}
  4222  }
  4223  
  4224  func TestBuildWithDepsLogTest_ValidationThroughDepfile(t *testing.T) {
  4225  	b := NewBuildTest(t)
  4226  	manifest := "build out: cat in |@ validate\nbuild validate: cat in2 | out\nbuild out2: cat in3\n  deps = gcc\n  depfile = out2.d\n"
  4227  
  4228  	{
  4229  		b.fs.Create("in", "")
  4230  		b.fs.Create("in2", "")
  4231  		b.fs.Create("in3", "")
  4232  		b.fs.Create("out2.d", "out: out")
  4233  
  4234  		state := NewState()
  4235  		b.AddCatRule(&state)
  4236  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  4237  
  4238  		depsLog := DepsLog{}
  4239  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  4240  			t.Fatal(err)
  4241  		}
  4242  		defer depsLog.Close()
  4243  
  4244  		builder := NewBuilder(&state, &b.config, nil, &depsLog, &b.fs, b.status, 0)
  4245  		builder.commandRunner = &b.commandRunner
  4246  
  4247  		if _, err := builder.addTargetName("out2"); err != nil {
  4248  			t.Fatal(err)
  4249  		}
  4250  
  4251  		if err := builder.Build(); err != nil {
  4252  			t.Fatal(err)
  4253  		}
  4254  
  4255  		// On the first build, only the out2 command is run.
  4256  		wantCommands := []string{"cat in3 > out2"}
  4257  		if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  4258  			t.Fatal(diff)
  4259  		}
  4260  
  4261  		// The deps file should have been removed.
  4262  		if mtime, err := b.fs.Stat("out2.d"); mtime != 0 || err != nil {
  4263  			t.Fatal(mtime, err)
  4264  		}
  4265  
  4266  		depsLog.Close()
  4267  	}
  4268  
  4269  	b.fs.Tick()
  4270  	b.commandRunner.commandsRan = nil
  4271  
  4272  	{
  4273  		b.fs.Create("in2", "")
  4274  		b.fs.Create("in3", "")
  4275  
  4276  		state := NewState()
  4277  		b.AddCatRule(&state)
  4278  		b.AssertParse(&state, manifest, ParseManifestOpts{})
  4279  
  4280  		depsLog := DepsLog{}
  4281  		if s, err := depsLog.Load("ninja_deps", &state); s != LoadSuccess || err != nil {
  4282  			t.Fatal(s, err)
  4283  		}
  4284  		if err := depsLog.OpenForWrite("ninja_deps"); err != nil {
  4285  			t.Fatal(err)
  4286  		}
  4287  
  4288  		builder := NewBuilder(&state, &b.config, nil, &depsLog, &b.fs, b.status, 0)
  4289  		builder.commandRunner = &b.commandRunner
  4290  
  4291  		if _, err := builder.addTargetName("out2"); err != nil {
  4292  			t.Fatal(err)
  4293  		}
  4294  
  4295  		if err := builder.Build(); err != nil {
  4296  			t.Fatal(err)
  4297  		}
  4298  
  4299  		// The out and validate actions should have been run as well as out2.
  4300  		if len(b.commandRunner.commandsRan) != 3 {
  4301  			t.Fatal(b.commandRunner.commandsRan)
  4302  		}
  4303  		// out has to run first, as both out2 and validate depend on it.
  4304  		if b.commandRunner.commandsRan[0] != "cat in > out" {
  4305  			t.Fatal(b.commandRunner.commandsRan)
  4306  		}
  4307  
  4308  		depsLog.Close()
  4309  	}
  4310  }
  4311  
  4312  func TestBuildTest_ValidationCircular(t *testing.T) {
  4313  	b := NewBuildTest(t)
  4314  	b.AssertParse(&b.state, "build out: cat in |@ out2\nbuild out2: cat in2 |@ out\n", ParseManifestOpts{})
  4315  	b.fs.Create("in", "")
  4316  	b.fs.Create("in2", "")
  4317  
  4318  	if _, err := b.builder.addTargetName("out"); err != nil {
  4319  		t.Fatal(err)
  4320  	}
  4321  
  4322  	if err := b.builder.Build(); err != nil {
  4323  		t.Fatal(err)
  4324  	}
  4325  
  4326  	if len(b.commandRunner.commandsRan) != 2 {
  4327  		t.Fatal(b.commandRunner.commandsRan)
  4328  	}
  4329  
  4330  	// Test touching "in" rebuilds "out".
  4331  	b.fs.Tick()
  4332  	b.fs.Create("in", "")
  4333  
  4334  	b.commandRunner.commandsRan = nil
  4335  	b.state.Reset()
  4336  	if _, err := b.builder.addTargetName("out"); err != nil {
  4337  		t.Fatal(err)
  4338  	}
  4339  
  4340  	if err := b.builder.Build(); err != nil {
  4341  		t.Fatal(err)
  4342  	}
  4343  
  4344  	wantCommands := []string{"cat in > out"}
  4345  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  4346  		t.Fatal(diff)
  4347  	}
  4348  
  4349  	// Test touching "in2" rebuilds "out2".
  4350  	b.fs.Tick()
  4351  	b.fs.Create("in2", "")
  4352  
  4353  	b.commandRunner.commandsRan = nil
  4354  	b.state.Reset()
  4355  	if _, err := b.builder.addTargetName("out"); err != nil {
  4356  		t.Fatal(err)
  4357  	}
  4358  
  4359  	if err := b.builder.Build(); err != nil {
  4360  		t.Fatal(err)
  4361  	}
  4362  
  4363  	wantCommands = []string{"cat in2 > out2"}
  4364  	if diff := cmp.Diff(wantCommands, b.commandRunner.commandsRan); diff != "" {
  4365  		t.Fatal(diff)
  4366  	}
  4367  }
  4368  
  4369  func TestBuildTest_ValidationWithCircularDependency(t *testing.T) {
  4370  	b := NewBuildTest(t)
  4371  	b.AssertParse(&b.state, "build out: cat in |@ validate\nbuild validate: cat validate_in | out\nbuild validate_in: cat validate\n", ParseManifestOpts{})
  4372  
  4373  	b.fs.Create("in", "")
  4374  
  4375  	if _, err := b.builder.addTargetName("out"); err == nil {
  4376  		t.Fatal("expected failure")
  4377  	} else if err.Error() != "dependency cycle: validate -> validate_in -> validate" {
  4378  		t.Fatal(err)
  4379  	}
  4380  }