xref: /aosp_15_r20/external/bazelbuild-rules_testing/tests/analysis_test_tests.bzl (revision d605057434dcabba796c020773aab68d9790ff9f)
1# Copyright 2022 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 analysis_test.bzl."""
16
17load("//lib:analysis_test.bzl", "analysis_test", "test_suite")
18load("//lib:truth.bzl", "matching")
19load("//lib:util.bzl", "TestingAspectInfo")
20
21###################################
22####### change_setting_test #######
23###################################
24
25_ChangeSettingInfo = provider(
26    doc = "min_os_version for change_setting_test",
27    fields = ["min_os_version"],
28)
29
30def _change_setting_fake_rule(ctx):
31    return [_ChangeSettingInfo(min_os_version = ctx.fragments.cpp.minimum_os_version())]
32
33change_setting_fake_rule = rule(
34    implementation = _change_setting_fake_rule,
35    fragments = ["cpp"],
36)
37
38def test_change_setting(name):
39    """Test to verify that an analysis test may change configuration."""
40    change_setting_fake_rule(name = name + "_fake_target", tags = ["manual"])
41
42    analysis_test(
43        name = name,
44        target = name + "_fake_target",
45        impl = _test_change_setting,
46        config_settings = {
47            "//command_line_option:minimum_os_version": "1234.5678",
48        },
49    )
50
51def _test_change_setting(env, target):
52    dep_min_os_version = target[_ChangeSettingInfo].min_os_version
53    env.expect.that_str(dep_min_os_version).equals("1234.5678")
54
55####################################
56####### failure_testing_test #######
57####################################
58
59def _failure_testing_fake_rule(_ctx):
60    fail("This rule should never work")
61
62failure_testing_fake_rule = rule(
63    implementation = _failure_testing_fake_rule,
64)
65
66def test_failure_testing(name):
67    """Test to verify that an analysis test may verify a rule fails with fail()."""
68    failure_testing_fake_rule(name = name + "_fake_target", tags = ["manual"])
69
70    analysis_test(
71        name = name,
72        target = name + "_fake_target",
73        impl = _test_failure_testing,
74        expect_failure = True,
75    )
76
77def _test_failure_testing(env, target):
78    env.expect.that_target(target).failures().contains_predicate(matching.contains("This rule should never work"))
79
80############################################
81####### fail_unexpected_passing_test #######
82############################################
83
84def _fail_unexpected_passing_fake_rule(_ctx):
85    return []
86
87fail_unexpected_passing_fake_rule = rule(
88    implementation = _fail_unexpected_passing_fake_rule,
89)
90
91# @unused # TODO(ilist): add a shell test checking it fails
92def test_fail_unexpected_passing(name):
93    """Test that fails by expecting an error that never occurs."""
94    fail_unexpected_passing_fake_rule(name = name + "_fake_target", tags = ["manual"])
95
96    analysis_test(
97        name = name,
98        target = name + "_fake_target",
99        impl = _test_fail_unexpected_passing,
100        expect_failure = True,
101    )
102
103def _test_fail_unexpected_passing(env, target):
104    env.expect.that_target(target).failures().contains_predicate(matching.contains("Oh no, going to fail"))
105
106################################################
107####### change_setting_with_failure_test #######
108################################################
109def _change_setting_with_failure_fake_rule(ctx):
110    if ctx.fragments.cpp.minimum_os_version() == "error_error":
111        fail("unexpected minimum_os_version!!!")
112    return []
113
114change_setting_with_failure_fake_rule = rule(
115    implementation = _change_setting_with_failure_fake_rule,
116    fragments = ["cpp"],
117)
118
119def test_change_setting_with_failure(name):
120    change_setting_with_failure_fake_rule(name = name + "_fake_target", tags = ["manual"])
121
122    analysis_test(
123        name = name,
124        target = name + "_fake_target",
125        impl = _test_change_setting_with_failure,
126        expect_failure = True,
127        config_settings = {
128            "//command_line_option:minimum_os_version": "error_error",
129        },
130    )
131
132def _test_change_setting_with_failure(env, target):
133    """Test verifying failure while changing configuration."""
134    env.expect.that_target(target).failures().contains_predicate(
135        matching.contains("unexpected minimum_os_version!!!"),
136    )
137
138####################################
139####### inspect_actions_test #######
140####################################
141def _inspect_actions_fake_rule(ctx):
142    out_file = ctx.actions.declare_file("out.txt")
143    ctx.actions.run_shell(
144        command = "echo 'hello' > %s" % out_file.basename,
145        outputs = [out_file],
146    )
147    return [DefaultInfo(files = depset([out_file]))]
148
149inspect_actions_fake_rule = rule(implementation = _inspect_actions_fake_rule)
150
151def test_inspect_actions(name):
152    """Test verifying actions registered by a target."""
153    inspect_actions_fake_rule(name = name + "_fake_target", tags = ["manual"])
154
155    analysis_test(name = name, target = name + "_fake_target", impl = _test_inspect_actions)
156
157def _test_inspect_actions(env, target):
158    env.expect.that_int(len(target[TestingAspectInfo].actions)).equals(1)
159    action_output = target[TestingAspectInfo].actions[0].outputs.to_list()[0]
160    env.expect.that_str(action_output.basename).equals("out.txt")
161
162####################################
163####### inspect_aspect_test #######
164####################################
165_AddedByAspectInfo = provider(
166    doc = "Example provider added by example aspect",
167    fields = {"value": "(str)"},
168)
169
170def _example_aspect_impl(_target, _ctx):
171    return [_AddedByAspectInfo(value = "attached by aspect")]
172
173example_aspect = aspect(implementation = _example_aspect_impl)
174
175def _inspect_aspect_fake_rule(ctx):
176    out_file = ctx.actions.declare_file("out.txt")
177    ctx.actions.run_shell(
178        command = "echo 'hello' > %s" % out_file.basename,
179        outputs = [out_file],
180    )
181    return [DefaultInfo(files = depset([out_file]))]
182
183inspect_aspect_fake_rule = rule(implementation = _inspect_aspect_fake_rule)
184
185def test_inspect_aspect(name):
186    """Test verifying aspect run on a target."""
187    inspect_aspect_fake_rule(name = name + "_fake_target", tags = ["manual"])
188
189    analysis_test(
190        name = name,
191        target = name + "_fake_target",
192        impl = _test_inspect_aspect,
193        extra_target_under_test_aspects = [example_aspect],
194    )
195
196def _test_inspect_aspect(env, target):
197    env.expect.that_str(target[_AddedByAspectInfo].value).equals("attached by aspect")
198
199########################################
200####### inspect_output_dirs_test #######
201########################################
202_OutputDirInfo = provider(
203    doc = "bin_path for inspect_output_dirs_test",
204    fields = ["bin_path"],
205)
206
207def _inspect_output_dirs_fake_rule(ctx):
208    return [_OutputDirInfo(bin_path = ctx.bin_dir.path)]
209
210inspect_output_dirs_fake_rule = rule(implementation = _inspect_output_dirs_fake_rule)
211
212########################################
213####### common_attributes_test #######
214########################################
215
216def _test_common_attributes(name):
217    native.filegroup(name = name + "_subject")
218    _toolchain_template_vars(name = name + "_toolchain_template_vars")
219    analysis_test(
220        name = name,
221        impl = _test_common_attributes_impl,
222        target = name + "_subject",
223        attr_values = dict(
224            features = ["some-feature"],
225            tags = ["taga", "tagb"],
226            visibility = ["//visibility:private"],
227            toolchains = [name + "_toolchain_template_vars"],
228            # An empty list means "compatible with everything"
229            target_compatible_with = [],
230        ),
231    )
232
233def _test_common_attributes_impl(env, target):
234    _ = target  # @unused
235    ctx = env.ctx
236    expect = env.expect
237
238    expect.that_collection(ctx.attr.tags).contains_at_least(["taga", "tagb"])
239
240    expect.that_collection(ctx.attr.features).contains_exactly(["some-feature"])
241
242    expect.that_collection(ctx.attr.visibility).contains_exactly([
243        Label("//visibility:private"),
244    ])
245
246    expect.that_collection(ctx.attr.target_compatible_with).contains_exactly([])
247
248    expanded = ctx.expand_make_variables("cmd", "$(key)", {})
249    expect.that_str(expanded).equals("value")
250
251def _toolchain_template_vars_impl(ctx):
252    _ = ctx  # @unused
253    return [platform_common.TemplateVariableInfo({"key": "value"})]
254
255_toolchain_template_vars = rule(implementation = _toolchain_template_vars_impl)
256
257def analysis_test_test_suite(name):
258    test_suite(
259        name = name,
260        tests = [
261            test_change_setting,
262            _test_common_attributes,
263            test_failure_testing,
264            test_change_setting_with_failure,
265            test_inspect_actions,
266            test_inspect_aspect,
267        ],
268    )
269