From dcc363cbfcedd1fd8170c87400b22e9b76857d3e Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Mon, 30 Jun 2025 18:26:29 -0500 Subject: [PATCH 1/3] Add ability to fully customize tests in `*_{ui,unit}_test_suite` macros Signed-off-by: Brentley Jones --- .../internal/testing/apple_test_assembler.bzl | 45 ++++++++++++--- apple/ios.bzl | 56 ++++++++++++------- doc/rules-apple.md | 2 +- doc/rules-ios.md | 24 ++++---- 4 files changed, 86 insertions(+), 41 deletions(-) diff --git a/apple/internal/testing/apple_test_assembler.bzl b/apple/internal/testing/apple_test_assembler.bzl index c696a313b5..a80e6ed96a 100644 --- a/apple/internal/testing/apple_test_assembler.bzl +++ b/apple/internal/testing/apple_test_assembler.bzl @@ -67,7 +67,14 @@ _SHARED_SUITE_TEST_ATTRS = { ] } -def _assemble(name, bundle_rule, test_rule, runner = None, runners = None, **kwargs): +def _assemble( + name, + bundle_rule, + test_rule, + generate_tests_func = None, + runner = None, + runners = None, + **kwargs): """Assembles the test bundle and test targets. This method expects that either `runner` or `runners` is populated, but never both. If `runner` @@ -82,6 +89,8 @@ def _assemble(name, bundle_rule, test_rule, runner = None, runners = None, **kwa name: The name of the test target or test suite to create. bundle_rule: The bundling rule to instantiate. test_rule: The test rule to instantiate. + generate_tests_func: A function that is passed the attributes for a test rule and returns a + list of attributes to use to create N test targets. Mutually exclusive with `runners`. runner: A single runner target to use for the test target. Mutually exclusive with `runners`. runners: A list of runner targets to use for the test targets. Mutually exclusive with @@ -90,8 +99,21 @@ def _assemble(name, bundle_rule, test_rule, runner = None, runners = None, **kwa """ if runner != None and runners != None: fail("Can't specify both runner and runners.") - elif not runner and not runners: - fail("Must specify one of runner or runners.") + elif not runner and not runners and not generate_tests_func: + fail("Must specify one of runner, runners, or generate_tests_func.") + + if runners: + if generate_tests_func: + fail("Can't specify both runners and generate_tests_func.") + + def generate_test(attrs): + return [ + attrs | { + "name": "{}_{}".format(name, runner.rsplit(":", 1)[-1]), + "runner": runner + } for runner in runners + ] + generate_tests_func = generate_test test_bundle_name = name + ".__internal__.__test_bundle" @@ -129,17 +151,22 @@ def _assemble(name, bundle_rule, test_rule, runner = None, runners = None, **kwa deps = [":{}".format(test_bundle_name)], **test_attrs ) - elif runners: + elif generate_tests_func: + all_test_attrs = generate_tests_func( + name = name, + deps = [":{}".format(test_bundle_name)], + **test_attrs + ) + tests = [] - for runner in runners: - test_name = "{}_{}".format(name, runner.rsplit(":", 1)[-1]) + for single_test_attrs in all_test_attrs: + test_name = single_test_attrs.pop("name") tests.append(":{}".format(test_name)) test_rule( name = test_name, - runner = runner, - deps = [":{}".format(test_bundle_name)], - **test_attrs + **single_test_attrs ) + shared_test_suite_attrs = {k: v for (k, v) in test_attrs.items() if k in _SHARED_SUITE_TEST_ATTRS} native.test_suite( name = name, diff --git a/apple/ios.bzl b/apple/ios.bzl index 2e922ed5f1..f51f547f80 100644 --- a/apple/ios.bzl +++ b/apple/ios.bzl @@ -75,41 +75,55 @@ def ios_ui_test(name, **kwargs): **kwargs ) -def ios_unit_test_suite(name, runners = None, **kwargs): - """Generates a [test_suite] containing an [ios_unit_test] for each of the given `runners`. - -`ios_unit_test_suite` takes the same parameters as [ios_unit_test], except `runner` is replaced by `runners`. - -[test_suite]: https://docs.bazel.build/versions/master/be/general.html#test_suite -[ios_unit_test]: #ios_unit_test - -Args: - runners: a list of runner targets - **kwargs: passed to the [ios_unit_test] -""" +def ios_unit_test_suite(name, generate_tests_func = None, runners = None, **kwargs): + """Generates a [test_suite] containing an [ios_unit_test] for each of the given `runners` or \ +results of `generate_tests_func`. + + `ios_unit_test_suite` takes the same parameters as [ios_unit_test], except `runner` is + replaced by `generate_tests_func` and `runners`. + + [test_suite]: https://docs.bazel.build/versions/master/be/general.html#test_suite + [ios_unit_test]: #ios_unit_test + + Args: + name: The name of the test suite to create. + generate_tests_func: A function that is passed the attributes for a test rule and returns a + list of attribute dictionaries to use to create N test targets. Mutually exclusive with + `runners`. + runners: A `list` of runner targets. + **kwargs: passed to the [ios_unit_test] + """ apple_test_assembler.assemble( name = name, bundle_rule = _ios_internal_unit_test_bundle, + generate_tests_func = generate_tests_func, test_rule = _ios_unit_test, runners = runners, **kwargs ) -def ios_ui_test_suite(name, runners = None, **kwargs): - """Generates a [test_suite] containing an [ios_ui_test] for each of the given `runners`. +def ios_ui_test_suite(name, generate_tests_func = None, runners = None, **kwargs): + """Generates a [test_suite] containing an [ios_ui_test] for each of the given `runners` or \ +results of `generate_tests_func`. -`ios_ui_test_suite` takes the same parameters as [ios_ui_test], except `runner` is replaced by `runners`. + `ios_ui_test_suite` takes the same parameters as [ios_ui_test], except `runner` is replaced by + `generate_tests_func` and `runners`. -[test_suite]: https://docs.bazel.build/versions/master/be/general.html#test_suite -[ios_ui_test]: #ios_ui_test + [test_suite]: https://docs.bazel.build/versions/master/be/general.html#test_suite + [ios_ui_test]: #ios_ui_test -Args: - runners: a list of runner targets - **kwargs: passed to the [ios_ui_test] -""" + Args: + name: The name of the test suite to create. + generate_tests_func: A function that is passed the attributes for a test rule and returns a + list of attribute dictionaries to use to create N test targets. Mutually exclusive with + `runners`. + runners: A `list` of runner targets. Mutually exclusive with `generate_tests_func`. + **kwargs: passed to the [ios_ui_test] + """ apple_test_assembler.assemble( name = name, bundle_rule = _ios_internal_ui_test_bundle, + generate_tests_func = generate_tests_func, test_rule = _ios_ui_test, runners = runners, **kwargs diff --git a/doc/rules-apple.md b/doc/rules-apple.md index 2b1db634c2..e72e58fdde 100755 --- a/doc/rules-apple.md +++ b/doc/rules-apple.md @@ -442,7 +442,7 @@ ios_application( | :------------- | :------------- | :------------- | :------------- | :------------- | | name | A unique name for this repository. | Name | required | | | fallback_profiles | - | Label | optional | `None` | -| repo_mapping | In `WORKSPACE` context only: a dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.

For example, an entry `"@foo": "@bar"` declares that, for any time this repository depends on `@foo` (such as a dependency on `@foo//some:target`), it should actually resolve that dependency within globally-declared `@bar` (`@bar//some:target`).

This attribute is _not_ supported in `MODULE.bazel` context (when invoking a repository rule inside a module extension's implementation function). | Dictionary: String -> String | optional | | +| repo_mapping | In `WORKSPACE` context only: a dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.

For example, an entry `"@foo": "@bar"` declares that, for any time this repository depends on `@foo` (such as a dependency on `@foo//some:target`, it should actually resolve that dependency within globally-declared `@bar` (`@bar//some:target`).

This attribute is _not_ supported in `MODULE.bazel` context (when invoking a repository rule inside a module extension's implementation function). | Dictionary: String -> String | optional | | **ENVIRONMENT VARIABLES** diff --git a/doc/rules-ios.md b/doc/rules-ios.md index 8e66f0ef2f..e82e8c956c 100644 --- a/doc/rules-ios.md +++ b/doc/rules-ios.md @@ -733,12 +733,13 @@ in Xcode. ## ios_ui_test_suite
-ios_ui_test_suite(name, runners, kwargs)
+ios_ui_test_suite(name, generate_tests_func, runners, kwargs)
 
-Generates a [test_suite] containing an [ios_ui_test] for each of the given `runners`. +Generates a [test_suite] containing an [ios_ui_test] for each of the given `runners` or results of `generate_tests_func`. -`ios_ui_test_suite` takes the same parameters as [ios_ui_test], except `runner` is replaced by `runners`. +`ios_ui_test_suite` takes the same parameters as [ios_ui_test], except `runner` is replaced by +`generate_tests_func` and `runners`. [test_suite]: https://docs.bazel.build/versions/master/be/general.html#test_suite [ios_ui_test]: #ios_ui_test @@ -749,8 +750,9 @@ Generates a [test_suite] containing an [ios_ui_test] for each of the given `runn | Name | Description | Default Value | | :------------- | :------------- | :------------- | -| name |

-

| none | -| runners | a list of runner targets | `None` | +| name | The name of the test suite to create. | none | +| generate_tests_func | A function that is passed the attributes for a test rule and returns a list of attribute dictionaries to use to create N test targets. Mutually exclusive with `runners`. | `None` | +| runners | A `list` of runner targets. Mutually exclusive with `generate_tests_func`. | `None` | | kwargs | passed to the [ios_ui_test] | none | @@ -759,12 +761,13 @@ Generates a [test_suite] containing an [ios_ui_test] for each of the given `runn ## ios_unit_test_suite
-ios_unit_test_suite(name, runners, kwargs)
+ios_unit_test_suite(name, generate_tests_func, runners, kwargs)
 
-Generates a [test_suite] containing an [ios_unit_test] for each of the given `runners`. +Generates a [test_suite] containing an [ios_unit_test] for each of the given `runners` or results of `generate_tests_func`. -`ios_unit_test_suite` takes the same parameters as [ios_unit_test], except `runner` is replaced by `runners`. +`ios_unit_test_suite` takes the same parameters as [ios_unit_test], except `runner` is +replaced by `generate_tests_func` and `runners`. [test_suite]: https://docs.bazel.build/versions/master/be/general.html#test_suite [ios_unit_test]: #ios_unit_test @@ -775,8 +778,9 @@ Generates a [test_suite] containing an [ios_unit_test] for each of the given `ru | Name | Description | Default Value | | :------------- | :------------- | :------------- | -| name |

-

| none | -| runners | a list of runner targets | `None` | +| name | The name of the test suite to create. | none | +| generate_tests_func | A function that is passed the attributes for a test rule and returns a list of attribute dictionaries to use to create N test targets. Mutually exclusive with `runners`. | `None` | +| runners | A `list` of runner targets. | `None` | | kwargs | passed to the [ios_unit_test] | none | From 17ff88918ac272190e6e547199e85f0cc0bdbf81 Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Mon, 30 Jun 2025 18:37:38 -0500 Subject: [PATCH 2/3] More Signed-off-by: Brentley Jones --- apple/internal/testing/apple_test_assembler.bzl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apple/internal/testing/apple_test_assembler.bzl b/apple/internal/testing/apple_test_assembler.bzl index a80e6ed96a..516f36e026 100644 --- a/apple/internal/testing/apple_test_assembler.bzl +++ b/apple/internal/testing/apple_test_assembler.bzl @@ -102,7 +102,10 @@ def _assemble( elif not runner and not runners and not generate_tests_func: fail("Must specify one of runner, runners, or generate_tests_func.") - if runners: + if runner: + if generate_tests_func: + fail("Can't specify both runner and generate_tests_func.") + elif runners: if generate_tests_func: fail("Can't specify both runners and generate_tests_func.") From 6fefe1daae5d7331b5af825225daf2d42ef6aebb Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Mon, 30 Jun 2025 18:38:58 -0500 Subject: [PATCH 3/3] More Signed-off-by: Brentley Jones --- apple/internal/testing/apple_test_assembler.bzl | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/apple/internal/testing/apple_test_assembler.bzl b/apple/internal/testing/apple_test_assembler.bzl index 516f36e026..10315e4609 100644 --- a/apple/internal/testing/apple_test_assembler.bzl +++ b/apple/internal/testing/apple_test_assembler.bzl @@ -109,14 +109,12 @@ def _assemble( if generate_tests_func: fail("Can't specify both runners and generate_tests_func.") - def generate_test(attrs): - return [ - attrs | { - "name": "{}_{}".format(name, runner.rsplit(":", 1)[-1]), - "runner": runner - } for runner in runners - ] - generate_tests_func = generate_test + generate_tests_func = lambda **attrs: [ + attrs | { + "name": "{}_{}".format(name, runner.rsplit(":", 1)[-1]), + "runner": runner + } for runner in runners + ] test_bundle_name = name + ".__internal__.__test_bundle"