Files
kikootwo dc7e557694 Add notification system with admin UI and backend
Introduces a full notification system with support for Discord and Pushover backends, event triggers, and message formatting. Adds backend services, processors, and API endpoints for managing notifications, as well as a new Notifications tab in the admin settings UI. Updates documentation, database schema, and tests to cover notification features and approval workflow improvements. Also changes project license from MIT to AGPL v3.
2026-01-28 11:42:00 -05:00

123 lines
3.8 KiB
TypeScript

/**
* Component: Path Mapper Tests
* Documentation: documentation/phase3/qbittorrent.md
*/
import { describe, expect, it } from 'vitest';
import { PathMapper } from '@/lib/utils/path-mapper';
describe('PathMapper', () => {
it('returns original path when mapping is disabled', () => {
const result = PathMapper.transform('/remote/path/book', {
enabled: false,
remotePath: '/remote/path',
localPath: '/local/path',
});
expect(result).toBe('/remote/path/book');
});
it('transforms remote path to local path when enabled', () => {
const result = PathMapper.transform('/remote/mnt/d/done/Book', {
enabled: true,
remotePath: '/remote/mnt/d/done',
localPath: '/downloads',
});
expect(result.replace(/\\/g, '/')).toBe('/downloads/Book');
});
it('returns original path when remote prefix does not match', () => {
const result = PathMapper.transform('/other/path/book', {
enabled: true,
remotePath: '/remote/path',
localPath: '/local/path',
});
expect(result).toBe('/other/path/book');
});
it('validates mapping configuration when enabled', () => {
expect(() =>
PathMapper.validate({ enabled: true, remotePath: '', localPath: '/local' })
).toThrow('Remote path cannot be empty');
expect(() =>
PathMapper.validate({ enabled: true, remotePath: '/remote', localPath: '' })
).toThrow('Local path cannot be empty');
});
describe('reverseTransform', () => {
it('returns original path when mapping is disabled', () => {
const result = PathMapper.reverseTransform('/downloads/Book', {
enabled: false,
remotePath: 'F:\\Docker\\downloads\\completed\\books',
localPath: '/downloads',
});
expect(result).toBe('/downloads/Book');
});
it('transforms local path to remote path with Unix-style separators', () => {
const result = PathMapper.reverseTransform('/downloads/Audiobook.Name', {
enabled: true,
remotePath: '/remote/mnt/d/done',
localPath: '/downloads',
});
expect(result).toBe('/remote/mnt/d/done/Audiobook.Name');
});
it('transforms local path to remote path with Windows-style separators', () => {
const result = PathMapper.reverseTransform('/downloads/Audiobook.Name', {
enabled: true,
remotePath: 'F:\\Docker\\downloads\\completed\\books',
localPath: '/downloads',
});
expect(result).toBe('F:\\Docker\\downloads\\completed\\books\\Audiobook.Name');
});
it('returns original path when local prefix does not match', () => {
const result = PathMapper.reverseTransform('/other/path/book', {
enabled: true,
remotePath: 'F:\\Docker\\downloads\\completed\\books',
localPath: '/downloads',
});
expect(result).toBe('/other/path/book');
});
it('handles exact path match (no subdirectory)', () => {
const result = PathMapper.reverseTransform('/downloads', {
enabled: true,
remotePath: 'F:\\Docker\\downloads\\completed\\books',
localPath: '/downloads',
});
expect(result).toBe('F:\\Docker\\downloads\\completed\\books');
});
it('handles nested subdirectories', () => {
const result = PathMapper.reverseTransform('/downloads/Author/Book Name/file.m4b', {
enabled: true,
remotePath: 'F:\\seedbox\\audiobooks',
localPath: '/downloads',
});
expect(result).toBe('F:\\seedbox\\audiobooks\\Author\\Book Name\\file.m4b');
});
it('handles trailing slashes in config', () => {
const result = PathMapper.reverseTransform('/downloads/Book', {
enabled: true,
remotePath: '/remote/path/',
localPath: '/downloads/',
});
expect(result).toBe('/remote/path/Book');
});
});
});