import { describe, expect, it } from 'vitest'; import { DEFAULT_BARK_BATTLE_CONFIG } from '../../application/BarkBattleConfig'; import { BarkDetector } from '../BarkDetector'; describe('BarkDetector', () => { it('每个监测点只检测瞬时响度,超过阈值立即触发', () => { const detector = new BarkDetector({ threshold: 0.45, minBarkGapMs: DEFAULT_BARK_BATTLE_CONFIG.minBarkGapMs, }); expect(detector.acceptSample({ atMs: 0, volume: 0.2 })).toEqual([]); const events = detector.acceptSample({ atMs: 40, volume: 0.72 }); expect(events).toHaveLength(1); expect(events[0]).toMatchObject({ side: 'player', atMs: 40, peakVolume: 0.72, durationMs: 0 }); }); it('持续噪音按冷却间隔触发,不需要等待响度回落', () => { const detector = new BarkDetector({ threshold: 0.4, minBarkGapMs: 250, }); const allEvents = [ ...detector.acceptSample({ atMs: 0, volume: 0.7 }), ...detector.acceptSample({ atMs: 100, volume: 0.72 }), ...detector.acceptSample({ atMs: 200, volume: 0.73 }), ...detector.acceptSample({ atMs: 300, volume: 0.75 }), ...detector.acceptSample({ atMs: 500, volume: 0.2 }), ...detector.acceptSample({ atMs: 560, volume: 0.76 }), ]; expect(allEvents.map((event) => event.atMs)).toEqual([0, 300, 560]); }); it('低于阈值的背景噪音和冷却内峰值不计数,最短持续时长不再参与判断', () => { const detector = new BarkDetector({ threshold: 0.5, minBarkGapMs: 300, }); expect(detector.acceptSample({ atMs: 0, volume: 0.48 })).toEqual([]); expect(detector.acceptSample({ atMs: 20, volume: 0.9 })).toHaveLength(1); expect(detector.acceptSample({ atMs: 60, volume: 0.95 })).toEqual([]); expect(detector.acceptSample({ atMs: 320, volume: 0.88 })).toHaveLength(1); expect(detector.acceptSample({ atMs: 420, volume: 0.2 })).toEqual([]); }); it('支持 100ms 级别间隔的快速连续有效叫声', () => { const detector = new BarkDetector({ threshold: 0.5, minBarkGapMs: 100, }); const allEvents = [ ...detector.acceptSample({ atMs: 0, volume: 0.86 }), ...detector.acceptSample({ atMs: 60, volume: 0.9 }), ...detector.acceptSample({ atMs: 120, volume: 0.91 }), ...detector.acceptSample({ atMs: 180, volume: 0.92 }), ...detector.acceptSample({ atMs: 240, volume: 0.93 }), ]; expect(allEvents).toHaveLength(3); expect(allEvents.map((event) => event.atMs)).toEqual([0, 120, 240]); }); it('非有限音量会归零,超过 1 的音量会夹到 1', () => { const detector = new BarkDetector({ threshold: 0.5, minBarkGapMs: 100, }); expect(detector.acceptSample({ atMs: 0, volume: Number.NaN })).toEqual([]); expect(detector.acceptSample({ atMs: 120, volume: Number.POSITIVE_INFINITY })).toEqual([]); const events = detector.acceptSample({ atMs: 240, volume: 2 }); expect(events).toHaveLength(1); expect(events[0]?.peakVolume).toBe(1); }); });