Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
kapoorlakshya committed Sep 13, 2024
1 parent 421d428 commit 5828884
Show file tree
Hide file tree
Showing 19 changed files with 665 additions and 0 deletions.
Binary file added .DS_Store
Binary file not shown.
6 changes: 6 additions & 0 deletions apple/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,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 @@ -811,6 +811,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
62 changes: 62 additions & 0 deletions apple/internal/xctrunner.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""
Rule for merging multiple test targets into a single XCTRunner.app bundle.
"""

load("@build_bazel_rules_apple//apple:providers.bzl", "AppleBundleInfo")

def _xctrunner_impl(ctx):
# Get test target info
bundle_info = [target[AppleBundleInfo] for target in ctx.attr.test_targets]
xctests = [info.archive for info in bundle_info] # xctest bundles
infoplist = [info.infoplist for info in bundle_info] # Info.plist files
output = ctx.actions.declare_directory(ctx.label.name + ".app")

# Args for _make_xctrunner
arguments = ctx.actions.args()
arguments.add("--name", ctx.label.name)
arguments.add("--platform", ctx.attr.platform)

# absolute paths to xctest bundles
xctest_paths = [xctest.path for xctest in xctests]
arguments.add_all(
xctest_paths,
before_each = "--xctest",
expand_directories = False,
)

# app bundle output path
arguments.add("--output", output.path)

ctx.actions.run(
inputs = depset(xctests + infoplist),
outputs = [output],
executable = ctx.executable._make_xctrunner,
arguments = [arguments],
mnemonic = "MakeXCTRunner",
)

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

xctrunner = rule(
implementation = _xctrunner_impl,
attrs = {
"test_targets": attr.label_list(
mandatory = True,
providers = [
AppleBundleInfo,
],
doc = "List of ios_ui_test targets to merge.",
),
"platform": attr.string(
default = "iPhoneOS.platform",
mandatory = False,
doc = "Platform to bundle for. Default: iPhoneOS.platform",
),
"_make_xctrunner": 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.",
),
},
)
24 changes: 24 additions & 0 deletions apple/xctrunner.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2024 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.

"""
Rules for creating XCTRunner.
"""

load(
"@build_bazel_rules_apple//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
Binary file added examples/.DS_Store
Binary file not shown.
Binary file added examples/ios/.DS_Store
Binary file not shown.
7 changes: 7 additions & 0 deletions examples/ios/HelloWorldSwift/BUILD
Original file line number Diff line number Diff line change
@@ -1,6 +1,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:xctrunner.bzl", "xctrunner")
load("//apple:ios.bzl", "ios_application", "ios_ui_test", "ios_unit_test")

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

xctrunner(
name = "HelloWorldSwiftXCTRunner",
test_targets = [":HelloWorldSwiftUITests"],
testonly = True,
)
148 changes: 148 additions & 0 deletions test/starlark_tests/xctrunner_tests.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Copyright 2024 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.

"""xctrunner Starlark tests."""

load(
"//test/starlark_tests/rules:common_verification_tests.bzl",
"archive_contents_test",
)

def xctrunner_test_suite(name):


def xcarchive_test_suite(name):
"""Test suite for xcarchive rule.
Args:
name: the base name to be used in things created by this macro
"""

# Verify xcarchive bundles required files and app for simulator and device.
archive_contents_test(
name = "{}_contains_xcarchive_files_simulator".format(name),
build_type = "simulator",
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_minimal.xcarchive",
contains = [
"$BUNDLE_ROOT/Info.plist",
"$BUNDLE_ROOT/Products/Applications/app_minimal.app",
],
plist_test_file = "$BUNDLE_ROOT/Info.plist",
plist_test_values = {
"ApplicationProperties:ApplicationPath": "Applications/app_minimal.app",
"ApplicationProperties:ArchiveVersion": "2",
"ApplicationProperties:CFBundleIdentifier": "com.google.example",
"ApplicationProperties:CFBundleShortVersionString": "1.0",
"ApplicationProperties:CFBundleVersion": "1.0",
"Name": "app_minimal",
"SchemeName": "app_minimal",
},
tags = [name],
)
archive_contents_test(
name = "{}_contains_xcarchive_files_simulator_dsyms".format(name),
build_type = "simulator",
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_minimal.xcarchive",
contains = [
"$BUNDLE_ROOT/dSYMs/app_minimal.app.dSYM",
"$BUNDLE_ROOT/dSYMs/app_minimal.app.dSYM/Contents/Resources/DWARF/app_minimal",
"$BUNDLE_ROOT/dSYMs/app_minimal.app.dSYM/Contents/Info.plist",
"$BUNDLE_ROOT/Info.plist",
"$BUNDLE_ROOT/Products/Applications/app_minimal.app",
],
plist_test_file = "$BUNDLE_ROOT/Info.plist",
plist_test_values = {
"ApplicationProperties:ApplicationPath": "Applications/app_minimal.app",
"ApplicationProperties:ArchiveVersion": "2",
"ApplicationProperties:CFBundleIdentifier": "com.google.example",
"ApplicationProperties:CFBundleShortVersionString": "1.0",
"ApplicationProperties:CFBundleVersion": "1.0",
"Name": "app_minimal",
"SchemeName": "app_minimal",
},
apple_generate_dsym = True,
tags = [name],
)
archive_contents_test(
name = "{}_contains_xcarchive_files_simulator_dsyms_extensions".format(name),
build_type = "simulator",
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_ext_space_in_path.xcarchive",
contains = [
"$BUNDLE_ROOT/dSYMs/app_with_ext_space_in_path.app.dSYM",
"$BUNDLE_ROOT/dSYMs/ext with space.appex.dSYM",
"$BUNDLE_ROOT/dSYMs/ext with space.appex.dSYM/Contents/Resources/DWARF/ext with space",
"$BUNDLE_ROOT/dSYMs/ext with space.appex.dSYM/Contents/Info.plist",
"$BUNDLE_ROOT/Info.plist",
"$BUNDLE_ROOT/Products/Applications/app_with_ext_space_in_path.app",
],
plist_test_file = "$BUNDLE_ROOT/Info.plist",
plist_test_values = {
"ApplicationProperties:ApplicationPath": "Applications/app_with_ext_space_in_path.app",
"ApplicationProperties:ArchiveVersion": "2",
"ApplicationProperties:CFBundleIdentifier": "com.google.example",
"ApplicationProperties:CFBundleShortVersionString": "1.0",
"ApplicationProperties:CFBundleVersion": "1.0",
"Name": "app_with_ext_space_in_path",
"SchemeName": "app_with_ext_space_in_path",
},
apple_generate_dsym = True,
tags = [name],
)
archive_contents_test(
name = "{}_contains_xcarchive_files_simulator_linkmaps".format(name),
build_type = "simulator",
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_minimal.xcarchive",
contains = [
"$BUNDLE_ROOT/Info.plist",
"$BUNDLE_ROOT/Linkmaps/app_minimal_x86_64.linkmap",
"$BUNDLE_ROOT/Products/Applications/app_minimal.app",
],
plist_test_file = "$BUNDLE_ROOT/Info.plist",
plist_test_values = {
"ApplicationProperties:ApplicationPath": "Applications/app_minimal.app",
"ApplicationProperties:ArchiveVersion": "2",
"ApplicationProperties:CFBundleIdentifier": "com.google.example",
"ApplicationProperties:CFBundleShortVersionString": "1.0",
"ApplicationProperties:CFBundleVersion": "1.0",
"Name": "app_minimal",
"SchemeName": "app_minimal",
},
objc_generate_linkmap = True,
tags = [name],
)
archive_contents_test(
name = "{}_contains_xcarchive_files_device".format(name),
build_type = "device",
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_minimal.xcarchive",
contains = [
"$BUNDLE_ROOT/Info.plist",
"$BUNDLE_ROOT/Products/Applications/app_minimal.app",
],
plist_test_file = "$BUNDLE_ROOT/Info.plist",
plist_test_values = {
"ApplicationProperties:ApplicationPath": "Applications/app_minimal.app",
"ApplicationProperties:ArchiveVersion": "2",
"ApplicationProperties:CFBundleIdentifier": "com.google.example",
"ApplicationProperties:CFBundleShortVersionString": "1.0",
"ApplicationProperties:CFBundleVersion": "1.0",
"Name": "app_minimal",
"SchemeName": "app_minimal",
},
tags = [name],
)

native.test_suite(
name = name,
tags = [name],
)
1 change: 1 addition & 0 deletions tools/wrapper_common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ py_library(
"//tools/swift_stdlib_tool:__pkg__",
"//tools/xcarchivetool:__pkg__",
"//tools/xctoolrunner:__pkg__",
"//tools/xctrunnertool:__pkg__",
],
)

Expand Down
16 changes: 16 additions & 0 deletions tools/xctrunnertool/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
py_library(
name = "lib",
srcs = glob(["lib/*.py"]),
imports = ["."],
visibility = ["//visibility:public"],
)

py_binary(
name = "run",
srcs = ["run.py"],
imports = [
".",
],
visibility = ["//visibility:public"],
deps = [":lib"],
)
24 changes: 24 additions & 0 deletions tools/xctrunnertool/lib/dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env python3

"""
List of dependencies (frameworks, private frameworks, dylibs, etc.)
to copy to the test bundle.
"""

FRAMEWORK_DEPS = [
"XCTest.framework",
"Testing.framework", # Xcode 16+
]

PRIVATE_FRAMEWORK_DEPS = [
"XCTAutomationSupport.framework", # Xcode 15+
"XCTestCore.framework",
"XCTestSupport.framework",
"XCUIAutomation.framework",
"XCUnit.framework",
]

DYLIB_DEPS = [
"libXCTestBundleInject.dylib",
"libXCTestSwiftSupport.dylib",
]
24 changes: 24 additions & 0 deletions tools/xctrunnertool/lib/lipo_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env python3

import shutil
from lib.shell import shell


class LipoUtil:
"Lipo utility class."

def __init__(self):
self.lipo_path = shutil.which("lipo")

def has_arch(self, bin_path: str, arch: str) -> bool:
"Returns True if the given binary has the given arch."
cmd = f"{self.lipo_path} -info {bin_path}"
output = shell(cmd, check_status=False)
return arch in output

def remove_arch(self, bin_path: str, arch: str):
"Removes the given arch from the binary."
if self.has_arch(bin_path, arch):
cmd = f"{self.lipo_path} {bin_path} -remove {arch} -output {bin_path}"
output = shell(cmd)
print(output)
Loading

0 comments on commit 5828884

Please sign in to comment.