test: add schema.ts edge case coverage for repair and JSON extraction

Test repairTruncatedCardsJson with whitespace variations, escaped quotes,
braces in string values, all-truncated cards, and empty arrays.
Add collectJsonObjectCandidates tests for empty input, nested objects,
braces in strings, and unclosed braces.

Change-Id: I82392bff6eaf457934dbbe63e7c5788ea6a44e19
This commit is contained in:
fancivez 2026-04-27 13:21:30 +08:00 committed by wujunchen
parent 4f5e9e9923
commit 1efacf695c
3 changed files with 50 additions and 14 deletions

26
main.js

File diff suppressed because one or more lines are too long

View file

@ -43,7 +43,7 @@ import {
supportsStreaming,
tokenLimitFieldForOpenAiChat,
} from './src/providers';
import { extractJson, normalizeCardsPayload, repairTruncatedCardsJson } from './src/schema';
import { collectJsonObjectCandidates, extractJson, normalizeCardsPayload, repairTruncatedCardsJson } from './src/schema';
import { createRafThrottledHandler, visibleTopProbeY } from './src/scroll';
import {
CACHE_SCHEMA_VERSION,
@ -732,6 +732,7 @@ export const __test = {
cacheEntryMatches,
cancellationNoticeKey,
classifyGenerationError,
collectJsonObjectCandidates,
copyToClipboard,
createRafThrottledHandler,
createBatchRunState,

View file

@ -107,6 +107,41 @@ const salvagedCards = normalizeCardsPayload(JSON.parse(repairTruncatedCardsJson(
assert.strictEqual(salvagedCards.length, 1, 'repair + normalize produces valid cards');
assert.strictEqual(salvagedCards[0].title, 'A', 'salvaged card has correct fields');
// repairTruncatedCardsJson edge cases
// Whitespace variations in the "cards":[ pattern
const spaced = '{ "cards" : [ {"title":"A","anchor":"a","gist":"g","bullets":[]},{"title":"B","anch';
const repairedSpaced = repairTruncatedCardsJson(spaced);
assert.ok(repairedSpaced, 'repair handles whitespace in cards pattern');
assert.strictEqual(JSON.parse(repairedSpaced).cards.length, 1, 'repair with whitespace keeps complete card');
// Cards with escaped quotes in string values
const escapedQuotes = '{"cards":[{"title":"A \\"quoted\\"","anchor":"a","gist":"g","bullets":["line \\"1\\""]},{"title":"B","anch';
const repairedEscaped = repairTruncatedCardsJson(escapedQuotes);
assert.ok(repairedEscaped, 'repair handles escaped quotes in values');
assert.strictEqual(JSON.parse(repairedEscaped).cards[0].title, 'A "quoted"', 'escaped quotes preserved');
// Cards with braces in string values
const bracesInStrings = '{"cards":[{"title":"func() { return }","anchor":"a","gist":"{obj}","bullets":[]},{"incomp';
const repairedBraces = repairTruncatedCardsJson(bracesInStrings);
assert.ok(repairedBraces, 'repair handles braces inside strings');
assert.strictEqual(JSON.parse(repairedBraces).cards[0].title, 'func() { return }', 'braces in string preserved');
// All cards truncated (only partial objects)
assert.strictEqual(repairTruncatedCardsJson('{"cards":[{"title":"incomp'), null, 'all truncated cards returns null');
// Empty cards array with truncation
assert.strictEqual(repairTruncatedCardsJson('{"cards":[]'), null, 'empty truncated array returns null');
// collectJsonObjectCandidates edge cases
const { collectJsonObjectCandidates } = t;
assert.deepStrictEqual(collectJsonObjectCandidates(''), [], 'empty string gives no candidates');
assert.deepStrictEqual(collectJsonObjectCandidates('no braces'), [], 'no braces gives no candidates');
assert.deepStrictEqual(collectJsonObjectCandidates('{"a":1}'), ['{"a":1}'], 'single object extracted');
assert.deepStrictEqual(collectJsonObjectCandidates('{"a":1} {"b":2}'), ['{"a":1}', '{"b":2}'], 'multiple objects extracted');
assert.deepStrictEqual(collectJsonObjectCandidates('{"a":{"b":1}}'), ['{"a":{"b":1}}'], 'nested objects extracted as one');
assert.deepStrictEqual(collectJsonObjectCandidates('{"a":"{}"}'), ['{"a":"{}"}'], 'braces in strings handled correctly');
assert.deepStrictEqual(collectJsonObjectCandidates('{unclosed'), [], 'unclosed brace gives no candidates');
// ── schema.ts: normalizeCardsPayload ──
assert.deepStrictEqual(normalizeCardsPayload(null), [], 'null payload returns empty array');