xref: /aosp_15_r20/external/bazel-skylib/tests/unittest_tests.bzl (revision bcb5dc7965af6ee42bf2f21341a2ec00233a8c8a)
1# Copyright 2019 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#    http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Unit tests for unittest.bzl."""
16
17load("//lib:partial.bzl", "partial")
18load("//lib:unittest.bzl", "analysistest", "asserts", "loadingtest", "unittest")
19
20###################################
21####### basic_failing_test ########
22###################################
23
24def _basic_failing_test(ctx):
25    """Unit tests for a basic library verification test that fails."""
26    env = unittest.begin(ctx)
27
28    asserts.equals(env, 1, 2)
29
30    return unittest.end(env)
31
32basic_failing_test = unittest.make(_basic_failing_test)
33
34###################################
35####### failure_message_test ######
36###################################
37
38def _failure_message_test(ctx):
39    """Failing unit test with arbitrary content in the message."""
40    env = unittest.begin(ctx)
41
42    if not ctx.attr.message:
43        unittest.fail(env, "Message must be non-empty.")
44    asserts.equals(env, "", ctx.attr.message)
45
46    return unittest.end(env)
47
48failure_message_test = unittest.make(
49    _failure_message_test,
50    attrs = {
51        "message": attr.string(),
52    },
53)
54
55###################################
56####### basic_passing_test ########
57###################################
58def _basic_passing_test(ctx):
59    """Unit tests for a basic library verification test."""
60    env = unittest.begin(ctx)
61
62    asserts.equals(env, 1, 1)
63
64    return unittest.end(env)
65
66basic_passing_test = unittest.make(_basic_passing_test)
67
68#################################################
69####### basic_passing_short_timeout_test ########
70#################################################
71def _basic_passing_short_timeout_test(ctx):
72    """Unit tests for a basic library verification test."""
73    env = unittest.begin(ctx)
74
75    asserts.equals(env, ctx.attr.timeout, "short")
76
77    return unittest.end(env)
78
79basic_passing_short_timeout_test = unittest.make(_basic_passing_short_timeout_test)
80
81###################################
82####### change_setting_test #######
83###################################
84def _change_setting_test(ctx):
85    """Test to verify that an analysis test may change configuration."""
86    env = analysistest.begin(ctx)
87
88    dep_min_os_version = analysistest.target_under_test(env)[_ChangeSettingInfo].min_os_version
89    asserts.equals(env, "1234.5678", dep_min_os_version)
90
91    return analysistest.end(env)
92
93_ChangeSettingInfo = provider(
94    doc = "min_os_version for change_setting_test",
95    fields = ["min_os_version"],
96)
97
98def _change_setting_fake_rule(ctx):
99    return [_ChangeSettingInfo(min_os_version = ctx.fragments.cpp.minimum_os_version())]
100
101change_setting_fake_rule = rule(
102    implementation = _change_setting_fake_rule,
103    fragments = ["cpp"],
104)
105
106change_setting_test = analysistest.make(
107    _change_setting_test,
108    config_settings = {
109        "//command_line_option:minimum_os_version": "1234.5678",
110    },
111)
112
113####################################
114####### failure_testing_test #######
115####################################
116def _failure_testing_test(ctx):
117    """Test to verify that an analysis test may verify a rule fails with fail()."""
118    env = analysistest.begin(ctx)
119
120    asserts.expect_failure(env, "This rule should never work")
121
122    return analysistest.end(env)
123
124def _failure_testing_fake_rule(ctx):
125    _ignore = [ctx]  # @unused
126    fail("This rule should never work")
127
128failure_testing_fake_rule = rule(
129    implementation = _failure_testing_fake_rule,
130)
131
132failure_testing_test = analysistest.make(
133    _failure_testing_test,
134    expect_failure = True,
135)
136
137############################################
138####### fail_unexpected_passing_test #######
139############################################
140def _fail_unexpected_passing_test(ctx):
141    """Test that fails by expecting an error that never occurs."""
142    env = analysistest.begin(ctx)
143
144    asserts.expect_failure(env, "Oh no, going to fail")
145
146    return analysistest.end(env)
147
148def _fail_unexpected_passing_fake_rule(ctx):
149    _ignore = [ctx]  # @unused
150    return []
151
152fail_unexpected_passing_fake_rule = rule(
153    implementation = _fail_unexpected_passing_fake_rule,
154)
155
156fail_unexpected_passing_test = analysistest.make(
157    _fail_unexpected_passing_test,
158    expect_failure = True,
159)
160
161################################################
162####### change_setting_with_failure_test #######
163################################################
164def _change_setting_with_failure_test(ctx):
165    """Test verifying failure while changing configuration."""
166    env = analysistest.begin(ctx)
167
168    asserts.expect_failure(env, "unexpected minimum_os_version!!!")
169
170    return analysistest.end(env)
171
172def _change_setting_with_failure_fake_rule(ctx):
173    if ctx.fragments.cpp.minimum_os_version() == "error_error":
174        fail("unexpected minimum_os_version!!!")
175    return []
176
177change_setting_with_failure_fake_rule = rule(
178    implementation = _change_setting_with_failure_fake_rule,
179    fragments = ["cpp"],
180)
181
182change_setting_with_failure_test = analysistest.make(
183    _change_setting_with_failure_test,
184    expect_failure = True,
185    config_settings = {
186        "//command_line_option:minimum_os_version": "error_error",
187    },
188)
189
190####################################
191####### inspect_actions_test #######
192####################################
193def _inspect_actions_test(ctx):
194    """Test verifying actions registered by a target."""
195    env = analysistest.begin(ctx)
196
197    actions = analysistest.target_actions(env)
198    asserts.equals(env, 1, len(actions))
199    action_output = actions[0].outputs.to_list()[0]
200    asserts.equals(env, "out.txt", action_output.basename)
201    return analysistest.end(env)
202
203def _inspect_actions_fake_rule(ctx):
204    out_file = ctx.actions.declare_file("out.txt")
205    ctx.actions.run_shell(
206        command = "echo 'hello' > %s" % out_file.basename,
207        outputs = [out_file],
208    )
209    return [DefaultInfo(files = depset([out_file]))]
210
211inspect_actions_fake_rule = rule(
212    implementation = _inspect_actions_fake_rule,
213)
214
215inspect_actions_test = analysistest.make(
216    _inspect_actions_test,
217)
218
219####################################
220####### inspect_aspect_test #######
221####################################
222_AddedByAspectInfo = provider(
223    doc = "Example provider added by example aspect",
224    fields = {
225        "value": "(str)",
226    },
227)
228
229def _example_aspect_impl(target, ctx):
230    _ignore = [target, ctx]  # @unused
231    return [
232        _AddedByAspectInfo(value = "attached by aspect"),
233    ]
234
235example_aspect = aspect(
236    implementation = _example_aspect_impl,
237)
238
239def _inspect_aspect_test(ctx):
240    """Test verifying aspect run on a target."""
241    env = analysistest.begin(ctx)
242
243    tut = env.ctx.attr.target_under_test
244    asserts.equals(env, "attached by aspect", tut[_AddedByAspectInfo].value)
245    return analysistest.end(env)
246
247def _inspect_aspect_fake_rule(ctx):
248    out_file = ctx.actions.declare_file("out.txt")
249    ctx.actions.run_shell(
250        command = "echo 'hello' > %s" % out_file.basename,
251        outputs = [out_file],
252    )
253    return [DefaultInfo(files = depset([out_file]))]
254
255inspect_aspect_fake_rule = rule(
256    implementation = _inspect_aspect_fake_rule,
257)
258
259inspect_aspect_test = analysistest.make(
260    _inspect_aspect_test,
261    extra_target_under_test_aspects = [example_aspect],
262)
263
264########################################
265####### inspect_output_dirs_test #######
266########################################
267_OutputDirInfo = provider(
268    doc = "bin_path for inspect_output_dirs_test",
269    fields = ["bin_path"],
270)
271
272def _inspect_output_dirs_test(ctx):
273    """Test verifying output directories used by a test."""
274    env = analysistest.begin(ctx)
275
276    # Assert that the output bin dir observed by the aspect added by analysistest
277    # is the same as those observed by the rule directly, even when that's
278    # under a config transition and therefore not the same as the bin dir
279    # used by the test rule.
280    bin_path = analysistest.target_bin_dir_path(env)
281    target_under_test = analysistest.target_under_test(env)
282    asserts.false(env, not bin_path, "bin dir path not found.")
283    asserts.false(
284        env,
285        bin_path == ctx.bin_dir.path,
286        "test bin dir (%s) expected to differ with target_under_test bin dir (%s)." % (bin_path, ctx.bin_dir.path),
287    )
288    asserts.equals(env, bin_path, target_under_test[_OutputDirInfo].bin_path)
289    return analysistest.end(env)
290
291def _inspect_output_dirs_fake_rule(ctx):
292    return [
293        _OutputDirInfo(
294            bin_path = ctx.bin_dir.path,
295        ),
296    ]
297
298inspect_output_dirs_fake_rule = rule(
299    implementation = _inspect_output_dirs_fake_rule,
300)
301
302inspect_output_dirs_test = analysistest.make(
303    _inspect_output_dirs_test,
304    # The output directories differ between the test and target under test when
305    # the target under test is under a config transition.
306    config_settings = {
307        "//command_line_option:minimum_os_version": "1234.5678",
308    },
309)
310
311def _loading_phase_test(env):
312    loadingtest.equals(env, "self_glob", ["unittest_tests.bzl"], native.glob(["unittest_tests.bzl"]))
313
314    # now use our own calls to assert we created a test case rule and test_suite for it.
315    loadingtest.equals(env, "test_exists", True, native.existing_rule(env.name + "_self_glob") != None)
316    loadingtest.equals(env, "suite_exists", True, native.existing_rule(env.name + "_tests") != None)
317
318#########################################
319
320# buildifier: disable=unnamed-macro
321def unittest_passing_tests_suite():
322    """Creates the test targets and test suite for passing unittest.bzl tests.
323
324    Not all tests are included. Some unittest.bzl tests verify a test fails
325    when assertions are not met. Such tests must be run in an e2e shell test.
326    This suite only includes tests which verify success tests.
327    """
328    unittest.suite(
329        "unittest_tests",
330        basic_passing_test,
331        partial.make(basic_passing_short_timeout_test, timeout = "short"),
332    )
333
334    change_setting_test(
335        name = "change_setting_test",
336        target_under_test = ":change_setting_fake_target",
337    )
338    change_setting_fake_rule(
339        name = "change_setting_fake_target",
340        tags = ["manual"],
341    )
342
343    failure_testing_test(
344        name = "failure_testing_test",
345        target_under_test = ":failure_testing_fake_target",
346    )
347    failure_testing_fake_rule(
348        name = "failure_testing_fake_target",
349        tags = ["manual"],
350    )
351
352    change_setting_with_failure_test(
353        name = "change_setting_with_failure_test",
354        target_under_test = ":change_setting_with_failure_fake_target",
355    )
356    change_setting_with_failure_fake_rule(
357        name = "change_setting_with_failure_fake_target",
358        tags = ["manual"],
359    )
360
361    inspect_actions_test(
362        name = "inspect_actions_test",
363        target_under_test = ":inspect_actions_fake_target",
364    )
365    inspect_actions_fake_rule(
366        name = "inspect_actions_fake_target",
367        tags = ["manual"],
368    )
369
370    inspect_aspect_test(
371        name = "inspect_aspect_test",
372        target_under_test = ":inspect_aspect_fake_target",
373    )
374    inspect_aspect_fake_rule(
375        name = "inspect_aspect_fake_target",
376        tags = ["manual"],
377    )
378
379    inspect_output_dirs_test(
380        name = "inspect_output_dirs_test",
381        target_under_test = ":inspect_output_dirs_fake_target",
382    )
383    inspect_output_dirs_fake_rule(
384        name = "inspect_output_dirs_fake_target",
385        tags = ["manual"],
386    )
387
388    loading_env = loadingtest.make("selftest")
389    _loading_phase_test(loading_env)
390