Skip to content

Commit 6511c93

Browse files
thymikeeclaude
andcommitted
refactor(move): move the runner's inline unit tests into UnitTests/
Every whole `#if AGENT_DEVICE_RUNNER_UNIT_TESTS` test block in a production runner source moves to `UnitTests/RunnerTests+<Source>Tests.swift` under the same guard, with the same test names and bodies. Production sources keep only the guarded test seams (overrides, injected failures, the recorder timestamp accessor, and RunnerTests' stored test properties). Declarations a moved test reads widen from private to internal. Fixture loaders that resolve contracts/fixtures from #filePath step up one more directory, as the existing UnitTests loaders do. Part of #2792 Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
1 parent 60e5332 commit 6511c93

51 files changed

Lines changed: 4083 additions & 4027 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerScrollViewportPolicy.swift‎

Lines changed: 4 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ import AgentDeviceSnapshotPresentation
1212
//
1313
// The pure rule below is geometry on purpose — no XCUIApplication — so its exact decision is proven
1414
// against the golden table shared with its TS twin, `clipScrollViewportAboveKeyboard` in
15-
// packages/contracts/src/scroll-gesture.ts, asserted in that file's test beside this one. The table
16-
// carries only frames representable in both languages: `CGRect` standardizes a negative extent into a
17-
// positive height at a moved origin, so a negative `height` is tested on the TS side alone.
15+
// packages/contracts/src/scroll-gesture.ts, asserted in that file's test and in
16+
// UnitTests/RunnerTests+ScrollViewportPolicyTests.swift. The table carries only frames
17+
// representable in both languages: `CGRect` standardizes a negative extent into a positive height
18+
// at a moved origin, so a negative `height` is tested on the TS side alone.
1819
//
1920
// The `extension RunnerTests` below is the one impure caller: it reads the runner's own live keyboard
2021
// frame, because a frame threaded from the daemon would predate the keyboard.
@@ -248,165 +249,3 @@ extension RunnerTests {
248249
}
249250
#endif
250251
}
251-
252-
#if AGENT_DEVICE_RUNNER_UNIT_TESTS
253-
private struct ScrollViewportPolicyFixture: Decodable {
254-
struct Frame: Decodable {
255-
let x: Double
256-
let y: Double
257-
let width: Double
258-
let height: Double
259-
260-
var cgRect: CGRect {
261-
CGRect(x: x, y: y, width: width, height: height)
262-
}
263-
}
264-
265-
struct Constants: Decodable {
266-
let minVisibleFraction: Double
267-
let accessoryAllowance: Double
268-
}
269-
270-
struct Expected: Decodable {
271-
let kind: String
272-
let viewport: Frame?
273-
let keyboardMinY: Double?
274-
let visibleHeight: Double?
275-
}
276-
277-
struct TestCase: Decodable {
278-
let name: String
279-
let viewport: Frame
280-
let keyboard: Frame
281-
let expected: Expected
282-
}
283-
284-
let constants: Constants
285-
let cases: [TestCase]
286-
}
287-
288-
extension RunnerTests {
289-
/// Golden parity table (#2500): every case in contracts/fixtures/scroll-keyboard-policy.json must
290-
/// agree with the vitest twin. Add cases there, never fork the rule.
291-
func testScrollViewportKeyboardClipMatchesGoldenParityTable() throws {
292-
let fixture = try loadScrollViewportPolicyFixture()
293-
XCTAssertFalse(fixture.cases.isEmpty, "parity table must not be empty")
294-
for testCase in fixture.cases {
295-
let clip = ScrollViewportPolicy.clip(
296-
viewport: testCase.viewport.cgRect,
297-
keyboard: testCase.keyboard.cgRect
298-
)
299-
switch testCase.expected.kind {
300-
case "unobstructed":
301-
XCTAssertEqual(clip, .unobstructed, testCase.name)
302-
case "avoided":
303-
let expectedFrame = try XCTUnwrap(testCase.expected.viewport, testCase.name).cgRect
304-
let expectedMinY = try XCTUnwrap(testCase.expected.keyboardMinY, testCase.name)
305-
XCTAssertEqual(
306-
clip,
307-
.avoided(frame: expectedFrame, keyboardMinY: expectedMinY),
308-
testCase.name
309-
)
310-
case "occluded":
311-
let expectedMinY = try XCTUnwrap(testCase.expected.keyboardMinY, testCase.name)
312-
let expectedVisibleHeight = try XCTUnwrap(testCase.expected.visibleHeight, testCase.name)
313-
XCTAssertEqual(
314-
clip,
315-
.occluded(keyboardMinY: expectedMinY, visibleHeight: expectedVisibleHeight),
316-
testCase.name
317-
)
318-
default:
319-
XCTFail("unknown expected kind `\(testCase.expected.kind)` in \(testCase.name)")
320-
}
321-
}
322-
}
323-
324-
/// The thresholds are the table's, not this file's. The refusal reason and the runner code are
325-
/// each one side's own vocabulary: the reason is what the host publishes, the code is what this
326-
/// runner answers with, and neither is a shared clip constant.
327-
func testScrollViewportPolicyUsesParityTableConstants() throws {
328-
let constants = try loadScrollViewportPolicyFixture().constants
329-
XCTAssertEqual(constants.minVisibleFraction, ScrollViewportPolicy.minVisibleFraction)
330-
XCTAssertEqual(constants.accessoryAllowance, ScrollViewportPolicy.accessoryAllowance)
331-
}
332-
333-
/// A clipped landscape band shortens the frame, and `CoordinateSpaceRotation.native(point:)` derives a
334-
/// `landscapeRight` native x from the frame's HEIGHT. Rotating inside the band therefore moves the
335-
/// dispatched path sideways by exactly what the keyboard took, off the lane the plan was built for,
336-
/// so the plan band and the coordinate basis stay separate values through dispatch (#2500).
337-
func testScrollViewportDispatchKeepsTheUnclippedFrameAsItsCoordinateRotationBasis() throws {
338-
let viewport = CGRect(x: 0, y: 0, width: 1210, height: 834)
339-
let keyboard = CGRect(x: 0, y: 588, width: 1210, height: 246)
340-
let clip = ScrollViewportPolicy.clip(viewport: viewport, keyboard: keyboard)
341-
guard case .avoided(let band, let keyboardMinY) = clip else {
342-
return XCTFail("expected a landscape keyboard to be avoided, got \(clip)")
343-
}
344-
XCTAssertEqual(band.height, 576)
345-
346-
guard case .gesture(let gesture) = ScrollViewportPolicy.frames(
347-
referenceFrame: viewport,
348-
clip: clip
349-
).gestureDispatch(direction: .up, amount: nil, pixels: nil) else {
350-
return XCTFail("expected a gesture inside the clipped band")
351-
}
352-
XCTAssertEqual(gesture.planFrame, band)
353-
XCTAssertEqual(gesture.keyboardMinY, keyboardMinY)
354-
XCTAssertEqual(gesture.coordinateFrame, viewport, "the rotation basis must survive the clip")
355-
XCTAssertLessThanOrEqual(
356-
max(gesture.plan.y1, gesture.plan.y2),
357-
keyboard.minY - ScrollViewportPolicy.accessoryAllowance,
358-
"a landscape swipe must stay clear of the keys"
359-
)
360-
361-
let reported = gesture.attachingEvidence(
362-
to: Response(
363-
ok: true,
364-
data: DataPayload(referenceWidth: viewport.width, referenceHeight: viewport.height),
365-
error: nil
366-
)
367-
)
368-
XCTAssertEqual(
369-
reported.data?.referenceHeight,
370-
band.height,
371-
"the payload names the band the plan ran inside, not the synthesis frame"
372-
)
373-
XCTAssertEqual(reported.data?.referenceWidth, viewport.width)
374-
XCTAssertEqual(reported.data?.keyboardMinY, keyboardMinY)
375-
XCTAssertEqual(reported.data?.keyboardAvoided, true)
376-
377-
let orientedStartY = gesture.planFrame.minY + gesture.plan.y1
378-
let dispatchedFromViewport = CoordinateSpaceRotation.native(
379-
point: CGPoint(x: gesture.planFrame.minX + gesture.plan.x1, y: orientedStartY),
380-
in: gesture.coordinateFrame,
381-
interfaceOrientation: RunnerInterfaceOrientation.landscapeRight
382-
)
383-
let dispatchedFromBand = CoordinateSpaceRotation.native(
384-
point: CGPoint(x: gesture.planFrame.minX + gesture.plan.x1, y: orientedStartY),
385-
in: gesture.planFrame,
386-
interfaceOrientation: RunnerInterfaceOrientation.landscapeRight
387-
)
388-
XCTAssertEqual(
389-
dispatchedFromViewport.x - dispatchedFromBand.x,
390-
viewport.height - band.height,
391-
accuracy: 0.001,
392-
"rotating inside the clipped band would shift native x by what the keyboard took"
393-
)
394-
}
395-
396-
private func loadScrollViewportPolicyFixture() throws -> ScrollViewportPolicyFixture {
397-
let fixtureURL = URL(fileURLWithPath: #filePath)
398-
.deletingLastPathComponent() // AgentDeviceRunnerUITests
399-
.deletingLastPathComponent() // AgentDeviceRunner
400-
.deletingLastPathComponent() // runner
401-
.deletingLastPathComponent() // apple
402-
.deletingLastPathComponent() // repo root
403-
.appendingPathComponent("contracts")
404-
.appendingPathComponent("fixtures")
405-
.appendingPathComponent("scroll-keyboard-policy.json")
406-
return try JSONDecoder().decode(
407-
ScrollViewportPolicyFixture.self,
408-
from: Data(contentsOf: fixtureURL)
409-
)
410-
}
411-
}
412-
#endif

‎apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSystemSurfaceHostPolicy.swift‎

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -30,51 +30,3 @@ enum SystemSurfaceHostRegistry {
3030
host(forBundleId: bundleId) != nil
3131
}
3232
}
33-
34-
#if AGENT_DEVICE_RUNNER_UNIT_TESTS
35-
import XCTest
36-
37-
private struct SystemSurfaceHostFixture: Decodable {
38-
struct Host: Decodable {
39-
let bundleId: String
40-
let kind: String
41-
}
42-
let hosts: [Host]
43-
}
44-
45-
extension RunnerTests {
46-
func testSystemSurfaceHostRegistryMirrorsGoldenFixture() throws {
47-
let fixtureURL = URL(fileURLWithPath: #filePath)
48-
.deletingLastPathComponent() // AgentDeviceRunnerUITests
49-
.deletingLastPathComponent() // AgentDeviceRunner
50-
.deletingLastPathComponent() // runner
51-
.deletingLastPathComponent() // apple
52-
.deletingLastPathComponent() // repo root
53-
.appendingPathComponent("contracts")
54-
.appendingPathComponent("fixtures")
55-
.appendingPathComponent("ios-system-surface-hosts.json")
56-
let fixture = try JSONDecoder().decode(
57-
SystemSurfaceHostFixture.self,
58-
from: Data(contentsOf: fixtureURL)
59-
)
60-
let registry = SystemSurfaceHostRegistry.hosts.map { [$0.bundleId, $0.kind.rawValue] }
61-
let golden = fixture.hosts.map { [$0.bundleId, $0.kind] }
62-
XCTAssertEqual(registry, golden, "SystemSurfaceHostRegistry drifted from the golden fixture")
63-
}
64-
65-
func testSystemSurfaceHostRegistryRecognizesRegisteredHosts() {
66-
XCTAssertTrue(SystemSurfaceHostRegistry.isSystemSurfaceHost("com.apple.SafariViewService"))
67-
XCTAssertTrue(SystemSurfaceHostRegistry.isSystemSurfaceHost("com.apple.PassbookUIService"))
68-
XCTAssertFalse(SystemSurfaceHostRegistry.isSystemSurfaceHost("com.example.app"))
69-
XCTAssertFalse(SystemSurfaceHostRegistry.isSystemSurfaceHost(nil))
70-
XCTAssertEqual(
71-
SystemSurfaceHostRegistry.host(forBundleId: "com.apple.SafariViewService")?.kind,
72-
.webAuth
73-
)
74-
XCTAssertEqual(
75-
SystemSurfaceHostRegistry.host(forBundleId: "com.apple.PassbookUIService")?.kind,
76-
.payment
77-
)
78-
}
79-
}
80-
#endif

‎apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTapPointPolicy.swift‎

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -25,53 +25,3 @@ enum TapPointPolicy {
2525
&& centerY >= windowFrame.minY && centerY <= windowFrame.maxY
2626
}
2727
}
28-
29-
#if AGENT_DEVICE_RUNNER_UNIT_TESTS
30-
private struct TapPointPolicyFixture: Decodable {
31-
struct Frame: Decodable {
32-
let x: Double
33-
let y: Double
34-
let width: Double
35-
let height: Double
36-
37-
var cgRect: CGRect {
38-
CGRect(x: x, y: y, width: width, height: height)
39-
}
40-
}
41-
42-
let name: String
43-
let elementFrame: Frame
44-
let windowFrame: Frame
45-
let allowed: Bool
46-
}
47-
48-
extension RunnerTests {
49-
// Golden parity table (ADR 0011 Layer 2): every case in
50-
// contracts/fixtures/tap-point-policy.json must agree with the vitest twin
51-
// (tap-point-policy-parity.test.ts). Add cases there, never fork the rule.
52-
func testTapPointPolicyMatchesGoldenParityTable() throws {
53-
let fixtureURL = URL(fileURLWithPath: #filePath)
54-
.deletingLastPathComponent() // AgentDeviceRunnerUITests
55-
.deletingLastPathComponent() // AgentDeviceRunner
56-
.deletingLastPathComponent() // runner
57-
.deletingLastPathComponent() // apple
58-
.deletingLastPathComponent() // repo root
59-
.appendingPathComponent("contracts")
60-
.appendingPathComponent("fixtures")
61-
.appendingPathComponent("tap-point-policy.json")
62-
let data = try Data(contentsOf: fixtureURL)
63-
let cases = try JSONDecoder().decode([TapPointPolicyFixture].self, from: data)
64-
XCTAssertFalse(cases.isEmpty, "parity table must not be empty")
65-
for fixture in cases {
66-
XCTAssertEqual(
67-
TapPointPolicy.isAllowed(
68-
elementFrame: fixture.elementFrame.cgRect,
69-
windowFrame: fixture.windowFrame.cgRect
70-
),
71-
fixture.allowed,
72-
fixture.name
73-
)
74-
}
75-
}
76-
}
77-
#endif

0 commit comments

Comments
 (0)