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 std::optional<std::string> sysroot;
30
31 CrateList crates;
32 Crate dep = Crate(SourceFile("/root/tortoise/lib.rs"), std::nullopt, 0,
33 "//tortoise:bar", "2015");
34 Crate target = Crate(SourceFile("/root/hare/lib.rs"),
35 OutputFile("gendir/hare/"), 1, "//hare:bar", "2015");
36 target.AddDependency(0, "tortoise");
37 target.AddConfigItem("unix");
38 target.AddConfigItem("feature=\"test\"");
39
40 crates.push_back(dep);
41 crates.push_back(target);
42
43 std::ostringstream stream;
44 WriteCrates(setup.build_settings(), crates, sysroot, stream);
45 std::string out = stream.str();
46 #if defined(OS_WIN)
47 base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
48 #endif
49 const char expected_json[] =
50 "{\n"
51 " \"crates\": [\n"
52 " {\n"
53 " \"crate_id\": 0,\n"
54 " \"root_module\": \"/root/tortoise/lib.rs\",\n"
55 " \"label\": \"//tortoise:bar\",\n"
56 " \"source\": {\n"
57 " \"include_dirs\": [\n"
58 " \"/root/tortoise/\"\n"
59 " ],\n"
60 " \"exclude_dirs\": []\n"
61 " },\n"
62 " \"deps\": [\n"
63 " ],\n"
64 " \"edition\": \"2015\",\n"
65 " \"cfg\": [\n"
66 " ]\n"
67 " },\n"
68 " {\n"
69 " \"crate_id\": 1,\n"
70 " \"root_module\": \"/root/hare/lib.rs\",\n"
71 " \"label\": \"//hare:bar\",\n"
72 " \"source\": {\n"
73 " \"include_dirs\": [\n"
74 " \"/root/hare/\",\n"
75 " \"out/Debug/gendir/hare/\"\n"
76 " ],\n"
77 " \"exclude_dirs\": []\n"
78 " },\n"
79 " \"deps\": [\n"
80 " {\n"
81 " \"crate\": 0,\n"
82 " \"name\": \"tortoise\"\n"
83 " }\n"
84 " ],\n"
85 " \"edition\": \"2015\",\n"
86 " \"cfg\": [\n"
87 " \"unix\",\n"
88 " \"feature=\\\"test\\\"\"\n"
89 " ]\n"
90 " }\n"
91 " ]\n"
92 "}\n";
93
94 ExpectEqOrShowDiff(expected_json, out);
95 }
96
TEST_F(RustProjectWriterHelper,SysrootDepsAreCorrect)97 TEST_F(RustProjectWriterHelper, SysrootDepsAreCorrect) {
98 TestWithScope setup;
99 setup.build_settings()->SetRootPath(UTF8ToFilePath("/root"));
100
101 std::optional<std::string> sysroot = "sysroot";
102 CrateList crates;
103
104 std::ostringstream stream;
105 WriteCrates(setup.build_settings(), crates, sysroot, 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 " \"sysroot\": \"/root/out/Debug/sysroot\",\n"
114 " \"crates\": [\n"
115 " ]\n"
116 "}\n";
117
118 ExpectEqOrShowDiff(expected_json, out);
119 }
120
TEST_F(RustProjectWriterHelper,ExtractCompilerTargetTupleSimple)121 TEST_F(RustProjectWriterHelper, ExtractCompilerTargetTupleSimple) {
122 TestWithScope setup;
123
124 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
125 target.set_output_type(Target::RUST_LIBRARY);
126 target.visibility().SetPublic();
127 SourceFile lib("//foo/lib.rs");
128 target.sources().push_back(lib);
129 target.source_types_used().Set(SourceFile::SOURCE_RS);
130 target.rust_values().set_crate_root(lib);
131 target.rust_values().crate_name() = "foo";
132 target.config_values().rustflags().push_back("--cfg=feature=\"foo_enabled\"");
133 target.config_values().rustflags().push_back("--target");
134 target.config_values().rustflags().push_back("x86-someos");
135 target.config_values().rustflags().push_back("--edition=2018");
136
137 auto args = ExtractCompilerArgs(&target);
138 std::optional<std::string> result = FindArgValue("--target", args);
139 auto expected = std::optional<std::string>{"x86-someos"};
140 EXPECT_EQ(expected, result);
141 }
142
TEST_F(RustProjectWriterHelper,ExtractCompilerTargetTupleMissing)143 TEST_F(RustProjectWriterHelper, ExtractCompilerTargetTupleMissing) {
144 TestWithScope setup;
145
146 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
147 target.set_output_type(Target::RUST_LIBRARY);
148 target.visibility().SetPublic();
149 SourceFile lib("//foo/lib.rs");
150 target.sources().push_back(lib);
151 target.source_types_used().Set(SourceFile::SOURCE_RS);
152 target.rust_values().set_crate_root(lib);
153 target.rust_values().crate_name() = "foo";
154 target.config_values().rustflags().push_back(
155 "--cfg=featur4e=\"foo_enabled\"");
156 target.config_values().rustflags().push_back("x86-someos");
157 target.config_values().rustflags().push_back("--edition=2018");
158
159 auto args = ExtractCompilerArgs(&target);
160 std::optional<std::string> result = FindArgValue("--target", args);
161 auto expected = std::nullopt;
162 EXPECT_EQ(expected, result);
163 }
164
TEST_F(RustProjectWriterHelper,ExtractCompilerTargetTupleDontFallOffEnd)165 TEST_F(RustProjectWriterHelper, ExtractCompilerTargetTupleDontFallOffEnd) {
166 TestWithScope setup;
167
168 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
169 target.set_output_type(Target::RUST_LIBRARY);
170 target.visibility().SetPublic();
171 SourceFile lib("//foo/lib.rs");
172 target.sources().push_back(lib);
173 target.source_types_used().Set(SourceFile::SOURCE_RS);
174 target.rust_values().set_crate_root(lib);
175 target.rust_values().crate_name() = "foo";
176 target.config_values().rustflags().push_back("--cfg=feature=\"foo_enabled\"");
177 target.config_values().rustflags().push_back("--edition=2018");
178 target.config_values().rustflags().push_back("--target");
179
180 auto args = ExtractCompilerArgs(&target);
181 std::optional<std::string> result = FindArgValue("--target", args);
182 auto expected = std::nullopt;
183 EXPECT_EQ(expected, result);
184 }
185
TEST_F(RustProjectWriterHelper,ExtractFirstArgValueWithPrefixMissing)186 TEST_F(RustProjectWriterHelper, ExtractFirstArgValueWithPrefixMissing) {
187 TestWithScope setup;
188
189 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
190 target.set_output_type(Target::RUST_LIBRARY);
191 target.visibility().SetPublic();
192 SourceFile lib("//foo/lib.rs");
193 target.sources().push_back(lib);
194 target.source_types_used().Set(SourceFile::SOURCE_RS);
195 target.rust_values().set_crate_root(lib);
196 target.rust_values().crate_name() = "foo";
197 target.config_values().rustflags().push_back("--cfg=feature=\"foo_enabled\"");
198 target.config_values().rustflags().push_back("--edition=2018");
199 target.config_values().rustflags().push_back("--target");
200
201 auto args = ExtractCompilerArgs(&target);
202 std::optional<std::string> result =
203 FindArgValueAfterPrefix("--missing", args);
204 auto expected = std::nullopt;
205 EXPECT_EQ(expected, result);
206 }
207
TEST_F(RustProjectWriterHelper,ExtractFirstArgValueWithPrefix)208 TEST_F(RustProjectWriterHelper, ExtractFirstArgValueWithPrefix) {
209 TestWithScope setup;
210
211 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
212 target.set_output_type(Target::RUST_LIBRARY);
213 target.visibility().SetPublic();
214 SourceFile lib("//foo/lib.rs");
215 target.sources().push_back(lib);
216 target.source_types_used().Set(SourceFile::SOURCE_RS);
217 target.rust_values().set_crate_root(lib);
218 target.rust_values().crate_name() = "foo";
219 target.config_values().rustflags().push_back("--cfg=feature=\"foo_enabled\"");
220 target.config_values().rustflags().push_back("--edition=2018");
221 target.config_values().rustflags().push_back("--target");
222
223 auto args = ExtractCompilerArgs(&target);
224 std::optional<std::string> result =
225 FindArgValueAfterPrefix("--edition=", args);
226 auto expected = std::optional<std::string>{"2018"};
227 EXPECT_EQ(expected, result);
228 }
229
TEST_F(RustProjectWriterHelper,ExtractAllArgValueWithPrefix)230 TEST_F(RustProjectWriterHelper, ExtractAllArgValueWithPrefix) {
231 TestWithScope setup;
232
233 Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
234 target.set_output_type(Target::RUST_LIBRARY);
235 target.visibility().SetPublic();
236 SourceFile lib("//foo/lib.rs");
237 target.sources().push_back(lib);
238 target.source_types_used().Set(SourceFile::SOURCE_RS);
239 target.rust_values().set_crate_root(lib);
240 target.rust_values().crate_name() = "foo";
241 target.config_values().rustflags().push_back("--cfg=feature=\"foo_enabled\"");
242 target.config_values().rustflags().push_back("--edition=2018");
243 target.config_values().rustflags().push_back("--cfg=feature=\"bar_enabled\"");
244 target.config_values().rustflags().push_back("--target");
245
246 auto args = ExtractCompilerArgs(&target);
247 std::vector<std::string> result = FindAllArgValuesAfterPrefix("--cfg=", args);
248 std::vector<std::string> expected = {"feature=\"foo_enabled\"",
249 "feature=\"bar_enabled\""};
250 EXPECT_EQ(expected, result);
251 }