1 // Copyright 2020 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 "gn/rust_project_writer_helpers.h"
6
7 #include "base/strings/string_util.h"
8 #include "gn/filesystem_utils.h"
9 #include "gn/string_output_buffer.h"
10 #include "gn/test_with_scheduler.h"
11 #include "gn/test_with_scope.h"
12 #include "util/build_config.h"
13 #include "util/test/test.h"
14
ExpectEqOrShowDiff(const char * expected,const std::string & actual)15 static void ExpectEqOrShowDiff(const char* expected,
16 const std::string& actual) {
17 if (expected != actual) {
18 printf("\nExpected: >>>\n%s<<<\n", expected);
19 printf(" Actual: >>>\n%s<<<\n", actual.c_str());
20 }
21 EXPECT_EQ(expected, actual);
22 }
23
24 using RustProjectWriterHelper = TestWithScheduler;
25
TEST_F(RustProjectWriterHelper,WriteCrates)26 TEST_F(RustProjectWriterHelper, WriteCrates) {
27 TestWithScope setup;
28
29 CrateList crates;
30 Crate dep = Crate(SourceFile("/root/tortoise/lib.rs"), std::nullopt, 0,
31 "//tortoise:bar", "2015");
32 Crate target = Crate(SourceFile("/root/hare/lib.rs"),
33 OutputFile("gendir/hare/"), 1, "//hare:bar", "2015");
34 target.AddDependency(0, "tortoise");
35 target.AddConfigItem("unix");
36 target.AddConfigItem("feature=\"test\"");
37
38 crates.push_back(dep);
39 crates.push_back(target);
40
41 std::ostringstream stream;
42 WriteCrates(setup.build_settings(), crates, stream);
43 std::string out = stream.str();
44 #if defined(OS_WIN)
45 base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
46 #endif
47 const char expected_json[] =
48 "{\n"
49 " \"crates\": [\n"
50 " {\n"
51 " \"crate_id\": 0,\n"
52 " \"root_module\": \"/root/tortoise/lib.rs\",\n"
53 " \"label\": \"//tortoise:bar\",\n"
54 " \"source\": {\n"
55 " \"include_dirs\": [\n"
56 " \"/root/tortoise/\"\n"
57 " ],\n"
58 " \"exclude_dirs\": []\n"
59 " },\n"
60 " \"deps\": [\n"
61 " ],\n"
62 " \"edition\": \"2015\",\n"
63 " \"cfg\": [\n"
64 " ]\n"
65 " },\n"
66 " {\n"
67 " \"crate_id\": 1,\n"
68 " \"root_module\": \"/root/hare/lib.rs\",\n"
69 " \"label\": \"//hare:bar\",\n"
70 " \"source\": {\n"
71 " \"include_dirs\": [\n"
72 " \"/root/hare/\",\n"
73 " \"out/Debug/gendir/hare/\"\n"
74 " ],\n"
75 " \"exclude_dirs\": []\n"
76 " },\n"
77 " \"deps\": [\n"
78 " {\n"
79 " \"crate\": 0,\n"
80 " \"name\": \"tortoise\"\n"
81 " }\n"
82 " ],\n"
83 " \"edition\": \"2015\",\n"
84 " \"cfg\": [\n"
85 " \"unix\",\n"
86 " \"feature=\\\"test\\\"\"\n"
87 " ]\n"
88 " }\n"
89 " ]\n"
90 "}\n";
91
92 ExpectEqOrShowDiff(expected_json, out);
93 }
94
TEST_F(RustProjectWriterHelper,SysrootDepsAreCorrect)95 TEST_F(RustProjectWriterHelper, SysrootDepsAreCorrect) {
96 TestWithScope setup;
97 setup.build_settings()->SetRootPath(UTF8ToFilePath("/root"));
98
99 SysrootIndexMap sysroot_lookup;
100 CrateList crates;
101
102 AddSysroot(setup.build_settings(), "sysroot", sysroot_lookup, crates);
103
104 std::ostringstream stream;
105 WriteCrates(setup.build_settings(), crates, stream);
106 std::string out = stream.str();
107 #if defined(OS_WIN)
108 base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
109 #endif
110
111 const char expected_json[] =
112 "{\n"
113 " \"crates\": [\n"
114 " {\n"
115 " \"crate_id\": 0,\n"
116 " \"root_module\": "
117 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/core/src/"
118 "lib.rs\",\n"
119 " \"label\": \"core\",\n"
120 " \"source\": {\n"
121 " \"include_dirs\": [\n"
122 " "
123 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/core/src/\"\n"
124 " ],\n"
125 " \"exclude_dirs\": []\n"
126 " },\n"
127 " \"deps\": [\n"
128 " ],\n"
129 " \"edition\": \"2018\",\n"
130 " \"cfg\": [\n"
131 " \"debug_assertions\"\n"
132 " ]\n"
133 " },\n"
134 " {\n"
135 " \"crate_id\": 1,\n"
136 " \"root_module\": "
137 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/alloc/src/"
138 "lib.rs\",\n"
139 " \"label\": \"alloc\",\n"
140 " \"source\": {\n"
141 " \"include_dirs\": [\n"
142 " "
143 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/alloc/src/\"\n"
144 " ],\n"
145 " \"exclude_dirs\": []\n"
146 " },\n"
147 " \"deps\": [\n"
148 " {\n"
149 " \"crate\": 0,\n"
150 " \"name\": \"core\"\n"
151 " }\n"
152 " ],\n"
153 " \"edition\": \"2018\",\n"
154 " \"cfg\": [\n"
155 " \"debug_assertions\"\n"
156 " ]\n"
157 " },\n"
158 " {\n"
159 " \"crate_id\": 2,\n"
160 " \"root_module\": "
161 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/panic_abort/src/"
162 "lib.rs\",\n"
163 " \"label\": \"panic_abort\",\n"
164 " \"source\": {\n"
165 " \"include_dirs\": [\n"
166 " "
167 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/panic_abort/src/"
168 "\"\n"
169 " ],\n"
170 " \"exclude_dirs\": []\n"
171 " },\n"
172 " \"deps\": [\n"
173 " ],\n"
174 " \"edition\": \"2018\",\n"
175 " \"cfg\": [\n"
176 " \"debug_assertions\"\n"
177 " ]\n"
178 " },\n"
179 " {\n"
180 " \"crate_id\": 3,\n"
181 " \"root_module\": "
182 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/unwind/src/"
183 "lib.rs\",\n"
184 " \"label\": \"unwind\",\n"
185 " \"source\": {\n"
186 " \"include_dirs\": [\n"
187 " "
188 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/unwind/src/\"\n"
189 " ],\n"
190 " \"exclude_dirs\": []\n"
191 " },\n"
192 " \"deps\": [\n"
193 " ],\n"
194 " \"edition\": \"2018\",\n"
195 " \"cfg\": [\n"
196 " \"debug_assertions\"\n"
197 " ]\n"
198 " },\n"
199 " {\n"
200 " \"crate_id\": 4,\n"
201 " \"root_module\": "
202 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/std/src/"
203 "lib.rs\",\n"
204 " \"label\": \"std\",\n"
205 " \"source\": {\n"
206 " \"include_dirs\": [\n"
207 " "
208 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/std/src/\"\n"
209 " ],\n"
210 " \"exclude_dirs\": []\n"
211 " },\n"
212 " \"deps\": [\n"
213 " {\n"
214 " \"crate\": 1,\n"
215 " \"name\": \"alloc\"\n"
216 " },\n"
217 " {\n"
218 " \"crate\": 0,\n"
219 " \"name\": \"core\"\n"
220 " },\n"
221 " {\n"
222 " \"crate\": 2,\n"
223 " \"name\": \"panic_abort\"\n"
224 " },\n"
225 " {\n"
226 " \"crate\": 3,\n"
227 " \"name\": \"unwind\"\n"
228 " }\n"
229 " ],\n"
230 " \"edition\": \"2018\",\n"
231 " \"cfg\": [\n"
232 " \"debug_assertions\"\n"
233 " ]\n"
234 " },\n"
235 " {\n"
236 " \"crate_id\": 5,\n"
237 " \"root_module\": "
238 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/panic_unwind/src/"
239 "lib.rs\",\n"
240 " \"label\": \"panic_unwind\",\n"
241 " \"source\": {\n"
242 " \"include_dirs\": [\n"
243 " "
244 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/panic_unwind/src/"
245 "\"\n"
246 " ],\n"
247 " \"exclude_dirs\": []\n"
248 " },\n"
249 " \"deps\": [\n"
250 " ],\n"
251 " \"edition\": \"2018\",\n"
252 " \"cfg\": [\n"
253 " \"debug_assertions\"\n"
254 " ]\n"
255 " },\n"
256 " {\n"
257 " \"crate_id\": 6,\n"
258 " \"root_module\": "
259 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/proc_macro/src/"
260 "lib.rs\",\n"
261 " \"label\": \"proc_macro\",\n"
262 " \"source\": {\n"
263 " \"include_dirs\": [\n"
264 " "
265 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/proc_macro/src/"
266 "\"\n"
267 " ],\n"
268 " \"exclude_dirs\": []\n"
269 " },\n"
270 " \"deps\": [\n"
271 " ],\n"
272 " \"edition\": \"2018\",\n"
273 " \"cfg\": [\n"
274 " \"debug_assertions\"\n"
275 " ]\n"
276 " },\n"
277 " {\n"
278 " \"crate_id\": 7,\n"
279 " \"root_module\": "
280 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/test/src/"
281 "lib.rs\",\n"
282 " \"label\": \"test\",\n"
283 " \"source\": {\n"
284 " \"include_dirs\": [\n"
285 " "
286 "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/test/src/\"\n"
287 " ],\n"
288 " \"exclude_dirs\": []\n"
289 " },\n"
290 " \"deps\": [\n"
291 " ],\n"
292 " \"edition\": \"2018\",\n"
293 " \"cfg\": [\n"
294 " \"debug_assertions\"\n"
295 " ]\n"
296 " }\n"
297 " ]\n"
298 "}\n";
299
300 ExpectEqOrShowDiff(expected_json, out);
301 }
302
TEST_F(RustProjectWriterHelper,ExtractCompilerTargetTupleSimple)303 TEST_F(RustProjectWriterHelper, ExtractCompilerTargetTupleSimple) {
304 TestWithScope setup;
305
306 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
307 target.set_output_type(Target::RUST_LIBRARY);
308 target.visibility().SetPublic();
309 SourceFile lib("//foo/lib.rs");
310 target.sources().push_back(lib);
311 target.source_types_used().Set(SourceFile::SOURCE_RS);
312 target.rust_values().set_crate_root(lib);
313 target.rust_values().crate_name() = "foo";
314 target.config_values().rustflags().push_back("--cfg=feature=\"foo_enabled\"");
315 target.config_values().rustflags().push_back("--target");
316 target.config_values().rustflags().push_back("x86-someos");
317 target.config_values().rustflags().push_back("--edition=2018");
318
319 auto args = ExtractCompilerArgs(&target);
320 std::optional<std::string> result = FindArgValue("--target", args);
321 auto expected = std::optional<std::string>{"x86-someos"};
322 EXPECT_EQ(expected, result);
323 }
324
TEST_F(RustProjectWriterHelper,ExtractCompilerTargetTupleMissing)325 TEST_F(RustProjectWriterHelper, ExtractCompilerTargetTupleMissing) {
326 TestWithScope setup;
327
328 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
329 target.set_output_type(Target::RUST_LIBRARY);
330 target.visibility().SetPublic();
331 SourceFile lib("//foo/lib.rs");
332 target.sources().push_back(lib);
333 target.source_types_used().Set(SourceFile::SOURCE_RS);
334 target.rust_values().set_crate_root(lib);
335 target.rust_values().crate_name() = "foo";
336 target.config_values().rustflags().push_back(
337 "--cfg=featur4e=\"foo_enabled\"");
338 target.config_values().rustflags().push_back("x86-someos");
339 target.config_values().rustflags().push_back("--edition=2018");
340
341 auto args = ExtractCompilerArgs(&target);
342 std::optional<std::string> result = FindArgValue("--target", args);
343 auto expected = std::nullopt;
344 EXPECT_EQ(expected, result);
345 }
346
TEST_F(RustProjectWriterHelper,ExtractCompilerTargetTupleDontFallOffEnd)347 TEST_F(RustProjectWriterHelper, ExtractCompilerTargetTupleDontFallOffEnd) {
348 TestWithScope setup;
349
350 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
351 target.set_output_type(Target::RUST_LIBRARY);
352 target.visibility().SetPublic();
353 SourceFile lib("//foo/lib.rs");
354 target.sources().push_back(lib);
355 target.source_types_used().Set(SourceFile::SOURCE_RS);
356 target.rust_values().set_crate_root(lib);
357 target.rust_values().crate_name() = "foo";
358 target.config_values().rustflags().push_back("--cfg=feature=\"foo_enabled\"");
359 target.config_values().rustflags().push_back("--edition=2018");
360 target.config_values().rustflags().push_back("--target");
361
362 auto args = ExtractCompilerArgs(&target);
363 std::optional<std::string> result = FindArgValue("--target", args);
364 auto expected = std::nullopt;
365 EXPECT_EQ(expected, result);
366 }
367
TEST_F(RustProjectWriterHelper,ExtractFirstArgValueWithPrefixMissing)368 TEST_F(RustProjectWriterHelper, ExtractFirstArgValueWithPrefixMissing) {
369 TestWithScope setup;
370
371 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
372 target.set_output_type(Target::RUST_LIBRARY);
373 target.visibility().SetPublic();
374 SourceFile lib("//foo/lib.rs");
375 target.sources().push_back(lib);
376 target.source_types_used().Set(SourceFile::SOURCE_RS);
377 target.rust_values().set_crate_root(lib);
378 target.rust_values().crate_name() = "foo";
379 target.config_values().rustflags().push_back("--cfg=feature=\"foo_enabled\"");
380 target.config_values().rustflags().push_back("--edition=2018");
381 target.config_values().rustflags().push_back("--target");
382
383 auto args = ExtractCompilerArgs(&target);
384 std::optional<std::string> result =
385 FindArgValueAfterPrefix("--missing", args);
386 auto expected = std::nullopt;
387 EXPECT_EQ(expected, result);
388 }
389
TEST_F(RustProjectWriterHelper,ExtractFirstArgValueWithPrefix)390 TEST_F(RustProjectWriterHelper, ExtractFirstArgValueWithPrefix) {
391 TestWithScope setup;
392
393 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
394 target.set_output_type(Target::RUST_LIBRARY);
395 target.visibility().SetPublic();
396 SourceFile lib("//foo/lib.rs");
397 target.sources().push_back(lib);
398 target.source_types_used().Set(SourceFile::SOURCE_RS);
399 target.rust_values().set_crate_root(lib);
400 target.rust_values().crate_name() = "foo";
401 target.config_values().rustflags().push_back("--cfg=feature=\"foo_enabled\"");
402 target.config_values().rustflags().push_back("--edition=2018");
403 target.config_values().rustflags().push_back("--target");
404
405 auto args = ExtractCompilerArgs(&target);
406 std::optional<std::string> result =
407 FindArgValueAfterPrefix("--edition=", args);
408 auto expected = std::optional<std::string>{"2018"};
409 EXPECT_EQ(expected, result);
410 }
411
TEST_F(RustProjectWriterHelper,ExtractAllArgValueWithPrefix)412 TEST_F(RustProjectWriterHelper, ExtractAllArgValueWithPrefix) {
413 TestWithScope setup;
414
415 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
416 target.set_output_type(Target::RUST_LIBRARY);
417 target.visibility().SetPublic();
418 SourceFile lib("//foo/lib.rs");
419 target.sources().push_back(lib);
420 target.source_types_used().Set(SourceFile::SOURCE_RS);
421 target.rust_values().set_crate_root(lib);
422 target.rust_values().crate_name() = "foo";
423 target.config_values().rustflags().push_back("--cfg=feature=\"foo_enabled\"");
424 target.config_values().rustflags().push_back("--edition=2018");
425 target.config_values().rustflags().push_back("--cfg=feature=\"bar_enabled\"");
426 target.config_values().rustflags().push_back("--target");
427
428 auto args = ExtractCompilerArgs(&target);
429 std::vector<std::string> result = FindAllArgValuesAfterPrefix("--cfg=", args);
430 std::vector<std::string> expected = {"feature=\"foo_enabled\"",
431 "feature=\"bar_enabled\""};
432 EXPECT_EQ(expected, result);
433 }