From 54ca64b11f4c2e4f3df57ad511b580621b201f6f Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sun, 16 Aug 2026 12:12:21 -0700 Subject: [PATCH] fix(test): sync ios-qa fixture mirrors with the #2585 DEBUG-guard templates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The #2585 absorb updated DebugBridgeTouch.m.template and Package.swift.template but not their FixtureApp mirrors, failing the template↔fixture parity gate. DebugBridgeTouch.m syncs byte-for-byte; the fixture Package.swift takes only the template's new cSettings DEBUG define on the Touch target (the fixture's own testTarget is fixture-only content the parity normalization deliberately ignores — a naive full copy breaks the XCTest invariant). 23/23 including the real swift build. Co-Authored-By: Claude Fable 5 --- test/fixtures/ios-qa/FixtureApp/Package.swift | 10 +++++++ .../DebugBridgeTouch/DebugBridgeTouch.m | 26 +++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/test/fixtures/ios-qa/FixtureApp/Package.swift b/test/fixtures/ios-qa/FixtureApp/Package.swift index 40477f0fe..c5b9a7318 100644 --- a/test/fixtures/ios-qa/FixtureApp/Package.swift +++ b/test/fixtures/ios-qa/FixtureApp/Package.swift @@ -32,7 +32,17 @@ let package = Package( dependencies: [], path: "Sources/DebugBridgeTouch", publicHeadersPath: "include", + cSettings: [ + // Explicit, because the source guard depends on it. SwiftPM's + // implicit DEBUG for C-family targets is not something to bet a + // private-API exposure on — the two Swift targets already declare + // it, and this target is the one that actually links private API. + .define("DEBUG", .when(configuration: .debug)), + ], linkerSettings: [ + // IOKit is loaded dynamically via dlopen at runtime (it's a + // private framework on iOS and can't be linked statically). + // UIKit links normally. .linkedFramework("UIKit", .when(platforms: [.iOS])), ] ), diff --git a/test/fixtures/ios-qa/FixtureApp/Sources/DebugBridgeTouch/DebugBridgeTouch.m b/test/fixtures/ios-qa/FixtureApp/Sources/DebugBridgeTouch/DebugBridgeTouch.m index aa6954c6d..e82199467 100644 --- a/test/fixtures/ios-qa/FixtureApp/Sources/DebugBridgeTouch/DebugBridgeTouch.m +++ b/test/fixtures/ios-qa/FixtureApp/Sources/DebugBridgeTouch/DebugBridgeTouch.m @@ -20,7 +20,29 @@ #import "DebugBridgeTouch.h" #import -#if TARGET_OS_IOS +#if !defined(DEBUG) + +// RELEASE BUILD: this file deliberately emits NOTHING — no class, no symbols, no +// private-API references. The header still declares the interface, which is inert +// on its own; every consumer of DebugBridgeTouch is itself `#if DEBUG` guarded, so +// nothing references it here and nothing fails to link. +// +// This guard was added because the comments at the top of this file and in the +// header both PROMISED "DEBUG-only; never shipped to App Store" and "never link in +// Release" — and nothing enforced it. Only `#if TARGET_OS_IOS` was tested, so a +// Release build for iOS compiled the whole implementation in. Measured on a real +// app (Seize Day, 2026-08-15), `nm -j` on a Release binary returned 15 DebugBridge +// symbols including +[DebugBridgeTouch sendTapAtPoint:inWindow:], plus +// IOHIDEventCreateDigitizer, AXSSetAutomationEnabled and IOKit.framework strings. +// That is a Guideline 2.5.1 private-API exposure in a shippable binary. +// +// Package.swift's stated guard — `.when(configuration: .debug)` on the consuming +// target's dependency — only exists for SwiftPM consumers. An app integrating this +// as a local package inside an .xcodeproj cannot express it: Xcode's Filters column +// in Frameworks/Libraries offers platform conditions only, never configuration. So +// the guard has to live here, in the source, where it holds for every consumer. + +#elif TARGET_OS_IOS #import #import @@ -340,4 +362,4 @@ static id DBT_HitTestView(UIWindow *window, CGPoint point) { } @end -#endif // TARGET_OS_IOS +#endif // !DEBUG / TARGET_OS_IOS