Restructure chat service, web routes, and add test suite
Split monolithic chat service into modular structure with Matrix client support, extract web server into per-resource route modules, introduce bootstrap/main-loop separation, and add comprehensive vitest coverage across services, repositories, and utilities. Adds project docs and CLAUDE.md agent instructions.
This commit is contained in:
1 parent
dfa0580859
commit
633bb0ec04
84 files changed
+19278
-3888
No files matched your search
@@ -0,0 +1,74 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { isValidImageMimeType, bufferToBase64 } from '../src/utils/image.js';
|
||||
|
||||
describe('isValidImageMimeType', () => {
|
||||
it('accepts valid image MIME types', () => {
|
||||
expect(isValidImageMimeType('image/jpeg')).toBe(true);
|
||||
expect(isValidImageMimeType('image/png')).toBe(true);
|
||||
expect(isValidImageMimeType('image/gif')).toBe(true);
|
||||
expect(isValidImageMimeType('image/webp')).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects invalid MIME types', () => {
|
||||
expect(isValidImageMimeType('text/plain')).toBe(false);
|
||||
expect(isValidImageMimeType('application/pdf')).toBe(false);
|
||||
expect(isValidImageMimeType('video/mp4')).toBe(false);
|
||||
expect(isValidImageMimeType('application/json')).toBe(false);
|
||||
expect(isValidImageMimeType('text/html')).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects empty string', () => {
|
||||
expect(isValidImageMimeType('')).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects null-like values', () => {
|
||||
expect(isValidImageMimeType('null' as unknown as string)).toBe(false);
|
||||
expect(isValidImageMimeType('undefined' as unknown as string)).toBe(false);
|
||||
});
|
||||
|
||||
it('is case-sensitive (lowercase required)', () => {
|
||||
// The function checks exact matches against lowercase values
|
||||
expect(isValidImageMimeType('IMAGE/JPEG')).toBe(false);
|
||||
expect(isValidImageMimeType('Image/Png')).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects MIME types with parameters', () => {
|
||||
expect(isValidImageMimeType('image/jpeg; charset=utf-8')).toBe(false);
|
||||
expect(isValidImageMimeType('image/png; alpha')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bufferToBase64', () => {
|
||||
it('converts buffer to base64 string', () => {
|
||||
const buffer = Buffer.from('hello world');
|
||||
const result = bufferToBase64(buffer);
|
||||
expect(result).toBe(btoa('hello world'));
|
||||
});
|
||||
|
||||
it('handles empty buffer', () => {
|
||||
const buffer = Buffer.from('');
|
||||
const result = bufferToBase64(buffer);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('handles binary data', () => {
|
||||
const buffer = Buffer.from([0x00, 0x01, 0x02, 0xff, 0xfe, 0xfd]);
|
||||
const result = bufferToBase64(buffer);
|
||||
expect(result).toBe(btoa('\x00\x01\x02\xff\xfe\xfd'));
|
||||
});
|
||||
|
||||
it('handles large buffer', () => {
|
||||
const buffer = Buffer.alloc(1024 * 1024); // 1MB
|
||||
buffer.fill(0x41); // 'A'
|
||||
const result = bufferToBase64(buffer);
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
// Base64 encodes each 3 bytes as 4 chars, rounding up.
|
||||
expect(result.length).toBe(Math.ceil((1024 * 1024) / 3) * 4);
|
||||
});
|
||||
|
||||
it('produces valid base64 (only valid chars)', () => {
|
||||
const buffer = Buffer.from(Math.random().toString(36).repeat(100));
|
||||
const result = bufferToBase64(buffer);
|
||||
expect(result).toMatch(/^[A-Za-z0-9+/]+=*$/);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user