velxio/frontend/src/__tests__/circuit-verifier-nonfinite....

65 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* circuitVerifier — the "cannot emulate" path.
*
* When ngspice cannot find a stable operating point it returns NaN/Infinity
* for the offending branch current (the classic case: an LED with no series
* resistor — a near-short across the supply). The verifier must surface that
* as a BLOCKING `unstable-solve` fault, NOT silently treat it as 0 A and wave
* the circuit through (the production bug behind the 9V→LED report).
*
* The real Node ngspice build always converges this circuit, so we mock the
* solver to deterministically return non-finite currents.
*/
import { describe, it, expect, vi } from 'vitest';
vi.mock('../simulation/spice/runNetlist', () => ({
runNetlist: vi.fn(async () => ({
variableNames: ['v(n0)', 'v(n1)', 'i(v_bat)', 'i(v_led1_sense)'],
dcValue: (name: string) => {
switch (name) {
case 'v(n0)':
return 1.05;
case 'v(n1)':
return -1.05;
case 'i(v_bat)':
return NaN; // source current — no stable solution
case 'i(v_led1_sense)':
return Infinity; // LED forward current — no stable solution
default:
return 0;
}
},
vec: () => [],
vAtLast: () => 0,
findVar: () => -1,
})),
}));
import { verifyCircuit } from '../simulation/verify/circuitVerifier';
import type { BuildNetlistInput } from '../simulation/spice/types';
describe('verifyCircuit — non-finite solve → unstable-solve fault', () => {
it('blocks a 9V battery wired straight to an LED (no resistor)', async () => {
const input: BuildNetlistInput = {
components: [
{ id: 'bat', metadataId: 'battery-9v', properties: {} },
{ id: 'led1', metadataId: 'led', properties: { color: 'red' } },
],
wires: [
{ id: 'w1', start: { componentId: 'bat', pinName: '+' }, end: { componentId: 'led1', pinName: 'A' } },
{ id: 'w2', start: { componentId: 'led1', pinName: 'C' }, end: { componentId: 'bat', pinName: '' } },
],
boards: [],
analysis: { kind: 'op' },
};
const result = await verifyCircuit(input);
const codes = result.errors.map((e) => e.code);
// Both the source and the LED report the unstable solve — either is enough
// to block, and both must be `unstable-solve` (not silently dropped to 0 A).
expect(codes, JSON.stringify(result.errors)).toContain('unstable-solve');
expect(result.errors.length).toBeGreaterThan(0);
const ledFault = result.errors.find((e) => e.componentId === 'led1');
expect(ledFault?.code).toBe('unstable-solve');
});
});