• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Unittests for rust rules."""
2
3load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
4load("@rules_cc//cc:defs.bzl", "cc_library")
5load("//rust:defs.bzl", "rust_binary", "rust_common", "rust_library", "rust_proc_macro", "rust_shared_library", "rust_static_library")
6
7def _is_dylib_on_windows(ctx):
8    return ctx.target_platform_has_constraint(ctx.attr._windows[platform_common.ConstraintValueInfo])
9
10def _assert_cc_info_has_library_to_link(env, tut, type, ccinfo_count):
11    asserts.true(env, CcInfo in tut, "rust_library should provide CcInfo")
12    cc_info = tut[CcInfo]
13    linker_inputs = cc_info.linking_context.linker_inputs.to_list()
14    asserts.equals(env, ccinfo_count, len(linker_inputs))
15    library_to_link = linker_inputs[0].libraries[0]
16    asserts.equals(env, False, library_to_link.alwayslink)
17
18    asserts.equals(env, [], library_to_link.lto_bitcode_files)
19    asserts.equals(env, [], library_to_link.pic_lto_bitcode_files)
20
21    asserts.equals(env, [], library_to_link.objects)
22    asserts.equals(env, [], library_to_link.pic_objects)
23
24    if type == "cdylib":
25        asserts.true(env, library_to_link.dynamic_library != None)
26        if _is_dylib_on_windows(env.ctx):
27            asserts.true(env, library_to_link.interface_library != None)
28            asserts.true(env, library_to_link.resolved_symlink_dynamic_library == None)
29        else:
30            asserts.equals(env, None, library_to_link.interface_library)
31            asserts.true(env, library_to_link.resolved_symlink_dynamic_library != None)
32        asserts.equals(env, None, library_to_link.resolved_symlink_interface_library)
33        asserts.equals(env, None, library_to_link.static_library)
34        asserts.equals(env, None, library_to_link.pic_static_library)
35    else:
36        asserts.equals(env, None, library_to_link.dynamic_library)
37        asserts.equals(env, None, library_to_link.interface_library)
38        asserts.equals(env, None, library_to_link.resolved_symlink_dynamic_library)
39        asserts.equals(env, None, library_to_link.resolved_symlink_interface_library)
40        asserts.true(env, library_to_link.static_library != None)
41        if type in ("rlib", "lib"):
42            asserts.true(env, library_to_link.static_library.basename.startswith("lib" + tut.label.name))
43        asserts.true(env, library_to_link.pic_static_library != None)
44        asserts.equals(env, library_to_link.static_library, library_to_link.pic_static_library)
45
46def _collect_user_link_flags(env, tut):
47    asserts.true(env, CcInfo in tut, "rust_library should provide CcInfo")
48    cc_info = tut[CcInfo]
49    linker_inputs = cc_info.linking_context.linker_inputs.to_list()
50    return [f for i in linker_inputs for f in i.user_link_flags]
51
52def _rlib_provides_cc_info_test_impl(ctx):
53    env = analysistest.begin(ctx)
54    tut = analysistest.target_under_test(env)
55    _assert_cc_info_has_library_to_link(env, tut, "rlib", 4)
56    return analysistest.end(env)
57
58def _rlib_with_dep_only_has_stdlib_linkflags_once_test_impl(ctx):
59    env = analysistest.begin(ctx)
60    tut = analysistest.target_under_test(env)
61    user_link_flags = _collect_user_link_flags(env, tut)
62    asserts.equals(
63        env,
64        depset(user_link_flags).to_list(),
65        user_link_flags,
66        "user_link_flags_should_not_have_duplicates_here",
67    )
68    return analysistest.end(env)
69
70def _bin_does_not_provide_cc_info_test_impl(ctx):
71    env = analysistest.begin(ctx)
72    tut = analysistest.target_under_test(env)
73    asserts.false(env, CcInfo in tut, "rust_binary should not provide CcInfo")
74    return analysistest.end(env)
75
76def _proc_macro_does_not_provide_cc_info_test_impl(ctx):
77    env = analysistest.begin(ctx)
78    tut = analysistest.target_under_test(env)
79    asserts.false(env, CcInfo in tut, "rust_proc_macro should not provide CcInfo")
80    return analysistest.end(env)
81
82def _cdylib_provides_cc_info_test_impl(ctx):
83    env = analysistest.begin(ctx)
84    tut = analysistest.target_under_test(env)
85    _assert_cc_info_has_library_to_link(env, tut, "cdylib", 2)
86    return analysistest.end(env)
87
88def _staticlib_provides_cc_info_test_impl(ctx):
89    env = analysistest.begin(ctx)
90    tut = analysistest.target_under_test(env)
91    _assert_cc_info_has_library_to_link(env, tut, "staticlib", 2)
92    return analysistest.end(env)
93
94def _crate_group_info_provides_cc_info_test_impl(ctx):
95    env = analysistest.begin(ctx)
96    tut = analysistest.target_under_test(env)
97    asserts.true(
98        env,
99        len(tut[rust_common.dep_info].transitive_noncrates.to_list()) == 1,
100        "crate_group_info should provide 1 non-crate transitive dependency",
101    )
102    return analysistest.end(env)
103
104rlib_provides_cc_info_test = analysistest.make(_rlib_provides_cc_info_test_impl)
105rlib_with_dep_only_has_stdlib_linkflags_once_test = analysistest.make(
106    _rlib_with_dep_only_has_stdlib_linkflags_once_test_impl,
107)
108bin_does_not_provide_cc_info_test = analysistest.make(_bin_does_not_provide_cc_info_test_impl)
109staticlib_provides_cc_info_test = analysistest.make(_staticlib_provides_cc_info_test_impl)
110cdylib_provides_cc_info_test = analysistest.make(_cdylib_provides_cc_info_test_impl, attrs = {
111    "_windows": attr.label(default = Label("@platforms//os:windows")),
112})
113proc_macro_does_not_provide_cc_info_test = analysistest.make(_proc_macro_does_not_provide_cc_info_test_impl)
114
115crate_group_info_provides_cc_info_test = analysistest.make(_crate_group_info_provides_cc_info_test_impl)
116
117def _rust_cc_injection_impl(ctx):
118    dep_variant_info = rust_common.dep_variant_info(
119        cc_info = ctx.attr.cc_dep[CcInfo],
120        crate_info = None,
121        dep_info = None,
122    )
123    return [
124        rust_common.crate_group_info(
125            dep_variant_infos = depset([dep_variant_info]),
126        ),
127    ]
128
129rust_cc_injection = rule(
130    attrs = {
131        "cc_dep": attr.label(
132            providers = [CcInfo],
133        ),
134    },
135    implementation = _rust_cc_injection_impl,
136)
137
138def _cc_info_test():
139    rust_library(
140        name = "rlib",
141        srcs = ["foo.rs"],
142        edition = "2018",
143    )
144
145    rust_library(
146        name = "rlib_with_dep",
147        srcs = ["foo.rs"],
148        edition = "2018",
149        deps = [":rlib"],
150    )
151
152    rust_binary(
153        name = "bin",
154        srcs = ["foo.rs"],
155        edition = "2018",
156    )
157
158    rust_static_library(
159        name = "staticlib",
160        srcs = ["foo.rs"],
161        edition = "2018",
162    )
163
164    rust_shared_library(
165        name = "cdylib",
166        srcs = ["foo.rs"],
167        edition = "2018",
168    )
169
170    rust_proc_macro(
171        name = "proc_macro",
172        srcs = ["proc_macro.rs"],
173        edition = "2018",
174        deps = ["//test/unit/native_deps:native_dep"],
175    )
176
177    cc_library(
178        name = "cc_lib",
179        srcs = ["foo.cc"],
180    )
181
182    rust_cc_injection(
183        name = "cc_lib_injected",
184        cc_dep = ":cc_lib",
185    )
186
187    rust_library(
188        name = "rust_lib_with_cc_lib_injected",
189        srcs = ["foo.rs"],
190        deps = [":cc_lib_injected"],
191        edition = "2018",
192    )
193
194    rlib_provides_cc_info_test(
195        name = "rlib_provides_cc_info_test",
196        target_under_test = ":rlib",
197    )
198    rlib_with_dep_only_has_stdlib_linkflags_once_test(
199        name = "rlib_with_dep_only_has_stdlib_linkflags_once_test",
200        target_under_test = ":rlib_with_dep",
201    )
202    bin_does_not_provide_cc_info_test(
203        name = "bin_does_not_provide_cc_info_test",
204        target_under_test = ":bin",
205    )
206    cdylib_provides_cc_info_test(
207        name = "cdylib_provides_cc_info_test",
208        target_under_test = ":cdylib",
209    )
210    staticlib_provides_cc_info_test(
211        name = "staticlib_provides_cc_info_test",
212        target_under_test = ":staticlib",
213    )
214    proc_macro_does_not_provide_cc_info_test(
215        name = "proc_macro_does_not_provide_cc_info_test",
216        target_under_test = ":proc_macro",
217    )
218    crate_group_info_provides_cc_info_test(
219        name = "crate_group_info_provides_cc_info_test",
220        target_under_test = ":rust_lib_with_cc_lib_injected",
221    )
222
223def cc_info_test_suite(name):
224    """Entry-point macro called from the BUILD file.
225
226    Args:
227        name: Name of the macro.
228    """
229    _cc_info_test()
230
231    native.test_suite(
232        name = name,
233        tests = [
234            ":rlib_provides_cc_info_test",
235            ":rlib_with_dep_only_has_stdlib_linkflags_once_test",
236            ":staticlib_provides_cc_info_test",
237            ":cdylib_provides_cc_info_test",
238            ":proc_macro_does_not_provide_cc_info_test",
239            ":bin_does_not_provide_cc_info_test",
240            ":crate_group_info_provides_cc_info_test",
241        ],
242    )
243