107 lines
3.8 KiB
JavaScript
107 lines
3.8 KiB
JavaScript
|
|
// Basic tests for MeasurementRouter.
|
||
|
|
|
||
|
|
const test = require('node:test');
|
||
|
|
const assert = require('node:assert/strict');
|
||
|
|
|
||
|
|
const { MeasurementContainer, coolprop } = require('generalFunctions');
|
||
|
|
const MeasurementRouter = require('../../src/measurement/measurementRouter');
|
||
|
|
|
||
|
|
// CoolProp is async-init; ensure it's warm before any pressure-conversion
|
||
|
|
// test runs.
|
||
|
|
test.before(async () => {
|
||
|
|
await coolprop.init({ refrigerant: 'Water' });
|
||
|
|
});
|
||
|
|
|
||
|
|
function makeBasin() {
|
||
|
|
return {
|
||
|
|
surfaceArea: 10,
|
||
|
|
minVol: 2,
|
||
|
|
maxVol: 50,
|
||
|
|
maxVolAtOverflow: 45,
|
||
|
|
overflowLevel: 4.5,
|
||
|
|
outflowLevel: 0.2,
|
||
|
|
inflowLevel: 3,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function makeMeasurements() {
|
||
|
|
return new MeasurementContainer({
|
||
|
|
autoConvert: true,
|
||
|
|
preferredUnits: { flow: 'm3/s', level: 'm', volume: 'm3' },
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function fakeLogger() {
|
||
|
|
const calls = { warn: [], info: [], error: [], debug: [] };
|
||
|
|
return {
|
||
|
|
warn: (m) => calls.warn.push(m),
|
||
|
|
info: (m) => calls.info.push(m),
|
||
|
|
error: (m) => calls.error.push(m),
|
||
|
|
debug: (m) => calls.debug.push(m),
|
||
|
|
_calls: calls,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
test('onLevelMeasurement writes volume + percent', async () => {
|
||
|
|
const measurements = makeMeasurements();
|
||
|
|
const basin = makeBasin();
|
||
|
|
const router = new MeasurementRouter({ measurements, basin });
|
||
|
|
|
||
|
|
router.onLevelMeasurement('atequipment', 2.5, { unit: 'm', timestamp: Date.now() });
|
||
|
|
|
||
|
|
const lvl = measurements.type('level').variant('measured').position('atequipment').getCurrentValue('m');
|
||
|
|
assert.ok(Math.abs(lvl - 2.5) < 1e-9);
|
||
|
|
|
||
|
|
const vol = measurements.type('volume').variant('measured').position('atequipment').getCurrentValue('m3');
|
||
|
|
// 2.5 m * 10 m² = 25 m3.
|
||
|
|
assert.ok(Math.abs(vol - 25) < 1e-9, `volume was ${vol}`);
|
||
|
|
|
||
|
|
const pct = measurements.type('volumePercent').variant('measured').position('atequipment').getCurrentValue('%');
|
||
|
|
// (25 - 2) / (45 - 2) * 100 ≈ 53.488...
|
||
|
|
assert.ok(pct > 53 && pct < 54, `percent was ${pct}`);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('onPressureMeasurement falls back to assumed temperature and warns', async () => {
|
||
|
|
const measurements = makeMeasurements();
|
||
|
|
const basin = makeBasin();
|
||
|
|
const logger = fakeLogger();
|
||
|
|
const router = new MeasurementRouter({ measurements, basin, logger });
|
||
|
|
|
||
|
|
// No temperature seeded — must fall back to assumed 15C.
|
||
|
|
measurements.type('pressure').variant('measured').position('atequipment')
|
||
|
|
.value(20000, Date.now(), 'Pa');
|
||
|
|
router.onPressureMeasurement('atequipment', 20000, { unit: 'Pa', timestamp: Date.now() });
|
||
|
|
|
||
|
|
const warned = logger._calls.warn.some((m) => /assuming 15C|temperature/i.test(m));
|
||
|
|
assert.ok(warned, 'expected a warn about missing temperature');
|
||
|
|
|
||
|
|
const assumedT = measurements.type('temperature').variant('assumed').position('atequipment')
|
||
|
|
.getCurrentValue('K');
|
||
|
|
assert.ok(Number.isFinite(assumedT), 'assumed temperature was not stored');
|
||
|
|
|
||
|
|
const lvl = measurements.type('level').variant('predicted').position('atequipment')
|
||
|
|
.getCurrentValue('m');
|
||
|
|
// 20000 Pa / (~999 kg/m³ * 9.80665) ≈ 2.04 m.
|
||
|
|
assert.ok(lvl > 1.9 && lvl < 2.2, `derived level was ${lvl}`);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('route() dispatches by measurement type', async () => {
|
||
|
|
const measurements = makeMeasurements();
|
||
|
|
const basin = makeBasin();
|
||
|
|
const router = new MeasurementRouter({ measurements, basin });
|
||
|
|
|
||
|
|
const handledLevel = router.route('level', 1.5, 'atequipment', { unit: 'm' });
|
||
|
|
assert.equal(handledLevel, true);
|
||
|
|
const lvl = measurements.type('level').variant('measured').position('atequipment').getCurrentValue('m');
|
||
|
|
assert.ok(Math.abs(lvl - 1.5) < 1e-9);
|
||
|
|
|
||
|
|
// Unknown type returns false (no dispatch).
|
||
|
|
const handledOther = router.route('flow', 0.1, 'in', {});
|
||
|
|
assert.equal(handledOther, false);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('constructor rejects missing context fields', async () => {
|
||
|
|
assert.throws(() => new MeasurementRouter({}));
|
||
|
|
assert.throws(() => new MeasurementRouter({ measurements: makeMeasurements() }));
|
||
|
|
});
|