OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include "tools/gn/analyzer.h" |
| 6 #include "base/memory/ptr_util.h" |
5 #include "testing/gtest/include/gtest/gtest.h" | 7 #include "testing/gtest/include/gtest/gtest.h" |
6 #include "tools/gn/analyzer.h" | |
7 #include "tools/gn/build_settings.h" | 8 #include "tools/gn/build_settings.h" |
8 #include "tools/gn/builder.h" | 9 #include "tools/gn/builder.h" |
| 10 #include "tools/gn/input_file.h" |
9 #include "tools/gn/loader.h" | 11 #include "tools/gn/loader.h" |
10 #include "tools/gn/settings.h" | 12 #include "tools/gn/settings.h" |
11 #include "tools/gn/source_file.h" | 13 #include "tools/gn/source_file.h" |
12 | 14 |
13 | |
14 namespace { | 15 namespace { |
15 | 16 |
16 class MockLoader : public Loader { | 17 class MockLoader : public Loader { |
17 public: | 18 public: |
18 MockLoader() {} | 19 MockLoader() {} |
19 | 20 |
20 void Load(const SourceFile& file, | 21 void Load(const SourceFile& file, |
21 const LocationRange& origin, | 22 const LocationRange& origin, |
22 const Label& toolchain_name) override {} | 23 const Label& toolchain_name) override {} |
23 void ToolchainLoaded(const Toolchain* toolchain) override {} | 24 void ToolchainLoaded(const Toolchain* toolchain) override {} |
24 Label GetDefaultToolchain() const override { | 25 Label GetDefaultToolchain() const override { |
25 return Label(SourceDir("//tc/"), "default"); | 26 return Label(SourceDir("//tc/"), "default"); |
26 } | 27 } |
27 const Settings* GetToolchainSettings(const Label& label) const override { | 28 const Settings* GetToolchainSettings(const Label& label) const override { |
28 return nullptr; | 29 return nullptr; |
29 } | 30 } |
30 | 31 |
31 private: | 32 private: |
32 ~MockLoader() override {} | 33 ~MockLoader() override {} |
33 }; | 34 }; |
34 | 35 |
35 class AnalyzerTest : public testing::Test { | 36 class AnalyzerTest : public testing::Test { |
36 public: | 37 public: |
| 38 using InputFileMap = base::hash_map<SourceFile, std::unique_ptr<InputFile>>; |
37 AnalyzerTest() | 39 AnalyzerTest() |
38 : loader_(new MockLoader), | 40 : loader_(new MockLoader), |
39 builder_(loader_.get()), | 41 builder_(loader_.get()), |
40 settings_(&build_settings_, std::string()) { | 42 settings_(&build_settings_, std::string()) { |
41 build_settings_.SetBuildDir(SourceDir("//out/")); | 43 build_settings_.SetBuildDir(SourceDir("//out/")); |
42 settings_.set_toolchain_label(Label(SourceDir("//tc/"), "default")); | 44 settings_.set_toolchain_label(Label(SourceDir("//tc/"), "default")); |
43 settings_.set_default_toolchain_label(settings_.toolchain_label()); | 45 settings_.set_default_toolchain_label(settings_.toolchain_label()); |
44 tc_dir_ = settings_.toolchain_label().dir(); | 46 tc_dir_ = settings_.toolchain_label().dir(); |
45 tc_name_ = settings_.toolchain_label().name(); | 47 tc_name_ = settings_.toolchain_label().name(); |
46 } | 48 } |
47 | 49 |
48 Target* MakeTarget(const std::string dir, | 50 Target* MakeTarget(const std::string dir, |
49 const std::string name, | 51 const std::string name, |
50 Target::OutputType type, | 52 Target::OutputType type, |
51 const std::vector<std::string>& sources, | 53 const std::vector<std::string>& sources, |
52 const std::vector<Target*>& deps) { | 54 const std::vector<Target*>& deps, |
| 55 const std::vector<std::string>& gn_files) { |
53 Label lbl(SourceDir(dir), name, tc_dir_, tc_name_); | 56 Label lbl(SourceDir(dir), name, tc_dir_, tc_name_); |
54 Target* target = new Target(&settings_, lbl); | 57 InputFileSet input_files; |
| 58 for (const auto& gn : gn_files) { |
| 59 SourceFile source_file(gn); |
| 60 auto found_input_file = input_files_.find(source_file); |
| 61 if (found_input_file != input_files_.end()) { |
| 62 input_files.insert(found_input_file->second.get()); |
| 63 } else { |
| 64 auto input_file = base::MakeUnique<InputFile>(source_file); |
| 65 input_files.insert(input_file.get()); |
| 66 input_files_.insert(std::make_pair(source_file, std::move(input_file))); |
| 67 } |
| 68 } |
| 69 Target* target = new Target(&settings_, lbl, input_files); |
55 target->set_output_type(type); | 70 target->set_output_type(type); |
56 for (const auto& s : sources) | 71 for (const auto& s : sources) |
57 target->sources().push_back(SourceFile(s)); | 72 target->sources().push_back(SourceFile(s)); |
58 for (const auto* d : deps) | 73 for (const auto* d : deps) |
59 target->public_deps().push_back(LabelTargetPair(d)); | 74 target->public_deps().push_back(LabelTargetPair(d)); |
60 builder_.ItemDefined(std::unique_ptr<Item>(target)); | 75 builder_.ItemDefined(std::unique_ptr<Item>(target)); |
61 return target; | 76 return target; |
62 } | 77 } |
63 | 78 |
64 void AddSource(Target* a, std::string path) {} | 79 void AddSource(Target* a, std::string path) {} |
65 | 80 |
66 void AddDep(Target* a, Target* b) {} | 81 void AddDep(Target* a, Target* b) {} |
67 | 82 |
68 void SetUpABasicBuildGraph() { | 83 void SetUpABasicBuildGraph() { |
69 std::vector<std::string> no_sources; | 84 std::vector<std::string> no_sources; |
70 std::vector<Target*> no_deps; | 85 std::vector<Target*> no_deps; |
71 | 86 |
72 // All of the targets below are owned by the builder, so none of them | 87 // All of the targets below are owned by the builder, so none of them |
73 // get leaked. | 88 // get leaked. |
74 | 89 |
75 // Ignore the returned target since nothing depends on it. | 90 // Ignore the returned target since nothing depends on it. |
76 MakeTarget("//", "a", Target::EXECUTABLE, {"//a.cc"}, no_deps); | 91 MakeTarget("//", "a", Target::EXECUTABLE, {"//a.cc"}, no_deps, |
| 92 {"//BUILD.gn", "//features.gni"}); |
77 | 93 |
78 Target* b = | 94 Target* b = MakeTarget("//d", "b", Target::SOURCE_SET, {"//d/b.cc"}, |
79 MakeTarget("//d", "b", Target::SOURCE_SET, {"//d/b.cc"}, no_deps); | 95 no_deps, {"//d/BUILD.gn"}); |
80 | 96 |
81 Target* b_unittests = MakeTarget("//d", "b_unittests", Target::EXECUTABLE, | 97 Target* b_unittests = |
82 {"//d/b_unittest.cc"}, {b}); | 98 MakeTarget("//d", "b_unittests", Target::EXECUTABLE, |
| 99 {"//d/b_unittest.cc"}, {b}, {"//d/BUILD.gn"}); |
83 | 100 |
84 Target* c = MakeTarget("//d", "c", Target::EXECUTABLE, {"//d/c.cc"}, {b}); | 101 Target* c = MakeTarget("//d", "c", Target::EXECUTABLE, {"//d/c.cc"}, {b}, |
| 102 {"//d/BUILD.gn"}); |
85 | 103 |
86 Target* b_unittests_and_c = | 104 Target* b_unittests_and_c = |
87 MakeTarget("//d", "b_unittests_and_c", Target::GROUP, no_sources, | 105 MakeTarget("//d", "b_unittests_and_c", Target::GROUP, no_sources, |
88 {b_unittests, c}); | 106 {b_unittests, c}, {"//d/BUILD.gn"}); |
89 | 107 |
90 Target* e = | 108 Target* e = MakeTarget("//d", "e", Target::EXECUTABLE, {"//d/e.cc"}, |
91 MakeTarget("//d", "e", Target::EXECUTABLE, {"//d/e.cc"}, no_deps); | 109 no_deps, {"//d/BUILD.gn"}); |
92 | 110 |
93 // Also ignore this returned target since nothing depends on it. | 111 // Also ignore this returned target since nothing depends on it. |
94 MakeTarget("//d", "d", Target::GROUP, no_sources, {b_unittests_and_c, e}); | 112 MakeTarget("//d", "d", Target::GROUP, no_sources, {b_unittests_and_c, e}, |
| 113 {"//d/BUILD.gn"}); |
95 } | 114 } |
96 | 115 |
97 void RunBasicTest(const std::string& input, | 116 void RunBasicTest(const std::string& input, |
98 const std::string& expected_output) { | 117 const std::string& expected_output) { |
99 SetUpABasicBuildGraph(); | 118 SetUpABasicBuildGraph(); |
100 Err err; | 119 Err err; |
101 std::string actual_output = Analyzer(builder_).Analyze(input, &err); | 120 Analyzer analyzer(builder_, build_settings_.build_config_file(), |
| 121 SourceFile("//.gn")); |
| 122 std::string actual_output = analyzer.Analyze(input, &err); |
102 EXPECT_EQ(err.has_error(), false); | 123 EXPECT_EQ(err.has_error(), false); |
103 EXPECT_EQ(expected_output, actual_output); | 124 EXPECT_EQ(expected_output, actual_output); |
104 } | 125 } |
105 | 126 |
106 protected: | 127 protected: |
107 scoped_refptr<MockLoader> loader_; | 128 scoped_refptr<MockLoader> loader_; |
108 Builder builder_; | 129 Builder builder_; |
109 BuildSettings build_settings_; | 130 BuildSettings build_settings_; |
110 Settings settings_; | 131 Settings settings_; |
111 SourceDir tc_dir_; | 132 SourceDir tc_dir_; |
112 std::string tc_name_; | 133 std::string tc_name_; |
| 134 InputFileMap input_files_; |
113 }; | 135 }; |
114 | 136 |
115 } // namespace | 137 } // namespace |
116 | 138 |
117 // TODO: clean this up when raw string literals are allowed. | 139 // TODO: clean this up when raw string literals are allowed. |
118 | 140 |
119 TEST_F(AnalyzerTest, AllWasPruned) { | 141 TEST_F(AnalyzerTest, AllWasPruned) { |
120 RunBasicTest( | 142 RunBasicTest( |
121 "{" | 143 "{" |
122 " \"files\": [ \"//d/b.cc\" ]," | 144 " \"files\": [ \"//d/b.cc\" ]," |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 " \"test_targets\": [ \"//:a\" ]" | 216 " \"test_targets\": [ \"//:a\" ]" |
195 "}", | 217 "}", |
196 "{" | 218 "{" |
197 "\"error\":" | 219 "\"error\":" |
198 "\"Input does not have a key named " | 220 "\"Input does not have a key named " |
199 "\\\"additional_compile_targets\\\" with a list value.\"," | 221 "\\\"additional_compile_targets\\\" with a list value.\"," |
200 "\"invalid_targets\":[]" | 222 "\"invalid_targets\":[]" |
201 "}"); | 223 "}"); |
202 } | 224 } |
203 | 225 |
204 TEST_F(AnalyzerTest, BuildFilesWereModified) { | 226 TEST_F(AnalyzerTest, DotGnFileWasModified) { |
205 // This tests that if a build file is modified, we bail out early with | |
206 // "Found dependency (all)" error since we can't handle changes to | |
207 // build files yet (crbug.com/555273). | |
208 RunBasicTest( | 227 RunBasicTest( |
209 "{" | 228 "{" |
210 " \"files\": [ \"//a.cc\", \"//BUILD.gn\" ]," | 229 " \"files\": [ \"//.gn\" ]," |
211 " \"additional_compile_targets\": []," | 230 " \"additional_compile_targets\": []," |
212 " \"test_targets\": [ \"//:a\" ]" | 231 " \"test_targets\": [ \"//:a\" ]" |
213 "}", | 232 "}", |
214 "{" | 233 "{" |
215 "\"compile_targets\":[\"//:a\"]," | 234 "\"compile_targets\":[\"//:a\"]," |
216 "\"status\":\"Found dependency (all)\"," | 235 "\"status\":\"Found dependency (all)\"," |
217 "\"test_targets\":[\"//:a\"]" | 236 "\"test_targets\":[\"//:a\"]" |
218 "}"); | 237 "}"); |
219 } | 238 } |
220 | 239 |
221 TEST_F(AnalyzerTest, BuildFilesWereModifiedAndCompilingAll) { | 240 TEST_F(AnalyzerTest, DotGnFileWasModifiedAndCompilingAll) { |
222 // This tests that if a build file is modified, we bail out early with | |
223 // "Found dependency (all)" error since we can't handle changes to | |
224 // build files yet (crbug.com/555273). | |
225 RunBasicTest( | 241 RunBasicTest( |
226 "{" | 242 "{" |
227 " \"files\": [ \"//a.cc\", \"//BUILD.gn\" ]," | 243 " \"files\": [ \"//.gn\" ]," |
228 " \"additional_compile_targets\": [ \"all\" ]," | 244 " \"additional_compile_targets\": [ \"all\" ]," |
229 " \"test_targets\": [ \"//:a\" ]" | 245 " \"test_targets\": [ \"//:a\" ]" |
230 "}", | 246 "}", |
231 "{" | 247 "{" |
232 "\"compile_targets\":[\"all\"]," | 248 "\"compile_targets\":[\"all\"]," |
233 "\"status\":\"Found dependency (all)\"," | 249 "\"status\":\"Found dependency (all)\"," |
234 "\"test_targets\":[\"//:a\"]" | 250 "\"test_targets\":[\"//:a\"]" |
235 "}"); | 251 "}"); |
236 } | 252 } |
| 253 |
| 254 TEST_F(AnalyzerTest, BuildFileWasModified) { |
| 255 RunBasicTest( |
| 256 "{" |
| 257 " \"files\": [ \"//BUILD.gn\" ]," |
| 258 " \"additional_compile_targets\": []," |
| 259 " \"test_targets\": [ \"//:a\" ]" |
| 260 "}", |
| 261 "{" |
| 262 "\"compile_targets\":[]," |
| 263 "\"status\":\"Found dependency\"," |
| 264 "\"test_targets\":[\"//:a\"]" |
| 265 "}"); |
| 266 } |
| 267 |
| 268 TEST_F(AnalyzerTest, BuildFileWasModifiedAndCompilingAll) { |
| 269 RunBasicTest( |
| 270 "{" |
| 271 " \"files\": [ \"//BUILD.gn\" ]," |
| 272 " \"additional_compile_targets\": [ \"all\" ]," |
| 273 " \"test_targets\": [ \"//:a\" ]" |
| 274 "}", |
| 275 "{" |
| 276 "\"compile_targets\":[\"//:a\"]," |
| 277 "\"status\":\"Found dependency\"," |
| 278 "\"test_targets\":[\"//:a\"]" |
| 279 "}"); |
| 280 } |
| 281 |
| 282 TEST_F(AnalyzerTest, UnnededBuildFileWasModified) { |
| 283 RunBasicTest( |
| 284 "{" |
| 285 " \"files\": [ \"//BUILD.gn\" ]," |
| 286 " \"additional_compile_targets\": []," |
| 287 " \"test_targets\": [ \"//d:b_unittests\" ]" |
| 288 "}", |
| 289 "{" |
| 290 "\"compile_targets\":[]," |
| 291 "\"status\":\"No dependency\"," |
| 292 "\"test_targets\":[]" |
| 293 "}"); |
| 294 } |
OLD | NEW |