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