• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.h"
6 #include "base/strings/string_util.h"
7 #include "base/files/file_path.h"
8 #include "gn/filesystem_utils.h"
9 #include "gn/substitution_list.h"
10 #include "gn/target.h"
11 #include "gn/test_with_scheduler.h"
12 #include "gn/test_with_scope.h"
13 #include "util/build_config.h"
14 #include "util/test/test.h"
15 
16 
ExpectEqOrShowDiff(const char * expected,const std::string & actual)17 static void ExpectEqOrShowDiff(const char* expected, const std::string& actual) {
18   if(expected != actual) {
19     printf("\nExpected: >>>\n%s<<<\n", expected);
20     printf("  Actual: >>>\n%s<<<\n", actual.c_str());
21   }
22   EXPECT_EQ(expected, actual);
23 }
24 
25 using RustProjectJSONWriter = TestWithScheduler;
26 
TEST_F(RustProjectJSONWriter,OneRustTarget)27 TEST_F(RustProjectJSONWriter, OneRustTarget) {
28   Err err;
29   TestWithScope setup;
30   setup.build_settings()->SetRootPath(UTF8ToFilePath("path"));
31 
32   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
33   target.set_output_type(Target::RUST_LIBRARY);
34   target.visibility().SetPublic();
35   SourceFile lib("//foo/lib.rs");
36   target.sources().push_back(lib);
37   target.source_types_used().Set(SourceFile::SOURCE_RS);
38   target.rust_values().set_crate_root(lib);
39   target.rust_values().crate_name() = "foo";
40   target.config_values().rustflags().push_back("--cfg=feature=\"foo_enabled\"");
41   target.SetToolchain(setup.toolchain());
42   ASSERT_TRUE(target.OnResolved(&err));
43 
44   std::ostringstream stream;
45   std::vector<const Target*> targets;
46   targets.push_back(&target);
47   RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream);
48   std::string out = stream.str();
49 #if defined(OS_WIN)
50   base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
51 #endif
52   const char expected_json[] =
53       "{\n"
54       "  \"crates\": [\n"
55       "    {\n"
56       "      \"crate_id\": 0,\n"
57       "      \"root_module\": \"path/foo/lib.rs\",\n"
58       "      \"label\": \"//foo:bar\",\n"
59       "      \"source\": {\n"
60       "          \"include_dirs\": [\n"
61       "               \"path/foo/\",\n"
62       "               \"path/out/Debug/gen/foo/\"\n"
63       "          ],\n"
64       "          \"exclude_dirs\": []\n"
65       "      },\n"
66       "      \"compiler_args\": [\"--cfg=feature=\\\"foo_enabled\\\"\"],\n"
67       "      \"deps\": [\n"
68       "      ],\n"
69       "      \"edition\": \"2015\",\n"
70       "      \"cfg\": [\n"
71       "        \"test\",\n"
72       "        \"debug_assertions\",\n"
73       "        \"feature=\\\"foo_enabled\\\"\"\n"
74       "      ]\n"
75       "    }\n"
76       "  ]\n"
77       "}\n";
78 
79   ExpectEqOrShowDiff(expected_json, out);
80 }
81 
TEST_F(RustProjectJSONWriter,RustTargetDep)82 TEST_F(RustProjectJSONWriter, RustTargetDep) {
83   Err err;
84   TestWithScope setup;
85 
86   Target dep(setup.settings(), Label(SourceDir("//tortoise/"), "bar"));
87   dep.set_output_type(Target::RUST_LIBRARY);
88   dep.visibility().SetPublic();
89   SourceFile tlib("//tortoise/lib.rs");
90   dep.sources().push_back(tlib);
91   dep.source_types_used().Set(SourceFile::SOURCE_RS);
92   dep.rust_values().set_crate_root(tlib);
93   dep.rust_values().crate_name() = "tortoise";
94   dep.SetToolchain(setup.toolchain());
95   ASSERT_TRUE(dep.OnResolved(&err));
96 
97   Target target(setup.settings(), Label(SourceDir("//hare/"), "bar"));
98   target.set_output_type(Target::RUST_LIBRARY);
99   target.visibility().SetPublic();
100   SourceFile harelib("//hare/lib.rs");
101   target.sources().push_back(harelib);
102   target.source_types_used().Set(SourceFile::SOURCE_RS);
103   target.rust_values().set_crate_root(harelib);
104   target.rust_values().crate_name() = "hare";
105   target.public_deps().push_back(LabelTargetPair(&dep));
106   target.SetToolchain(setup.toolchain());
107   ASSERT_TRUE(target.OnResolved(&err));
108 
109   std::ostringstream stream;
110   std::vector<const Target*> targets;
111   targets.push_back(&target);
112   RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream);
113   std::string out = stream.str();
114 #if defined(OS_WIN)
115   base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
116 #endif
117   const char expected_json[] =
118       "{\n"
119       "  \"crates\": [\n"
120       "    {\n"
121       "      \"crate_id\": 0,\n"
122       "      \"root_module\": \"tortoise/lib.rs\",\n"
123       "      \"label\": \"//tortoise:bar\",\n"
124       "      \"source\": {\n"
125       "          \"include_dirs\": [\n"
126       "               \"tortoise/\",\n"
127       "               \"out/Debug/gen/tortoise/\"\n"
128       "          ],\n"
129       "          \"exclude_dirs\": []\n"
130       "      },\n"
131       "      \"deps\": [\n"
132       "      ],\n"
133       "      \"edition\": \"2015\",\n"
134       "      \"cfg\": [\n"
135       "        \"test\",\n"
136       "        \"debug_assertions\"\n"
137       "      ]\n"
138       "    },\n"
139       "    {\n"
140       "      \"crate_id\": 1,\n"
141       "      \"root_module\": \"hare/lib.rs\",\n"
142       "      \"label\": \"//hare:bar\",\n"
143       "      \"source\": {\n"
144       "          \"include_dirs\": [\n"
145       "               \"hare/\",\n"
146       "               \"out/Debug/gen/hare/\"\n"
147       "          ],\n"
148       "          \"exclude_dirs\": []\n"
149       "      },\n"
150       "      \"deps\": [\n"
151       "        {\n"
152       "          \"crate\": 0,\n"
153       "          \"name\": \"tortoise\"\n"
154       "        }\n"
155       "      ],\n"
156       "      \"edition\": \"2015\",\n"
157       "      \"cfg\": [\n"
158       "        \"test\",\n"
159       "        \"debug_assertions\"\n"
160       "      ]\n"
161       "    }\n"
162       "  ]\n"
163       "}\n";
164 
165   ExpectEqOrShowDiff(expected_json, out);
166 }
167 
TEST_F(RustProjectJSONWriter,RustTargetDepTwo)168 TEST_F(RustProjectJSONWriter, RustTargetDepTwo) {
169   Err err;
170   TestWithScope setup;
171 
172   Target dep(setup.settings(), Label(SourceDir("//tortoise/"), "bar"));
173   dep.set_output_type(Target::RUST_LIBRARY);
174   dep.visibility().SetPublic();
175   SourceFile tlib("//tortoise/lib.rs");
176   dep.sources().push_back(tlib);
177   dep.source_types_used().Set(SourceFile::SOURCE_RS);
178   dep.rust_values().set_crate_root(tlib);
179   dep.rust_values().crate_name() = "tortoise";
180   dep.SetToolchain(setup.toolchain());
181   ASSERT_TRUE(dep.OnResolved(&err));
182 
183   Target dep2(setup.settings(), Label(SourceDir("//achilles/"), "bar"));
184   dep2.set_output_type(Target::RUST_LIBRARY);
185   dep2.visibility().SetPublic();
186   SourceFile alib("//achilles/lib.rs");
187   dep2.sources().push_back(alib);
188   dep2.source_types_used().Set(SourceFile::SOURCE_RS);
189   dep2.rust_values().set_crate_root(alib);
190   dep2.rust_values().crate_name() = "achilles";
191   dep2.SetToolchain(setup.toolchain());
192   ASSERT_TRUE(dep2.OnResolved(&err));
193 
194   Target target(setup.settings(), Label(SourceDir("//hare/"), "bar"));
195   target.set_output_type(Target::RUST_LIBRARY);
196   target.visibility().SetPublic();
197   SourceFile harelib("//hare/lib.rs");
198   target.sources().push_back(harelib);
199   target.source_types_used().Set(SourceFile::SOURCE_RS);
200   target.rust_values().set_crate_root(harelib);
201   target.rust_values().crate_name() = "hare";
202   target.public_deps().push_back(LabelTargetPair(&dep));
203   target.public_deps().push_back(LabelTargetPair(&dep2));
204   target.SetToolchain(setup.toolchain());
205   ASSERT_TRUE(target.OnResolved(&err));
206 
207   std::ostringstream stream;
208   std::vector<const Target*> targets;
209   targets.push_back(&target);
210   RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream);
211   std::string out = stream.str();
212 #if defined(OS_WIN)
213   base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
214 #endif
215   const char expected_json[] =
216       "{\n"
217       "  \"crates\": [\n"
218       "    {\n"
219       "      \"crate_id\": 0,\n"
220       "      \"root_module\": \"tortoise/lib.rs\",\n"
221       "      \"label\": \"//tortoise:bar\",\n"
222       "      \"source\": {\n"
223       "          \"include_dirs\": [\n"
224       "               \"tortoise/\",\n"
225       "               \"out/Debug/gen/tortoise/\"\n"
226       "          ],\n"
227       "          \"exclude_dirs\": []\n"
228       "      },\n"
229       "      \"deps\": [\n"
230       "      ],\n"
231       "      \"edition\": \"2015\",\n"
232       "      \"cfg\": [\n"
233       "        \"test\",\n"
234       "        \"debug_assertions\"\n"
235       "      ]\n"
236       "    },\n"
237       "    {\n"
238       "      \"crate_id\": 1,\n"
239       "      \"root_module\": \"achilles/lib.rs\",\n"
240       "      \"label\": \"//achilles:bar\",\n"
241       "      \"source\": {\n"
242       "          \"include_dirs\": [\n"
243       "               \"achilles/\",\n"
244       "               \"out/Debug/gen/achilles/\"\n"
245       "          ],\n"
246       "          \"exclude_dirs\": []\n"
247       "      },\n"
248       "      \"deps\": [\n"
249       "      ],\n"
250       "      \"edition\": \"2015\",\n"
251       "      \"cfg\": [\n"
252       "        \"test\",\n"
253       "        \"debug_assertions\"\n"
254       "      ]\n"
255       "    },\n"
256       "    {\n"
257       "      \"crate_id\": 2,\n"
258       "      \"root_module\": \"hare/lib.rs\",\n"
259       "      \"label\": \"//hare:bar\",\n"
260       "      \"source\": {\n"
261       "          \"include_dirs\": [\n"
262       "               \"hare/\",\n"
263       "               \"out/Debug/gen/hare/\"\n"
264       "          ],\n"
265       "          \"exclude_dirs\": []\n"
266       "      },\n"
267       "      \"deps\": [\n"
268       "        {\n"
269       "          \"crate\": 0,\n"
270       "          \"name\": \"tortoise\"\n"
271       "        },\n"
272       "        {\n"
273       "          \"crate\": 1,\n"
274       "          \"name\": \"achilles\"\n"
275       "        }\n"
276       "      ],\n"
277       "      \"edition\": \"2015\",\n"
278       "      \"cfg\": [\n"
279       "        \"test\",\n"
280       "        \"debug_assertions\"\n"
281       "      ]\n"
282       "    }\n"
283       "  ]\n"
284       "}\n";
285   ExpectEqOrShowDiff(expected_json, out);
286 }
287 
288 // Test that when outputting dependencies, only Rust deps are returned,
289 // and that any groups are inspected to see if they include Rust deps.
TEST_F(RustProjectJSONWriter,RustTargetGetDepRustOnly)290 TEST_F(RustProjectJSONWriter, RustTargetGetDepRustOnly) {
291   Err err;
292   TestWithScope setup;
293 
294   Target dep(setup.settings(), Label(SourceDir("//tortoise/"), "bar"));
295   dep.set_output_type(Target::RUST_LIBRARY);
296   dep.visibility().SetPublic();
297   SourceFile tlib("//tortoise/lib.rs");
298   dep.sources().push_back(tlib);
299   dep.source_types_used().Set(SourceFile::SOURCE_RS);
300   dep.rust_values().set_crate_root(tlib);
301   dep.rust_values().crate_name() = "tortoise";
302   dep.SetToolchain(setup.toolchain());
303   ASSERT_TRUE(dep.OnResolved(&err));
304 
305   Target dep2(setup.settings(), Label(SourceDir("//achilles/"), "bar"));
306   dep2.set_output_type(Target::STATIC_LIBRARY);
307   dep2.visibility().SetPublic();
308   SourceFile alib("//achilles/lib.o");
309   dep2.SetToolchain(setup.toolchain());
310   ASSERT_TRUE(dep2.OnResolved(&err));
311 
312   Target dep3(setup.settings(), Label(SourceDir("//achilles/"), "group"));
313   dep3.set_output_type(Target::GROUP);
314   dep3.visibility().SetPublic();
315   dep3.public_deps().push_back(LabelTargetPair(&dep));
316   dep3.SetToolchain(setup.toolchain());
317   ASSERT_TRUE(dep3.OnResolved(&err));
318 
319   Target dep4(setup.settings(), Label(SourceDir("//tortoise/"), "macro"));
320   dep4.set_output_type(Target::RUST_PROC_MACRO);
321   dep4.visibility().SetPublic();
322   SourceFile tmlib("//tortoise/macro/lib.rs");
323   dep4.sources().push_back(tmlib);
324   dep4.source_types_used().Set(SourceFile::SOURCE_RS);
325   dep4.rust_values().set_crate_root(tmlib);
326   dep4.rust_values().crate_name() = "tortoise_macro";
327   dep4.SetToolchain(setup.toolchain());
328   ASSERT_TRUE(dep4.OnResolved(&err));
329 
330   Target target(setup.settings(), Label(SourceDir("//hare/"), "bar"));
331   target.set_output_type(Target::RUST_LIBRARY);
332   target.visibility().SetPublic();
333   SourceFile harelib("//hare/lib.rs");
334   target.sources().push_back(harelib);
335   target.source_types_used().Set(SourceFile::SOURCE_RS);
336   target.rust_values().set_crate_root(harelib);
337   target.rust_values().crate_name() = "hare";
338   target.public_deps().push_back(LabelTargetPair(&dep));
339   target.public_deps().push_back(LabelTargetPair(&dep3));
340   target.public_deps().push_back(LabelTargetPair(&dep4));
341   target.SetToolchain(setup.toolchain());
342   ASSERT_TRUE(target.OnResolved(&err));
343 
344   std::ostringstream stream;
345   std::vector<const Target*> targets;
346   targets.push_back(&target);
347   RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream);
348   std::string out = stream.str();
349 #if defined(OS_WIN)
350   base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
351 #endif
352   const char expected_json[] =
353       "{\n"
354       "  \"crates\": [\n"
355       "    {\n"
356       "      \"crate_id\": 0,\n"
357       "      \"root_module\": \"tortoise/lib.rs\",\n"
358       "      \"label\": \"//tortoise:bar\",\n"
359       "      \"source\": {\n"
360       "          \"include_dirs\": [\n"
361       "               \"tortoise/\",\n"
362       "               \"out/Debug/gen/tortoise/\"\n"
363       "          ],\n"
364       "          \"exclude_dirs\": []\n"
365       "      },\n"
366       "      \"deps\": [\n"
367       "      ],\n"
368       "      \"edition\": \"2015\",\n"
369       "      \"cfg\": [\n"
370       "        \"test\",\n"
371       "        \"debug_assertions\"\n"
372       "      ]\n"
373       "    },\n"
374       "    {\n"
375       "      \"crate_id\": 1,\n"
376       "      \"root_module\": \"tortoise/macro/lib.rs\",\n"
377       "      \"label\": \"//tortoise:macro\",\n"
378       "      \"source\": {\n"
379       "          \"include_dirs\": [\n"
380       "               \"tortoise/macro/\",\n"
381       "               \"out/Debug/gen/tortoise/\"\n"
382       "          ],\n"
383       "          \"exclude_dirs\": []\n"
384       "      },\n"
385       "      \"deps\": [\n"
386       "      ],\n"
387       "      \"edition\": \"2015\",\n"
388       "      \"is_proc_macro\": true,\n"
389       "      \"proc_macro_dylib_path\": "
390       "\"out/Debug/obj/tortoise/libmacro.so\",\n"
391       "      \"cfg\": [\n"
392       "        \"test\",\n"
393       "        \"debug_assertions\"\n"
394       "      ]\n"
395       "    },\n"
396       "    {\n"
397       "      \"crate_id\": 2,\n"
398       "      \"root_module\": \"hare/lib.rs\",\n"
399       "      \"label\": \"//hare:bar\",\n"
400       "      \"source\": {\n"
401       "          \"include_dirs\": [\n"
402       "               \"hare/\",\n"
403       "               \"out/Debug/gen/hare/\"\n"
404       "          ],\n"
405       "          \"exclude_dirs\": []\n"
406       "      },\n"
407       "      \"deps\": [\n"
408       "        {\n"
409       "          \"crate\": 0,\n"
410       "          \"name\": \"tortoise\"\n"
411       "        },\n"
412       "        {\n"
413       "          \"crate\": 1,\n"
414       "          \"name\": \"tortoise_macro\"\n"
415       "        }\n"
416       "      ],\n"
417       "      \"edition\": \"2015\",\n"
418       "      \"cfg\": [\n"
419       "        \"test\",\n"
420       "        \"debug_assertions\"\n"
421       "      ]\n"
422       "    }\n"
423       "  ]\n"
424       "}\n";
425 
426   ExpectEqOrShowDiff(expected_json, out);
427 }
428 
TEST_F(RustProjectJSONWriter,OneRustTargetWithRustcTargetSet)429 TEST_F(RustProjectJSONWriter, OneRustTargetWithRustcTargetSet) {
430   Err err;
431   TestWithScope setup;
432   setup.build_settings()->SetRootPath(UTF8ToFilePath("path"));
433 
434   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
435   target.set_output_type(Target::RUST_LIBRARY);
436   target.visibility().SetPublic();
437   SourceFile lib("//foo/lib.rs");
438   target.sources().push_back(lib);
439   target.source_types_used().Set(SourceFile::SOURCE_RS);
440   target.rust_values().set_crate_root(lib);
441   target.rust_values().crate_name() = "foo";
442   target.config_values().rustflags().push_back("--target");
443   target.config_values().rustflags().push_back("x86-64_unknown");
444   target.SetToolchain(setup.toolchain());
445   ASSERT_TRUE(target.OnResolved(&err));
446 
447   std::ostringstream stream;
448   std::vector<const Target*> targets;
449   targets.push_back(&target);
450   RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream);
451   std::string out = stream.str();
452 #if defined(OS_WIN)
453   base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
454 #endif
455   const char expected_json[] =
456       "{\n"
457       "  \"crates\": [\n"
458       "    {\n"
459       "      \"crate_id\": 0,\n"
460       "      \"root_module\": \"path/foo/lib.rs\",\n"
461       "      \"label\": \"//foo:bar\",\n"
462       "      \"source\": {\n"
463       "          \"include_dirs\": [\n"
464       "               \"path/foo/\",\n"
465       "               \"path/out/Debug/gen/foo/\"\n"
466       "          ],\n"
467       "          \"exclude_dirs\": []\n"
468       "      },\n"
469       "      \"target\": \"x86-64_unknown\",\n"
470       "      \"compiler_args\": [\"--target\", \"x86-64_unknown\"],\n"
471       "      \"deps\": [\n"
472       "      ],\n"
473       "      \"edition\": \"2015\",\n"
474       "      \"cfg\": [\n"
475       "        \"test\",\n"
476       "        \"debug_assertions\"\n"
477       "      ]\n"
478       "    }\n"
479       "  ]\n"
480       "}\n";
481 
482   ExpectEqOrShowDiff(expected_json, out);
483 }
484 
TEST_F(RustProjectJSONWriter,OneRustTargetWithEditionSet)485 TEST_F(RustProjectJSONWriter, OneRustTargetWithEditionSet) {
486   Err err;
487   TestWithScope setup;
488   setup.build_settings()->SetRootPath(UTF8ToFilePath("path"));
489 
490   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
491   target.set_output_type(Target::RUST_LIBRARY);
492   target.visibility().SetPublic();
493   SourceFile lib("//foo/lib.rs");
494   target.sources().push_back(lib);
495   target.source_types_used().Set(SourceFile::SOURCE_RS);
496   target.rust_values().set_crate_root(lib);
497   target.rust_values().crate_name() = "foo";
498   target.config_values().rustflags().push_back("--edition=2018");
499   target.SetToolchain(setup.toolchain());
500   ASSERT_TRUE(target.OnResolved(&err));
501 
502   std::ostringstream stream;
503   std::vector<const Target*> targets;
504   targets.push_back(&target);
505   RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream);
506   std::string out = stream.str();
507 #if defined(OS_WIN)
508   base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
509 #endif
510   const char expected_json[] =
511       "{\n"
512       "  \"crates\": [\n"
513       "    {\n"
514       "      \"crate_id\": 0,\n"
515       "      \"root_module\": \"path/foo/lib.rs\",\n"
516       "      \"label\": \"//foo:bar\",\n"
517       "      \"source\": {\n"
518       "          \"include_dirs\": [\n"
519       "               \"path/foo/\",\n"
520       "               \"path/out/Debug/gen/foo/\"\n"
521       "          ],\n"
522       "          \"exclude_dirs\": []\n"
523       "      },\n"
524       "      \"compiler_args\": [\"--edition=2018\"],\n"
525       "      \"deps\": [\n"
526       "      ],\n"
527       "      \"edition\": \"2018\",\n"
528       "      \"cfg\": [\n"
529       "        \"test\",\n"
530       "        \"debug_assertions\"\n"
531       "      ]\n"
532       "    }\n"
533       "  ]\n"
534       "}\n";
535 
536   ExpectEqOrShowDiff(expected_json, out);
537 }
538 
TEST_F(RustProjectJSONWriter,OneRustTargetWithEditionSetAlternate)539 TEST_F(RustProjectJSONWriter, OneRustTargetWithEditionSetAlternate) {
540   Err err;
541   TestWithScope setup;
542   setup.build_settings()->SetRootPath(UTF8ToFilePath("path"));
543 
544   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
545   target.set_output_type(Target::RUST_LIBRARY);
546   target.visibility().SetPublic();
547   SourceFile lib("//foo/lib.rs");
548   target.sources().push_back(lib);
549   target.source_types_used().Set(SourceFile::SOURCE_RS);
550   target.rust_values().set_crate_root(lib);
551   target.rust_values().crate_name() = "foo";
552   target.config_values().rustflags().push_back("--edition");
553   target.config_values().rustflags().push_back("2018");
554   target.SetToolchain(setup.toolchain());
555   ASSERT_TRUE(target.OnResolved(&err));
556 
557   std::ostringstream stream;
558   std::vector<const Target*> targets;
559   targets.push_back(&target);
560   RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream);
561   std::string out = stream.str();
562 #if defined(OS_WIN)
563   base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
564 #endif
565   const char expected_json[] =
566       "{\n"
567       "  \"crates\": [\n"
568       "    {\n"
569       "      \"crate_id\": 0,\n"
570       "      \"root_module\": \"path/foo/lib.rs\",\n"
571       "      \"label\": \"//foo:bar\",\n"
572       "      \"source\": {\n"
573       "          \"include_dirs\": [\n"
574       "               \"path/foo/\",\n"
575       "               \"path/out/Debug/gen/foo/\"\n"
576       "          ],\n"
577       "          \"exclude_dirs\": []\n"
578       "      },\n"
579       "      \"compiler_args\": [\"--edition\", \"2018\"],\n"
580       "      \"deps\": [\n"
581       "      ],\n"
582       "      \"edition\": \"2018\",\n"
583       "      \"cfg\": [\n"
584       "        \"test\",\n"
585       "        \"debug_assertions\"\n"
586       "      ]\n"
587       "    }\n"
588       "  ]\n"
589       "}\n";
590 
591   ExpectEqOrShowDiff(expected_json, out);
592 }
593 
TEST_F(RustProjectJSONWriter,OneRustProcMacroTarget)594 TEST_F(RustProjectJSONWriter, OneRustProcMacroTarget) {
595   Err err;
596   TestWithScope setup;
597   setup.build_settings()->SetRootPath(UTF8ToFilePath("path"));
598 
599   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
600   target.set_output_type(Target::RUST_PROC_MACRO);
601   target.visibility().SetPublic();
602   SourceFile lib("//foo/lib.rs");
603   target.sources().push_back(lib);
604   target.source_types_used().Set(SourceFile::SOURCE_RS);
605   target.rust_values().set_crate_root(lib);
606   target.config_values().rustenv().push_back("TEST_ENV_VAR=baz");
607   target.config_values().rustenv().push_back("TEST_ENV_VAR2=baz2");
608   target.rust_values().crate_name() = "foo";
609   target.config_values().rustflags().push_back("--cfg=feature=\"foo_enabled\"");
610   target.SetToolchain(setup.toolchain());
611   ASSERT_TRUE(target.OnResolved(&err));
612 
613   std::ostringstream stream;
614   std::vector<const Target*> targets;
615   targets.push_back(&target);
616   RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream);
617   std::string out = stream.str();
618 #if defined(OS_WIN)
619   base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
620 #endif
621   const char expected_json[] =
622       "{\n"
623       "  \"crates\": [\n"
624       "    {\n"
625       "      \"crate_id\": 0,\n"
626       "      \"root_module\": \"path/foo/lib.rs\",\n"
627       "      \"label\": \"//foo:bar\",\n"
628       "      \"source\": {\n"
629       "          \"include_dirs\": [\n"
630       "               \"path/foo/\",\n"
631       "               \"path/out/Debug/gen/foo/\"\n"
632       "          ],\n"
633       "          \"exclude_dirs\": []\n"
634       "      },\n"
635       "      \"compiler_args\": [\"--cfg=feature=\\\"foo_enabled\\\"\"],\n"
636       "      \"deps\": [\n"
637       "      ],\n"
638       "      \"edition\": \"2015\",\n"
639       "      \"is_proc_macro\": true,\n"
640       "      \"proc_macro_dylib_path\": \"path/out/Debug/obj/foo/libbar.so\",\n"
641       "      \"cfg\": [\n"
642       "        \"test\",\n"
643       "        \"debug_assertions\",\n"
644       "        \"feature=\\\"foo_enabled\\\"\"\n"
645       "      ],\n"
646       "      \"env\": {\n"
647       "        \"TEST_ENV_VAR\": \"baz\",\n"
648       "        \"TEST_ENV_VAR2\": \"baz2\"\n"
649       "      }\n"
650       "    }\n"
651       "  ]\n"
652       "}\n";
653 
654   ExpectEqOrShowDiff(expected_json, out);
655 }
656