From d8e9e502be2648826116720e14354a4bc01b7200 Mon Sep 17 00:00:00 2001 From: cliffhall Date: Wed, 26 Aug 2026 02:09:44 -0400 Subject: [PATCH] test: cover the non-object property-declaration paths in rootUnion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit's coverage gate failed on `core/json/rootUnion.ts` branches (89.81%). A property declared with JSON Schema's boolean form has no keywords to merge, so the two sides agree only by being the same declaration — now tested both ways, and the dead `baseProperty !== undefined` guard is gone (`conflicts` is only reached for a name the base declares). Signed-off-by: cliffhall --- clients/web/src/test/core/rootUnion.test.ts | 27 +++++++++++++++++++++ core/json/rootUnion.ts | 8 +++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/clients/web/src/test/core/rootUnion.test.ts b/clients/web/src/test/core/rootUnion.test.ts index 9e5f3200..21794afd 100644 --- a/clients/web/src/test/core/rootUnion.test.ts +++ b/clients/web/src/test/core/rootUnion.test.ts @@ -202,6 +202,33 @@ describe("resolveRootUnion", () => { }); }); + it("carries an identical non-object declaration across", () => { + // JSON Schema's boolean form is legal as a property schema. There are no + // keywords to merge, so the two agree only by being the same declaration. + const { branches } = resolveRootUnion({ + type: "object", + properties: { x: true as unknown }, + anyOf: [ + { type: "object", properties: { x: true as unknown } }, + { type: "object", properties: { other: { type: "string" } } }, + ], + }); + expect(branches).toHaveLength(2); + expect(branches[0].schema.properties?.x).toBe(true); + }); + + it("declines a union whose branch redeclares a non-object property differently", () => { + const { branches } = resolveRootUnion({ + type: "object", + properties: { x: true as unknown }, + anyOf: [ + { type: "object", properties: { x: false as unknown } }, + { type: "object", properties: { other: { type: "string" } } }, + ], + }); + expect(branches).toEqual([]); + }); + it("declines a union whose branch contradicts the root's type for a field", () => { // `string` under a base `number` describes a value that cannot exist, so // flattening it would render one type and accept what the schema rejects. diff --git a/core/json/rootUnion.ts b/core/json/rootUnion.ts index 469df7a1..52fd029a 100644 --- a/core/json/rootUnion.ts +++ b/core/json/rootUnion.ts @@ -183,9 +183,11 @@ function conflicts(baseProperty: unknown, branchProperty: unknown): boolean { const a = toBranch(baseProperty); const b = toBranch(branchProperty); if (a === null || b === null) { - return ( - baseProperty !== undefined && !sameValue(baseProperty, branchProperty) - ); + // At least one side is not a readable schema object — JSON Schema's boolean + // form, or something malformed. Nothing can be merged keyword-wise, so the + // two agree only if they are the same declaration. (Only reached for a name + // the base declares, so `baseProperty` is never simply absent here.) + return !sameValue(baseProperty, branchProperty); } const left = a as Record; const right = b as Record;