// Basic unit tests for BasinGeometry. // Run with: node --test test/basic/BasinGeometry.basic.test.js const test = require('node:test'); const assert = require('node:assert/strict'); const BasinGeometry = require('../../src/basin/BasinGeometry'); function makeBasin(overrides = {}) { const basin = { volume: 50, height: 5, inflowLevel: 3, outflowLevel: 0.2, overflowLevel: 4.5, ...overrides.basin, }; const hydraulics = { minHeightBasedOn: 'outlet', ...overrides.hydraulics, }; return new BasinGeometry(basin, hydraulics); } test('constructor produces correct surfaceArea = volume / height', () => { const g = makeBasin(); assert.equal(g.surfaceArea, 10); // 50 / 5 assert.equal(g.heightBasin, 5); assert.equal(g.volEmptyBasin, 50); }); test('maxVolAtOverflow equals overflowLevel × surfaceArea', () => { const g = makeBasin(); assert.equal(g.maxVolAtOverflow, 4.5 * 10); // 45 assert.equal(g.minVolAtInflow, 3 * 10); // 30 assert.equal(g.minVolAtOutflow, 0.2 * 10); // 2 assert.equal(g.maxVol, 50); }); test("minVol selects outlet-based when minHeightBasedOn = 'outlet'", () => { const g = makeBasin(); assert.equal(g.minVol, g.minVolAtOutflow); assert.equal(g.minHeightBasedOn, 'outlet'); }); test("minVol selects inlet-based when minHeightBasedOn = 'inlet'", () => { const g = makeBasin({ hydraulics: { minHeightBasedOn: 'inlet' } }); assert.equal(g.minVol, g.minVolAtInflow); assert.equal(g.minHeightBasedOn, 'inlet'); }); test('volumeFromLevel(0) returns 0; negative level clamps to 0', () => { const g = makeBasin(); assert.equal(g.volumeFromLevel(0), 0); assert.equal(g.volumeFromLevel(-1), 0); assert.equal(g.volumeFromLevel(-1e9), 0); }); test('volumeFromLevel(positive) is level × surfaceArea', () => { const g = makeBasin(); assert.equal(g.volumeFromLevel(2.5), 25); assert.equal(g.volumeFromLevel(5), 50); }); test('levelFromVolume(maxVol) returns heightBasin', () => { const g = makeBasin(); assert.equal(g.levelFromVolume(g.maxVol), g.heightBasin); }); test('levelFromVolume(0) returns 0; negative volume clamps to 0', () => { const g = makeBasin(); assert.equal(g.levelFromVolume(0), 0); assert.equal(g.levelFromVolume(-10), 0); }); test('round-trip: volumeFromLevel(levelFromVolume(v)) ≈ v for v in range', () => { const g = makeBasin(); for (const v of [0, 0.001, 1, 12.34, 25, 49.999, 50]) { const back = g.volumeFromLevel(g.levelFromVolume(v)); assert.ok(Math.abs(back - v) < 1e-9, `round-trip failed for v=${v}, got ${back}`); } }); test('round-trip: levelFromVolume(volumeFromLevel(L)) ≈ L for L in range', () => { const g = makeBasin(); for (const L of [0, 0.05, 1, 2.5, 4.5, 5]) { const back = g.levelFromVolume(g.volumeFromLevel(L)); assert.ok(Math.abs(back - L) < 1e-9, `round-trip failed for L=${L}, got ${back}`); } }); test('snapshot() exposes legacy this.basin field names', () => { const g = makeBasin(); const s = g.snapshot(); const expectedKeys = [ 'volEmptyBasin', 'heightBasin', 'inflowLevel', 'outflowLevel', 'overflowLevel', 'surfaceArea', 'maxVol', 'maxVolAtOverflow', 'minVolAtInflow', 'minVolAtOutflow', 'minVol', 'minHeightBasedOn', ]; for (const k of expectedKeys) { assert.ok(k in s, `snapshot missing key: ${k}`); } assert.equal(s.volEmptyBasin, 50); assert.equal(s.surfaceArea, 10); assert.equal(s.minHeightBasedOn, 'outlet'); });