59 lines
2.1 KiB
JavaScript
59 lines
2.1 KiB
JavaScript
import { describe, it, expect } from 'vitest';
|
|
import { priceOf, advancePlanet, marketView, applyTrade } from '../src/sim/economy.js';
|
|
import { BASE_PRICE, GOODS, TYPICAL_STOCK } from '../src/sim/constants.js';
|
|
|
|
function makePlanet() {
|
|
return {
|
|
id: 0, systemId: 0, name: 'Test Prime',
|
|
produces: { food: 10 }, consumes: { fuel: 5 },
|
|
stock: { ore: 100, food: 100, fuel: 100, tech: 100, meds: 100, luxury: 100 },
|
|
stockTime: 0,
|
|
};
|
|
}
|
|
|
|
describe('economy', () => {
|
|
it('price falls as stock rises, clamped to [0.25x, 4x] base', () => {
|
|
expect(priceOf('ore', TYPICAL_STOCK)).toBeCloseTo(BASE_PRICE.ore, 1);
|
|
expect(priceOf('ore', 10)).toBeGreaterThan(priceOf('ore', 500));
|
|
expect(priceOf('ore', 0)).toBe(BASE_PRICE.ore * 4);
|
|
expect(priceOf('ore', 1e9)).toBe(BASE_PRICE.ore * 0.25);
|
|
});
|
|
|
|
it('advancePlanet applies production/consumption over elapsed time', () => {
|
|
const p = makePlanet();
|
|
advancePlanet(p, 10);
|
|
expect(p.stock.food).toBeCloseTo(200, 5); // +10/day
|
|
expect(p.stock.fuel).toBeCloseTo(50, 5); // -5/day
|
|
expect(p.stock.ore).toBeCloseTo(100, 5); // untouched
|
|
expect(p.stockTime).toBe(10);
|
|
});
|
|
|
|
it('advancePlanet never goes negative and is idempotent', () => {
|
|
const p = makePlanet();
|
|
advancePlanet(p, 100);
|
|
expect(p.stock.fuel).toBe(0);
|
|
const snapshot = { ...p.stock };
|
|
advancePlanet(p, 100); // same time again: no change
|
|
expect(p.stock).toEqual(snapshot);
|
|
});
|
|
|
|
it('applyTrade returns pre-trade price and mutates stock', () => {
|
|
const p = makePlanet();
|
|
const price = applyTrade(p, 0, 'ore', -20); // a buyer removes 20
|
|
expect(price).toBeCloseTo(priceOf('ore', 100), 5);
|
|
expect(p.stock.ore).toBe(80);
|
|
applyTrade(p, 0, 'ore', 50); // a seller delivers 50
|
|
expect(p.stock.ore).toBe(130);
|
|
});
|
|
|
|
it('marketView lists all goods with integer stock and price', () => {
|
|
const p = makePlanet();
|
|
const view = marketView(p, 5);
|
|
expect(view.map((r) => r.good)).toEqual(GOODS);
|
|
for (const row of view) {
|
|
expect(Number.isInteger(row.stock)).toBe(true);
|
|
expect(row.price).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
});
|