1"""Tests for make variables provided by `rust_toolchain`"""
2
3load("@bazel_skylib//lib:unittest.bzl", "analysistest")
4load("//rust:defs.bzl", "rust_binary", "rust_library", "rust_test")
5load("//test/unit:common.bzl", "assert_action_mnemonic", "assert_env_value")
6
7_RUST_TOOLCHAIN_ENV = {
8    "ENV_VAR_CARGO": "$(CARGO)",
9    "ENV_VAR_RUSTC": "$(RUSTC)",
10    "ENV_VAR_RUSTDOC": "$(RUSTDOC)",
11    "ENV_VAR_RUST_DEFAULT_EDITION": "$(RUST_DEFAULT_EDITION)",
12    "ENV_VAR_RUST_SYSROOT": "$(RUST_SYSROOT)",
13}
14
15_RUSTFMT_TOOLCHAIN_ENV = {
16    "ENV_VAR_RUSTFMT": "$(RUSTFMT)",
17}
18
19def _rust_toolchain_make_variable_expansion_test_common_impl(ctx, mnemonic):
20    env = analysistest.begin(ctx)
21    target = analysistest.target_under_test(env)
22    action = target.actions[0]
23
24    assert_action_mnemonic(
25        env = env,
26        action = action,
27        mnemonic = mnemonic,
28    )
29
30    if mnemonic in ["RustFmtToolchainConsumer", "CurrentRustFmtToolchainConsumer"]:
31        toolchain = ctx.attr._current_rustfmt_toolchain[platform_common.ToolchainInfo]
32        env_vars = _RUSTFMT_TOOLCHAIN_ENV
33        expected_values = {
34            "ENV_VAR_RUSTFMT": toolchain.rustfmt.path,
35        }
36    else:
37        toolchain = ctx.attr._current_rust_toolchain[platform_common.ToolchainInfo]
38        env_vars = _RUST_TOOLCHAIN_ENV
39        expected_values = {
40            "ENV_VAR_CARGO": toolchain.cargo.path,
41            "ENV_VAR_RUSTC": toolchain.rustc.path,
42            "ENV_VAR_RUSTDOC": toolchain.rust_doc.path,
43            "ENV_VAR_RUST_DEFAULT_EDITION": toolchain.default_edition or "",
44            "ENV_VAR_RUST_SYSROOT": toolchain.sysroot,
45        }
46
47    for key in env_vars:
48        assert_env_value(
49            env = env,
50            action = action,
51            key = key,
52            value = expected_values[key],
53        )
54
55    return analysistest.end(env)
56
57def rust_toolchain_make_toolchain_make_variable_test(impl):
58    return analysistest.make(
59        impl = impl,
60        attrs = {
61            "_current_rust_toolchain": attr.label(
62                doc = "The currently registered rust toolchain",
63                default = Label("//rust/toolchain:current_rust_toolchain"),
64            ),
65        },
66    )
67
68def rustfmt_toolchain_make_toolchain_make_variable_test(impl):
69    return analysistest.make(
70        impl = impl,
71        attrs = {
72            "_current_rustfmt_toolchain": attr.label(
73                doc = "The currently registered rustfmt toolchain",
74                default = Label("//rust/toolchain:current_rustfmt_toolchain"),
75            ),
76        },
77    )
78
79def _rustc_env_variable_expansion_test_impl(ctx):
80    return _rust_toolchain_make_variable_expansion_test_common_impl(ctx, "Rustc")
81
82rustc_env_variable_expansion_test = rust_toolchain_make_toolchain_make_variable_test(
83    impl = _rustc_env_variable_expansion_test_impl,
84)
85
86def _rust_toolchain_make_variable_expansion_test(ctx):
87    return _rust_toolchain_make_variable_expansion_test_common_impl(ctx, "RustToolchainConsumer")
88
89rust_toolchain_make_variable_expansion_test = rust_toolchain_make_toolchain_make_variable_test(
90    impl = _rust_toolchain_make_variable_expansion_test,
91)
92
93def _current_rust_toolchain_make_variable_expansion_test_impl(ctx):
94    return _rust_toolchain_make_variable_expansion_test_common_impl(ctx, "CurrentRustToolchainConsumer")
95
96current_rust_toolchain_make_variable_expansion_test = rust_toolchain_make_toolchain_make_variable_test(
97    impl = _current_rust_toolchain_make_variable_expansion_test_impl,
98)
99
100def _rustfmt_env_variable_expansion_test_impl(ctx):
101    return _rust_toolchain_make_variable_expansion_test_common_impl(ctx, "RustFmtToolchainConsumer")
102
103rustfmt_env_variable_expansion_test = rustfmt_toolchain_make_toolchain_make_variable_test(
104    impl = _rustfmt_env_variable_expansion_test_impl,
105)
106
107def _current_rustfmt_toolchain_make_variable_expansion_test_impl(ctx):
108    return _rust_toolchain_make_variable_expansion_test_common_impl(ctx, "CurrentRustFmtToolchainConsumer")
109
110current_rustfmt_toolchain_make_variable_expansion_test = rustfmt_toolchain_make_toolchain_make_variable_test(
111    impl = _current_rustfmt_toolchain_make_variable_expansion_test_impl,
112)
113
114def _rust_toolchain_consumer_common_impl(ctx, mnemonic):
115    output = ctx.actions.declare_file(ctx.label.name)
116
117    args = ctx.actions.args()
118    args.add(output)
119
120    # Expand make variables
121    env = {
122        key: ctx.expand_make_variables(
123            key,
124            val,
125            {},
126        )
127        for key, val in ctx.attr.env.items()
128    }
129
130    ctx.actions.run(
131        outputs = [output],
132        executable = ctx.executable.writer,
133        mnemonic = mnemonic,
134        env = env,
135        arguments = [args],
136    )
137
138    return DefaultInfo(
139        files = depset([output]),
140    )
141
142def _rust_toolchain_consumer_impl(ctx):
143    return _rust_toolchain_consumer_common_impl(ctx, "RustToolchainConsumer")
144
145rust_toolchain_consumer = rule(
146    implementation = _rust_toolchain_consumer_impl,
147    doc = "A helper rule to test make variable expansion of rules that depend on `rust_toolchain`.",
148    attrs = {
149        "env": attr.string_dict(
150            doc = "Environment variables used for expansion",
151            mandatory = True,
152        ),
153        "writer": attr.label(
154            doc = "An executable for creating an action output",
155            cfg = "exec",
156            executable = True,
157            mandatory = True,
158        ),
159    },
160    toolchains = [
161        "@rules_rust//rust:toolchain_type",
162    ],
163)
164
165def _current_rust_toolchain_consumer_impl(ctx):
166    return _rust_toolchain_consumer_common_impl(ctx, "CurrentRustToolchainConsumer")
167
168current_rust_toolchain_consumer = rule(
169    implementation = _current_rust_toolchain_consumer_impl,
170    doc = "A helper rule to test make variable expansion of `current_rust_toolchain`.",
171    attrs = {
172        "env": attr.string_dict(
173            doc = "Environment variables used for expansion",
174            mandatory = True,
175        ),
176        "writer": attr.label(
177            doc = "An executable for creating an action output",
178            cfg = "exec",
179            executable = True,
180            mandatory = True,
181        ),
182    },
183)
184
185def _rustfmt_toolchain_consumer_impl(ctx):
186    return _rust_toolchain_consumer_common_impl(ctx, "RustFmtToolchainConsumer")
187
188rustfmt_toolchain_consumer = rule(
189    implementation = _rustfmt_toolchain_consumer_impl,
190    doc = "A helper rule to test make variable expansion of rules that depend on `rust_toolchain`.",
191    attrs = {
192        "env": attr.string_dict(
193            doc = "Environment variables used for expansion",
194            mandatory = True,
195        ),
196        "writer": attr.label(
197            doc = "An executable for creating an action output",
198            cfg = "exec",
199            executable = True,
200            mandatory = True,
201        ),
202    },
203    toolchains = [
204        "@rules_rust//rust/rustfmt:toolchain_type",
205    ],
206)
207
208def _current_rustfmt_toolchain_consumer_impl(ctx):
209    return _rust_toolchain_consumer_common_impl(ctx, "CurrentRustFmtToolchainConsumer")
210
211current_rustfmt_toolchain_consumer = rule(
212    implementation = _current_rustfmt_toolchain_consumer_impl,
213    doc = "A helper rule to test make variable expansion of `current_rust_toolchain`.",
214    attrs = {
215        "env": attr.string_dict(
216            doc = "Environment variables used for expansion",
217            mandatory = True,
218        ),
219        "writer": attr.label(
220            doc = "An executable for creating an action output",
221            cfg = "exec",
222            executable = True,
223            mandatory = True,
224        ),
225    },
226    toolchains = [
227        "@rules_rust//rust/rustfmt:toolchain_type",
228    ],
229)
230
231def _define_targets():
232    rust_library(
233        name = "library",
234        srcs = ["main.rs"],
235        rustc_env = _RUST_TOOLCHAIN_ENV,
236        edition = "2018",
237    )
238
239    rust_binary(
240        name = "binary",
241        srcs = ["main.rs"],
242        rustc_env = _RUST_TOOLCHAIN_ENV,
243        edition = "2018",
244    )
245
246    rust_test(
247        name = "integration_test",
248        srcs = ["test.rs"],
249        rustc_env = _RUST_TOOLCHAIN_ENV,
250        edition = "2018",
251    )
252
253    rust_test(
254        name = "unit_test",
255        crate = "library",
256        rustc_env = _RUST_TOOLCHAIN_ENV,
257    )
258
259    rust_toolchain_consumer(
260        name = "rust_toolchain_consumer",
261        env = _RUST_TOOLCHAIN_ENV,
262        writer = ":binary",
263    )
264
265    current_rust_toolchain_consumer(
266        name = "current_rust_toolchain_consumer",
267        env = _RUST_TOOLCHAIN_ENV,
268        toolchains = ["//rust/toolchain:current_rust_toolchain"],
269        writer = ":binary",
270    )
271
272    rustfmt_toolchain_consumer(
273        name = "rustfmt_toolchain_consumer",
274        env = _RUSTFMT_TOOLCHAIN_ENV,
275        writer = ":binary",
276    )
277
278    current_rustfmt_toolchain_consumer(
279        name = "current_rustfmt_toolchain_consumer",
280        env = _RUSTFMT_TOOLCHAIN_ENV,
281        toolchains = ["//rust/toolchain:current_rustfmt_toolchain"],
282        writer = ":binary",
283    )
284
285def toolchain_make_variable_test_suite(name):
286    """Defines a test suite
287
288    Args:
289        name (str): The name of the test suite
290    """
291    _define_targets()
292
293    rustc_env_variable_expansion_test(
294        name = "rustc_env_variable_expansion_library_test",
295        target_under_test = ":library",
296    )
297
298    rustc_env_variable_expansion_test(
299        name = "rustc_env_variable_expansion_binary_test",
300        target_under_test = ":binary",
301    )
302
303    rustc_env_variable_expansion_test(
304        name = "rustc_env_variable_expansion_integration_test_test",
305        target_under_test = ":integration_test",
306    )
307
308    rustc_env_variable_expansion_test(
309        name = "rustc_env_variable_expansion_unit_test_test",
310        target_under_test = ":unit_test",
311    )
312
313    rust_toolchain_make_variable_expansion_test(
314        name = "rust_toolchain_make_variable_expansion_test",
315        target_under_test = ":rust_toolchain_consumer",
316    )
317
318    current_rust_toolchain_make_variable_expansion_test(
319        name = "current_rust_toolchain_make_variable_expansion_test",
320        target_under_test = ":current_rust_toolchain_consumer",
321    )
322
323    rustfmt_env_variable_expansion_test(
324        name = "rustfmt_env_variable_expansion_test",
325        target_under_test = ":rustfmt_toolchain_consumer",
326    )
327
328    current_rustfmt_toolchain_make_variable_expansion_test(
329        name = "current_rustfmt_toolchain_make_variable_expansion_test",
330        target_under_test = ":current_rustfmt_toolchain_consumer",
331    )
332
333    native.test_suite(
334        name = name,
335        tests = [
336            # rust_toolchain tests
337            ":rustc_env_variable_expansion_library_test",
338            ":rustc_env_variable_expansion_binary_test",
339            ":rustc_env_variable_expansion_integration_test_test",
340            ":rustc_env_variable_expansion_unit_test_test",
341            ":rust_toolchain_make_variable_expansion_test",
342            ":current_rust_toolchain_make_variable_expansion_test",
343        ] + [
344            # rustfmt_toolchain tests
345            ":rustfmt_env_variable_expansion_test",
346            ":current_rustfmt_toolchain_make_variable_expansion_test",
347        ],
348    )
349