diff --git a/tests/boundary/filesystem/interfaceBuilderBundle.test.ts b/tests/boundary/filesystem/interfaceBuilderBundle.test.ts
index a418c8f0bd..73f9425d04 100644
--- a/tests/boundary/filesystem/interfaceBuilderBundle.test.ts
+++ b/tests/boundary/filesystem/interfaceBuilderBundle.test.ts
@@ -1013,12 +1013,12 @@ describe("bounded Interface Builder archive decoding", () => {
);
});
- it("decodes an archive whose date the decoder cannot represent", async () => {
+ it("decodes an archive with a date year beyond four digits", async () => {
const root = await createTestTempDirectory("rea-ib-test-");
const bundle = join(root, "Example.app");
const resources = join(bundle, "Contents", "Resources");
await mkdir(resources, { recursive: true });
- // plutil writes years past 9999 unsigned, which the decoder rejects.
+ // XML property-list dates use an extended ISO year in the public schema.
await writeFile(
join(resources, "Far.nib"),
'$archiverNSKeyedArchiver$objects$null11507-08-17T05:20:00Z$top',
@@ -1030,7 +1030,10 @@ describe("bounded Interface Builder archive decoding", () => {
});
expect(result.documents).toHaveLength(1);
- expect(result.limitations).toContainEqual(
+ expect(result.graph.coverage).toContainEqual(
+ expect.objectContaining({ facet: "archive_decode", status: "complete" }),
+ );
+ expect(result.limitations).not.toContainEqual(
expect.stringMatching(
/^Contents\/Resources\/Far\.nib: 1 date value\(s\)/u,
),
@@ -1039,7 +1042,9 @@ describe("bounded Interface Builder archive decoding", () => {
expect.stringContaining("could not be decoded"),
);
});
+});
+describe("Xcode-compiled Interface Builder archives", () => {
it.skipIf(!xcodeIbtoolAvailable)(
"decodes an Xcode-compiled storyboard NIB and recovers its UI routes",
async () => {
diff --git a/tests/boundary/filesystem/keyedArchiveDateRange.test.ts b/tests/boundary/filesystem/keyedArchiveDateRange.test.ts
index 235b402d66..fd5b984a98 100644
--- a/tests/boundary/filesystem/keyedArchiveDateRange.test.ts
+++ b/tests/boundary/filesystem/keyedArchiveDateRange.test.ts
@@ -10,11 +10,11 @@ import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
cliTest(
- "built CLI reports a date the decoder cannot represent as unknown",
+ "built CLI preserves dates with years beyond four digits",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-keyed-archive-date-");
const path = join(root, "archive.plist");
- // plutil writes years past 9999 unsigned, which the decoder rejects.
+ // XML property-list dates use an extended ISO year in the public schema.
const xml = build({
$archiver: "NSKeyedArchiver",
$version: 100000,
@@ -37,15 +37,19 @@ cliTest(
result.objects.map(({ id, kind, value }) => ({ id, kind, value })),
).toEqual([
{ id: 0, kind: "nil", value: "$null" },
- { id: 1, kind: "scalar", value: { $plist_type: "date", iso8601: null } },
+ {
+ id: 1,
+ kind: "scalar",
+ value: { $plist_type: "date", iso8601: "+011507-08-17T05:20:00.000Z" },
+ },
{
id: 2,
kind: "scalar",
value: { $plist_type: "date", iso8601: "2020-01-01T00:00:00.000Z" },
},
]);
- expect(result.limitations).toContainEqual(
- expect.stringContaining("1 date value(s)"),
+ expect(result.limitations).not.toContainEqual(
+ expect.stringContaining("date value(s)"),
);
},
);
diff --git a/tests/boundary/mcp/nativeUiFinalizationMcp.test.ts b/tests/boundary/mcp/nativeUiFinalizationMcp.test.ts
index 51c7c587bd..2a389e1554 100644
--- a/tests/boundary/mcp/nativeUiFinalizationMcp.test.ts
+++ b/tests/boundary/mcp/nativeUiFinalizationMcp.test.ts
@@ -76,13 +76,15 @@ it.each([false, true])(
});
expect(parseMcpToolError(result)).toMatchObject({
error: {
- code: fails ? "cleanup_incomplete" : "cancelled",
+ code: fails ? "cleanup_incomplete" : "provider_timeout",
details: {
- cleanup: fails ? "incomplete" : "complete",
...(fails
? {
+ cleanup: "incomplete",
execution_failure: "execution_failure",
- diagnostics: { primary_error: { code: "cancelled" } },
+ diagnostics: {
+ primary_error: { code: "provider_timeout" },
+ },
resources: ["controlled-ui-runtime"],
}
: {}),
@@ -94,6 +96,7 @@ it.each([false, true])(
},
},
});
+ expect(cleanupLease.released).toBe(!fails);
allowClose = true;
const closed = await client.callTool({
name: "close_binary",
diff --git a/tests/fixtures/keyedArchiveNumberMetadata.ts b/tests/fixtures/keyedArchiveNumberMetadata.ts
index 9369692c93..79ba543e3a 100644
--- a/tests/fixtures/keyedArchiveNumberMetadata.ts
+++ b/tests/fixtures/keyedArchiveNumberMetadata.ts
@@ -11,8 +11,17 @@ import { createTestTempDirectory } from "./temporaryDirectory.js";
const EXACT_INTEGER = { $plist_type: "integer", decimal: "9007199254740993" };
const ROUNDED = 9007199254740992;
+const unknownInteger = (
+ literal: string,
+ reason: "invalid-literal" | "unsupported-markup",
+) => ({
+ $plist_type: "unknown",
+ element: "integer",
+ literal,
+ reason,
+});
-/** Accepted decoder representations whose supplemental metadata needs care. */
+/** Boundary cases that retain exact integers or explicit unknown literals. */
export const mixedArchiveNumberElements = [
"90071992547409923",
"9007199254740992",
@@ -23,8 +32,19 @@ export const mixedArchiveNumberElements = [
"9007199254740992x",
] as const;
+interface MetadataCase {
+ readonly name: string;
+ readonly source: JsonValue;
+ readonly element: string;
+ readonly expected: JsonValue;
+ readonly knownIntegerCount?: number;
+ readonly unknownScalarCount?: number;
+ readonly malformedReference: boolean;
+ readonly integerElement?: string;
+}
+
/** Ordinary dictionaries and malformed numeric references at the same boundary. */
-export const archiveNumberMetadataCases = [
+export const archiveNumberMetadataCases: readonly MetadataCase[] = [
...[
{
element: "9007199254740992",
@@ -39,15 +59,23 @@ export const archiveNumberMetadataCases = [
source: { first: "__INTEGER__", other: "__OTHER__" },
element,
expected: { first: EXACT_INTEGER, other: value },
- incomplete: false,
malformedReference: false,
})),
...mixedArchiveNumberElements.map((element) => ({
name: element,
source: { first: "__INTEGER__", other: "__OTHER__" },
element,
- expected: { first: ROUNDED, other: ROUNDED },
- incomplete: true,
+ expected: {
+ first: EXACT_INTEGER,
+ other: unknownInteger(
+ element.slice("".length, -"".length),
+ element.endsWith("x")
+ ? "invalid-literal"
+ : "unsupported-markup",
+ ),
+ },
+ knownIntegerCount: 1,
+ unknownScalarCount: 1,
malformedReference: false,
})),
...(["UID", "CF$UID"] as const).flatMap((key) => [
@@ -56,7 +84,6 @@ export const archiveNumberMetadataCases = [
source: { [key]: { amount: "__INTEGER__" } },
element: "",
expected: { [key]: { amount: EXACT_INTEGER } },
- incomplete: false,
malformedReference: false,
},
{
@@ -64,7 +91,6 @@ export const archiveNumberMetadataCases = [
source: { [key]: ["__INTEGER__"] },
element: "",
expected: { [key]: [EXACT_INTEGER] },
- incomplete: false,
malformedReference: false,
},
{
@@ -72,30 +98,23 @@ export const archiveNumberMetadataCases = [
source: { [key]: "__INTEGER__" },
element: "",
expected: { [key]: ROUNDED },
- incomplete: false,
malformedReference: true,
},
]),
{
- name: "entity-encoded integer text",
+ // Native plist integer grammar reads raw text, unlike real elements.
+ name: "entity-encoded integer rejected by native plist grammar",
source: { amount: "__INTEGER__" },
element: "",
- expected: { amount: EXACT_INTEGER },
- incomplete: false,
+ expected: {
+ amount: unknownInteger("9007199254740993", "invalid-literal"),
+ },
+ knownIntegerCount: 0,
+ unknownScalarCount: 1,
malformedReference: false,
integerElement: "9007199254740993",
},
-] satisfies readonly {
- name: string;
- source: JsonValue;
- element: string;
- expected: JsonValue;
- incomplete: boolean;
- malformedReference: boolean;
- integerElement?: string;
-}[];
-
-type MetadataCase = (typeof archiveNumberMetadataCases)[number];
+];
/** Write one inert archive and retain the original byte digest for assertions. */
export const keyedArchiveNumberMetadataFixture = async (item: MetadataCase) => {
@@ -108,9 +127,7 @@ export const keyedArchiveNumberMetadataFixture = async (item: MetadataCase) => {
})
.replace(
"__INTEGER__",
- "integerElement" in item
- ? item.integerElement
- : "9007199254740993",
+ item.integerElement ?? "9007199254740993",
)
.replace("__OTHER__", item.element);
const bytes = Buffer.from(xml);
@@ -145,14 +162,26 @@ export const expectKeyedArchiveNumberMetadata = (
status: "resolved",
raw: { CF$UID: 1 },
});
- if (item.incomplete) {
+ if (item.unknownScalarCount !== undefined) {
expect(result.limitations).toContainEqual(
+ expect.stringMatching(
+ new RegExp(
+ `^${String(item.unknownScalarCount)} XML scalar value\\(s\\) could not be established`,
+ "u",
+ ),
+ ),
+ );
+ expect(result.limitations).not.toContainEqual(
expect.stringMatching(/metadata.*completely observed.*precision/u),
);
- expect(
- result.limitations.some((note) => note.includes("unambiguous integer")),
- ).toBe(false);
- } else if (item.malformedReference) {
+ } else {
+ expect(result.limitations).not.toContainEqual(
+ expect.stringMatching(
+ /^\d+ XML scalar value\(s\) could not be established/u,
+ ),
+ );
+ }
+ if (item.malformedReference) {
expect(result.references).toContainEqual({
source: 1,
path: [],
@@ -162,8 +191,20 @@ export const expectKeyedArchiveNumberMetadata = (
});
} else {
expect(result.references).toHaveLength(1);
- expect(result.limitations).toContainEqual(
- expect.stringMatching(/^1 unambiguous integer value/u),
- );
+ const knownIntegerCount = item.knownIntegerCount ?? 1;
+ if (knownIntegerCount === 0) {
+ expect(result.limitations).not.toContainEqual(
+ expect.stringMatching(/^\d+ unambiguous integer value/u),
+ );
+ } else {
+ expect(result.limitations).toContainEqual(
+ expect.stringMatching(
+ new RegExp(
+ `^${String(knownIntegerCount)} unambiguous integer value`,
+ "u",
+ ),
+ ),
+ );
+ }
}
};