'use strict'; const test = require('node:test'); const assert = require('node:assert'); const { TerritoryModel } = require('../src/core/territoryModel'); const chunkPos = require('../src/core/chunkPos'); /** * 构造一个邦国状态。 * @param {string} name * @param {Array<[number, number]>} coords */ function makeState(name, coords, capital) { const chunks = new Set(coords.map(([x, z]) => chunkPos.key(x, z))); return { name, capital: capital || { x: coords[0][0], z: coords[0][1] }, chunks, color: 0x75bd20 }; } test('构造时建立 allClaimed 并集', () => { const model = new TerritoryModel(new Map([ ['A', makeState('A', [[0, 0], [1, 0]])], ['B', makeState('B', [[5, 5]])] ])); assert.strictEqual(model.stateCount, 2); assert.strictEqual(model.allClaimedChunks().size, 3); assert.ok(model.allClaimedChunks().has(chunkPos.key(1, 0))); }); test('findContainingState 找到覆盖区块的邦国', () => { const model = new TerritoryModel(new Map([ ['A', makeState('A', [[0, 0], [1, 0]])], ['B', makeState('B', [[5, 5]])] ])); assert.strictEqual(model.findContainingState({ x: 1, z: 0 }).name, 'A'); assert.strictEqual(model.findContainingState({ x: 5, z: 5 }).name, 'B'); assert.strictEqual(model.findContainingState({ x: 9, z: 9 }), null); }); test('飞地识别:四周被同一邦国包围的空洞', () => { // 3×3 中空方块:中心 (1,1) 是飞地 const coords = []; for (let x = 0; x <= 2; x++) { for (let z = 0; z <= 2; z++) { if (x === 1 && z === 1) continue; coords.push([x, z]); } } const model = new TerritoryModel(new Map([['A', makeState('A', coords)]])); const flying = model.selfFlyingChunks(); // 未设置己方邦国名时为空集 assert.strictEqual(flying.size, 0); model.setSelfStateName('A'); const selfFlying = model.selfFlyingChunks(); assert.strictEqual(selfFlying.size, 1); assert.ok(selfFlying.has(chunkPos.key(1, 1))); assert.strictEqual(model.flyingChunks().size, 1); }); test('飞地不包含被其他邦国占领的区块', () => { const aCoords = []; for (let x = 0; x <= 2; x++) { for (let z = 0; z <= 2; z++) { if (x === 1 && z === 1) continue; aCoords.push([x, z]); } } const model = new TerritoryModel(new Map([ ['A', makeState('A', aCoords)], ['B', makeState('B', [[1, 1]])] ])); model.setSelfStateName('A'); assert.strictEqual(model.selfFlyingChunks().size, 0); }); test('addSessionClaim 同步更新会话集合、全局集合与己方邦国', () => { const model = new TerritoryModel(new Map([['A', makeState('A', [[0, 0]])]])); model.setSelfStateName('A'); model.addSessionClaim({ x: 1, z: 0 }); assert.ok(model.sessionClaimsSet().has(chunkPos.key(1, 0))); assert.ok(model.allClaimedChunks().has(chunkPos.key(1, 0))); assert.ok(model.selfState().chunks.has(chunkPos.key(1, 0))); }); test('addSessionClaim 后飞地缓存失效并重算', () => { const coords = []; for (let x = 0; x <= 2; x++) { for (let z = 0; z <= 2; z++) { if (x === 1 && z === 1) continue; coords.push([x, z]); } } const model = new TerritoryModel(new Map([['A', makeState('A', coords)]])); model.setSelfStateName('A'); assert.strictEqual(model.selfFlyingChunks().size, 1); // 填上飞地后飞地应为空 model.addSessionClaim({ x: 1, z: 1 }); assert.strictEqual(model.selfFlyingChunks().size, 0); }); test('mergeApiData:API 独有邦国新增、共有邦国取并集且 Dynmap 颜色优先', () => { const model = new TerritoryModel(new Map([['A', makeState('A', [[0, 0]])]])); const apiChunks = new Map([ ['A', new Set([chunkPos.key(1, 0)])], ['C', new Set([chunkPos.key(9, 9)])] ]); const apiCapitals = new Map([['C', { x: 9, z: 9 }]]); model.mergeApiData(apiChunks, apiCapitals, 0xff43de); const a = model.state('A'); assert.strictEqual(a.chunks.size, 2, 'A 的区块应为并集'); assert.strictEqual(a.color, 0x75bd20, 'Dynmap 已有邦国应保留原颜色'); const c = model.state('C'); assert.ok(c, 'API 独有邦国应被新增'); assert.strictEqual(c.color, 0xff43de); assert.deepStrictEqual(c.capital, { x: 9, z: 9 }); assert.ok(model.allClaimedChunks().has(chunkPos.key(9, 9))); }); test('mergeApiData:Dynmap 王城优先于 API 王城', () => { const model = new TerritoryModel(new Map([['A', makeState('A', [[0, 0]], { x: 7, z: 7 })]])); model.mergeApiData(new Map([['A', new Set([chunkPos.key(1, 0)])]]), new Map([['A', { x: 99, z: 99 }]]), 0); assert.deepStrictEqual(model.state('A').capital, { x: 7, z: 7 }); }); test('mergeApiData:空输入直接返回不改动模型', () => { const model = new TerritoryModel(new Map([['A', makeState('A', [[0, 0]])]])); model.mergeApiData(new Map(), new Map(), 0); assert.strictEqual(model.stateCount, 1); });