|
| 1 | +import assert from 'node:assert/strict'; |
| 2 | +import fs from 'node:fs'; |
| 3 | +import path from 'node:path'; |
| 4 | +import { fileURLToPath } from 'node:url'; |
| 5 | +import { test } from 'vitest'; |
| 6 | + |
| 7 | +const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); |
| 8 | +const commandExecutionSwiftPath = path.join( |
| 9 | + repoRoot, |
| 10 | + 'apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift', |
| 11 | +); |
| 12 | + |
| 13 | +test('Apple gesture command preserves the fling fast-swipe and coordinate fallback route', () => { |
| 14 | + const source = fs.readFileSync(commandExecutionSwiftPath, 'utf8'); |
| 15 | + const gestureCase = extractSwiftSwitchCase(source, '.gesture', '.gestureViewport'); |
| 16 | + const fastSwipeBranch = extractSourceSegment( |
| 17 | + gestureCase, |
| 18 | + 'if plannedGestureExecution(for: plan) == .fastSwipe', |
| 19 | + 'let (timing, outcome)', |
| 20 | + ); |
| 21 | + |
| 22 | + assert.match(fastSwipeBranch, /executeDragGesture\(/); |
| 23 | + assert.match(fastSwipeBranch, /synthesized:\s*true/); |
| 24 | + assert.match(fastSwipeBranch, /synthesizedPolicyKind:\s*\.synthesizedDrag/); |
| 25 | + assert.match(fastSwipeBranch, /synthesizedProfile:\s*\.fastSwipe/); |
| 26 | + assert.doesNotMatch(fastSwipeBranch, /sampledPlannedGesture/); |
| 27 | + |
| 28 | + const dragExecutor = extractSwiftFunction(source, 'executeDragGesture'); |
| 29 | + assert.match( |
| 30 | + dragExecutor, |
| 31 | + /fallback = gestureFallback\(strategy: "xctest-coordinate-drag", from: outcome\)/, |
| 32 | + ); |
| 33 | + assert.match(dragExecutor, /dragAt\(/); |
| 34 | +}); |
| 35 | + |
| 36 | +function extractSwiftSwitchCase(source: string, name: string, nextName: string): string { |
| 37 | + return extractSourceSegment(source, `case ${name}:`, `case ${nextName}:`); |
| 38 | +} |
| 39 | + |
| 40 | +function extractSourceSegment(source: string, startMarker: string, endMarker: string): string { |
| 41 | + const start = source.indexOf(startMarker); |
| 42 | + assert.notEqual(start, -1, `missing source marker ${startMarker}`); |
| 43 | + const end = source.indexOf(endMarker, start); |
| 44 | + assert.notEqual(end, -1, `missing source marker ${endMarker}`); |
| 45 | + return source.slice(start, end); |
| 46 | +} |
| 47 | + |
| 48 | +function extractSwiftFunction(source: string, name: string): string { |
| 49 | + const signatureIndex = source.indexOf(`func ${name}`); |
| 50 | + assert.notEqual(signatureIndex, -1, `missing Swift function ${name}`); |
| 51 | + const bodyStart = source.indexOf('{', signatureIndex); |
| 52 | + assert.notEqual(bodyStart, -1, `missing Swift function body ${name}`); |
| 53 | + let depth = 0; |
| 54 | + for (let index = bodyStart; index < source.length; index += 1) { |
| 55 | + const char = source[index]; |
| 56 | + if (char === '{') depth += 1; |
| 57 | + if (char === '}') depth -= 1; |
| 58 | + if (depth === 0) return source.slice(signatureIndex, index + 1); |
| 59 | + } |
| 60 | + assert.fail(`unterminated Swift function ${name}`); |
| 61 | +} |
0 commit comments