// 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() })); });