mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-18 07:13:13 +00:00
206 lines
7.8 KiB
TypeScript
206 lines
7.8 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
vi.mock('@tauri-apps/api/path', () => ({
|
|
join: vi.fn(async (...parts: string[]) =>
|
|
parts
|
|
.map((part, index) => index === 0 ? part.replace(/[\\/]+$/, '') : part.replace(/^[\\/]+|[\\/]+$/g, ''))
|
|
.join('/')
|
|
)
|
|
}));
|
|
|
|
import {
|
|
downloadLocationEquals,
|
|
DEFAULT_CATEGORY_SUBFOLDERS,
|
|
deriveBatchFolderName,
|
|
formatDerivedCategoryPath,
|
|
normalizeCategorySubfolder,
|
|
normalizeDownloadLocationSettings,
|
|
resolveInitialAddWindowLocation,
|
|
resolveCategoryDestination,
|
|
resolveSubfolderDestination,
|
|
sanitizeBatchFolderName,
|
|
subfolderFromDerivedCategoryPath
|
|
} from './downloadLocations';
|
|
|
|
describe('download locations', () => {
|
|
it('matches backend platform path case semantics', () => {
|
|
expect(downloadLocationEquals('D:\\Downloads', 'Movie.MP4', 'd:/downloads', 'movie.mp4', 'windows')).toBe(true);
|
|
expect(downloadLocationEquals('/Users/Test', 'Movie.MP4', '/users/test', 'movie.mp4', 'macos')).toBe(false);
|
|
expect(downloadLocationEquals('/home/Test', 'Movie.MP4', '/home/test', 'movie.mp4', 'linux')).toBe(false);
|
|
});
|
|
|
|
it('uses a remembered Add-window directory only when the setting is enabled', () => {
|
|
expect(resolveInitialAddWindowLocation(
|
|
'D:\\Downloads',
|
|
true,
|
|
'D:\\Course_Videos'
|
|
)).toEqual({ path: 'D:\\Course_Videos', isManual: true });
|
|
|
|
expect(resolveInitialAddWindowLocation(
|
|
'D:\\Downloads',
|
|
false,
|
|
'D:\\Course_Videos'
|
|
)).toEqual({ path: 'D:\\Downloads', isManual: false });
|
|
});
|
|
|
|
it('falls back to the normalized base folder when no directory was remembered', () => {
|
|
expect(resolveInitialAddWindowLocation(' ', true, null))
|
|
.toEqual({ path: '~/Downloads', isManual: false });
|
|
});
|
|
|
|
it('derives safe batch folder names from title, referer, and timestamp fallback', () => {
|
|
expect(deriveBatchFolderName(
|
|
'Gallery / Chapter: 1',
|
|
'https://example.com/gallery'
|
|
)).toBe('Gallery - Chapter- 1');
|
|
expect(deriveBatchFolderName(
|
|
'New Tab',
|
|
'https://example.com/gallery/part-1?token=secret'
|
|
)).toBe('example.com-gallery-part-1');
|
|
expect(deriveBatchFolderName(
|
|
'New Tab',
|
|
'https://example.com/gallery',
|
|
new Date('2026-07-20T12:34:56.789Z'),
|
|
['example.part1.rar', 'example.part2.rar']
|
|
)).toBe('example');
|
|
expect(deriveBatchFolderName(
|
|
'CON',
|
|
null,
|
|
new Date('2026-07-20T12:34:56.789Z')
|
|
)).toBe('batch-CON');
|
|
expect(deriveBatchFolderName(
|
|
'',
|
|
null,
|
|
new Date('2026-07-20T12:34:56.789Z')
|
|
)).toBe('firelink-batch-2026-07-20-12-34-56-789');
|
|
expect(deriveBatchFolderName(
|
|
'',
|
|
null,
|
|
new Date('2026-07-20T12:34:56.789Z'),
|
|
['example.part1.rar', 'example.part2.rar']
|
|
)).toBe('example');
|
|
expect(sanitizeBatchFolderName('../Example: Parts')).toBe('Example- Parts');
|
|
expect(sanitizeBatchFolderName('😀'.repeat(100))).toBe('😀'.repeat(96));
|
|
});
|
|
|
|
it('places the optional folder below an existing category destination', async () => {
|
|
expect(await resolveSubfolderDestination(
|
|
'/Users/test/Downloads/Compressed',
|
|
'Example: Parts'
|
|
)).toBe('/Users/test/Downloads/Compressed/Example- Parts');
|
|
});
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('migrates legacy derived directories without creating overrides', () => {
|
|
const settings = normalizeDownloadLocationSettings({
|
|
defaultDownloadPath: '/Users/test/Downloads',
|
|
downloadDirectories: {
|
|
Movies: '/Users/test/Downloads/Movies',
|
|
Documents: '/Users/test/Downloads/Documents'
|
|
}
|
|
});
|
|
|
|
expect(settings.baseDownloadFolder).toBe('/Users/test/Downloads');
|
|
expect(settings.categorySubfolders).toEqual(DEFAULT_CATEGORY_SUBFOLDERS);
|
|
expect(settings.categoryDirectoryOverrides).toEqual({});
|
|
});
|
|
|
|
it('preserves legacy custom category directories as overrides', () => {
|
|
const settings = normalizeDownloadLocationSettings({
|
|
defaultDownloadPath: '/Users/test/Downloads',
|
|
downloadDirectories: {
|
|
Video: '/Volumes/Media/Movies'
|
|
}
|
|
});
|
|
|
|
expect(settings.categoryDirectoryOverrides.Movies).toBe('/Volumes/Media/Movies');
|
|
});
|
|
|
|
it('resolves automatic and overridden category destinations', async () => {
|
|
const automatic = normalizeDownloadLocationSettings({
|
|
baseDownloadFolder: '/Users/test/Downloads',
|
|
categorySubfolders: { Movies: 'Video Files' }
|
|
});
|
|
expect(await resolveCategoryDestination(automatic, 'Movies'))
|
|
.toBe('/Users/test/Downloads/Video Files');
|
|
|
|
automatic.categoryDirectoryOverrides.Movies = '/Volumes/Media';
|
|
expect(await resolveCategoryDestination(automatic, 'Movies')).toBe('/Volumes/Media');
|
|
});
|
|
|
|
it('defaults Torrent downloads to the Torrents folder and respects overrides', async () => {
|
|
const settings = normalizeDownloadLocationSettings({
|
|
baseDownloadFolder: '/Users/test/Downloads'
|
|
});
|
|
|
|
expect(settings.categorySubfolders.Torrents).toBe('Torrents');
|
|
expect(await resolveCategoryDestination(settings, 'Torrents'))
|
|
.toBe('/Users/test/Downloads/Torrents');
|
|
|
|
settings.categoryDirectoryOverrides.Torrents = '/Volumes/Archive/Torrents';
|
|
expect(await resolveCategoryDestination(settings, 'Torrents'))
|
|
.toBe('/Volumes/Archive/Torrents');
|
|
|
|
settings.categorySubfoldersEnabled = false;
|
|
expect(await resolveCategoryDestination(settings, 'Torrents'))
|
|
.toBe('/Users/test/Downloads');
|
|
});
|
|
|
|
it('defaults category subfolders on and sends every category to the base folder when disabled', async () => {
|
|
const automatic = normalizeDownloadLocationSettings({
|
|
baseDownloadFolder: '/Users/test/Downloads'
|
|
});
|
|
expect(automatic.categorySubfoldersEnabled).toBe(true);
|
|
|
|
const disabled = normalizeDownloadLocationSettings({
|
|
baseDownloadFolder: '/Users/test/Downloads',
|
|
categorySubfoldersEnabled: false,
|
|
categorySubfolders: { Movies: 'Video Files' },
|
|
categoryDirectoryOverrides: { Movies: '/Volumes/Media' }
|
|
});
|
|
|
|
expect(disabled.categorySubfoldersEnabled).toBe(false);
|
|
expect(await resolveCategoryDestination(disabled, 'Movies'))
|
|
.toBe('/Users/test/Downloads');
|
|
expect(await resolveCategoryDestination(disabled, 'Documents'))
|
|
.toBe('/Users/test/Downloads');
|
|
});
|
|
|
|
it('keeps an explicit empty category subfolder as the base folder', async () => {
|
|
const settings = normalizeDownloadLocationSettings({
|
|
baseDownloadFolder: '/Users/test/Downloads',
|
|
categorySubfolders: { Movies: '' }
|
|
});
|
|
|
|
expect(settings.categorySubfolders.Movies).toBe('');
|
|
expect(settings.categorySubfolders.Documents).toBe('Documents');
|
|
expect(formatDerivedCategoryPath('/Users/test/Downloads', '')).toBe('/Users/test/Downloads');
|
|
expect(await resolveCategoryDestination(settings, 'Movies')).toBe('/Users/test/Downloads');
|
|
});
|
|
|
|
it('keeps category subfolders relative and permits nested folders', () => {
|
|
expect(normalizeCategorySubfolder('../Media/./Movies', 'Movies')).toBe('Media/Movies');
|
|
expect(normalizeCategorySubfolder('C:\\Media\\Movies', 'Movies')).toBe('Media/Movies');
|
|
expect(normalizeCategorySubfolder('../../', 'Movies')).toBe('Movies');
|
|
});
|
|
|
|
it('formats and parses derived category paths with platform path separators', () => {
|
|
expect(formatDerivedCategoryPath('/Users/test/Downloads', 'Video Files'))
|
|
.toBe('/Users/test/Downloads/Video Files');
|
|
expect(formatDerivedCategoryPath('D:\\Downloads', 'Video Files'))
|
|
.toBe('D:\\Downloads\\Video Files');
|
|
expect(subfolderFromDerivedCategoryPath(
|
|
'D:\\Downloads\\Video Files',
|
|
'd:\\downloads'
|
|
)).toBe('Video Files');
|
|
expect(subfolderFromDerivedCategoryPath(
|
|
'/Users/test/Downloads/Video Files',
|
|
'/Users/test/Downloads'
|
|
)).toBe('Video Files');
|
|
expect(subfolderFromDerivedCategoryPath('/Volumes/Media', '/Users/test/Downloads'))
|
|
.toBeNull();
|
|
});
|
|
});
|