1# Protocol Buffers - Google's data interchange format 2# Copyright 2024 Google Inc. All rights reserved. 3# 4# Use of this source code is governed by a BSD-style 5# license that can be found in the LICENSE file or at 6# https://developers.google.com/open-source/licenses/bsd 7# 8"""Tests for `proto_common.compile` function.""" 9 10load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") 11load("@rules_testing//lib:truth.bzl", "matching") 12load("@rules_testing//lib:util.bzl", "util") 13load("//bazel:proto_library.bzl", "proto_library") 14load("//bazel/tests/testdata:compile_rule.bzl", "compile_rule") 15 16protocol_compiler = "/protoc" 17 18def proto_common_compile_test_suite(name): 19 util.helper_target( 20 proto_library, 21 name = "simple_proto", 22 srcs = ["A.proto"], 23 ) 24 test_suite( 25 name = name, 26 tests = [ 27 _test_compile_basic, 28 _test_compile_noplugin, 29 _test_compile_with_plugin_output, 30 _test_compile_with_directory_plugin_output, 31 _test_compile_additional_args, 32 _test_compile_additional_tools, 33 _test_compile_additional_tools_no_plugin, 34 _test_compile_additional_inputs, 35 _test_compile_resource_set, 36 _test_compile_protoc_opts, 37 _test_compile_direct_generated_protos, 38 _test_compile_indirect_generated_protos, 39 ], 40 ) 41 42# Verifies basic usage of `proto_common.compile`. 43def _test_compile_basic(name): 44 util.helper_target( 45 compile_rule, 46 name = name + "_compile", 47 proto_dep = ":simple_proto", 48 ) 49 50 analysis_test( 51 name = name, 52 target = name + "_compile", 53 impl = _test_compile_basic_impl, 54 ) 55 56def _test_compile_basic_impl(env, target): 57 action = env.expect.that_target(target).action_named("MyMnemonic") 58 action.argv().contains_exactly_predicates( 59 [ 60 matching.str_endswith(protocol_compiler), 61 matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), 62 matching.equals_wrapper("-I."), 63 matching.str_endswith("/A.proto"), 64 ], 65 ) 66 action.mnemonic().equals("MyMnemonic") 67 68# Verifies usage of proto_common.generate_code with no plugin specified by toolchain. 69def _test_compile_noplugin(name): 70 util.helper_target( 71 compile_rule, 72 name = name + "_compile", 73 proto_dep = ":simple_proto", 74 toolchain = "//bazel/tests/testdata:toolchain_noplugin", 75 ) 76 77 analysis_test( 78 name = name, 79 target = name + "_compile", 80 impl = _test_compile_noplugin_impl, 81 ) 82 83def _test_compile_noplugin_impl(env, target): 84 action = env.expect.that_target(target).action_named("MyMnemonic") 85 action.argv().contains_exactly_predicates( 86 [ 87 matching.str_endswith(protocol_compiler), 88 matching.equals_wrapper("-I."), 89 matching.str_endswith("/A.proto"), 90 ], 91 ) 92 93# Verifies usage of `proto_common.compile` with `plugin_output` parameter set to file. 94def _test_compile_with_plugin_output(name): 95 util.helper_target( 96 compile_rule, 97 name = name + "_compile", 98 proto_dep = ":simple_proto", 99 plugin_output = "single", 100 ) 101 102 analysis_test( 103 name = name, 104 target = name + "_compile", 105 impl = _test_compile_with_plugin_output_impl, 106 ) 107 108def _test_compile_with_plugin_output_impl(env, target): 109 action = env.expect.that_target(target).action_named("MyMnemonic") 110 action.argv().contains_exactly_predicates( 111 [ 112 matching.str_endswith(protocol_compiler), 113 matching.str_matches("--java_out=param1,param2:b*-out/*/test_compile_with_plugin_output_compile"), 114 matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), 115 matching.equals_wrapper("-I."), 116 matching.str_endswith("/A.proto"), 117 ], 118 ) 119 120# Verifies usage of `proto_common.compile` with `plugin_output` parameter set to file. 121def _test_compile_with_directory_plugin_output(name): 122 util.helper_target( 123 compile_rule, 124 name = name + "_compile", 125 proto_dep = ":simple_proto", 126 plugin_output = "multiple", 127 ) 128 129 analysis_test( 130 name = name, 131 target = name + "_compile", 132 impl = _test_compile_with_directory_plugin_output_impl, 133 ) 134 135def _test_compile_with_directory_plugin_output_impl(env, target): 136 action = env.expect.that_target(target).action_named("MyMnemonic") 137 action.argv().contains_exactly_predicates( 138 [ 139 matching.str_endswith(protocol_compiler), 140 matching.str_matches("--java_out=param1,param2:b*-out/*/bin"), 141 matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), 142 matching.equals_wrapper("-I."), 143 matching.str_endswith("/A.proto"), 144 ], 145 ) 146 147# Verifies usage of `proto_common.compile` with `additional_args` parameter 148def _test_compile_additional_args(name): 149 util.helper_target( 150 compile_rule, 151 name = name + "_compile", 152 proto_dep = ":simple_proto", 153 additional_args = ["--a", "--b"], 154 ) 155 156 analysis_test( 157 name = name, 158 target = name + "_compile", 159 impl = _test_compile_additional_args_impl, 160 ) 161 162def _test_compile_additional_args_impl(env, target): 163 action = env.expect.that_target(target).action_named("MyMnemonic") 164 action.argv().contains_exactly_predicates( 165 [ 166 matching.str_endswith(protocol_compiler), 167 matching.equals_wrapper("--a"), 168 matching.equals_wrapper("--b"), 169 matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), 170 matching.equals_wrapper("-I."), 171 matching.str_endswith("/A.proto"), 172 ], 173 ) 174 175# Verifies usage of `proto_common.compile` with `additional_tools` parameter 176def _test_compile_additional_tools(name): 177 util.helper_target( 178 compile_rule, 179 name = name + "_compile", 180 proto_dep = ":simple_proto", 181 additional_tools = [ 182 "//bazel/tests/testdata:_tool1", 183 "//bazel/tests/testdata:_tool2", 184 ], 185 ) 186 187 analysis_test( 188 name = name, 189 target = name + "_compile", 190 impl = _test_compile_additional_tools_impl, 191 ) 192 193def _test_compile_additional_tools_impl(env, target): 194 action = env.expect.that_target(target).action_named("MyMnemonic") 195 action.inputs().contains_at_least_predicates( 196 [ 197 matching.file_basename_equals("_tool1"), 198 matching.file_basename_equals("_tool2"), 199 matching.file_basename_equals("plugin"), 200 ], 201 ) 202 203# Verifies usage of `proto_common.compile` with `additional_tools` parameter and no plugin on the toolchain. 204def _test_compile_additional_tools_no_plugin(name): 205 util.helper_target( 206 compile_rule, 207 name = name + "_compile", 208 proto_dep = ":simple_proto", 209 additional_tools = [ 210 "//bazel/tests/testdata:_tool1", 211 "//bazel/tests/testdata:_tool2", 212 ], 213 toolchain = "//bazel/tests/testdata:toolchain_noplugin", 214 ) 215 216 analysis_test( 217 name = name, 218 target = name + "_compile", 219 impl = _test_compile_additional_tools_no_plugin_impl, 220 ) 221 222def _test_compile_additional_tools_no_plugin_impl(env, target): 223 action = env.expect.that_target(target).action_named("MyMnemonic") 224 action.inputs().contains_at_least_predicates( 225 [ 226 matching.file_basename_equals("_tool1"), 227 matching.file_basename_equals("_tool2"), 228 ], 229 ) 230 action.inputs().not_contains_predicate(matching.file_basename_equals("plugin")) 231 232# Verifies usage of `proto_common.compile` with `additional_inputs` parameter. 233def _test_compile_additional_inputs(name): 234 util.helper_target( 235 compile_rule, 236 name = name + "_compile", 237 proto_dep = ":simple_proto", 238 additional_inputs = ["input1.txt", "input2.txt"], 239 ) 240 241 analysis_test( 242 name = name, 243 target = name + "_compile", 244 impl = _test_compile_additional_inputs_impl, 245 ) 246 247def _test_compile_additional_inputs_impl(env, target): 248 action = env.expect.that_target(target).action_named("MyMnemonic") 249 action.inputs().contains_at_least_predicates( 250 [ 251 matching.file_basename_equals("input1.txt"), 252 matching.file_basename_equals("input2.txt"), 253 ], 254 ) 255 256# Verifies usage of `proto_common.compile` with `additional_tools` parameter and no plugin on the toolchain. 257def _test_compile_resource_set(name): 258 util.helper_target( 259 compile_rule, 260 name = name + "_compile", 261 proto_dep = ":simple_proto", 262 use_resource_set = True, 263 ) 264 265 analysis_test( 266 name = name, 267 target = name + "_compile", 268 impl = _test_compile_resource_set_impl, 269 ) 270 271def _test_compile_resource_set_impl(env, target): 272 action = env.expect.that_target(target).action_named("MyMnemonic") # @unused 273 # We can't check the specification of the resource set, but we at least verify analysis passes 274 275# Verifies `--protocopts` are passed to command line. 276def _test_compile_protoc_opts(name): 277 util.helper_target( 278 compile_rule, 279 name = name + "_compile", 280 proto_dep = ":simple_proto", 281 ) 282 283 analysis_test( 284 name = name, 285 target = name + "_compile", 286 config_settings = {"//command_line_option:protocopt": ["--foo", "--bar"]}, 287 impl = _test_compile_protoc_opts_impl, 288 ) 289 290def _test_compile_protoc_opts_impl(env, target): 291 action = env.expect.that_target(target).action_named("MyMnemonic") 292 action.argv().contains_exactly_predicates( 293 [ 294 matching.str_endswith(protocol_compiler), 295 matching.equals_wrapper("--foo"), 296 matching.equals_wrapper("--bar"), 297 matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), 298 matching.equals_wrapper("-I."), 299 matching.str_endswith("/A.proto"), 300 ], 301 ) 302 303# Verifies `proto_common.compile`> correctly handles direct generated `.proto` files. 304def _test_compile_direct_generated_protos(name): 305 util.helper_target(native.genrule, name = name + "_generate_G", cmd = "", outs = ["G.proto"]) 306 util.helper_target( 307 proto_library, 308 name = name + "_directly_generated_proto", 309 srcs = ["A.proto", "G.proto"], 310 ) 311 util.helper_target( 312 compile_rule, 313 name = name + "_compile", 314 proto_dep = name + "_directly_generated_proto", 315 ) 316 317 analysis_test( 318 name = name, 319 target = name + "_compile", 320 impl = _test_compile_direct_generated_protos_impl, 321 ) 322 323def _test_compile_direct_generated_protos_impl(env, target): 324 action = env.expect.that_target(target).action_named("MyMnemonic") 325 action.argv().contains_exactly_predicates( 326 [ 327 matching.str_endswith(protocol_compiler), 328 matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), 329 matching.str_matches("-Ib*-out/*/*"), 330 matching.equals_wrapper("-I."), 331 matching.str_endswith("/A.proto"), 332 matching.str_matches("*-out/*/*/*/G.proto"), 333 ], 334 ) 335 336# Verifies usage of `proto_common.compile` with `plugin_output` parameter 337def _test_compile_indirect_generated_protos(name): 338 util.helper_target(native.genrule, name = "_generate_h", srcs = ["A.txt"], cmd = "", outs = ["H.proto"]) 339 util.helper_target(proto_library, name = "_generated_proto", srcs = ["H.proto"]) 340 util.helper_target( 341 proto_library, 342 name = name + "_indirectly_generated_proto", 343 srcs = ["A.proto"], 344 deps = [":_generated_proto"], 345 ) 346 util.helper_target( 347 compile_rule, 348 name = name + "_compile", 349 proto_dep = name + "_indirectly_generated_proto", 350 ) 351 352 analysis_test( 353 name = name, 354 target = name + "_compile", 355 impl = _test_compile_indirect_generated_protos_impl, 356 ) 357 358def _test_compile_indirect_generated_protos_impl(env, target): 359 action = env.expect.that_target(target).action_named("MyMnemonic") 360 action.argv().contains_exactly_predicates( 361 [ 362 matching.str_endswith(protocol_compiler), 363 matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), 364 matching.str_matches("-Ib*-out/*/*"), 365 matching.equals_wrapper("-I."), 366 matching.str_endswith("/A.proto"), 367 ], 368 ) 369