| // Copyright (c) 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "gn/json_project_writer.h" |
| #include "base/strings/string_util.h" |
| #include "gn/substitution_list.h" |
| #include "gn/target.h" |
| #include "gn/test_with_scheduler.h" |
| #include "gn/test_with_scope.h" |
| #include "util/build_config.h" |
| #include "util/test/test.h" |
| |
| using JSONWriter = TestWithScheduler; |
| |
| TEST_F(JSONWriter, ActionWithResponseFile) { |
| Err err; |
| TestWithScope setup; |
| |
| Target target(setup.settings(), Label(SourceDir("//foo/"), "bar")); |
| target.set_output_type(Target::ACTION); |
| |
| target.sources().push_back(SourceFile("//foo/source1.txt")); |
| target.config_values().inputs().push_back(SourceFile("//foo/input1.txt")); |
| target.action_values().set_script(SourceFile("//foo/script.py")); |
| |
| target.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(target.OnResolved(&err)); |
| |
| // Make sure we get interesting substitutions for both the args and the |
| // response file contents. |
| target.action_values().args() = |
| SubstitutionList::MakeForTest("{{response_file_name}}"); |
| target.action_values().rsp_file_contents() = |
| SubstitutionList::MakeForTest("-j", "3"); |
| target.action_values().outputs() = |
| SubstitutionList::MakeForTest("//out/Debug/output1.out"); |
| |
| setup.build_settings()->set_python_path( |
| base::FilePath(FILE_PATH_LITERAL("/usr/bin/python"))); |
| std::vector<const Target*> targets; |
| targets.push_back(&target); |
| #if defined(OS_WIN) |
| base::FilePath root_path = |
| base::FilePath(FILE_PATH_LITERAL("c:/path/to/src")); |
| #else |
| base::FilePath root_path = base::FilePath(FILE_PATH_LITERAL("/path/to/src")); |
| #endif |
| setup.build_settings()->SetRootPath(root_path); |
| g_scheduler->AddGenDependency(root_path.Append(FILE_PATH_LITERAL(".gn"))); |
| g_scheduler->AddGenDependency( |
| root_path.Append(FILE_PATH_LITERAL("BUILD.gn"))); |
| g_scheduler->AddGenDependency( |
| root_path.Append(FILE_PATH_LITERAL("build/BUILD.gn"))); |
| std::string out = |
| JSONProjectWriter::RenderJSON(setup.build_settings(), targets); |
| #if defined(OS_WIN) |
| base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n"); |
| #endif |
| const char expected_json[] = |
| "{\n" |
| " \"build_settings\": {\n" |
| " \"build_dir\": \"//out/Debug/\",\n" |
| " \"default_toolchain\": \"//toolchain:default\",\n" |
| " \"gen_input_files\": [ \"//.gn\", \"//BUILD.gn\", " |
| "\"//build/BUILD.gn\" ],\n" |
| #if defined(OS_WIN) |
| " \"root_path\": \"c:/path/to/src\"\n" |
| #else |
| " \"root_path\": \"/path/to/src\"\n" |
| #endif |
| " },\n" |
| " \"targets\": {\n" |
| " \"//foo:bar()\": {\n" |
| " \"args\": [ \"{{response_file_name}}\" ],\n" |
| " \"deps\": [ ],\n" |
| " \"inputs\": [ \"//foo/input1.txt\" ],\n" |
| " \"metadata\": {\n" |
| "\n" |
| " },\n" |
| " \"outputs\": [ \"//out/Debug/output1.out\" ],\n" |
| " \"public\": \"*\",\n" |
| " \"response_file_contents\": [ \"-j\", \"3\" ],\n" |
| " \"script\": \"//foo/script.py\",\n" |
| " \"sources\": [ \"//foo/source1.txt\" ],\n" |
| " \"testonly\": false,\n" |
| " \"toolchain\": \"\",\n" |
| " \"type\": \"action\",\n" |
| " \"visibility\": [ ]\n" |
| " }\n" |
| " }\n" |
| "}\n"; |
| EXPECT_EQ(expected_json, out) << out; |
| } |
| |
| TEST_F(JSONWriter, RustTarget) { |
| Err err; |
| TestWithScope setup; |
| |
| Target target(setup.settings(), Label(SourceDir("//foo/"), "bar")); |
| target.set_output_type(Target::RUST_LIBRARY); |
| target.visibility().SetPublic(); |
| SourceFile lib("//foo/lib.rs"); |
| target.sources().push_back(lib); |
| target.source_types_used().Set(SourceFile::SOURCE_RS); |
| target.rust_values().set_crate_root(lib); |
| target.rust_values().crate_name() = "foo"; |
| target.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(target.OnResolved(&err)); |
| |
| std::vector<const Target*> targets; |
| targets.push_back(&target); |
| std::string out = |
| JSONProjectWriter::RenderJSON(setup.build_settings(), targets); |
| #if defined(OS_WIN) |
| base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n"); |
| #endif |
| const char expected_json[] = |
| "{\n" |
| " \"build_settings\": {\n" |
| " \"build_dir\": \"//out/Debug/\",\n" |
| " \"default_toolchain\": \"//toolchain:default\",\n" |
| " \"gen_input_files\": [ ],\n" |
| " \"root_path\": \"\"\n" |
| " },\n" |
| " \"targets\": {\n" |
| " \"//foo:bar()\": {\n" |
| " \"allow_circular_includes_from\": [ ],\n" |
| " \"check_includes\": true,\n" |
| " \"crate_name\": \"foo\",\n" |
| " \"crate_root\": \"//foo/lib.rs\",\n" |
| " \"deps\": [ ],\n" |
| " \"externs\": {\n" |
| "\n" |
| " },\n" |
| " \"metadata\": {\n" |
| "\n" |
| " },\n" |
| " \"outputs\": [ \"//out/Debug/obj/foo/libbar.rlib\" ],\n" |
| " \"public\": \"*\",\n" |
| " \"sources\": [ \"//foo/lib.rs\" ],\n" |
| " \"testonly\": false,\n" |
| " \"toolchain\": \"\",\n" |
| " \"type\": \"rust_library\",\n" |
| " \"visibility\": [ \"*\" ]\n" |
| " }\n" |
| " }\n" |
| "}\n"; |
| EXPECT_EQ(expected_json, out); |
| } |
| |
| TEST_F(JSONWriter, ForEachWithResponseFile) { |
| Err err; |
| TestWithScope setup; |
| |
| Target target(setup.settings(), Label(SourceDir("//foo/"), "bar")); |
| target.set_output_type(Target::ACTION_FOREACH); |
| |
| target.sources().push_back(SourceFile("//foo/input1.txt")); |
| target.action_values().set_script(SourceFile("//foo/script.py")); |
| |
| target.SetToolchain(setup.toolchain()); |
| ASSERT_TRUE(target.OnResolved(&err)); |
| |
| // Make sure we get interesting substitutions for both the args and the |
| // response file contents. |
| target.action_values().args() = SubstitutionList::MakeForTest( |
| "{{source}}", "{{source_file_part}}", "{{response_file_name}}"); |
| target.action_values().rsp_file_contents() = |
| SubstitutionList::MakeForTest("-j", "{{source_name_part}}"); |
| target.action_values().outputs() = |
| SubstitutionList::MakeForTest("//out/Debug/{{source_name_part}}.out"); |
| |
| setup.build_settings()->set_python_path( |
| base::FilePath(FILE_PATH_LITERAL("/usr/bin/python"))); |
| std::vector<const Target*> targets; |
| targets.push_back(&target); |
| #if defined(OS_WIN) |
| base::FilePath root_path = |
| base::FilePath(FILE_PATH_LITERAL("c:/path/to/src")); |
| #else |
| base::FilePath root_path = base::FilePath(FILE_PATH_LITERAL("/path/to/src")); |
| #endif |
| setup.build_settings()->SetRootPath(root_path); |
| g_scheduler->AddGenDependency(root_path.Append(FILE_PATH_LITERAL(".gn"))); |
| g_scheduler->AddGenDependency( |
| root_path.Append(FILE_PATH_LITERAL("BUILD.gn"))); |
| std::string out = |
| JSONProjectWriter::RenderJSON(setup.build_settings(), targets); |
| #if defined(OS_WIN) |
| base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n"); |
| #endif |
| const char expected_json[] = |
| "{\n" |
| " \"build_settings\": {\n" |
| " \"build_dir\": \"//out/Debug/\",\n" |
| " \"default_toolchain\": \"//toolchain:default\",\n" |
| " \"gen_input_files\": [ \"//.gn\", \"//BUILD.gn\" ],\n" |
| #if defined(OS_WIN) |
| " \"root_path\": \"c:/path/to/src\"\n" |
| #else |
| " \"root_path\": \"/path/to/src\"\n" |
| #endif |
| " },\n" |
| " \"targets\": {\n" |
| " \"//foo:bar()\": {\n" |
| " \"args\": [ \"{{source}}\", \"{{source_file_part}}\", " |
| "\"{{response_file_name}}\" ],\n" |
| " \"deps\": [ ],\n" |
| " \"metadata\": {\n" |
| "\n" |
| " },\n" |
| " \"output_patterns\": [ " |
| "\"//out/Debug/{{source_name_part}}.out\" ],\n" |
| " \"outputs\": [ \"//out/Debug/input1.out\" ],\n" |
| " \"public\": \"*\",\n" |
| " \"response_file_contents\": [ \"-j\", \"{{source_name_part}}\" " |
| "],\n" |
| " \"script\": \"//foo/script.py\",\n" |
| " \"source_outputs\": {\n" |
| " \"//foo/input1.txt\": [ \"input1.out\" ]\n" |
| " },\n" |
| " \"sources\": [ \"//foo/input1.txt\" ],\n" |
| " \"testonly\": false,\n" |
| " \"toolchain\": \"\",\n" |
| " \"type\": \"action_foreach\",\n" |
| " \"visibility\": [ ]\n" |
| " }\n" |
| " }\n" |
| "}\n"; |
| EXPECT_EQ(expected_json, out); |
| } |