84 lines
3.0 KiB
TypeScript
84 lines
3.0 KiB
TypeScript
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);
|
|
});
|
|
});
|