1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/strings/string_util.h"
6 #include "gn/json_project_writer.h"
7 #include "gn/substitution_list.h"
8 #include "gn/target.h"
9 #include "gn/test_with_scope.h"
10 #include "gn/test_with_scheduler.h"
11 #include "util/build_config.h"
12 #include "util/test/test.h"
13
14 using JSONWriter = TestWithScheduler;
15
TEST_F(JSONWriter,ActionWithResponseFile)16 TEST_F(JSONWriter, ActionWithResponseFile) {
17 Err err;
18 TestWithScope setup;
19
20 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
21 target.set_output_type(Target::ACTION);
22
23 target.sources().push_back(SourceFile("//foo/source1.txt"));
24 target.config_values().inputs().push_back(SourceFile("//foo/input1.txt"));
25 target.action_values().set_script(SourceFile("//foo/script.py"));
26
27 target.SetToolchain(setup.toolchain());
28 ASSERT_TRUE(target.OnResolved(&err));
29
30 // Make sure we get interesting substitutions for both the args and the
31 // response file contents.
32 target.action_values().args() =
33 SubstitutionList::MakeForTest("{{response_file_name}}");
34 target.action_values().rsp_file_contents() =
35 SubstitutionList::MakeForTest("-j", "3");
36 target.action_values().outputs() =
37 SubstitutionList::MakeForTest("//out/Debug/output1.out");
38
39 setup.build_settings()->set_python_path(
40 base::FilePath(FILE_PATH_LITERAL("/usr/bin/python")));
41 std::vector<const Target*> targets;
42 targets.push_back(&target);
43 #if defined(OS_WIN)
44 base::FilePath root_path = base::FilePath(FILE_PATH_LITERAL("c:/path/to/src"));
45 #else
46 base::FilePath root_path = base::FilePath(FILE_PATH_LITERAL("/path/to/src"));
47 #endif
48 setup.build_settings()->SetRootPath(root_path);
49 g_scheduler->AddGenDependency(root_path.Append(FILE_PATH_LITERAL(".gn")));
50 g_scheduler->AddGenDependency(root_path.Append(FILE_PATH_LITERAL("BUILD.gn")));
51 g_scheduler->AddGenDependency(root_path.Append(FILE_PATH_LITERAL("build/BUILD.gn")));
52 std::string out =
53 JSONProjectWriter::RenderJSON(setup.build_settings(), targets);
54 #if defined(OS_WIN)
55 base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
56 #endif
57 const char expected_json[] =
58 "{\n"
59 " \"build_settings\": {\n"
60 " \"build_dir\": \"//out/Debug/\",\n"
61 " \"default_toolchain\": \"//toolchain:default\",\n"
62 " \"gen_input_files\": [ \"//.gn\", \"//BUILD.gn\", \"//build/BUILD.gn\" ],\n"
63 #if defined(OS_WIN)
64 " \"root_path\": \"c:/path/to/src\"\n"
65 #else
66 " \"root_path\": \"/path/to/src\"\n"
67 #endif
68 " },\n"
69 " \"targets\": {\n"
70 " \"//foo:bar()\": {\n"
71 " \"args\": [ \"{{response_file_name}}\" ],\n"
72 " \"deps\": [ ],\n"
73 " \"inputs\": [ \"//foo/input1.txt\" ],\n"
74 " \"metadata\": {\n"
75 "\n"
76 " },\n"
77 " \"outputs\": [ \"//out/Debug/output1.out\" ],\n"
78 " \"public\": \"*\",\n"
79 " \"response_file_contents\": [ \"-j\", \"3\" ],\n"
80 " \"script\": \"//foo/script.py\",\n"
81 " \"sources\": [ \"//foo/source1.txt\" ],\n"
82 " \"testonly\": false,\n"
83 " \"toolchain\": \"\",\n"
84 " \"type\": \"action\",\n"
85 " \"visibility\": [ ]\n"
86 " }\n"
87 " }\n"
88 "}\n";
89 EXPECT_EQ(expected_json, out);
90 }
91
TEST_F(JSONWriter,RustTarget)92 TEST_F(JSONWriter, RustTarget) {
93 Err err;
94 TestWithScope setup;
95
96 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
97 target.set_output_type(Target::RUST_LIBRARY);
98 target.visibility().SetPublic();
99 SourceFile lib("//foo/lib.rs");
100 target.sources().push_back(lib);
101 target.source_types_used().Set(SourceFile::SOURCE_RS);
102 target.rust_values().set_crate_root(lib);
103 target.rust_values().crate_name() = "foo";
104 target.SetToolchain(setup.toolchain());
105 ASSERT_TRUE(target.OnResolved(&err));
106
107 std::vector<const Target*> targets;
108 targets.push_back(&target);
109 std::string out =
110 JSONProjectWriter::RenderJSON(setup.build_settings(), targets);
111 #if defined(OS_WIN)
112 base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
113 #endif
114 const char expected_json[] =
115 "{\n"
116 " \"build_settings\": {\n"
117 " \"build_dir\": \"//out/Debug/\",\n"
118 " \"default_toolchain\": \"//toolchain:default\",\n"
119 " \"gen_input_files\": [ ],\n"
120 " \"root_path\": \"\"\n"
121 " },\n"
122 " \"targets\": {\n"
123 " \"//foo:bar()\": {\n"
124 " \"allow_circular_includes_from\": [ ],\n"
125 " \"check_includes\": true,\n"
126 " \"crate_name\": \"foo\",\n"
127 " \"crate_root\": \"//foo/lib.rs\",\n"
128 " \"deps\": [ ],\n"
129 " \"externs\": {\n"
130 "\n"
131 " },\n"
132 " \"metadata\": {\n"
133 "\n"
134 " },\n"
135 " \"outputs\": [ \"//out/Debug/obj/foo/libbar.rlib\" ],\n"
136 " \"public\": \"*\",\n"
137 " \"sources\": [ \"//foo/lib.rs\" ],\n"
138 " \"testonly\": false,\n"
139 " \"toolchain\": \"\",\n"
140 " \"type\": \"rust_library\",\n"
141 " \"visibility\": [ \"*\" ]\n"
142 " }\n"
143 " }\n"
144 "}\n";
145 EXPECT_EQ(expected_json, out);
146 }
147
TEST_F(JSONWriter,ForEachWithResponseFile)148 TEST_F(JSONWriter, ForEachWithResponseFile) {
149 Err err;
150 TestWithScope setup;
151
152 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
153 target.set_output_type(Target::ACTION_FOREACH);
154
155 target.sources().push_back(SourceFile("//foo/input1.txt"));
156 target.action_values().set_script(SourceFile("//foo/script.py"));
157
158 target.SetToolchain(setup.toolchain());
159 ASSERT_TRUE(target.OnResolved(&err));
160
161 // Make sure we get interesting substitutions for both the args and the
162 // response file contents.
163 target.action_values().args() = SubstitutionList::MakeForTest(
164 "{{source}}", "{{source_file_part}}", "{{response_file_name}}");
165 target.action_values().rsp_file_contents() =
166 SubstitutionList::MakeForTest("-j", "{{source_name_part}}");
167 target.action_values().outputs() =
168 SubstitutionList::MakeForTest("//out/Debug/{{source_name_part}}.out");
169
170 setup.build_settings()->set_python_path(
171 base::FilePath(FILE_PATH_LITERAL("/usr/bin/python")));
172 std::vector<const Target*> targets;
173 targets.push_back(&target);
174 #if defined(OS_WIN)
175 base::FilePath root_path = base::FilePath(FILE_PATH_LITERAL("c:/path/to/src"));
176 #else
177 base::FilePath root_path = base::FilePath(FILE_PATH_LITERAL("/path/to/src"));
178 #endif
179 setup.build_settings()->SetRootPath(root_path);
180 g_scheduler->AddGenDependency(root_path.Append(FILE_PATH_LITERAL(".gn")));
181 g_scheduler->AddGenDependency(root_path.Append(FILE_PATH_LITERAL("BUILD.gn")));
182 std::string out =
183 JSONProjectWriter::RenderJSON(setup.build_settings(), targets);
184 #if defined(OS_WIN)
185 base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
186 #endif
187 const char expected_json[] =
188 "{\n"
189 " \"build_settings\": {\n"
190 " \"build_dir\": \"//out/Debug/\",\n"
191 " \"default_toolchain\": \"//toolchain:default\",\n"
192 " \"gen_input_files\": [ \"//.gn\", \"//BUILD.gn\" ],\n"
193 #if defined(OS_WIN)
194 " \"root_path\": \"c:/path/to/src\"\n"
195 #else
196 " \"root_path\": \"/path/to/src\"\n"
197 #endif
198 " },\n"
199 " \"targets\": {\n"
200 " \"//foo:bar()\": {\n"
201 " \"args\": [ \"{{source}}\", \"{{source_file_part}}\", "
202 "\"{{response_file_name}}\" ],\n"
203 " \"deps\": [ ],\n"
204 " \"metadata\": {\n"
205 "\n"
206 " },\n"
207 " \"output_patterns\": [ "
208 "\"//out/Debug/{{source_name_part}}.out\" ],\n"
209 " \"outputs\": [ \"//out/Debug/input1.out\" ],\n"
210 " \"public\": \"*\",\n"
211 " \"response_file_contents\": [ \"-j\", \"{{source_name_part}}\" "
212 "],\n"
213 " \"script\": \"//foo/script.py\",\n"
214 " \"sources\": [ \"//foo/input1.txt\" ],\n"
215 " \"testonly\": false,\n"
216 " \"toolchain\": \"\",\n"
217 " \"type\": \"action_foreach\",\n"
218 " \"visibility\": [ ]\n"
219 " }\n"
220 " }\n"
221 "}\n";
222 EXPECT_EQ(expected_json, out);
223 }
224