blob: db865063059d57a31debc32afb933915f5d9bfb0 [file] [log] [blame]
"""Unittest to verify proc-macro targets"""
load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
load("//rust:defs.bzl", "rust_library", "rust_proc_macro", "rust_test")
def _proc_macro_does_not_leak_deps_impl(ctx):
env = analysistest.begin(ctx)
actions = analysistest.target_under_test(env).actions
rustc_action = None
for action in actions:
if action.mnemonic == "Rustc":
rustc_action = action
break
asserts.false(env, rustc_action == None)
# Our test target has a dependency on "proc_macro_dep" via a rust_proc_macro target,
# so the proc_macro_dep rlib should not appear as an input to the Rustc action, nor as -Ldependency on the command line.
proc_macro_dep_inputs = [i for i in rustc_action.inputs.to_list() if "proc_macro_dep" in i.path]
proc_macro_dep_args = [arg for arg in rustc_action.argv if "proc_macro_dep" in arg]
asserts.equals(env, 0, len(proc_macro_dep_inputs))
asserts.equals(env, 0, len(proc_macro_dep_args))
# Our test target depends on proc_macro_dep:native directly, as well as transitively through the
# proc_macro. The proc_macro should not leak its dependency, so we should only get the "native"
# library once on the command line.
native_deps = [arg for arg in rustc_action.argv if arg.startswith("-Clink-arg=-lnative")]
asserts.equals(env, 1, len(native_deps))
return analysistest.end(env)
def _proc_macro_does_not_leak_deps_test():
rust_proc_macro(
name = "proc_macro_definition",
srcs = ["leaks_deps/proc_macro_definition.rs"],
edition = "2018",
deps = ["//test/unit/proc_macro/leaks_deps/proc_macro_dep"],
)
rust_proc_macro(
name = "proc_macro_with_native_dep",
srcs = ["leaks_deps/proc_macro_definition_with_native_dependency.rs"],
edition = "2018",
deps = [
"//test/unit/proc_macro/leaks_deps/proc_macro_dep:proc_macro_dep_with_native_dep",
"//test/unit/proc_macro/leaks_deps/native",
],
)
rust_test(
name = "deps_not_leaked",
srcs = ["leaks_deps/proc_macro_user.rs"],
edition = "2018",
deps = [
"//test/unit/proc_macro/leaks_deps/native",
],
proc_macro_deps = [
":proc_macro_definition",
":proc_macro_with_native_dep",
],
)
proc_macro_does_not_leak_deps_test(
name = "proc_macro_does_not_leak_deps_test",
target_under_test = ":deps_not_leaked",
)
proc_macro_does_not_leak_deps_test = analysistest.make(_proc_macro_does_not_leak_deps_impl)
# Tests that a lib_a -> proc_macro -> lib_b does not propagate lib_b to the inputs of lib_a
def _proc_macro_does_not_leak_lib_deps_impl(ctx):
env = analysistest.begin(ctx)
actions = analysistest.target_under_test(env).actions
rustc_actions = []
for action in actions:
if action.mnemonic == "Rustc" or action.mnemonic == "RustcMetadata":
rustc_actions.append(action)
# We should have a RustcMetadata and a Rustc action.
asserts.true(env, len(rustc_actions) == 2, "expected 2 actions, got %d" % len(rustc_actions))
for rustc_action in rustc_actions:
# lib :a has a dependency on :my_macro via a rust_proc_macro target.
# lib :b (which is a dependency of :my_macro) should not appear in the inputs of :a
b_inputs = [i for i in rustc_action.inputs.to_list() if "libb" in i.path]
b_args = [arg for arg in rustc_action.argv if "libb" in arg]
asserts.equals(env, 0, len(b_inputs))
asserts.equals(env, 0, len(b_args))
return analysistest.end(env)
def _proc_macro_does_not_leak_lib_deps_test():
rust_library(
name = "b",
srcs = ["leaks_deps/lib/b.rs"],
edition = "2018",
)
rust_proc_macro(
name = "my_macro",
srcs = ["leaks_deps/lib/my_macro.rs"],
edition = "2018",
deps = [
":b",
],
)
rust_library(
name = "a",
srcs = ["leaks_deps/lib/a.rs"],
edition = "2018",
proc_macro_deps = [
":my_macro",
],
)
NOT_WINDOWS = select({
"@platforms//os:linux": [],
"@platforms//os:macos": [],
"//conditions:default": ["@platforms//:incompatible"],
})
proc_macro_does_not_leak_lib_deps_test(
name = "proc_macro_does_not_leak_lib_deps_test",
target_under_test = ":a",
target_compatible_with = NOT_WINDOWS,
)
proc_macro_does_not_leak_lib_deps_test = analysistest.make(_proc_macro_does_not_leak_lib_deps_impl, config_settings = {"@//rust/settings:pipelined_compilation": True})
def proc_macro_does_not_leak_deps_test_suite(name):
"""Entry-point macro called from the BUILD file.
Args:
name: Name of the macro.
"""
_proc_macro_does_not_leak_deps_test()
_proc_macro_does_not_leak_lib_deps_test()
native.test_suite(
name = name,
tests = [
":proc_macro_does_not_leak_deps_test",
":proc_macro_does_not_leak_lib_deps_test",
],
)