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:paths.bzl", "paths") 16load("@bazel_skylib//lib:sets.bzl", "sets") 17load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") 18 19def _assert_flags_present_in_action(env, action, expected_flags): 20 if action.argv == None: 21 asserts.true( 22 env, 23 False, 24 "expected %s action to have arguments, but argv was None" % ( 25 action.mnemonic, 26 ), 27 ) 28 return 29 for flag in expected_flags: 30 asserts.true( 31 env, 32 flag in action.argv, 33 "%s action did not contain flag %s; argv: %s" % ( 34 action.mnemonic, 35 flag, 36 action.argv, 37 ), 38 ) 39 40# Checks for the presence of a set of given flags in a set of given actions 41# non-exclusively. In other words, it confirms that the specified actions 42# contain the given flags, but does not confirm that other actions do not 43# contain them. 44def _action_flags_present_for_mnemonic_nonexclusive_test_impl(ctx): 45 env = analysistest.begin(ctx) 46 47 for action in analysistest.target_actions(env): 48 if action.mnemonic in ctx.attr.mnemonics: 49 _assert_flags_present_in_action( 50 env, 51 action, 52 ctx.attr.expected_flags, 53 ) 54 55 return analysistest.end(env) 56 57action_flags_present_for_mnemonic_nonexclusive_test = analysistest.make( 58 _action_flags_present_for_mnemonic_nonexclusive_test_impl, 59 attrs = { 60 "mnemonics": attr.string_list( 61 doc = """ 62 Actions with these mnemonics will be expected to have the flags 63 specified in expected_flags 64 """, 65 ), 66 "expected_flags": attr.string_list(doc = "The flags to be checked for"), 67 }, 68) 69 70# Checks for the presence of a set of given flags in a set of given actions 71# exclusively. In other words, it confirms that *only* the specified actions 72# contain the specified flags. 73def _action_flags_present_only_for_mnemonic_test_impl(ctx): 74 env = analysistest.begin(ctx) 75 76 actions = analysistest.target_actions(env) 77 found_at_least_one_action = False 78 for action in actions: 79 if action.mnemonic in ctx.attr.mnemonics: 80 found_at_least_one_action = True 81 _assert_flags_present_in_action( 82 env, 83 action, 84 ctx.attr.expected_flags, 85 ) 86 elif action.argv != None: 87 for flag in ctx.attr.expected_flags: 88 asserts.false( 89 env, 90 flag in action.argv, 91 "%s action unexpectedly contained flag %s; argv: %s" % ( 92 action.mnemonic, 93 flag, 94 action.argv, 95 ), 96 ) 97 asserts.true( 98 env, 99 found_at_least_one_action, 100 "did not find any actions with mnemonic %s, found: %s" % ( 101 ctx.attr.mnemonics, 102 [a.mnemonic for a in actions], 103 ), 104 ) 105 return analysistest.end(env) 106 107def action_flags_present_only_for_mnemonic_test_with_config_settings(config_settings = {}): 108 return analysistest.make( 109 _action_flags_present_only_for_mnemonic_test_impl, 110 attrs = { 111 "mnemonics": attr.string_list( 112 doc = """ 113 Actions with these mnemonics will be expected to have the flags 114 specified in expected_flags 115 """, 116 ), 117 "expected_flags": attr.string_list(doc = "The flags to be checked for"), 118 }, 119 config_settings = config_settings, 120 ) 121 122action_flags_present_only_for_mnemonic_test = action_flags_present_only_for_mnemonic_test_with_config_settings() 123 124action_flags_present_only_for_mnemonic_aosp_arm64_test = action_flags_present_only_for_mnemonic_test_with_config_settings({ 125 "//command_line_option:platforms": "@//build/bazel/tests/products:aosp_arm64_for_testing", 126}) 127 128action_flags_present_only_for_mnemonic_aosp_arm64_host_test = action_flags_present_only_for_mnemonic_test_with_config_settings({ 129 "//command_line_option:platforms": "@//build/bazel/tests/products:aosp_arm64_for_testing_linux_x86_64", 130}) 131 132# Checks that a given set of flags are NOT present in a given set of actions. 133# Unlike the above test, this test does NOT confirm the absence of flags 134# *exclusively*. It does not confirm that the flags are present in actions 135# other than those specified 136def _action_flags_absent_for_mnemonic_test_impl(ctx): 137 env = analysistest.begin(ctx) 138 139 actions = analysistest.target_actions(env) 140 for action in actions: 141 if action.mnemonic in ctx.attr.mnemonics and action.argv != None: 142 for flag in ctx.attr.expected_absent_flags: 143 asserts.false( 144 env, 145 flag in action.argv, 146 "%s action unexpectedly contained flag %s; argv: %s" % ( 147 action.mnemonic, 148 flag, 149 action.argv, 150 ), 151 ) 152 153 return analysistest.end(env) 154 155def action_flags_absent_for_mnemonic_test_with_config_settings(config_settings = {}): 156 return analysistest.make( 157 _action_flags_absent_for_mnemonic_test_impl, 158 attrs = { 159 "mnemonics": attr.string_list( 160 doc = """ 161 Actions with these mnemonics will be expected NOT to have the flags 162 specificed in expected_flags 163 """, 164 ), 165 "expected_absent_flags": attr.string_list( 166 doc = """ 167 The flags to be confirmed are absent from the actions in mnemonics 168 """, 169 ), 170 }, 171 config_settings = config_settings, 172 ) 173 174action_flags_absent_for_mnemonic_test = action_flags_absent_for_mnemonic_test_with_config_settings() 175 176action_flags_absent_for_mnemonic_aosp_arm64_test = action_flags_absent_for_mnemonic_test_with_config_settings({ 177 "//command_line_option:platforms": "@//build/bazel/tests/products:aosp_arm64_for_testing", 178}) 179 180action_flags_absent_for_mnemonic_aosp_arm64_host_test = action_flags_absent_for_mnemonic_test_with_config_settings({ 181 "//command_line_option:platforms": "@//build/bazel/tests/products:aosp_arm64_for_testing_linux_x86_64", 182}) 183 184def _input_output_verification_test_impl(ctx): 185 env = analysistest.begin(ctx) 186 actions = [a for a in analysistest.target_actions(env) if a.mnemonic == ctx.attr.mnemonic] 187 asserts.true( 188 env, 189 len(actions) == 1, 190 "Action not found: %s" % actions, 191 ) 192 package_root = ctx.label.package 193 194 input_files = [paths.join(package_root, a) for a in ctx.attr.input_files] 195 output_files = [paths.join(package_root, a) for a in ctx.attr.output_files] 196 197 action = actions[0] 198 199 if len(input_files) > 0: 200 expected = sets.make( 201 input_files, 202 ) 203 actual = sets.make([ 204 file.short_path 205 for file in action.inputs.to_list() 206 ]) 207 asserts.true( 208 env, 209 sets.is_subset(expected, actual), 210 "Not all input files are present %s %s" % (expected, actual), 211 ) 212 213 if len(output_files) > 0: 214 expected = sets.make( 215 output_files, 216 ) 217 actual = sets.make([ 218 file.short_path 219 for file in action.outputs.to_list() 220 ]) 221 asserts.true( 222 env, 223 sets.is_equal(expected, actual), 224 "Not all output files are present %s %s" % (expected, actual), 225 ) 226 227 return analysistest.end(env) 228 229input_output_verification_test = analysistest.make( 230 _input_output_verification_test_impl, 231 attrs = { 232 "mnemonic": attr.string(), 233 "input_files": attr.string_list(), 234 "output_files": attr.string_list(), 235 }, 236) 237