'use strict'; const test = require('node:test'); const assert = require('node:assert'); const { SimpApiClient, SimpApiV2Client, BASE_URL, BASE_URL_V2, componentToText, normalizeLimit, parseUnionSummary, parseTerritoryChunk } = require('../src/core/simpApiClient'); test('componentToText 把公告的组件 JSON 压平成纯文本', () => { const raw = '{"color":"gold","extra":[{"color":"aqua","text":"wans7891"},' + '{"color":"yellow","text":" 在坐标 (-8109, -8976)"},' + '{"color":"gold","text":" 创立了新的邦国 "},' + '{"color":"aqua","text":"「雅典维亚城邦」"}]}'; assert.strictEqual(componentToText(raw), 'wans7891 在坐标 (-8109, -8976) 创立了新的邦国 「雅典维亚城邦」'); // 嵌套 extra const nested = '{"text":"公告: ","extra":[{"text":"外层","extra":[{"text":"内层"}]}]}'; assert.strictEqual(componentToText(nested), '公告: 外层内层'); }); test('componentToText 对非 JSON 文本原样返回', () => { assert.strictEqual(componentToText('普通公告'), '普通公告'); assert.strictEqual(componentToText(''), ''); assert.strictEqual(componentToText(null), ''); }); test('normalizeLimit 钳制到 1..1000', () => { assert.strictEqual(normalizeLimit(0), 1); assert.strictEqual(normalizeLimit(50), 50); assert.strictEqual(normalizeLimit(99999), 1000); assert.strictEqual(normalizeLimit('abc'), 100, '非法值回退到文档默认值 100'); assert.strictEqual(normalizeLimit(undefined), 100); }); test('parseUnionSummary 解析邦国摘要并按方块坐标换算王城区块', () => { const union = parseUnionSummary({ id: 12, name: '养老院', leader_name: 'LouieMAIN', member_count: 6, territory_chunk_count: 28853, territory_block_area: 7386368, special_output_material: 'TERRACOTTA', capital_x: 6763.4, capital_z: 11929.2 }); assert.strictEqual(union.name, '养老院'); assert.strictEqual(union.leader, 'LouieMAIN'); assert.strictEqual(union.memberCount, 6); assert.strictEqual(union.chunkCount, 28853); assert.strictEqual(union.specialOutput, 'TERRACOTTA'); // 方块坐标 ÷ 16 才是区块坐标 assert.deepStrictEqual(union.capital, { x: 422, z: 745 }); }); test('parseUnionSummary 缺王城坐标时返回 null 而不是 NaN', () => { const union = parseUnionSummary({ name: '没有王城的邦国', capital_x: null, capital_z: null }); assert.strictEqual(union.capital, null); assert.strictEqual(parseUnionSummary({}), null, '没有邦国名应视为无效'); assert.strictEqual(parseUnionSummary(null), null); }); test('parseTerritoryChunk 解析区块并拒绝坐标缺失的行', () => { const chunk = parseTerritoryChunk({ x: 1, z: -2, union_id: 12, union_name: '养老院', loyalty: 100, last_claimed_at: '2025-08-08T13:43:21.323+08:00' }); assert.deepStrictEqual(chunk, { x: 1, z: -2, unionId: 12, unionName: '养老院', loyalty: 100, lastClaimedAt: '2025-08-08T13:43:21.323+08:00' }); assert.strictEqual(parseTerritoryChunk({ x: null, z: 1 }), null); assert.strictEqual(parseTerritoryChunk({}), null); assert.strictEqual(parseTerritoryChunk(null), null); }); test('客户端在未配置 Key 时把错误写清楚,而不是静默失败', async () => { const client = new SimpApiClient(null); assert.strictEqual(client.hasApiKey(), false); assert.strictEqual(await client.getUnionTerritoryStats('x'), null); assert.strictEqual(client.lastError(), '未配置 API Key'); const v2 = new SimpApiV2Client(null); // 列表类接口在无 Key 时返回空列表,但 lastError 必须说明原因 assert.deepStrictEqual(await v2.getOnlinePlayers(), []); assert.strictEqual(v2.lastError(), '未配置 API-V2 Key'); assert.strictEqual(await v2.getDragon(), null); }); test('setApiKey 变更时清空缓存,避免旧 Key 的响应串味', () => { const client = new SimpApiClient(null); client.cache.set('info/unions', { body: '[]', expiresAt: Date.now() + 10000 }); client.setApiKey('first'); assert.strictEqual(client.cache.size, 0, '第一次设置也应从空 Key 状态切换'); client.cache.set('info/unions', { body: '[]', expiresAt: Date.now() + 10000 }); client.setApiKey('second'); assert.strictEqual(client.cache.size, 0, '换 Key 必须清缓存'); // 相同 Key 重复设置不应清缓存(否则每次配置下发都会白打接口) client.cache.set('info/unions', { body: '[]', expiresAt: Date.now() + 10000 }); client.setApiKey('second'); assert.strictEqual(client.cache.size, 1); }); test('API 与 API-V2 是两个独立的基础地址与密钥', () => { const v1 = new SimpApiClient(null, {}); const v2 = new SimpApiV2Client(null, {}); assert.strictEqual(v1.baseUrl, BASE_URL); assert.strictEqual(v2.baseUrl, BASE_URL_V2); assert.notStrictEqual(v1.baseUrl, v2.baseUrl); v1.setApiKey('key-v1'); assert.strictEqual(v1.hasApiKey(), true); assert.strictEqual(v2.hasApiKey(), false, 'V1 的 Key 不应影响 V2'); }); test('snapshot 暴露用量与缓存统计供控制台展示', () => { const client = new SimpApiClient(null); const snap = client.snapshot(); assert.strictEqual(snap.hasKey, false); assert.strictEqual(snap.requestCount, 0); assert.strictEqual(snap.cacheHits, 0); assert.strictEqual(snap.cachedPaths, 0); assert.strictEqual(snap.baseUrl, BASE_URL); });