Spaces:
Running
Running
File size: 7,641 Bytes
b8cc2bf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | import { describe, it, expect, beforeEach } from 'vitest';
import { RingBuffer } from './RingBuffer';
describe('RingBuffer', () => {
let ringBuffer: RingBuffer;
const SAMPLE_RATE = 16000;
const DURATION_SECONDS = 1; // 1 second buffer for easy calculations
const MAX_FRAMES = SAMPLE_RATE * DURATION_SECONDS;
beforeEach(() => {
ringBuffer = new RingBuffer(SAMPLE_RATE, DURATION_SECONDS);
});
describe('Initialization', () => {
it('should initialize with correct parameters', () => {
expect(ringBuffer.sampleRate).toBe(SAMPLE_RATE);
expect(ringBuffer.maxFrames).toBe(MAX_FRAMES);
expect(ringBuffer.getSize()).toBe(MAX_FRAMES);
expect(ringBuffer.getCurrentFrame()).toBe(0);
expect(ringBuffer.getFillCount()).toBe(0);
});
it('should calculate maxFrames based on duration', () => {
const rb = new RingBuffer(8000, 0.5);
expect(rb.maxFrames).toBe(4000);
});
});
describe('Writing Data', () => {
it('should write data correctly when buffer is empty', () => {
const chunk = new Float32Array([1, 2, 3]);
ringBuffer.write(chunk);
expect(ringBuffer.getCurrentFrame()).toBe(3);
expect(ringBuffer.getFillCount()).toBe(3);
const readData = ringBuffer.read(0, 3);
expect(readData).toEqual(chunk);
});
it('should append data correctly', () => {
const chunk1 = new Float32Array([1, 2]);
const chunk2 = new Float32Array([3, 4]);
ringBuffer.write(chunk1);
ringBuffer.write(chunk2);
expect(ringBuffer.getCurrentFrame()).toBe(4);
const readData = ringBuffer.read(0, 4);
expect(readData).toEqual(new Float32Array([1, 2, 3, 4]));
});
it('should handle wrap-around correctly', () => {
// Fill buffer almost to the end
const initialFill = new Float32Array(MAX_FRAMES - 2);
initialFill.fill(0.5);
ringBuffer.write(initialFill);
// Write a chunk that wraps around
const chunk = new Float32Array([1, 2, 3, 4]);
ringBuffer.write(chunk);
expect(ringBuffer.getCurrentFrame()).toBe(MAX_FRAMES - 2 + 4);
// Read the wrapped chunk
// Start reading from where we wrote the chunk
const startFrame = MAX_FRAMES - 2;
const endFrame = startFrame + 4;
const readData = ringBuffer.read(startFrame, endFrame);
expect(readData).toEqual(chunk);
});
it('should handle chunk larger than buffer size', () => {
const largeChunk = new Float32Array(MAX_FRAMES + 10);
for(let i = 0; i < largeChunk.length; i++) {
largeChunk[i] = i;
}
ringBuffer.write(largeChunk);
expect(ringBuffer.getCurrentFrame()).toBe(MAX_FRAMES + 10);
expect(ringBuffer.getFillCount()).toBe(MAX_FRAMES);
// Should contain the last MAX_FRAMES of the large chunk
const expectedData = largeChunk.subarray(10);
// The buffer now holds frames from 10 to MAX_FRAMES + 10
const readData = ringBuffer.read(10, MAX_FRAMES + 10);
expect(readData).toEqual(expectedData);
});
});
describe('Reading Data', () => {
it('should read valid range correctly', () => {
const chunk = new Float32Array([1, 2, 3, 4, 5]);
ringBuffer.write(chunk);
const readData = ringBuffer.read(1, 4); // indices 1, 2, 3
expect(readData).toEqual(new Float32Array([2, 3, 4]));
});
it('should return empty array when startFrame >= endFrame', () => {
const chunk = new Float32Array([1, 2, 3]);
ringBuffer.write(chunk);
expect(ringBuffer.read(1, 1).length).toBe(0);
expect(ringBuffer.read(2, 1).length).toBe(0);
});
it('should throw RangeError when startFrame is negative', () => {
expect(() => ringBuffer.read(-1, 5)).toThrow(RangeError);
});
it('should throw RangeError when reading overwritten data', () => {
// Write more than capacity
const chunk = new Float32Array(MAX_FRAMES + 10);
ringBuffer.write(chunk);
// Oldest available frame is 10
// Trying to read frame 5 should fail
expect(() => ringBuffer.read(5, 15)).toThrow(RangeError);
});
it('should throw RangeError when reading future data', () => {
const chunk = new Float32Array([1, 2, 3]);
ringBuffer.write(chunk);
// Current frame is 3. Requesting up to 5 should fail.
expect(() => ringBuffer.read(0, 5)).toThrow(RangeError);
});
it('should handle reading across wrap-around point', () => {
// Fill buffer almost to the end
const initialFill = new Float32Array(MAX_FRAMES - 2);
for (let i = 0; i < MAX_FRAMES - 2; i++) initialFill[i] = i;
ringBuffer.write(initialFill);
// Write more to wrap around
const chunk = new Float32Array([100, 101, 102, 103]);
ringBuffer.write(chunk);
// Buffer now has:
// [ ... (MAX_FRAMES-2 items), 100, 101, 102, 103 ] logically
// Physically:
// Indices [MAX_FRAMES-2, MAX_FRAMES-1] have [100, 101]
// Indices [0, 1] have [102, 103]
// Read across the boundary
const startFrame = MAX_FRAMES - 3; // One before the new chunk
const endFrame = MAX_FRAMES + 1; // Into the wrapped part
const readData = ringBuffer.read(startFrame, endFrame);
// Expected: [last of initial, 100, 101, 102]
const expected = new Float32Array([
initialFill[initialFill.length - 1],
100, 101, 102
]);
expect(readData).toEqual(expected);
});
});
describe('Helper Methods', () => {
it('getCurrentTime should return correct time in seconds', () => {
// 1 second buffer
const chunk = new Float32Array(SAMPLE_RATE / 2); // 0.5 seconds
ringBuffer.write(chunk);
expect(ringBuffer.getCurrentTime()).toBe(0.5);
});
it('getBaseFrameOffset should return 0 when not full', () => {
const chunk = new Float32Array(100);
ringBuffer.write(chunk);
expect(ringBuffer.getBaseFrameOffset()).toBe(0);
});
it('getBaseFrameOffset should update when overwritten', () => {
const chunk = new Float32Array(MAX_FRAMES + 50);
ringBuffer.write(chunk);
expect(ringBuffer.getBaseFrameOffset()).toBe(50);
});
it('reset should clear buffer and reset counters', () => {
const chunk = new Float32Array([1, 2, 3]);
ringBuffer.write(chunk);
ringBuffer.reset();
expect(ringBuffer.getCurrentFrame()).toBe(0);
expect(ringBuffer.getFillCount()).toBe(0);
expect(ringBuffer.read(0, 0).length).toBe(0); // Check consistency
// Verify buffer content is cleared (or at least pointer is reset)
// Writing new data should start from 0
const newChunk = new Float32Array([9, 9]);
ringBuffer.write(newChunk);
expect(ringBuffer.read(0, 2)).toEqual(newChunk);
});
});
});
|