| 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 |