test(app): 補齊 isSafeRepoPath/extractBalancedJSON/normalizeText/repairJSONArrayWithAI/格式化函式測試
為可測性 export 三個內部函式(isSafeRepoPath、extractBalancedJSON/extractJSONText、normalizeText)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
fc10ab7266
commit
775cc575ae
@@ -1,6 +1,7 @@
|
||||
import { describe, it, beforeEach, afterEach, mock } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import axios from 'axios';
|
||||
import { extractBalancedJSON, extractJSONText } from '../llm.js';
|
||||
|
||||
const ENV_KEYS = [
|
||||
'OPENCODE_BASE_URL', 'OPENCODE_MODEL', 'OPENCODE_PROVIDER',
|
||||
@@ -143,3 +144,90 @@ describe('chatJSON', async () => {
|
||||
assert.deepEqual(result, []);
|
||||
});
|
||||
});
|
||||
|
||||
describe('extractBalancedJSON', () => {
|
||||
it('returns the whole object for a simple object from index 0', () => {
|
||||
const text = '{"a":1}';
|
||||
|
||||
assert.equal(extractBalancedJSON(text, 0), '{"a":1}');
|
||||
});
|
||||
|
||||
it('returns the full balanced segment for deeply nested object/array', () => {
|
||||
const text = '{"a":[1,{"b":[2,{"c":3}]}],"d":4}';
|
||||
|
||||
assert.equal(extractBalancedJSON(text, 0), '{"a":[1,{"b":[2,{"c":3}]}],"d":4}');
|
||||
});
|
||||
|
||||
it('does not let braces inside a string value break balancing', () => {
|
||||
const text = '{"a":"}{"}';
|
||||
|
||||
assert.equal(extractBalancedJSON(text, 0), '{"a":"}{"}');
|
||||
});
|
||||
|
||||
it('handles an escaped quote inside a string value', () => {
|
||||
const text = '{"a":"\\""}';
|
||||
|
||||
assert.equal(extractBalancedJSON(text, 0), '{"a":"\\""}');
|
||||
});
|
||||
|
||||
it('returns null for truncated/incomplete JSON', () => {
|
||||
const text = '{"a":1';
|
||||
|
||||
assert.equal(extractBalancedJSON(text, 0), null);
|
||||
});
|
||||
|
||||
it('extracts a balanced array when starting at a "["', () => {
|
||||
const text = '[1,[2,3],{"a":4}]';
|
||||
|
||||
assert.equal(extractBalancedJSON(text, 0), '[1,[2,3],{"a":4}]');
|
||||
});
|
||||
|
||||
it('excludes trailing content after the balanced segment', () => {
|
||||
const text = '{"a":1} trailing text {"b":2}';
|
||||
|
||||
assert.equal(extractBalancedJSON(text, 0), '{"a":1}');
|
||||
});
|
||||
});
|
||||
|
||||
describe('extractJSONText', () => {
|
||||
it('strips a fenced ```json block', () => {
|
||||
const text = '```json\n{"a":1}\n```';
|
||||
|
||||
const result = extractJSONText(text);
|
||||
|
||||
assert.deepEqual(JSON.parse(result), { a: 1 });
|
||||
});
|
||||
|
||||
it('extracts a JSON object after leading prose', () => {
|
||||
const text = 'Here are the findings:\n{"level":"critical"}';
|
||||
|
||||
const result = extractJSONText(text);
|
||||
|
||||
assert.deepEqual(JSON.parse(result), { level: 'critical' });
|
||||
});
|
||||
|
||||
it('extracts an array embedded in surrounding text', () => {
|
||||
const text = 'prefix [1,2,3] suffix';
|
||||
|
||||
const result = extractJSONText(text);
|
||||
|
||||
assert.deepEqual(JSON.parse(result), [1, 2, 3]);
|
||||
});
|
||||
|
||||
it('returns an already-pure JSON string as-is', () => {
|
||||
const text = '{"a":1,"b":[2,3]}';
|
||||
|
||||
const result = extractJSONText(text);
|
||||
|
||||
assert.equal(result, '{"a":1,"b":[2,3]}');
|
||||
assert.deepEqual(JSON.parse(result), { a: 1, b: [2, 3] });
|
||||
});
|
||||
|
||||
it('returns the de-fenced original text when no valid JSON is found', () => {
|
||||
const text = '```\nnot json at all\n```';
|
||||
|
||||
const result = extractJSONText(text);
|
||||
|
||||
assert.equal(result, 'not json at all');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user