mirror of
https://github.com/Shik3i/KoalaSync.git
synced 2026-09-03 22:45:21 +00:00
154 lines
5.8 KiB
JavaScript
154 lines
5.8 KiB
JavaScript
import { describe, expect, it } from 'vitest';
|
|
import {
|
|
EPISODE_WIRE_TITLE_LENGTH,
|
|
createLocalEpisodeDeadline,
|
|
createEpisodeWireIdentity,
|
|
extractEpisodeId,
|
|
sameEpisode,
|
|
sameEpisodeIdentity,
|
|
sameEpisodeStrict,
|
|
isEpisodeSyncV2StartContextCurrent,
|
|
matchesEpisodeSyncV2StartRejection,
|
|
toEpisodeWireTitle
|
|
} from './episode-utils.js';
|
|
|
|
describe('episode title matching', () => {
|
|
it.each([
|
|
['S01E01', 'S01E01'],
|
|
['S1E1', 'S01E01'],
|
|
['s01e01', 'S01E01'],
|
|
['Season 1 Episode 2', 'S01E02'],
|
|
['season 01 episode 02', 'S01E02'],
|
|
['S01 - E01', 'S01E01'],
|
|
['S01.E01', 'S01E01'],
|
|
['S01/E01', 'S01E01'],
|
|
['S01:E01', 'S01E01'],
|
|
['S01,E01', 'S01E01'],
|
|
['S01 E01', 'S01E01'],
|
|
['Folge 5', 'EP005'],
|
|
['Episode 12', 'EP012'],
|
|
['Ep. 3', 'EP003'],
|
|
['#42', 'EP042'],
|
|
['S01E001', 'S01E001']
|
|
])('extracts %s as %s', (title, expected) => {
|
|
expect(extractEpisodeId(title)).toBe(expected);
|
|
});
|
|
|
|
it.each([null, undefined, '', 123, 'Some Movie Title', 'Breaking Bad'])(
|
|
'returns null for non-episode input %j',
|
|
input => expect(extractEpisodeId(input)).toBeNull()
|
|
);
|
|
|
|
it.each([
|
|
['S01E01', 'S01E01'],
|
|
['S01E01 - Pilot', 'S01E01'],
|
|
['Folge 5', 'Episode 5'],
|
|
['Episode 12', 'Ep. 12'],
|
|
['#42', 'Folge 42'],
|
|
[null, null],
|
|
['', ''],
|
|
['Some Movie', 'Some Movie']
|
|
])('matches equivalent titles %j and %j', (left, right) => {
|
|
expect(sameEpisode(left, right)).toBe(true);
|
|
});
|
|
|
|
it.each([
|
|
['S01E01', 'S01E02'],
|
|
['S01E01', 'S02E01'],
|
|
['Folge 1', 'Folge 2'],
|
|
['Some Movie', 'Other Movie'],
|
|
['S01E01', null],
|
|
[null, 'Episode 5'],
|
|
['S01E05', 'Episode 5'],
|
|
['S01E01', 'EP001']
|
|
])('rejects different titles %j and %j', (left, right) => {
|
|
expect(sameEpisode(left, right)).toBe(false);
|
|
});
|
|
|
|
it('keeps transactional matching strict when both titles expose context', () => {
|
|
expect(sameEpisodeStrict('S1:E6 - Visiting Ours', 'S01E06 - Visiting Ours')).toBe(true);
|
|
expect(sameEpisodeStrict('S1:E6 - Visiting Ours', 'S1:E6 - Another Show')).toBe(false);
|
|
expect(sameEpisodeStrict('S1:E6', 'S01E06 - Visiting Ours')).toBe(true);
|
|
expect(sameEpisodeStrict(
|
|
'Arrested Development - S1:E6 - Visiting Ours',
|
|
'S01E06 - Visiting Ours'
|
|
)).toBe(true);
|
|
expect(sameEpisodeStrict(
|
|
'Arrested Development - S1:E6 - Visiting Ours',
|
|
'Different Series - S01E06 - Visiting Ours'
|
|
)).toBe(false);
|
|
});
|
|
|
|
it('mirrors the relay title clamp before strict comparison', () => {
|
|
const title = `S01E06 - ${'Very Long Episode Context '.repeat(8)}`;
|
|
const wireTitle = toEpisodeWireTitle(title);
|
|
|
|
expect(EPISODE_WIRE_TITLE_LENGTH).toBe(100);
|
|
expect(wireTitle).toHaveLength(100);
|
|
expect(sameEpisodeStrict(title, wireTitle)).toBe(true);
|
|
});
|
|
|
|
it('keeps the full-title episode id in a bounded wire identity', () => {
|
|
const title = `${'Long Series Context '.repeat(8)} S01E06`;
|
|
const identity = createEpisodeWireIdentity(title);
|
|
|
|
expect(identity).toEqual({
|
|
expectedTitle: title.substring(0, 100),
|
|
expectedEpisodeId: 'S01E06'
|
|
});
|
|
expect(sameEpisodeIdentity(title, identity.expectedTitle, identity.expectedEpisodeId)).toBe(true);
|
|
expect(sameEpisodeIdentity(title.replace('S01E06', 'S01E07'), identity.expectedTitle, identity.expectedEpisodeId)).toBe(false);
|
|
});
|
|
|
|
it('bounds oversized and UTF-16 titles exactly like relay substring sanitization', () => {
|
|
const title = `${'x'.repeat(99)}😀S01E06${'y'.repeat(5000)}`;
|
|
expect(toEpisodeWireTitle(title)).toBe(title.substring(0, 100));
|
|
expect(toEpisodeWireTitle(title).length).toBe(100);
|
|
expect(toEpisodeWireTitle(null)).toBeNull();
|
|
});
|
|
|
|
it('converts relay remaining duration to a bounded local deadline without wall-clock trust', () => {
|
|
expect(createLocalEpisodeDeadline(30_000, 120_000, 1_000)).toEqual({
|
|
remainingMs: 30_000,
|
|
deadlineAt: 31_000
|
|
});
|
|
expect(createLocalEpisodeDeadline(undefined, 120_000, 1_000)).toEqual({
|
|
remainingMs: 120_000,
|
|
deadlineAt: 121_000
|
|
});
|
|
expect(createLocalEpisodeDeadline(999_999, 120_000, 1_000).remainingMs).toBe(120_000);
|
|
expect(createLocalEpisodeDeadline(-1, 120_000, 1_000).remainingMs).toBe(0);
|
|
});
|
|
|
|
it('rejects stale or mismatched capability fallback responses', () => {
|
|
const pending = {
|
|
roomId: 'ROOM-A',
|
|
connectionGeneration: 4,
|
|
targetGeneration: 7,
|
|
tabId: 12,
|
|
expectedTitle: 'S01E06 - Visiting Ours',
|
|
expectedEpisodeId: 'S01E06',
|
|
requestedAt: 10_000
|
|
};
|
|
const current = {
|
|
roomId: 'ROOM-A',
|
|
connectionGeneration: 4,
|
|
targetGeneration: 7,
|
|
tabId: 12
|
|
};
|
|
const rejection = {
|
|
expectedTitle: 'S01E06 - Visiting Ours',
|
|
expectedEpisodeId: 's01e06'
|
|
};
|
|
|
|
expect(isEpisodeSyncV2StartContextCurrent(pending, current, 20_000)).toBe(true);
|
|
expect(matchesEpisodeSyncV2StartRejection(pending, current, rejection, 20_000)).toBe(true);
|
|
expect(matchesEpisodeSyncV2StartRejection(pending, { ...current, targetGeneration: 8 }, rejection, 20_000)).toBe(false);
|
|
expect(matchesEpisodeSyncV2StartRejection(pending, current, rejection, 25_001)).toBe(false);
|
|
expect(matchesEpisodeSyncV2StartRejection(pending, current, {
|
|
...rejection,
|
|
expectedTitle: 'S01E07 - Different'
|
|
}, 20_000)).toBe(false);
|
|
});
|
|
});
|