xref: /aosp_15_r20/build/bazel/rules/gensrcs_test.bzl (revision 7594170e27e0732bc44b93d1440d87a54b6ffe7c)
1# Copyright (C) 2022 The Android Open Source Project
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
15load("@bazel_skylib//lib:new_sets.bzl", "sets")
16load("@bazel_skylib//lib:paths.bzl", "paths")
17load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
18load("//build/bazel/rules:gensrcs.bzl", "gensrcs")
19
20SRCS = [
21    "texts/src1.txt",
22    "texts/src2.txt",
23    "src3.txt",
24]
25
26OUTPUT_EXTENSION = "out"
27
28EXPECTED_OUTS = [
29    "texts/src1.out",
30    "texts/src2.out",
31    "src3.out",
32]
33
34# ==== Check the actions created by gensrcs ====
35
36def _test_actions_impl(ctx):
37    env = analysistest.begin(ctx)
38    target = analysistest.target_under_test(env)
39    actions = analysistest.target_actions(env)
40
41    # Expect an action for each pair of input/output file
42    asserts.equals(env, expected = len(SRCS), actual = len(actions))
43
44    package = target.label.package
45    data_paths = [paths.join(package, d) for d in ctx.attr.data]
46    data_set = sets.make(data_paths)
47    for action in actions:
48        for d in data_paths:
49            asserts.true(
50                env,
51                d in " ".join(action.argv),
52                "Expected data file %s to be in command %s" % (d, action.argv),
53            )
54        inputs = sets.make([i.path for i in action.inputs.to_list()])
55        asserts.true(
56            env,
57            sets.is_subset(data_set, inputs),
58            "Expected %s to be a subset of all inputs %s" % (data_set, inputs),
59        )
60
61    asserts.set_equals(
62        env,
63        sets.make([
64            # given an input file build/bazel/rules/texts/src1.txt
65            # the corresponding output file is
66            # <GENDIR>/build/bazel/rules/build/bazel/rules/texts/src1.out
67            # the second "build/bazel/rules" is to accomodate the srcs from
68            # external package
69            paths.join(
70                ctx.genfiles_dir.path,
71                "build/bazel/rules",
72                "build/bazel/rules",
73                out,
74            )
75            for out in EXPECTED_OUTS
76        ]),
77        sets.make([file.path for file in target.files.to_list()]),
78    )
79
80    return analysistest.end(env)
81
82actions_test = analysistest.make(
83    _test_actions_impl,
84    attrs = {
85        "data": attr.string_list(),
86    },
87)
88
89def _test_actions():
90    name = "gensrcs_output_paths"
91    test_name = name + "_test"
92    data = ["foo/bar.txt", "baz.txt"]
93
94    # Rule under test
95    gensrcs(
96        name = name,
97        cmd = "cat $(SRC) > $(OUT) && cat $(location foo/bar.txt) >> $(OUT) && cat $(location baz.txt) >> $(OUT)",
98        srcs = SRCS,
99        output_extension = OUTPUT_EXTENSION,
100        data = data,
101        tags = ["manual"],  # make sure it's not built using `:all`
102    )
103
104    actions_test(
105        name = test_name,
106        target_under_test = name,
107        data = data,
108    )
109    return test_name
110
111# ==== Check the output file when out_extension is unset ====
112
113def _test_unset_output_extension_impl(ctx):
114    env = analysistest.begin(ctx)
115
116    actions = analysistest.target_actions(env)
117    asserts.equals(env, expected = 1, actual = len(actions))
118    action = actions[0]
119    asserts.equals(
120        env,
121        expected = "input.",
122        actual = action.outputs.to_list()[0].basename,
123    )
124
125    return analysistest.end(env)
126
127unset_output_extension_test = analysistest.make(_test_unset_output_extension_impl)
128
129def _test_unset_output_extension():
130    name = "unset_output_extension"
131    test_name = name + "_test"
132
133    # Rule under test
134    gensrcs(
135        name = "TSTSS",
136        cmd = "cat $(SRC) > $(OUT)",
137        srcs = ["input.txt"],
138        tags = ["manual"],  # make sure it's not built using `:all`
139    )
140
141    unset_output_extension_test(
142        name = test_name,
143        target_under_test = "TSTSS",
144    )
145    return test_name
146
147TOOL_FILE_NAME = "out.sh"
148
149def _test_gensrcs_tool_builds_for_host_impl(ctx):
150    env = analysistest.begin(ctx)
151    actions = analysistest.target_actions(env)
152    asserts.equals(env, expected = 1, actual = len(actions), msg = "expected actions")
153
154    action = actions[0]
155    inputs = action.inputs.to_list()
156    asserts.equals(env, expected = 2, actual = len(inputs), msg = "expected inputs")
157
158    input_map = {}
159    for i in inputs:
160        input_map[i.basename] = i
161    tool = input_map[TOOL_FILE_NAME]
162    asserts.true(
163        env,
164        # because we set --experimental_platform_in_output_dir, we expect the
165        # platform to be in the output path of a generated file
166        "linux" in tool.path,  # host platform
167        "expected 'linux' in tool path, got '%s'" % tool.path,
168    )
169
170    outputs = action.outputs.to_list()
171    asserts.equals(env, expected = 1, actual = len(outputs), msg = "expected outputs %s" % outputs)
172    output = outputs[0]
173    asserts.true(
174        env,
175        # because we set --experimental_platform_in_output_dir, we expect the
176        # platform to be in the output path of a generated file. However, the platform
177        # will be the android product name, like aosp_arm, so we can't check if anything
178        # in particular is in the path. Check that linux is not in the path instead.
179        "linux" not in output.path,  # target platform
180        "expected 'linux' to not be in output path, got '%s'" % output.path,
181    )
182
183    return analysistest.end(env)
184
185__gensrcs_tool_builds_for_host_test = analysistest.make(
186    _test_gensrcs_tool_builds_for_host_impl,
187)
188
189def _gensrcs_tool_builds_for_host_test(**kwargs):
190    __gensrcs_tool_builds_for_host_test(
191        target_compatible_with = ["//build/bazel_common_rules/platforms/os:android"],  # ensure target != host so there is a transition
192        **kwargs
193    )
194
195def _test_gensrcs_tool_builds_for_host():
196    native.genrule(
197        name = "gensrcs_test_bin",
198        outs = [TOOL_FILE_NAME],
199        executable = True,
200        cmd = "touch $@",
201        target_compatible_with = select({
202            # only supported OS is that specified as host_platform
203            "//build/bazel_common_rules/platforms/os:linux": [],
204            "//conditions:default": ["@platforms//:incompatible"],
205        }),
206        tags = ["manual"],
207    )
208
209    gensrcs(
210        name = "gensrcs_test_tool_builds_for_host",
211        tools = [":gensrcs_test_bin"],
212        srcs = ["input.txt"],
213        output_extension = OUTPUT_EXTENSION,
214        cmd = "",
215        tags = ["manual"],
216    )
217
218    test_name = "gensrcs_tools_build_for_host_test"
219    _gensrcs_tool_builds_for_host_test(
220        name = test_name,
221        target_under_test = ":gensrcs_test_tool_builds_for_host",
222    )
223    return test_name
224
225def gensrcs_tests_suite(name):
226    """Creates test targets for gensrcs.bzl"""
227    native.test_suite(
228        name = name,
229        tests = [
230            _test_actions(),
231            _test_unset_output_extension(),
232            _test_gensrcs_tool_builds_for_host(),
233        ],
234    )
235