Integrate the current development branch, preserve the album comment fixes, and align the changes with repository formatting and dependency tooling.
134 lines
4.8 KiB
TypeScript
134 lines
4.8 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest';
|
|
import { MediaIndexer } from '../src/media-indexer';
|
|
import type { MessageElement } from '@snowluma/protocol/events';
|
|
|
|
function makeMediaStore() {
|
|
return {
|
|
rememberImage: vi.fn(),
|
|
rememberRecord: vi.fn(),
|
|
rememberVideo: vi.fn(),
|
|
};
|
|
}
|
|
|
|
describe('MediaIndexer', () => {
|
|
it('image: maps element fields into rememberImage with file fallback to fileId', async () => {
|
|
const store = makeMediaStore();
|
|
const indexer = new MediaIndexer(store as any);
|
|
const element: MessageElement = {
|
|
type: 'image',
|
|
fileId: 'img-fid',
|
|
fileSize: 1024,
|
|
subType: 1,
|
|
summary: '[image]',
|
|
imageUrl: 'http://orig',
|
|
md5Hex: 'abcd',
|
|
sha1Hex: 'efgh',
|
|
width: 800,
|
|
height: 600,
|
|
picFormat: 1000,
|
|
};
|
|
await indexer.remember('image', element, { url: 'http://x', file: '' }, true, 99999);
|
|
|
|
expect(store.rememberImage).toHaveBeenCalledOnce();
|
|
const arg = store.rememberImage.mock.calls[0]![0];
|
|
expect(arg).toMatchObject({
|
|
file: 'img-fid', // data.file was '', fell back to element.fileId
|
|
url: 'http://x',
|
|
fileSize: 1024,
|
|
subType: 1,
|
|
summary: '[image]',
|
|
imageUrl: 'http://orig',
|
|
isGroup: true,
|
|
sessionId: 99999,
|
|
md5Hex: 'abcd',
|
|
sha1Hex: 'efgh',
|
|
width: 800,
|
|
height: 600,
|
|
picFormat: 1000,
|
|
});
|
|
});
|
|
|
|
it('record: maps element fields into rememberRecord with file fallback chain', async () => {
|
|
const store = makeMediaStore();
|
|
const indexer = new MediaIndexer(store as any);
|
|
const element: MessageElement = {
|
|
type: 'record',
|
|
fileId: 'rec-fid',
|
|
fileName: 'voice.amr',
|
|
fileSize: 2048,
|
|
duration: 5,
|
|
fileHash: 'h',
|
|
mediaNode: { fileUuid: 'uuid' },
|
|
md5Hex: 'm',
|
|
sha1Hex: 's',
|
|
voiceFormat: 1,
|
|
};
|
|
await indexer.remember('record', element, { url: 'http://r', file: '' }, false, 12345);
|
|
|
|
const arg = store.rememberRecord.mock.calls[0]![0];
|
|
expect(arg.file).toBe('voice.amr'); // data.file '' → element.fileName
|
|
expect(arg.fileId).toBe('rec-fid');
|
|
expect(arg.duration).toBe(5);
|
|
expect(arg.isGroup).toBe(false);
|
|
expect(arg.sessionId).toBe(12345);
|
|
expect(arg.voiceFormat).toBe(1);
|
|
});
|
|
|
|
it('video: maps element fields into rememberVideo', async () => {
|
|
const store = makeMediaStore();
|
|
const indexer = new MediaIndexer(store as any);
|
|
const element: MessageElement = {
|
|
type: 'video',
|
|
fileId: 'vid-fid',
|
|
fileName: 'clip.mp4',
|
|
fileSize: 99999,
|
|
duration: 30,
|
|
width: 1920,
|
|
height: 1080,
|
|
videoFormat: 2,
|
|
};
|
|
await indexer.remember(
|
|
'video',
|
|
element,
|
|
{ url: 'http://v', file: 'override.mp4' },
|
|
true,
|
|
11111,
|
|
);
|
|
|
|
const arg = store.rememberVideo.mock.calls[0]![0];
|
|
expect(arg.file).toBe('override.mp4'); // data.file used when non-empty
|
|
expect(arg.fileId).toBe('vid-fid');
|
|
expect(arg.duration).toBe(30);
|
|
expect(arg.width).toBe(1920);
|
|
expect(arg.videoFormat).toBe(2);
|
|
});
|
|
|
|
it('falls back to element.fileId when data.file AND element.fileName are missing (record)', async () => {
|
|
const store = makeMediaStore();
|
|
const indexer = new MediaIndexer(store as any);
|
|
const element: MessageElement = { type: 'record', fileId: 'only-fid' };
|
|
await indexer.remember('record', element, { url: '', file: '' }, false, 1);
|
|
expect(store.rememberRecord.mock.calls[0]![0].file).toBe('only-fid');
|
|
});
|
|
|
|
it('defaults missing numeric fields to 0 / missing strings to ""', async () => {
|
|
const store = makeMediaStore();
|
|
const indexer = new MediaIndexer(store as any);
|
|
await indexer.remember('image', { type: 'image' }, { url: '', file: '' }, false, 0);
|
|
const arg = store.rememberImage.mock.calls[0]![0];
|
|
expect(arg.fileSize).toBe(0);
|
|
expect(arg.subType).toBe(0);
|
|
expect(arg.summary).toBe('');
|
|
expect(arg.imageUrl).toBe('');
|
|
});
|
|
|
|
it('only the matching rememberX is called', async () => {
|
|
const store = makeMediaStore();
|
|
const indexer = new MediaIndexer(store as any);
|
|
await indexer.remember('image', { type: 'image' }, { url: '', file: 'a' }, true, 1);
|
|
expect(store.rememberImage).toHaveBeenCalledOnce();
|
|
expect(store.rememberRecord).not.toHaveBeenCalled();
|
|
expect(store.rememberVideo).not.toHaveBeenCalled();
|
|
});
|
|
});
|