'use strict'; const { CameraSwitch } = require('../src/cameraSwitch'); // Mockt die FFmpeg-berührenden Methoden – getestet wird NUR die // Entscheidungslogik von reconfigure() (kill/spawn/no-op), keine Hardware. function makeSwitch(opts = {}) { const sw = new CameraSwitch({ id: 'camT', device: '/dev/null', liveSize: '640x480', ...opts }); sw._killCurrentAndWait = jest.fn(() => { sw.proc = null; sw.state = 'stopped'; return Promise.resolve(); }); sw._spawnLive = jest.fn(() => { sw.proc = {}; sw.state = 'live'; }); return sw; } describe('CameraSwitch.reconfigure', () => { test('geänderte liveSize → genau 1× kill + 1× spawn', async () => { const sw = makeSwitch({ onDemand: false }); sw.proc = {}; sw.state = 'live'; await sw.reconfigure({ liveSize: '320x240', stream: true }); expect(sw.liveSize).toBe('320x240'); expect(sw._killCurrentAndWait).toHaveBeenCalledTimes(1); expect(sw._spawnLive).toHaveBeenCalledTimes(1); }); test('gleiche liveSize → no-op (kein kill, kein spawn)', async () => { const sw = makeSwitch({ onDemand: false }); sw.proc = {}; sw.state = 'live'; await sw.reconfigure({ liveSize: '640x480', stream: true }); expect(sw._killCurrentAndWait).not.toHaveBeenCalled(); expect(sw._spawnLive).not.toHaveBeenCalled(); }); test('lock aktiv (HD-Grab) → nur Feld setzen, kein kill/spawn', async () => { const sw = makeSwitch({ onDemand: false }); sw.lock = true; sw.proc = {}; sw.state = 'grabbing'; await sw.reconfigure({ liveSize: '320x240', stream: true }); expect(sw.liveSize).toBe('320x240'); expect(sw._killCurrentAndWait).not.toHaveBeenCalled(); expect(sw._spawnLive).not.toHaveBeenCalled(); }); test('stream:false → kill, KEIN respawn, streamEnabled=false', async () => { const sw = makeSwitch({ onDemand: false }); sw.proc = {}; sw.state = 'live'; await sw.reconfigure({ stream: false }); expect(sw._killCurrentAndWait).toHaveBeenCalledTimes(1); expect(sw._spawnLive).not.toHaveBeenCalled(); expect(sw.streamEnabled).toBe(false); }); test('On-Demand ohne Verbraucher → kill bei Resize, aber kein spawn', async () => { const sw = makeSwitch({ onDemand: true }); sw.subscribers = 0; sw.proc = {}; sw.state = 'live'; await sw.reconfigure({ liveSize: '320x240', stream: true }); expect(sw._killCurrentAndWait).toHaveBeenCalledTimes(1); expect(sw._spawnLive).not.toHaveBeenCalled(); }); test('On-Demand mit Verbraucher → kill + spawn (nahtloser Resize)', async () => { const sw = makeSwitch({ onDemand: true }); sw.subscribers = 1; sw.proc = {}; sw.state = 'live'; await sw.reconfigure({ liveSize: '320x240', stream: true }); expect(sw._killCurrentAndWait).toHaveBeenCalledTimes(1); expect(sw._spawnLive).toHaveBeenCalledTimes(1); }); test('Wiedereinschalten (stream:true) startet bei vorhandenem Verbraucher', async () => { const sw = makeSwitch({ onDemand: true, stream: false }); sw.subscribers = 1; sw.state = 'stopped'; sw.proc = null; await sw.reconfigure({ liveSize: '320x240', stream: true }); expect(sw.streamEnabled).toBe(true); expect(sw._spawnLive).toHaveBeenCalledTimes(1); }); });