Skip to content

Commit c3720f9

Browse files
committed
Add XCUIAutomation and XCTest
Fixes #737.
1 parent e5318d3 commit c3720f9

File tree

29 files changed

+941
-30
lines changed

29 files changed

+941
-30
lines changed

.github/workflows/ci.yml

Lines changed: 13 additions & 13 deletions
Large diffs are not rendered by default.

Cargo.lock

Lines changed: 79 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ objc2-vision = { path = "framework-crates/objc2-vision", version = "0.3.1", defa
277277
objc2-watch-connectivity = { path = "framework-crates/objc2-watch-connectivity", version = "0.3.1", default-features = false }
278278
objc2-watch-kit = { path = "framework-crates/objc2-watch-kit", version = "0.3.1", default-features = false }
279279
objc2-web-kit = { path = "framework-crates/objc2-web-kit", version = "0.3.1", default-features = false }
280+
objc2-xc-test = { path = "framework-crates/objc2-xc-test", version = "0.3.1", default-features = false }
281+
objc2-xc-ui-automation = { path = "framework-crates/objc2-xc-ui-automation", version = "0.3.1", default-features = false }
280282
objc2-itunes-library = { path = "framework-crates/objc2-itunes-library", version = "0.3.1", default-features = false }
281283

282284
# These are useful for examples, since it allows them to be self-contained.
@@ -467,4 +469,6 @@ objc2-vision = { path = "framework-crates/objc2-vision" }
467469
objc2-watch-connectivity = { path = "framework-crates/objc2-watch-connectivity" }
468470
objc2-watch-kit = { path = "framework-crates/objc2-watch-kit" }
469471
objc2-web-kit = { path = "framework-crates/objc2-web-kit" }
472+
objc2-xc-test = { path = "framework-crates/objc2-xc-test" }
473+
objc2-xc-ui-automation = { path = "framework-crates/objc2-xc-ui-automation" }
470474
objc2-itunes-library = { path = "framework-crates/objc2-itunes-library" }

crates/header-translator/configs/skipped.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Kerberos = "Too low-level"
88
Kernel = "Too low-level"
99
PCSC = "Too low-level, consider crates like `pcsc` instead"
1010
Matter = "Mostly available [here](https://github.com/project-chip/connectedhomeip)"
11+
Python3 = "Better served by dedicated crates like `pyo3-ffi`"
1112

1213
ForceFeedback = "Very C-centric and old"
1314
GSS = "Very C-centric and old"
@@ -73,13 +74,14 @@ SwiftUI = "Swift-only"
7374
SwiftUICore = "Swift-only"
7475
TabletopKit = "Swift-only"
7576
TabularData = "Swift-only"
77+
Testing = "Swift-only"
7678
TipKit = "Swift-only"
7779
Translation = "Swift-only"
7880
TranslationUIProvider = "Swift-only"
7981
VisionKit = "Swift-only"
8082
WeatherKit = "Swift-only"
81-
WorkoutKit = "Swift-only"
8283
WidgetKit = "Mostly Swift-only"
84+
WorkoutKit = "Swift-only"
8385

8486
AppleScriptKit = "Basically empty nowadays" # requires !swift
8587
AppleScriptObjC = "Basically empty nowadays"
@@ -120,6 +122,11 @@ JavaRuntimeSupport = "Probably not really interesting."
120122
CalendarStore = "Very deprecated" # requires !swift
121123
CoreMIDIServer = "Very deprecated"
122124

125+
InterfaceBuilderKit = "TODO. Developer-only"
126+
XcodeKit = "TODO. Developer-only"
127+
StoreKitTest = "TODO. Developer-only"
128+
LiveExecutionResultsLogger = "Removed in Xcode 26"
129+
123130
Network = "TODO, see [#646](https://github.com/madsmtm/objc2/issues/646)"
124131
DeviceDiscoveryUI = "Needs Network first"
125132

crates/header-translator/src/bin/check_all_frameworks_known.rs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,25 @@
77
//! ```
88
use std::fs;
99
use std::os::unix::ffi::OsStrExt;
10+
use std::path::Path;
1011
use std::{collections::BTreeSet, process::ExitCode};
1112

1213
use apple_sdk::{AppleSdk, DeveloperDirectory, Platform, SimpleSdk};
1314
use header_translator::{load_config, load_skipped};
1415

16+
fn parse_framework_from_path(path: &Path) -> Option<String> {
17+
if path.file_name().unwrap().as_bytes().starts_with(b"_") {
18+
// Ignore private/underscored frameworks
19+
return None;
20+
}
21+
22+
if path.extension().unwrap() != "framework" {
23+
return None;
24+
}
25+
26+
Some(path.file_stem().unwrap().to_string_lossy().into_owned())
27+
}
28+
1529
fn all_frameworks() -> BTreeSet<String> {
1630
let developer_dir = DeveloperDirectory::from_env()
1731
.unwrap()
@@ -28,18 +42,28 @@ fn all_frameworks() -> BTreeSet<String> {
2842
}
2943

3044
for dir in fs::read_dir(sdk.path().join("System/Library/Frameworks")).unwrap() {
31-
let path = dir.unwrap().path();
32-
33-
if path.file_name().unwrap().as_bytes().starts_with(b"_") {
34-
// Ignore private/underscored frameworks
35-
continue;
45+
if let Some(framework) = parse_framework_from_path(&dir.unwrap().path()) {
46+
res.insert(framework);
3647
}
48+
}
49+
}
3750

38-
if path.extension().unwrap() != "framework" {
39-
continue;
51+
for platform in developer_dir.platforms().unwrap() {
52+
if *(platform.as_ref() as &Platform) == Platform::DriverKit {
53+
// Ignore DriverKit for now
54+
continue;
55+
}
56+
57+
for dir in fs::read_dir(platform.path().join("Developer/Library/Frameworks")).unwrap() {
58+
if let Some(framework) = parse_framework_from_path(&dir.unwrap().path()) {
59+
res.insert(framework);
4060
}
61+
}
62+
}
4163

42-
res.insert(path.file_stem().unwrap().to_string_lossy().into_owned());
64+
for dir in fs::read_dir(developer_dir.path().join("Library/Frameworks")).unwrap() {
65+
if let Some(framework) = parse_framework_from_path(&dir.unwrap().path()) {
66+
res.insert(framework);
4367
}
4468
}
4569

crates/header-translator/src/config.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ pub struct LibraryConfig {
253253
#[serde(rename = "is-library")]
254254
#[serde(default)]
255255
pub is_library: bool,
256+
#[serde(rename = "located-outside-sdk")]
257+
#[serde(default)]
258+
pub located_outside_sdk: bool,
256259

257260
#[serde(default = "link_default")]
258261
pub link: bool,
@@ -656,7 +659,10 @@ impl LibraryConfig {
656659
config.krate.replace("objc2-", "").replace('-', ""),
657660
"crate name had an unexpected format",
658661
);
659-
if matches!(&*config.krate, "objc2-tv-ml-kit" | "objc2-tv-ui-kit") {
662+
if matches!(
663+
&*config.krate,
664+
"objc2-tv-ml-kit" | "objc2-tv-ui-kit" | "objc2-xc-ui-automation"
665+
) {
660666
// Named this way for better consistency with other tv-specific crates.
661667
return Ok(config);
662668
}

crates/header-translator/src/main.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,24 @@ fn get_translation_unit<'i: 'c, 'c>(
484484
}
485485
}
486486

487+
// Certain developer frameworks like XCTest are found in the platform
488+
// path instead of the SDK path.
489+
let platform_framework_path = sdk
490+
.path
491+
.parent()
492+
.unwrap()
493+
.parent()
494+
.unwrap()
495+
.join("Library/Frameworks");
496+
497+
let platform_path = platform_framework_path.join(format!(
498+
"{}.framework/Modules/module.modulemap",
499+
data.framework
500+
));
501+
if data.located_outside_sdk {
502+
path = platform_path;
503+
}
504+
487505
// Find the framework module name
488506
let module = if data.modulemap.is_none() {
489507
let re = regex::Regex::new(r"(?m)^framework +module +(\w*)").unwrap();
@@ -575,6 +593,13 @@ fn get_translation_unit<'i: 'c, 'c>(
575593
]);
576594
}
577595

596+
if data.located_outside_sdk {
597+
arguments.extend(&[
598+
"-iframework",
599+
platform_framework_path.as_os_str().to_str().unwrap(),
600+
]);
601+
}
602+
578603
arguments.extend(data.flags.iter().map(|flag| &**flag));
579604

580605
let tu = index

crates/header-translator/src/unexposed_attr.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,24 +102,31 @@ impl UnexposedAttr {
102102
// `nullability` is already exposed, so we won't bother with that.
103103
// `sendability` is most for backwards-compatibility with older
104104
// versions of system headers that didn't assign sendability.
105-
"NS_HEADER_AUDIT_BEGIN" | "WK_HEADER_AUDIT_BEGIN" => None,
105+
"NS_HEADER_AUDIT_BEGIN" | "WK_HEADER_AUDIT_BEGIN" | "XCT_HEADER_AUDIT_BEGIN" => None,
106106
// Nullability attributes
107107
s if s.starts_with("DISPATCH_NONNULL") => None,
108108
s if s.starts_with("XPC_NONNULL") => None,
109109
"NS_SWIFT_SENDABLE" | "AS_SWIFT_SENDABLE" | "CM_SWIFT_SENDABLE"
110-
| "CT_SWIFT_SENDABLE" | "CV_SWIFT_SENDABLE" => Some(Self::Sendable),
110+
| "CT_SWIFT_SENDABLE" | "CV_SWIFT_SENDABLE" | "XCT_SWIFT_SENDABLE" => {
111+
Some(Self::Sendable)
112+
}
111113
"NS_SWIFT_NONSENDABLE" | "CM_SWIFT_NONSENDABLE" | "CV_SWIFT_NONSENDABLE" => {
112114
Some(Self::NonSendable)
113115
}
114-
"NS_SWIFT_UI_ACTOR" | "WK_SWIFT_UI_ACTOR" => Some(Self::UIActor),
116+
// The main and UI actor is effectively the same on Apple platforms.
117+
"NS_SWIFT_UI_ACTOR"
118+
| "WK_SWIFT_UI_ACTOR"
119+
| "XCT_SWIFT_MAIN_ACTOR"
120+
| "XCUI_SWIFT_MAIN_ACTOR" => Some(Self::UIActor),
115121
"NS_SWIFT_NONISOLATED" | "UIKIT_SWIFT_ACTOR_INDEPENDENT" => Some(Self::NonIsolated),
116122
// TODO
117123
"CF_FORMAT_ARGUMENT" | "CF_FORMAT_FUNCTION" | "NS_FORMAT_FUNCTION"
118124
| "NS_FORMAT_ARGUMENT" => {
119125
let _ = get_arguments();
120126
None
121127
}
122-
"CF_NOESCAPE" | "DISPATCH_NOESCAPE" | "NS_NOESCAPE" => Some(Self::NoEscape),
128+
"CF_NOESCAPE" | "DISPATCH_NOESCAPE" | "NS_NOESCAPE" | "XCT_NOESCAPE"
129+
| "XCUI_NOESCAPE" => Some(Self::NoEscape),
123130
"DISPATCH_NOTHROW" | "NS_SWIFT_NOTHROW" => Some(Self::NoThrow),
124131
// TODO: We could potentially automatically elide this argument
125132
// from the method call, though it's rare enough that it's
@@ -282,7 +289,12 @@ impl UnexposedAttr {
282289
| "WEBKIT_ENUM_DEPRECATED_MAC"
283290
| "WK_AVAILABLE_WATCHOS_ONLY"
284291
| "WK_DEPRECATED_WATCHOS"
285-
| "WK_DEPRECATED_WITH_REPLACEMENT" => {
292+
| "WK_DEPRECATED_WITH_REPLACEMENT"
293+
| "XCT_UNAVAILABLE"
294+
| "XCT_DEPRECATED_WITH_REPLACEMENT"
295+
| "XCUI_UNAVAILABLE"
296+
| "XCUI_DEPRECATED_WITH_REPLACEMENT"
297+
| "XCUI_DEPRECATED_WITH_DIRECT_REPLACEMENT" => {
286298
let _ = get_arguments();
287299
None
288300
}
@@ -354,7 +366,9 @@ impl UnexposedAttr {
354366
| "MP_DEPRECATED_BEGIN"
355367
| "SEC_ASN1_API_DEPRECATED"
356368
| "SECUREDOWNLOAD_API_DEPRECATED"
357-
| "VS_INIT_UNAVAILABLE" => None,
369+
| "VS_INIT_UNAVAILABLE"
370+
| "XCT_METRIC_API_AVAILABLE"
371+
| "XCUI_PROTECTED_RESOURCES_RESET_API_AVAILABLE" => None,
358372
s if s.starts_with("AVAILABLE_MAC_OS_X_VERSION_") => None,
359373
s if s.starts_with("DEPRECATED_IN_MAC_OS_X_VERSION_") => None,
360374
s if s.starts_with("FILEPROVIDER_API_AVAILABILITY_") => None,
@@ -364,6 +378,7 @@ impl UnexposedAttr {
364378
"swift_name"
365379
| "CF_SWIFT_NAME"
366380
| "CF_SWIFT_UNAVAILABLE_FROM_ASYNC"
381+
| "XCT_SWIFT_UNAVAILABLE_FROM_ASYNC"
367382
| "DISPATCH_SWIFT_NAME"
368383
| "IOSFC_SWIFT_NAME"
369384
| "MPS_SWIFT_NAME"
@@ -402,6 +417,8 @@ impl UnexposedAttr {
402417
let _ = get_arguments();
403418
None
404419
}
420+
// Weak imports are still unsupported by Rust.
421+
"XCT_WEAK_EXPORT" => None,
405422
// Irrelevant, we don't emit dispatch_object_t anyhow.
406423
"DISPATCH_TRANSPARENT_UNION" => None,
407424
_ => return Err(()),

crates/objc2/src/topics/about_generated/list_data.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,6 @@
179179
| `WatchConnectivity` | [`objc2-watch-connectivity`](https://crates.io/crates/objc2-watch-connectivity) | [![docs.rs](https://docs.rs/objc2-watch-connectivity/badge.svg)](https://docs.rs/objc2-watch-connectivity/) |
180180
| `WatchKit` | [`objc2-watch-kit`](https://crates.io/crates/objc2-watch-kit) | [![docs.rs](https://docs.rs/objc2-watch-kit/badge.svg)](https://docs.rs/objc2-watch-kit/) |
181181
| `WebKit` | [`objc2-web-kit`](https://crates.io/crates/objc2-web-kit) | [![docs.rs](https://docs.rs/objc2-web-kit/badge.svg)](https://docs.rs/objc2-web-kit/) |
182+
| `XCTest` | [`objc2-xc-test`](https://crates.io/crates/objc2-xc-test) | [![docs.rs](https://docs.rs/objc2-xc-test/badge.svg)](https://docs.rs/objc2-xc-test/) |
183+
| `XCUIAutomation` | [`objc2-xc-ui-automation`](https://crates.io/crates/objc2-xc-ui-automation) | [![docs.rs](https://docs.rs/objc2-xc-ui-automation/badge.svg)](https://docs.rs/objc2-xc-ui-automation/) |
182184
| `iTunesLibrary` | [`objc2-itunes-library`](https://crates.io/crates/objc2-itunes-library) | [![docs.rs](https://docs.rs/objc2-itunes-library/badge.svg)](https://docs.rs/objc2-itunes-library/) |

0 commit comments

Comments
 (0)