Ninja
graph_test.cc
Go to the documentation of this file.
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "graph.h"
16 
17 #include "test.h"
18 
20  GraphTest() : scan_(&state_, NULL, NULL, &fs_) {}
21 
24 };
25 
26 TEST_F(GraphTest, MissingImplicit) {
27  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
28 "build out: cat in | implicit\n"));
29  fs_.Create("in", "");
30  fs_.Create("out", "");
31 
32  Edge* edge = GetNode("out")->in_edge();
33  string err;
34  EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
35  ASSERT_EQ("", err);
36 
37  // A missing implicit dep *should* make the output dirty.
38  // (In fact, a build will fail.)
39  // This is a change from prior semantics of ninja.
40  EXPECT_TRUE(GetNode("out")->dirty());
41 }
42 
43 TEST_F(GraphTest, ModifiedImplicit) {
44  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
45 "build out: cat in | implicit\n"));
46  fs_.Create("in", "");
47  fs_.Create("out", "");
48  fs_.Tick();
49  fs_.Create("implicit", "");
50 
51  Edge* edge = GetNode("out")->in_edge();
52  string err;
53  EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
54  ASSERT_EQ("", err);
55 
56  // A modified implicit dep should make the output dirty.
57  EXPECT_TRUE(GetNode("out")->dirty());
58 }
59 
60 TEST_F(GraphTest, FunkyMakefilePath) {
61  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
62 "rule catdep\n"
63 " depfile = $out.d\n"
64 " command = cat $in > $out\n"
65 "build out.o: catdep foo.cc\n"));
66  fs_.Create("foo.cc", "");
67  fs_.Create("out.o.d", "out.o: ./foo/../implicit.h\n");
68  fs_.Create("out.o", "");
69  fs_.Tick();
70  fs_.Create("implicit.h", "");
71 
72  Edge* edge = GetNode("out.o")->in_edge();
73  string err;
74  EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
75  ASSERT_EQ("", err);
76 
77  // implicit.h has changed, though our depfile refers to it with a
78  // non-canonical path; we should still find it.
79  EXPECT_TRUE(GetNode("out.o")->dirty());
80 }
81 
82 TEST_F(GraphTest, ExplicitImplicit) {
83  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
84 "rule catdep\n"
85 " depfile = $out.d\n"
86 " command = cat $in > $out\n"
87 "build implicit.h: cat data\n"
88 "build out.o: catdep foo.cc || implicit.h\n"));
89  fs_.Create("implicit.h", "");
90  fs_.Create("foo.cc", "");
91  fs_.Create("out.o.d", "out.o: implicit.h\n");
92  fs_.Create("out.o", "");
93  fs_.Tick();
94  fs_.Create("data", "");
95 
96  Edge* edge = GetNode("out.o")->in_edge();
97  string err;
98  EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
99  ASSERT_EQ("", err);
100 
101  // We have both an implicit and an explicit dep on implicit.h.
102  // The implicit dep should "win" (in the sense that it should cause
103  // the output to be dirty).
104  EXPECT_TRUE(GetNode("out.o")->dirty());
105 }
106 
107 TEST_F(GraphTest, PathWithCurrentDirectory) {
108  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
109 "rule catdep\n"
110 " depfile = $out.d\n"
111 " command = cat $in > $out\n"
112 "build ./out.o: catdep ./foo.cc\n"));
113  fs_.Create("foo.cc", "");
114  fs_.Create("out.o.d", "out.o: foo.cc\n");
115  fs_.Create("out.o", "");
116 
117  Edge* edge = GetNode("out.o")->in_edge();
118  string err;
119  EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
120  ASSERT_EQ("", err);
121 
122  EXPECT_FALSE(GetNode("out.o")->dirty());
123 }
124 
125 TEST_F(GraphTest, RootNodes) {
126  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
127 "build out1: cat in1\n"
128 "build mid1: cat in1\n"
129 "build out2: cat mid1\n"
130 "build out3 out4: cat mid1\n"));
131 
132  string err;
133  vector<Node*> root_nodes = state_.RootNodes(&err);
134  EXPECT_EQ(4u, root_nodes.size());
135  for (size_t i = 0; i < root_nodes.size(); ++i) {
136  string name = root_nodes[i]->path();
137  EXPECT_EQ("out", name.substr(0, 3));
138  }
139 }
140 
141 TEST_F(GraphTest, VarInOutQuoteSpaces) {
142  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
143 "build a$ b: cat nospace with$ space nospace2\n"));
144 
145  Edge* edge = GetNode("a b")->in_edge();
146  EXPECT_EQ("cat nospace \"with space\" nospace2 > \"a b\"",
147  edge->EvaluateCommand());
148 }
149 
150 // Regression test for https://github.com/martine/ninja/issues/380
151 TEST_F(GraphTest, DepfileWithCanonicalizablePath) {
152  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
153 "rule catdep\n"
154 " depfile = $out.d\n"
155 " command = cat $in > $out\n"
156 "build ./out.o: catdep ./foo.cc\n"));
157  fs_.Create("foo.cc", "");
158  fs_.Create("out.o.d", "out.o: bar/../foo.cc\n");
159  fs_.Create("out.o", "");
160 
161  Edge* edge = GetNode("out.o")->in_edge();
162  string err;
163  EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
164  ASSERT_EQ("", err);
165 
166  EXPECT_FALSE(GetNode("out.o")->dirty());
167 }
168 
169 // Regression test for https://github.com/martine/ninja/issues/404
170 TEST_F(GraphTest, DepfileRemoved) {
171  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
172 "rule catdep\n"
173 " depfile = $out.d\n"
174 " command = cat $in > $out\n"
175 "build ./out.o: catdep ./foo.cc\n"));
176  fs_.Create("foo.h", "");
177  fs_.Create("foo.cc", "");
178  fs_.Tick();
179  fs_.Create("out.o.d", "out.o: foo.h\n");
180  fs_.Create("out.o", "");
181 
182  Edge* edge = GetNode("out.o")->in_edge();
183  string err;
184  EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
185  ASSERT_EQ("", err);
186  EXPECT_FALSE(GetNode("out.o")->dirty());
187 
188  state_.Reset();
189  fs_.RemoveFile("out.o.d");
190  EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
191  ASSERT_EQ("", err);
192  EXPECT_TRUE(GetNode("out.o")->dirty());
193 }
194 
195 // Check that rule-level variables are in scope for eval.
196 TEST_F(GraphTest, RuleVariablesInScope) {
197  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
198 "rule r\n"
199 " depfile = x\n"
200 " command = depfile is $depfile\n"
201 "build out: r in\n"));
202  Edge* edge = GetNode("out")->in_edge();
203  EXPECT_EQ("depfile is x", edge->EvaluateCommand());
204 }
205 
206 // Check that build statements can override rule builtins like depfile.
207 TEST_F(GraphTest, DepfileOverride) {
208  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
209 "rule r\n"
210 " depfile = x\n"
211 " command = unused\n"
212 "build out: r in\n"
213 " depfile = y\n"));
214  Edge* edge = GetNode("out")->in_edge();
215  EXPECT_EQ("y", edge->GetBinding("depfile"));
216 }
217 
218 // Check that overridden values show up in expansion of rule-level bindings.
219 TEST_F(GraphTest, DepfileOverrideParent) {
220  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
221 "rule r\n"
222 " depfile = x\n"
223 " command = depfile is $depfile\n"
224 "build out: r in\n"
225 " depfile = y\n"));
226  Edge* edge = GetNode("out")->in_edge();
227  EXPECT_EQ("depfile is y", edge->GetBinding("command"));
228 }
An implementation of DiskInterface that uses an in-memory representation of disk state.
Definition: test.h:49
void AssertParse(State *state, const char *input)
Definition: test.cc:90
An edge in the dependency graph; links between Nodes using Rules.
Definition: graph.h:137
string EvaluateCommand(bool incl_rsp_file=false)
Expand all variables in a command and return it as a string.
Definition: graph.cc:274
A base test fixture that includes a State object with a builtin "cat" rule.
Definition: test.h:30
VirtualFileSystem fs_
Definition: graph_test.cc:22
DependencyScan scan_
Definition: graph_test.cc:23
string GetBinding(const string &key)
Definition: graph.cc:284
DependencyScan manages the process of scanning the files in a graph and updating the dirty/outputs_re...
Definition: graph.h:230
TEST_F(GraphTest, MissingImplicit)
Definition: graph_test.cc:26