107 lines
3.4 KiB
JavaScript
107 lines
3.4 KiB
JavaScript
|
|
// 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');
|
|||
|
|
});
|