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