const test = require('node:test'); const assert = require('node:assert/strict'); const Machine = require('../../src/specificClass'); const { makeMachineConfig, makeStateConfig } = require('../helpers/factories'); function makePressurizedOperationalMachine() { const machine = new Machine(makeMachineConfig(), makeStateConfig({ state: { current: 'operational' } })); machine.updateMeasuredPressure(800, 'upstream', { timestamp: Date.now(), unit: 'mbar', childName: 'pt-up' }); machine.updateMeasuredPressure(1200, 'downstream', { timestamp: Date.now(), unit: 'mbar', childName: 'pt-down' }); return machine; } test('calcCog returns valid peak efficiency and index', () => { const machine = makePressurizedOperationalMachine(); const result = machine.calcCog(); assert.ok(Number.isFinite(result.cog), 'cog should be finite'); assert.ok(result.cog > 0, 'peak efficiency should be positive'); assert.ok(Number.isFinite(result.cogIndex), 'cogIndex should be finite'); assert.ok(result.cogIndex >= 0, 'cogIndex should be non-negative'); assert.ok(Number.isFinite(result.NCog), 'NCog should be finite'); assert.ok(result.NCog >= 0 && result.NCog <= 1, 'NCog should be between 0 and 1'); assert.ok(Number.isFinite(result.minEfficiency), 'minEfficiency should be finite'); assert.ok(result.minEfficiency >= 0, 'minEfficiency should be non-negative'); }); test('calcCog peak is always >= minEfficiency', () => { const machine = makePressurizedOperationalMachine(); const result = machine.calcCog(); assert.ok(result.cog >= result.minEfficiency, 'Peak must be >= min'); }); test('calcEfficiencyCurve produces correct specific flow ratio', () => { const machine = makePressurizedOperationalMachine(); const { powerCurve, flowCurve } = machine.getCurrentCurves(); const { efficiencyCurve, peak, peakIndex, minEfficiency } = machine.calcEfficiencyCurve(powerCurve, flowCurve); assert.ok(efficiencyCurve.length > 0, 'Efficiency curve should not be empty'); assert.equal(efficiencyCurve.length, powerCurve.y.length, 'Should match curve length'); // Verify each point: efficiency = flow / power (unrounded, canonical units) for (let i = 0; i < efficiencyCurve.length; i++) { const power = powerCurve.y[i]; const flow = flowCurve.y[i]; if (power > 0 && flow >= 0) { const expected = flow / power; assert.ok(Math.abs(efficiencyCurve[i] - expected) < 1e-12, `Mismatch at index ${i}`); } } // Peak should be the max const actualMax = Math.max(...efficiencyCurve); assert.equal(peak, actualMax, 'Peak should match max of efficiency curve'); assert.equal(efficiencyCurve[peakIndex], peak, 'peakIndex should point to peak value'); assert.equal(minEfficiency, Math.min(...efficiencyCurve), 'minEfficiency should match min'); }); test('calcEfficiencyCurve handles empty curves gracefully', () => { const machine = new Machine(makeMachineConfig(), makeStateConfig({ state: { current: 'operational' } })); const result = machine.calcEfficiencyCurve({ x: [], y: [] }, { x: [], y: [] }); assert.deepEqual(result.efficiencyCurve, []); assert.equal(result.peak, 0); assert.equal(result.peakIndex, 0); assert.equal(result.minEfficiency, 0); }); test('calcDistanceBEP returns absolute and relative distances', () => { const machine = makePressurizedOperationalMachine(); const efficiency = 5; const maxEfficiency = 10; const minEfficiency = 2; const result = machine.calcDistanceBEP(efficiency, maxEfficiency, minEfficiency); assert.ok(Number.isFinite(result.absDistFromPeak), 'abs distance should be finite'); assert.equal(result.absDistFromPeak, Math.abs(efficiency - maxEfficiency)); assert.ok(Number.isFinite(result.relDistFromPeak), 'rel distance should be finite'); }); test('calcRelativeDistanceFromPeak returns 1 when maxEfficiency equals minEfficiency', () => { const machine = makePressurizedOperationalMachine(); const result = machine.calcRelativeDistanceFromPeak(5, 5, 5); assert.equal(result, 1, 'Should return default distance when max==min (division by zero guard)'); }); test('showCoG returns structured data with curve guards', () => { const machine = makePressurizedOperationalMachine(); const result = machine.showCoG(); assert.ok('cog' in result); assert.ok('cogIndex' in result); assert.ok('NCog' in result); assert.ok('NCogPercent' in result); assert.ok('minEfficiency' in result); assert.ok('currentEfficiencyCurve' in result); assert.ok(result.cog > 0); assert.equal(result.NCogPercent, Math.round(result.NCog * 100 * 100) / 100); }); test('showCoG returns safe fallback when no curve is available', () => { const machine = new Machine( makeMachineConfig({ asset: { model: null } }), makeStateConfig() ); const result = machine.showCoG(); assert.equal(result.cog, 0); assert.ok('error' in result); }); test('showWorkingCurves returns safe fallback when no curve is available', () => { const machine = new Machine( makeMachineConfig({ asset: { model: null } }), makeStateConfig() ); const result = machine.showWorkingCurves(); assert.ok('error' in result); }); test('efficiency output fields are present in getOutput', () => { const machine = makePressurizedOperationalMachine(); // Move to a position so predictions produce values machine.state.transitionToState('operational'); machine.updatePosition(); const output = machine.getOutput(); assert.ok('cog' in output); assert.ok('NCog' in output); assert.ok('NCogPercent' in output); assert.ok('effDistFromPeak' in output); assert.ok('effRelDistFromPeak' in output); assert.ok('predictionQuality' in output); assert.ok('predictionConfidence' in output); assert.ok('predictionPressureSource' in output); });