Skip to content

Commit

Permalink
Add xctrunner and xctrunnertool
Browse files Browse the repository at this point in the history
  • Loading branch information
kapoorlakshya committed Mar 4, 2025
1 parent ec9d864 commit 8cd6f3b
Show file tree
Hide file tree
Showing 19 changed files with 789 additions and 0 deletions.
6 changes: 6 additions & 0 deletions apple/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,12 @@ bzl_library(
deps = ["//apple/internal:xcarchive"],
)

bzl_library(
name = "xctrunner",
srcs = ["xctrunner.bzl"],
deps = ["//apple/internal:xctrunner"],
)

bzl_library(
name = "docc",
srcs = ["docc.bzl"],
Expand Down
12 changes: 12 additions & 0 deletions apple/internal/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,18 @@ bzl_library(
],
)

bzl_library(
name = "xctrunner",
srcs = ["xctrunner.bzl"],
visibility = [
"//apple:__subpackages__",
],
deps = [
"//apple:providers",
"//apple/internal/providers:apple_debug_info",
],
)

bzl_library(
name = "docc",
srcs = ["docc.bzl"],
Expand Down
189 changes: 189 additions & 0 deletions apple/internal/xctrunner.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# Copyright 2025 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Rule for creating a XCTRunner.app with one or more .xctest bundles. Retains same
platform and architectures as the given `tests` bundles.
"""

load(
"//apple:providers.bzl",
"AppleBundleInfo",
)
load(
"//apple/internal:providers.bzl",
"new_applebinaryinfo",
)

_TestBundleInfo = provider(
"Test bundle info for tests that will be run.",
fields = {
"platform_type": "The platform to bundle for.",
"infoplists": "A `depset` of `File`s of `Info.plist` files.",
"xctests": "A `depset` of paths of XCTest bundles.",
},
)

def _test_bundle_info_aspect_impl(target, ctx):
rule_attr = ctx.rule.attr

if AppleBundleInfo in target:
info = target[AppleBundleInfo]
xctests = depset([info.archive])
infoplists = depset([info.infoplist])
platform_type = target[AppleBundleInfo].platform_type
else:
deps = getattr(rule_attr, "tests", [])
xctests = depset(
transitive = [
dep[_TestBundleInfo].xctests
for dep in deps
],
)
infoplists = depset(
transitive = [
dep[_TestBundleInfo].infoplists
for dep in deps
],
)
platform_types = [
dep[AppleBundleInfo].platform_type
for dep in deps
]

# Ensure all test bundles are for the same platform
for type in platform_types:
if type != platform_types[0]:
ctx.attr.test_bundle_info_aspect.error(
"All test bundles must be for the same platform: %s" % platform_types,
)
platform_type = platform_types[0] # Pick one, all are same

return [
_TestBundleInfo(
infoplists = infoplists,
xctests = xctests,
platform_type = platform_type,
),
]

test_bundle_info_aspect = aspect(
attr_aspects = ["tests"],
implementation = _test_bundle_info_aspect_impl,
)

def _xctrunner_impl(ctx):
output = ctx.actions.declare_directory(ctx.label.name + ".app")
infos = [target[_TestBundleInfo] for target in ctx.attr.tests]
infoplists = depset(
transitive = [info.infoplists for info in infos],
)
xctests = depset(
transitive = [info.xctests for info in infos],
)
platform = infos[0].platform_type # Pick one, all should be same
platform_map = {
"ios": "iPhoneOS.platform",
"macos": "MacOSX.platform",
"tvos": "AppleTVOS.platform",
"watchos": "WatchOS.platform",
"visionos": "VisionOS.platform",
}

# Args for `_xctrunnertool`
args = ctx.actions.args()
args.add("--name", ctx.attr.name)
args.add("--platform", platform_map[platform])
if ctx.attr.verbose:
args.add("--verbose", ctx.attr.verbose)

# Absolute paths to xctest bundles
args.add_all(
xctests,
before_each = "--xctest",
expand_directories = False,
)

# App bundle output path
args.add("--output", output.path)

ctx.actions.run(
inputs = depset(transitive = [xctests, infoplists]),
outputs = [output],
executable = ctx.attr._xctrunnertool[DefaultInfo].files_to_run,
arguments = [args],
mnemonic = "MakeXCTRunner",
)

# Limiting the contents of AppleBinaryInfo to what is necessary
# for testing and validation.
xctrunner_binary_info = new_applebinaryinfo(
binary = output,
infoplist = None,
product_type = None,
)

return [
DefaultInfo(files = depset([output])),
xctrunner_binary_info,
]

xctrunner = rule(
implementation = _xctrunner_impl,
attrs = {
"tests": attr.label_list(
mandatory = True,
aspects = [test_bundle_info_aspect],
doc = "List of test targets and suites to include.",
),
"verbose": attr.bool(
mandatory = False,
default = False,
doc = "Print logs from xctrunnertool to console.",
),
"_xctrunnertool": attr.label(
default = Label("//tools/xctrunnertool:run"),
executable = True,
cfg = "exec",
doc = """
An executable binary that can merge separate xctest into a single XCTestRunner
bundle.
""",
),
},
doc = """
Packages one or more .xctest bundles into a XCTRunner.app. Retains same
platform and architectures as the given `tests` bundles.
Example:
````starlark
load("//apple:xctrunner.bzl", "xctrunner")
ios_ui_test(
name = "HelloWorldSwiftUITests",
minimum_os_version = "15.0",
runner = "@build_bazel_rules_apple//apple/testing/default_runner:ios_xctestrun_ordered_runner",
test_host = ":HelloWorldSwift",
deps = [":UITests"],
)
xctrunner(
name = "HelloWorldSwiftXCTRunner",
tests = [":HelloWorldSwiftUITests"],
testonly = True,
)
````
""",
)
25 changes: 25 additions & 0 deletions apple/xctrunner.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright 2025 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Rule for creating a XCTRunner.app with one or more .xctest bundles. Retains same
platform and architectures as the given `tests` bundles.
"""

load(
"//apple/internal:xctrunner.bzl",
_xctrunner = "xctrunner",
)

xctrunner = _xctrunner
1 change: 1 addition & 0 deletions doc/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ _RULES_DOC_SRCS = [
"visionos.doc",
"watchos.doc",
"xcarchive",
"xctrunner",
]

_DOC_SRCS = _PLAIN_DOC_SRCS + _RULES_DOC_SRCS
Expand Down
4 changes: 4 additions & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ below.
<td valign="top"><code>@build_bazel_rules_apple//apple:versioning.bzl</code></td>
<td valign="top"><code><a href="rules-versioning.md#apple_bundle_version">apple_bundle_version</a></code><br/></td>
</tr>
<tr>
<td valign="top"><code>@build_bazel_rules_apple//apple:xctrunner.bzl</code></td>
<td valign="top"><code><a href="rules-xctrunner.md#xctrunner">xctrunner</a></code></td>
</tr>
</tr>
<tr>
<th align="left" valign="top" rowspan="1">Resources</th>
Expand Down
46 changes: 46 additions & 0 deletions doc/rules-xctrunner.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!-- Generated with Stardoc: http://skydoc.bazel.build -->

Rule for creating a XCTRunner.app with one or more .xctest bundles. Retains same
platform and architectures as the given `tests` bundles.

<a id="xctrunner"></a>

## xctrunner

<pre>
xctrunner(<a href="#xctrunner-name">name</a>, <a href="#xctrunner-tests">tests</a>, <a href="#xctrunner-verbose">verbose</a>)
</pre>

Packages one or more .xctest bundles into a XCTRunner.app. Retains same
platform and architectures as the given `tests` bundles.

Example:

````starlark
load("//apple:xctrunner.bzl", "xctrunner")

ios_ui_test(
name = "HelloWorldSwiftUITests",
minimum_os_version = "15.0",
runner = "@build_bazel_rules_apple//apple/testing/default_runner:ios_xctestrun_ordered_runner",
test_host = ":HelloWorldSwift",
deps = [":UITests"],
)

xctrunner(
name = "HelloWorldSwiftXCTRunner",
tests = [":HelloWorldSwiftUITests"],
testonly = True,
)
````

**ATTRIBUTES**


| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="xctrunner-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="xctrunner-tests"></a>tests | List of test targets and suites to include. | <a href="https://bazel.build/concepts/labels">List of labels</a> | required | |
| <a id="xctrunner-verbose"></a>verbose | Print logs from xctrunnertool to console. | Boolean | optional | `False` |


7 changes: 7 additions & 0 deletions examples/ios/HelloWorldSwift/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
load("//apple:docc.bzl", "docc_archive")
load("//apple:ios.bzl", "ios_application", "ios_ui_test", "ios_unit_test")
load("//apple:xctrunner.bzl", "xctrunner")

licenses(["notice"])

Expand Down Expand Up @@ -103,3 +104,9 @@ docc_archive(
fallback_display_name = "HelloWorldSwift",
minimum_access_level = "internal",
)

xctrunner(
name = "HelloWorldSwiftXCTRunner",
testonly = True,
tests = [":HelloWorldSwiftUITests"],
)
3 changes: 3 additions & 0 deletions test/starlark_tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ load(":watchos_static_framework_tests.bzl", "watchos_static_framework_test_suite
load(":watchos_ui_test_tests.bzl", "watchos_ui_test_test_suite")
load(":watchos_unit_test_tests.bzl", "watchos_unit_test_test_suite")
load(":xcarchive_tests.bzl", "xcarchive_test_suite")
load(":xctrunner_tests.bzl", "xctrunner_test_suite")

licenses(["notice"])

Expand Down Expand Up @@ -183,6 +184,8 @@ watchos_unit_test_test_suite(name = "watchos_unit_test")

xcarchive_test_suite(name = "xcarchive")

xctrunner_test_suite(name = "xctrunner")

docc_test_suite(name = "docc")

test_suite(name = "all_tests")
Expand Down
19 changes: 19 additions & 0 deletions test/starlark_tests/targets_under_test/ios/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ load(
"//apple:xcarchive.bzl",
"xcarchive",
)
load(
"//apple:xctrunner.bzl",
"xctrunner",
)
load(
"//test/starlark_tests:common.bzl",
"common",
Expand Down Expand Up @@ -3366,6 +3370,21 @@ ios_ui_test(
],
)

xctrunner(
name = "ui_test_xctrunner_app",
testonly = True,
tests = [":ui_test"],
)

xctrunner(
name = "ui_test_xctrunner_app_multiple_targets",
testonly = True,
tests = [
":ui_test",
":ui_test_with_fmwk",
],
)

# ---------------------------------------------------------------------------------------

ios_unit_test(
Expand Down
Loading

0 comments on commit 8cd6f3b

Please sign in to comment.