rearrange handling of builtin bindings to make rules simpler
[platform/upstream/ninja.git] / src / graph_test.cc
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
19 struct GraphTest : public StateTestWithBuiltinRules {
20   GraphTest() : scan_(&state_, NULL, &fs_) {}
21
22   VirtualFileSystem fs_;
23   DependencyScan scan_;
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", 1, "");
30   fs_.Create("out", 1, "");
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", 1, "");
47   fs_.Create("out", 1, "");
48   fs_.Create("implicit", 2, "");
49
50   Edge* edge = GetNode("out")->in_edge();
51   string err;
52   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
53   ASSERT_EQ("", err);
54
55   // A modified implicit dep should make the output dirty.
56   EXPECT_TRUE(GetNode("out")->dirty());
57 }
58
59 TEST_F(GraphTest, FunkyMakefilePath) {
60   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
61 "rule catdep\n"
62 "  depfile = $out.d\n"
63 "  command = cat $in > $out\n"
64 "build out.o: catdep foo.cc\n"));
65   fs_.Create("implicit.h", 2, "");
66   fs_.Create("foo.cc", 1, "");
67   fs_.Create("out.o.d", 1, "out.o: ./foo/../implicit.h\n");
68   fs_.Create("out.o", 1, "");
69
70   Edge* edge = GetNode("out.o")->in_edge();
71   string err;
72   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
73   ASSERT_EQ("", err);
74
75   // implicit.h has changed, though our depfile refers to it with a
76   // non-canonical path; we should still find it.
77   EXPECT_TRUE(GetNode("out.o")->dirty());
78 }
79
80 TEST_F(GraphTest, ExplicitImplicit) {
81   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
82 "rule catdep\n"
83 "  depfile = $out.d\n"
84 "  command = cat $in > $out\n"
85 "build implicit.h: cat data\n"
86 "build out.o: catdep foo.cc || implicit.h\n"));
87   fs_.Create("data", 2, "");
88   fs_.Create("implicit.h", 1, "");
89   fs_.Create("foo.cc", 1, "");
90   fs_.Create("out.o.d", 1, "out.o: implicit.h\n");
91   fs_.Create("out.o", 1, "");
92
93   Edge* edge = GetNode("out.o")->in_edge();
94   string err;
95   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
96   ASSERT_EQ("", err);
97
98   // We have both an implicit and an explicit dep on implicit.h.
99   // The implicit dep should "win" (in the sense that it should cause
100   // the output to be dirty).
101   EXPECT_TRUE(GetNode("out.o")->dirty());
102 }
103
104 TEST_F(GraphTest, PathWithCurrentDirectory) {
105   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
106 "rule catdep\n"
107 "  depfile = $out.d\n"
108 "  command = cat $in > $out\n"
109 "build ./out.o: catdep ./foo.cc\n"));
110   fs_.Create("foo.cc", 1, "");
111   fs_.Create("out.o.d", 1, "out.o: foo.cc\n");
112   fs_.Create("out.o", 1, "");
113
114   Edge* edge = GetNode("out.o")->in_edge();
115   string err;
116   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
117   ASSERT_EQ("", err);
118
119   EXPECT_FALSE(GetNode("out.o")->dirty());
120 }
121
122 TEST_F(GraphTest, RootNodes) {
123   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
124 "build out1: cat in1\n"
125 "build mid1: cat in1\n"
126 "build out2: cat mid1\n"
127 "build out3 out4: cat mid1\n"));
128
129   string err;
130   vector<Node*> root_nodes = state_.RootNodes(&err);
131   EXPECT_EQ(4u, root_nodes.size());
132   for (size_t i = 0; i < root_nodes.size(); ++i) {
133     string name = root_nodes[i]->path();
134     EXPECT_EQ("out", name.substr(0, 3));
135   }
136 }
137
138 TEST_F(GraphTest, VarInOutQuoteSpaces) {
139   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
140 "build a$ b: cat nospace with$ space nospace2\n"));
141
142   Edge* edge = GetNode("a b")->in_edge();
143   EXPECT_EQ("cat nospace \"with space\" nospace2 > \"a b\"",
144       edge->EvaluateCommand());
145 }
146
147 // Regression test for https://github.com/martine/ninja/issues/380
148 TEST_F(GraphTest, DepfileWithCanonicalizablePath) {
149   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
150 "rule catdep\n"
151 "  depfile = $out.d\n"
152 "  command = cat $in > $out\n"
153 "build ./out.o: catdep ./foo.cc\n"));
154   fs_.Create("foo.cc", 1, "");
155   fs_.Create("out.o.d", 1, "out.o: bar/../foo.cc\n");
156   fs_.Create("out.o", 1, "");
157
158   Edge* edge = GetNode("out.o")->in_edge();
159   string err;
160   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
161   ASSERT_EQ("", err);
162
163   EXPECT_FALSE(GetNode("out.o")->dirty());
164 }
165
166 // Regression test for https://github.com/martine/ninja/issues/404
167 TEST_F(GraphTest, DepfileRemoved) {
168   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
169 "rule catdep\n"
170 "  depfile = $out.d\n"
171 "  command = cat $in > $out\n"
172 "build ./out.o: catdep ./foo.cc\n"));
173   fs_.Create("foo.h", 1, "");
174   fs_.Create("foo.cc", 1, "");
175   fs_.Create("out.o.d", 2, "out.o: foo.h\n");
176   fs_.Create("out.o", 2, "");
177
178   Edge* edge = GetNode("out.o")->in_edge();
179   string err;
180   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
181   ASSERT_EQ("", err);
182   EXPECT_FALSE(GetNode("out.o")->dirty());
183
184   state_.Reset();
185   fs_.RemoveFile("out.o.d");
186   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
187   ASSERT_EQ("", err);
188   EXPECT_TRUE(GetNode("out.o")->dirty());
189 }
190
191 // Check that rule-level variables are in scope for eval.
192 TEST_F(GraphTest, RuleVariablesInScope) {
193   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
194 "rule r\n"
195 "  depfile = x\n"
196 "  command = depfile is $depfile\n"
197 "build out: r in\n"));
198   Edge* edge = GetNode("out")->in_edge();
199   EXPECT_EQ("depfile is x", edge->EvaluateCommand());
200 }
201
202 // Check that build statements can override rule builtins like depfile.
203 TEST_F(GraphTest, DepfileOverride) {
204   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
205 "rule r\n"
206 "  depfile = x\n"
207 "  command = unused\n"
208 "build out: r in\n"
209 "  depfile = y\n"));
210   Edge* edge = GetNode("out")->in_edge();
211   EXPECT_EQ("y", edge->GetBinding("depfile"));
212 }
213
214 // Check that overridden values show up in expansion of rule-level bindings.
215 TEST_F(GraphTest, DepfileOverrideParent) {
216   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
217 "rule r\n"
218 "  depfile = x\n"
219 "  command = depfile is $depfile\n"
220 "build out: r in\n"
221 "  depfile = y\n"));
222   Edge* edge = GetNode("out")->in_edge();
223   EXPECT_EQ("depfile is y", edge->GetBinding("command"));
224 }