1"""Copyright (C) 2022 The Android Open Source Project 2 3Licensed under the Apache License, Version 2.0 (the "License"); 4you may not use this file except in compliance with the License. 5You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9Unless required by applicable law or agreed to in writing, software 10distributed under the License is distributed on an "AS IS" BASIS, 11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12See the License for the specific language governing permissions and 13limitations under the License. 14""" 15 16load("@bazel_skylib//lib:new_sets.bzl", "sets") 17load("@bazel_skylib//lib:paths.bzl", "paths") 18load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") 19load("//build/bazel/rules/aidl:aidl_interface.bzl", "aidl_interface") 20load("//build/bazel/rules/aidl:aidl_library.bzl", "AidlGenInfo") 21load("//build/bazel/rules/test_common:rules.bzl", "target_under_test_exist_test") 22load("//build/bazel/rules/test_common:flags.bzl", "action_flags_present_only_for_mnemonic_test_with_config_settings") 23 24def _ndk_backend_test_impl(ctx): 25 env = analysistest.begin(ctx) 26 actions = analysistest.target_actions(env) 27 asserts.true( 28 env, 29 len(actions) == 1, 30 "expected to have one action per aidl_library target", 31 ) 32 cc_aidl_code_gen_target = analysistest.target_under_test(env) 33 34 # output_path: <bazel-bin>/<package-dir>/<cc_aidl_library-labelname>_aidl_code_gen 35 # Since cc_aidl_library-label is unique among cpp and ndk backends, 36 # the output_path is guaranteed to be unique 37 output_path = paths.join( 38 ctx.genfiles_dir.path, 39 ctx.label.package, 40 cc_aidl_code_gen_target.label.name, 41 ) 42 expected_outputs = [ 43 # headers for ndk backend are nested in aidl directory to prevent 44 # collision in c++ namespaces with cpp backend 45 paths.join(output_path, "aidl/b/BpFoo.h"), 46 paths.join(output_path, "aidl/b/BnFoo.h"), 47 paths.join(output_path, "aidl/b/Foo.h"), 48 paths.join(output_path, "b/Foo.cpp"), 49 ] 50 51 # Check output files in DefaultInfo provider 52 asserts.set_equals( 53 env, 54 sets.make(expected_outputs), 55 sets.make([ 56 output.path 57 for output in cc_aidl_code_gen_target[DefaultInfo].files.to_list() 58 ]), 59 ) 60 61 # Check the output path is correctly added to includes in CcInfo.compilation_context 62 asserts.true( 63 env, 64 output_path in cc_aidl_code_gen_target[CcInfo].compilation_context.includes.to_list(), 65 "output path is added to CcInfo.compilation_context.includes", 66 ) 67 68 return analysistest.end(env) 69 70ndk_backend_test = analysistest.make( 71 _ndk_backend_test_impl, 72) 73 74def _ndk_backend_test(): 75 name = "foo" 76 aidl_library_target = name + "-ndk" 77 aidl_code_gen_target = aidl_library_target + "_aidl_code_gen" 78 test_name = aidl_code_gen_target + "_test" 79 80 aidl_interface( 81 name = "foo", 82 ndk_config = { 83 "enabled": True, 84 }, 85 unstable = True, 86 srcs = ["a/b/Foo.aidl"], 87 strip_import_prefix = "a", 88 tags = ["manual"], 89 ) 90 91 ndk_backend_test( 92 name = test_name, 93 target_under_test = aidl_code_gen_target, 94 ) 95 96 return test_name 97 98def _ndk_config_test_impl(ctx): 99 env = analysistest.begin(ctx) 100 actions = analysistest.target_actions(env) 101 asserts.true( 102 env, 103 len(actions) == 1, 104 "expected to have one action per aidl_library target", 105 ) 106 asserts.true( 107 env, 108 "--min_sdk_version=30", 109 "expected to have min_sdk_version flag", 110 ) 111 return analysistest.end(env) 112 113ndk_config_test = analysistest.make( 114 _ndk_config_test_impl, 115) 116 117def _ndk_config_test(): 118 name = "ndk-config" 119 aidl_library_target = name + "-ndk" 120 aidl_code_gen_target = aidl_library_target + "_aidl_code_gen" 121 test_name = aidl_code_gen_target + "_test" 122 123 aidl_interface( 124 name = name, 125 unstable = True, 126 ndk_config = { 127 "enabled": True, 128 "min_sdk_version": "30", 129 }, 130 srcs = ["Foo.aidl"], 131 tags = ["manual"], 132 ) 133 134 ndk_config_test( 135 name = test_name, 136 target_under_test = aidl_code_gen_target, 137 ) 138 139 return test_name 140 141def _aidl_library_has_flags_test_impl(ctx): 142 env = analysistest.begin(ctx) 143 target_under_test = analysistest.target_under_test(env) 144 145 asserts.true( 146 env, 147 AidlGenInfo in target_under_test, 148 "", 149 ) 150 asserts.equals( 151 env, 152 ctx.attr.expected_flags, 153 target_under_test[AidlGenInfo].flags, 154 "", 155 ) 156 157 return analysistest.end(env) 158 159aidl_library_has_flags_test = analysistest.make( 160 _aidl_library_has_flags_test_impl, 161 attrs = { 162 "expected_flags": attr.string_list(), 163 }, 164) 165 166def _test_aidl_interface_passes_flags_to_aidl_libraries(): 167 name = "aidl_interface_passes_version_flags_to_aidl_libraries" 168 aidl_interface( 169 name = name, 170 srcs = ["Foo.aidl"], 171 tags = ["manual"], 172 versions_with_info = [ 173 { 174 "version": "1", 175 }, 176 { 177 "version": "2", 178 }, 179 ], 180 ) 181 182 target_v1_test_name = name + "_test-V1" 183 aidl_library_has_flags_test( 184 name = target_v1_test_name, 185 target_under_test = name + "-V1", 186 expected_flags = [ 187 "--structured", 188 "--version=1", 189 ], 190 ) 191 target_v2_test_name = name + "_test-V2" 192 aidl_library_has_flags_test( 193 name = target_v2_test_name, 194 target_under_test = name + "-V2", 195 expected_flags = [ 196 "--structured", 197 "--version=2", 198 ], 199 ) 200 target_v_next_test_name = name + "_test-V_next" 201 aidl_library_has_flags_test( 202 name = target_v_next_test_name, 203 target_under_test = name + "-V3", 204 expected_flags = [ 205 "--structured", 206 "--version=3", 207 ], 208 ) 209 210 return [ 211 target_v1_test_name, 212 target_v2_test_name, 213 target_v_next_test_name, 214 ] 215 216def _next_version_for_unversioned_stable_interface_test(): 217 name = "unversioned_stable_interface_next_version" 218 test_name = name + "_test" 219 next_version_aidl_library_target = name + "-V1" 220 221 aidl_interface( 222 name = name, 223 srcs = ["Foo.aidl"], 224 tags = ["manual"], 225 ) 226 227 target_under_test_exist_test( 228 name = test_name, 229 target_under_test = next_version_aidl_library_target, 230 ) 231 232 return test_name 233 234def _next_version_for_versioned_stable_interface_test(): 235 name = "versioned_stable_interface_next_version" 236 test_name = name + "_test" 237 next_version_aidl_library_target = name + "-V3" 238 239 aidl_interface( 240 name = name, 241 versions_with_info = [ 242 { 243 "version": "1", 244 }, 245 { 246 "version": "2", 247 }, 248 ], 249 srcs = ["Foo.aidl"], 250 tags = ["manual"], 251 ) 252 253 target_under_test_exist_test( 254 name = test_name, 255 target_under_test = next_version_aidl_library_target, 256 ) 257 258 return test_name 259 260def _tidy_flags_has_generated_directory_header_filter_test_impl(ctx): 261 env = analysistest.begin(ctx) 262 263 actions = analysistest.target_actions(env) 264 clang_tidy_actions = [a for a in actions if a.mnemonic == "ClangTidy"] 265 266 action_header_filter = None 267 for action in clang_tidy_actions: 268 for arg in action.argv: 269 if arg.startswith("-header-filter="): 270 action_header_filter = arg 271 272 if action_header_filter == None: 273 asserts.true( 274 env, 275 False, 276 "did not find header-filter in ClangTidy actions: `%s`" % ( 277 clang_tidy_actions 278 ), 279 ) 280 281 # The genfiles path for tests and cc_libraries is different (the latter contains a 282 # configuration prefix ST-<hash>). So instead (lacking regexes) we can just check 283 # that the beginning and end of the header-filter is correct. 284 expected_header_filter_prefix = "-header-filter=" + paths.join(ctx.genfiles_dir.path) 285 expected_header_filter_prefix = expected_header_filter_prefix.removesuffix("/bin") 286 expected_header_filter_suffix = ctx.label.package + ".*" 287 asserts.true( 288 env, 289 action_header_filter.startswith(expected_header_filter_prefix), 290 "expected header-filter to start with `%s`; but was `%s`" % ( 291 expected_header_filter_prefix, 292 action_header_filter, 293 ), 294 ) 295 asserts.true( 296 env, 297 action_header_filter.endswith(expected_header_filter_suffix), 298 "expected header-filter to end with `%s`; but was `%s`" % ( 299 expected_header_filter_suffix, 300 action_header_filter, 301 ), 302 ) 303 304 return analysistest.end(env) 305 306_tidy_flags_has_generated_directory_header_filter_test = analysistest.make( 307 _tidy_flags_has_generated_directory_header_filter_test_impl, 308 config_settings = { 309 "@//build/bazel/flags/cc/tidy:allow_local_tidy_true": True, 310 }, 311) 312 313def _test_aidl_interface_generated_header_filter(): 314 name = "aidl_interface_generated_header_filter" 315 test_name = name + "_test" 316 aidl_library_target = name + "-cpp" 317 shared_target_under_test = aidl_library_target + "__internal_root" 318 shared_test_name = test_name + "_shared" 319 static_target_under_test = aidl_library_target + "_bp2build_cc_library_static" 320 static_test_name = test_name + "_static" 321 322 aidl_interface( 323 name = name, 324 cpp_config = { 325 "enabled": True, 326 }, 327 unstable = True, 328 srcs = ["a/b/Foo.aidl"], 329 tags = ["manual"], 330 ) 331 332 _tidy_flags_has_generated_directory_header_filter_test( 333 name = shared_test_name, 334 target_under_test = shared_target_under_test, 335 ) 336 _tidy_flags_has_generated_directory_header_filter_test( 337 name = static_test_name, 338 target_under_test = static_target_under_test, 339 ) 340 return [ 341 shared_test_name, 342 static_test_name, 343 ] 344 345_action_flags_present_with_tidy_test = action_flags_present_only_for_mnemonic_test_with_config_settings({ 346 "@//build/bazel/flags/cc/tidy:allow_local_tidy_true": True, 347}) 348 349def _test_aidl_interface_generated_cc_library_has_correct_tidy_checks_as_errors(): 350 name = "aidl_interface_generated_cc_library_has_correct_tidy_checks_as_errors" 351 test_name = name + "_test" 352 aidl_library_target = name + "-cpp" 353 shared_target_under_test = aidl_library_target + "__internal_root" 354 shared_test_name = test_name + "_shared" 355 static_target_under_test = aidl_library_target + "_bp2build_cc_library_static" 356 static_test_name = test_name + "_static" 357 358 aidl_interface( 359 name = name, 360 cpp_config = { 361 "enabled": True, 362 }, 363 unstable = True, 364 srcs = ["a/b/Foo.aidl"], 365 tags = ["manual"], 366 ) 367 368 _action_flags_present_with_tidy_test( 369 name = shared_test_name, 370 target_under_test = shared_target_under_test, 371 mnemonics = ["ClangTidy"], 372 expected_flags = [ 373 "-warnings-as-errors=*,-clang-analyzer-deadcode.DeadStores,-clang-analyzer-cplusplus.NewDeleteLeaks,-clang-analyzer-optin.performance.Padding,-bugprone-assignment-in-if-condition,-bugprone-branch-clone,-bugprone-signed-char-misuse,-misc-const-correctness,-bugprone-unsafe-functions,-cert-msc24-c,-cert-msc33-c,-modernize-type-traits,-readability-avoid-unconditional-preprocessor-if", 374 ], 375 ) 376 _action_flags_present_with_tidy_test( 377 name = static_test_name, 378 target_under_test = static_target_under_test, 379 mnemonics = ["ClangTidy"], 380 expected_flags = [ 381 "-warnings-as-errors=*,-clang-analyzer-deadcode.DeadStores,-clang-analyzer-cplusplus.NewDeleteLeaks,-clang-analyzer-optin.performance.Padding,-bugprone-assignment-in-if-condition,-bugprone-branch-clone,-bugprone-signed-char-misuse,-misc-const-correctness,-bugprone-unsafe-functions,-cert-msc24-c,-cert-msc33-c,-modernize-type-traits,-readability-avoid-unconditional-preprocessor-if", 382 ], 383 ) 384 return [ 385 shared_test_name, 386 static_test_name, 387 ] 388 389def _cc_library_has_flags_test_impl(ctx): 390 env = analysistest.begin(ctx) 391 target = analysistest.target_under_test(env) 392 actions = [a for a in target.actions if a.mnemonic == "CppCompile"] 393 394 asserts.true( 395 env, 396 len(actions) == 1, 397 "There should be one cc compile action: %s" % actions, 398 ) 399 400 action = actions[0] 401 for flag in ctx.attr.expected_flags: 402 if flag not in action.argv: 403 fail("{} is not in list of flags for linking {}".format(flag, action.argv)) 404 405 return analysistest.end(env) 406 407cc_library_has_flags_test = analysistest.make( 408 _cc_library_has_flags_test_impl, 409 attrs = { 410 "expected_flags": attr.string_list(), 411 }, 412) 413 414def _test_aidl_interface_sets_flags_to_cc_libraries(): 415 name = "aidl_interface_sets_flags_to_cc_libraries" 416 test_name = name + "_test" 417 aidl_library_target = name + "-ndk" 418 shared_target_under_test = aidl_library_target + "__internal_root_cpp" 419 shared_test_name = test_name + "_shared" 420 static_target_under_test = aidl_library_target + "_bp2build_cc_library_static_cpp" 421 static_test_name = test_name + "_static" 422 423 aidl_interface( 424 name = name, 425 ndk_config = { 426 "enabled": True, 427 }, 428 srcs = ["Foo.aidl"], 429 unstable = True, 430 tags = ["manual"], 431 ) 432 433 cc_library_has_flags_test( 434 name = shared_test_name, 435 target_under_test = shared_target_under_test, 436 expected_flags = [ 437 "-DBINDER_STABILITY_SUPPORT", 438 ], 439 ) 440 441 cc_library_has_flags_test( 442 name = static_test_name, 443 target_under_test = static_target_under_test, 444 expected_flags = [ 445 "-DBINDER_STABILITY_SUPPORT", 446 ], 447 ) 448 449 return [ 450 shared_test_name, 451 static_test_name, 452 ] 453 454def aidl_interface_test_suite(name): 455 native.test_suite( 456 name = name, 457 tests = ( 458 [ 459 "//build/bazel/rules/aidl/testing:generated_targets_have_correct_srcs_test", 460 "//build/bazel/rules/aidl/testing:interface_macro_produces_all_targets_test", 461 _ndk_backend_test(), 462 _ndk_config_test(), 463 _next_version_for_unversioned_stable_interface_test(), 464 _next_version_for_versioned_stable_interface_test(), 465 ] + 466 _test_aidl_interface_generated_header_filter() + 467 _test_aidl_interface_passes_flags_to_aidl_libraries() + 468 _test_aidl_interface_sets_flags_to_cc_libraries() + 469 _test_aidl_interface_generated_cc_library_has_correct_tidy_checks_as_errors() 470 ), 471 ) 472