136 lines
4.9 KiB
TypeScript
136 lines
4.9 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import {
|
|
summarizeNationPeriod,
|
|
projectCurrentSettlement,
|
|
zAuditNation,
|
|
type AuditNationData,
|
|
type NationMonthPoint,
|
|
} from '../src/router/playAudit/nationSeries.js';
|
|
|
|
const population = {
|
|
count: 0,
|
|
crew: null,
|
|
gold: 0,
|
|
rice: 0,
|
|
dex: { dex1: 0, dex2: 0, dex3: 0, dex4: 0, dex5: 0 },
|
|
averageGold: null,
|
|
averageRice: null,
|
|
averageDex: { dex1: null, dex2: null, dex3: null, dex4: null, dex5: null },
|
|
};
|
|
const nation = (month: number): AuditNationData => ({
|
|
id: 1,
|
|
name: `국가${month}`,
|
|
color: '#ffffff',
|
|
gold: month * 100,
|
|
rice: month * 200,
|
|
tech: month * 10,
|
|
appliedRate: 20,
|
|
incomeGold: month,
|
|
incomeRice: 0,
|
|
paidGold: month / 2,
|
|
paidRice: 0,
|
|
populations: { human: population, npc: population, troopNpc: population },
|
|
});
|
|
const months: NationMonthPoint[] = Array.from({ length: 6 }, (_, index) => ({
|
|
ordinal: 2400 + index,
|
|
collected: true,
|
|
settlementsComplete: true,
|
|
data: nation(index + 1),
|
|
}));
|
|
|
|
describe('play audit half-year summary', () => {
|
|
it('sums flows but takes stock, names and population denominators from the last month', () => {
|
|
const summary = summarizeNationPeriod(2400, 6, months);
|
|
expect(summary).toMatchObject({
|
|
year: 200,
|
|
month: 1,
|
|
complete: true,
|
|
stockAsOf: { year: 200, month: 6 },
|
|
stock: {
|
|
name: '국가6',
|
|
gold: 600,
|
|
rice: 1200,
|
|
tech: 60,
|
|
populations: { human: { count: 0, averageGold: null } },
|
|
},
|
|
flows: { incomeGold: 21, incomeRice: 0, paidGold: 10.5, paidRice: 0 },
|
|
});
|
|
});
|
|
it('reports partial range independently from complete collection of the requested months', () => {
|
|
expect(summarizeNationPeriod(2400, 6, months.slice(0, 2))).toMatchObject({
|
|
complete: false,
|
|
from: { year: 200, month: 1 },
|
|
to: { year: 200, month: 2 },
|
|
flows: { incomeGold: 3 },
|
|
});
|
|
});
|
|
it('does not call a missing month or absent nation zero income', () => {
|
|
const missing = months.map((point, index) =>
|
|
index === 1 ? { ...point, collected: false, data: null } : point
|
|
);
|
|
expect(summarizeNationPeriod(2400, 6, missing)).toMatchObject({ complete: false, flows: { incomeGold: null } });
|
|
expect(
|
|
summarizeNationPeriod(
|
|
2400,
|
|
6,
|
|
months.map((point) => ({ ...point, data: null }))
|
|
)
|
|
).toMatchObject({
|
|
complete: false,
|
|
stock: null,
|
|
stockAsOf: null,
|
|
flows: { incomeRice: null },
|
|
});
|
|
});
|
|
it('keeps incomplete settlement coverage unknown while preserving stock coverage', () => {
|
|
const partial = months.map((point, index) => ({ ...point, settlementsComplete: index !== 0 }));
|
|
expect(summarizeNationPeriod(2400, 6, partial)).toMatchObject({ complete: true, flows: { incomeGold: null } });
|
|
expect(summarizeNationPeriod(2400, 6, [])).toMatchObject({
|
|
complete: false,
|
|
stock: null,
|
|
flows: { incomeGold: null },
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('current committed settlement', () => {
|
|
it.each([
|
|
[1, 'gold'],
|
|
[7, 'rice'],
|
|
] as const)('exposes month %s settlement before month-end', (month, resource) => {
|
|
const meta = {
|
|
playAuditFlows: {
|
|
year: 200,
|
|
month,
|
|
complete: true,
|
|
entries: { [`2:${resource}`]: { nationId: 2, resource, income: 1234.5, paid: 234 } },
|
|
},
|
|
};
|
|
expect(projectCurrentSettlement(meta, 200, month, 2)[resource]).toEqual({ income: 1234.5, paid: 234 });
|
|
expect(projectCurrentSettlement(meta, 200, month + 1, 2)[resource]).toBeNull();
|
|
expect(projectCurrentSettlement(meta, 200, month, 3)[resource]).toBeNull();
|
|
});
|
|
it('keeps absent and malformed observations unknown, preserves actual zero', () => {
|
|
expect(projectCurrentSettlement({}, 200, 1, 2).gold).toBeNull();
|
|
const meta = {
|
|
playAuditFlows: {
|
|
year: 200,
|
|
month: 1,
|
|
complete: false,
|
|
entries: { '2:gold': { nationId: 2, resource: 'gold', income: 0, paid: 0 } },
|
|
},
|
|
};
|
|
expect(projectCurrentSettlement(meta, 200, 1, 2)).toMatchObject({
|
|
gold: { income: 0, paid: 0 },
|
|
complete: false,
|
|
});
|
|
meta.playAuditFlows.entries['2:gold'].income = NaN;
|
|
expect(projectCurrentSettlement(meta, 200, 1, 2).gold).toBeNull();
|
|
});
|
|
it('reads old snapshots without inventing troop counts', () => {
|
|
const old = JSON.parse(JSON.stringify(nation(1)));
|
|
delete old.populations.human.crew;
|
|
expect(zAuditNation.parse(old).populations.human.crew).toBeNull();
|
|
});
|
|
});
|