also looking at this
fix(android): make every Zig decline speak, and prove Zig answers
#205
8 files
+616
-255
| @@ -357,3 +357,40 @@ export const ZIG_TESTED_ACTIONS = [ | ||
| 357 | 357 | |
| 358 | 358 | /** The one action the suite configures off, so Zig must refuse it by name. */ |
| 359 | 359 | export const ZIG_REFUSED_ACTION = 'getCurrentPosition' |
| 360 | ||
| 361 | /** | |
| 362 | * The three ways an Android native says it gave up, as `android_dispatch.zig` | |
| 363 | * writes them. | |
| 364 | * | |
| 365 | * - fell through to the shim: Kotlin served the action instead of Zig. | |
| 366 | * - failed with no fallback: a callback into Zig gave up, and nothing will. | |
| 367 | * - could not reach the page: Zig had the answer and could not deliver it. | |
| 368 | * | |
| 369 | * `test/android_declines_test.zig` keeps every decline routed through one of | |
| 370 | * these, and `protocol.test.ts` reads the Zig source to check the wording has | |
| 371 | * not drifted from what is matched here. Either half alone would let the suite | |
| 372 | * stop seeing declines and keep passing. | |
| 373 | */ | |
| 374 | export const ANDROID_DECLINE_PHRASES = [ | |
| 375 | 'fell through to the shim', | |
| 376 | 'failed with no fallback', | |
| 377 | 'could not reach the page', | |
| 378 | ] | |
| 379 | ||
| 380 | /** | |
| 381 | * Every Android decline line in a logcat dump, as `action: phrase (error)`. | |
| 382 | * | |
| 383 | * Why the runtime leg needs this rather than the registration line alone: the | |
| 384 | * first run in which the Zig library loaded reported "registered 103 natives" | |
| 385 | * and passed every case — while `getDeviceInfo` threw `NoSuchFieldError` on | |
| 386 | * every call and Kotlin quietly answered instead. Registration proves the | |
| 387 | * library bound. Only the absence of declines, with every decline made to | |
| 388 | * speak, proves Zig answered. | |
| 389 | */ | |
| 390 | export function androidDeclines(text: string): string[] { | |
| 391 | const plain = text.replace(ANSI, '') | |
| 392 | const phrases = ANDROID_DECLINE_PHRASES.map(phrase => phrase.replace(/ /g, '\\s')).join('|') | |
| 393 | const pattern = new RegExp(`craft: (\\w+) (${phrases}) \\(([^)]*)\\)`, 'g') | |
| 394 | return [...plain.matchAll(pattern)].map(match => `${match[1]}: ${match[2]} (${match[3]})`) | |
| 395 | } | |
| 396 | ||