xref: /aosp_15_r20/external/bazelbuild-rules_rust/test/unit/stamp/stamp_test.bzl (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
1"""Unittest to verify workspace status stamping is applied to environment files"""
2
3load("@bazel_skylib//lib:unittest.bzl", "analysistest")
4load("//rust:defs.bzl", "rust_binary", "rust_common", "rust_library", "rust_test")
5load(
6    "//test/unit:common.bzl",
7    "assert_action_mnemonic",
8    "assert_argv_contains",
9    "assert_argv_contains_not",
10)
11
12_STAMP_ATTR_VALUES = (0, 1, -1)
13_BUILD_FLAG_VALUES = ("true", "false")
14
15def _assert_stamped(env, action):
16    assert_argv_contains(env, action, "--volatile-status-file")
17    assert_argv_contains(env, action, "bazel-out/volatile-status.txt")
18
19    assert_argv_contains(env, action, "--stable-status-file")
20    assert_argv_contains(env, action, "bazel-out/stable-status.txt")
21
22def _assert_not_stamped(env, action):
23    assert_argv_contains_not(env, action, "--volatile-status-file")
24    assert_argv_contains_not(env, action, "bazel-out/volatile-status.txt")
25
26    assert_argv_contains_not(env, action, "--stable-status-file")
27    assert_argv_contains_not(env, action, "bazel-out/stable-status.txt")
28
29def _stamp_build_flag_test_impl(ctx, flag_value):
30    env = analysistest.begin(ctx)
31    target = analysistest.target_under_test(env)
32
33    action = target.actions[0]
34    assert_action_mnemonic(env, action, "Rustc")
35
36    is_test = target[rust_common.crate_info].is_test
37    is_bin = target[rust_common.crate_info].type == "bin"
38
39    # bazel build --stamp should lead to stamped rust binaries, but not
40    # libraries and tests.
41    if flag_value:
42        if is_bin and not is_test:
43            _assert_stamped(env, action)
44        else:
45            _assert_not_stamped(env, action)
46    else:
47        _assert_not_stamped(env, action)
48
49    return analysistest.end(env)
50
51def _stamp_build_flag_is_true_impl(ctx):
52    return _stamp_build_flag_test_impl(ctx, True)
53
54def _stamp_build_flag_is_false_impl(ctx):
55    return _stamp_build_flag_test_impl(ctx, False)
56
57stamp_build_flag_is_true_test = analysistest.make(
58    _stamp_build_flag_is_true_impl,
59    config_settings = {
60        "//command_line_option:stamp": True,
61    },
62)
63
64stamp_build_flag_is_false_test = analysistest.make(
65    _stamp_build_flag_is_false_impl,
66    config_settings = {
67        "//command_line_option:stamp": False,
68    },
69)
70
71def _build_flag_tests():
72    tests = []
73    for stamp_value in _BUILD_FLAG_VALUES:
74        if stamp_value == "true":
75            name = "default_with_build_flag_on"
76            features = ["always_stamp"]
77            build_flag_stamp_test = stamp_build_flag_is_true_test
78        else:
79            name = "default_with_build_flag_off"
80            features = ["never_stamp"]
81            build_flag_stamp_test = stamp_build_flag_is_false_test
82
83        rust_library(
84            name = "{}_lib".format(name),
85            srcs = ["stamp.rs"],
86            rustc_env_files = ["stamp.env"],
87            edition = "2018",
88            # Building with --stamp should not affect rust libraries
89            crate_features = ["never_stamp"],
90        )
91
92        rust_binary(
93            name = "{}_bin".format(name),
94            srcs = ["stamp_main.rs"],
95            edition = "2018",
96            deps = ["{}_lib".format(name)],
97            rustc_env_files = ["stamp.env"],
98            crate_features = features,
99        )
100
101        rust_test(
102            name = "{}_test".format(name),
103            crate = "{}_lib".format(name),
104            edition = "2018",
105            rustc_env_files = ["stamp.env"],
106            # Building with --stamp should not affect tests
107            crate_features = ["never_stamp"],
108        )
109
110        build_flag_stamp_test(
111            name = "lib_{}_test".format(name),
112            target_under_test = "{}_lib".format(name),
113        )
114        build_flag_stamp_test(
115            name = "bin_{}_test".format(name),
116            target_under_test = "{}_bin".format(name),
117        )
118
119        build_flag_stamp_test(
120            name = "test_{}_test".format(name),
121            target_under_test = "{}_test".format(name),
122        )
123
124        tests.extend([
125            "lib_{}_test".format(name),
126            "bin_{}_test".format(name),
127            "test_{}_test".format(name),
128        ])
129    return tests
130
131def _attribute_stamp_test_impl(ctx, attribute_value, build_flag_value):
132    env = analysistest.begin(ctx)
133    target = analysistest.target_under_test(env)
134
135    action = target.actions[0]
136    assert_action_mnemonic(env, action, "Rustc")
137
138    if attribute_value == 1:
139        _assert_stamped(env, action)
140    elif attribute_value == 0:
141        _assert_not_stamped(env, action)
142    elif build_flag_value:
143        _assert_stamped(env, action)
144    else:
145        _assert_not_stamped(env, action)
146
147    return analysistest.end(env)
148
149def _always_stamp_build_flag_is_true_test_impl(ctx):
150    return _attribute_stamp_test_impl(ctx, attribute_value = 1, build_flag_value = True)
151
152def _always_stamp_build_flag_is_false_test_impl(ctx):
153    return _attribute_stamp_test_impl(ctx, attribute_value = 1, build_flag_value = False)
154
155def _never_stamp_build_flag_is_true_test_impl(ctx):
156    return _attribute_stamp_test_impl(ctx, attribute_value = 0, build_flag_value = True)
157
158def _never_stamp_build_flag_is_false_test_impl(ctx):
159    return _attribute_stamp_test_impl(ctx, attribute_value = 0, build_flag_value = False)
160
161def _consult_build_flag_value_is_true_test_impl(ctx):
162    return _attribute_stamp_test_impl(ctx, attribute_value = -1, build_flag_value = True)
163
164def _consult_build_flag_value_is_false_test_impl(ctx):
165    return _attribute_stamp_test_impl(ctx, attribute_value = -1, build_flag_value = False)
166
167always_stamp_test_build_flag_is_true_test = analysistest.make(
168    _always_stamp_build_flag_is_true_test_impl,
169    config_settings = {
170        "//command_line_option:stamp": True,
171    },
172)
173
174always_stamp_test_build_flag_is_false_test = analysistest.make(
175    _always_stamp_build_flag_is_false_test_impl,
176    config_settings = {
177        "//command_line_option:stamp": False,
178    },
179)
180
181never_stamp_test_build_flag_is_true_test = analysistest.make(
182    _never_stamp_build_flag_is_true_test_impl,
183    config_settings = {
184        "//command_line_option:stamp": True,
185    },
186)
187
188never_stamp_test_build_flag_is_false_test = analysistest.make(
189    _never_stamp_build_flag_is_false_test_impl,
190    config_settings = {
191        "//command_line_option:stamp": False,
192    },
193)
194
195consult_build_flag_value_is_true_test = analysistest.make(
196    _consult_build_flag_value_is_true_test_impl,
197    config_settings = {
198        "//command_line_option:stamp": True,
199    },
200)
201
202consult_build_flag_value_is_false_test = analysistest.make(
203    _consult_build_flag_value_is_false_test_impl,
204    config_settings = {
205        "//command_line_option:stamp": False,
206    },
207)
208
209def _stamp_attribute_tests():
210    tests = []
211
212    for stamp_value in _STAMP_ATTR_VALUES:
213        for flag_value in _BUILD_FLAG_VALUES:
214            if stamp_value == 1:
215                name = "always_stamp_build_flag_{}".format(flag_value)
216                features = ["always_stamp_build_flag_{}".format(flag_value)]
217                stamp_attr_test = always_stamp_test_build_flag_is_true_test if flag_value == "true" else always_stamp_test_build_flag_is_false_test
218            elif stamp_value == 0:
219                name = "never_stamp_build_flag_{}".format(flag_value)
220                features = ["never_stamp_build_flag_{}".format(flag_value)]
221                stamp_attr_test = never_stamp_test_build_flag_is_true_test if flag_value == "true" else never_stamp_test_build_flag_is_false_test
222            else:
223                name = "consult_cmdline_value_is_{}".format(flag_value)
224                features = ["consult_cmdline_value_is_{}".format(flag_value)]
225                stamp_attr_test = consult_build_flag_value_is_true_test if flag_value == "true" else consult_build_flag_value_is_false_test
226
227            rust_library(
228                name = "{}_lib".format(name),
229                srcs = ["stamp.rs"],
230                edition = "2018",
231                rustc_env_files = [":stamp.env"],
232                stamp = stamp_value,
233                crate_features = features,
234            )
235
236            rust_test(
237                name = "{}_unit_test".format(name),
238                crate = ":{}_lib".format(name),
239                edition = "2018",
240                rustc_env_files = [":stamp.env"],
241                stamp = stamp_value,
242                crate_features = features,
243                # We disable this test so that it doesn't try to run with bazel test //test/...
244                # The reason for this is because then it is sensitive to the --stamp value which
245                # we override in the unit test implementation.
246                tags = ["manual"],
247            )
248
249            rust_binary(
250                name = "{}_bin".format(name),
251                srcs = ["stamp_main.rs"],
252                edition = "2018",
253                deps = [":{}_lib".format(name)],
254                rustc_env_files = [":stamp.env"],
255                stamp = stamp_value,
256                crate_features = features,
257            )
258
259            stamp_attr_test(
260                name = "lib_{}_test".format(name),
261                target_under_test = "{}_lib".format(name),
262            )
263            stamp_attr_test(
264                name = "bin_{}_test".format(name),
265                target_under_test = "{}_bin".format(name),
266            )
267
268            stamp_attr_test(
269                name = "test_{}_test".format(name),
270                target_under_test = "{}_unit_test".format(name),
271            )
272
273            tests.extend([
274                "lib_{}_test".format(name),
275                "bin_{}_test".format(name),
276                "test_{}_test".format(name),
277            ])
278    return tests
279
280def _process_wrapper_with_stamp_test_impl(ctx):
281    env = analysistest.begin(ctx)
282    target = analysistest.target_under_test(env)
283
284    action = target.actions[0]
285    assert_action_mnemonic(env, action, "Rustc")
286
287    _assert_not_stamped(env, action)
288
289    return analysistest.end(env)
290
291process_wrapper_with_stamp_test = analysistest.make(
292    _process_wrapper_with_stamp_test_impl,
293    config_settings = {
294        "//command_line_option:stamp": True,
295    },
296)
297
298def _process_wrapper_tests():
299    process_wrapper_with_stamp_test(
300        name = "test_process_wrapper_with_stamp_test",
301        target_under_test = "//util/process_wrapper:process_wrapper",
302    )
303
304    return ["test_process_wrapper_with_stamp_test"]
305
306def stamp_test_suite(name):
307    """Entry-point macro called from the BUILD file.
308
309    Args:
310        name (str): Name of the macro.
311    """
312    tests = _build_flag_tests() + _stamp_attribute_tests() + _process_wrapper_tests()
313
314    native.test_suite(
315        name = name,
316        tests = tests,
317    )
318