tests/srt.test.cjs (4292 bytes)
1 /* node --test tests */ 2 const test = require('node:test'); 3 const assert = require('node:assert/strict'); 4 const { parse, cueAt, subtitleTime, videoTime, seconds } = require('../src/srt.js'); 5 6 test('an .srt is read: numbers, stamps, text of more than one line, tags removed', () => { 7 const cues = parse('1\r\n00:00:01,500 --> 00:00:04,000\r\nIt was a <i>dark</i> night;\r\nthe rain fell.\r\n\r\n' + 8 '2\r\n01:02:03,004 --> 01:02:05,000\r\n吾輩は猫である。\r\n'); 9 assert.deepEqual(cues, [ 10 { start: 1.5, end: 4, text: 'It was a dark night;\nthe rain fell.' }, 11 { start: 3723.004, end: 3725, text: '吾輩は猫である。' }, 12 ]); 13 }); 14 15 test('the text of each checked language is kept as it is: accents, inverted marks, quotes, kana', () => { 16 const lines = { 17 en: 'It was a dark night; the rain fell.', 18 pt: '— Não me parece bonito — disse ela, à porta.', 19 es: '¿Qué es esto? ¡Ñandú, señor Quijote!', 20 ru: '«Ёлка, — сказал он, — и её огни».', 21 ja: '「女のいない男たち」 東京で暮らしている。', 22 }; 23 const source = Object.values(lines).map((text, i) => `${i + 1}\n00:00:0${i},000 --> 00:00:0${i},900\n${text}\n`).join('\n'); 24 const cues = parse(source); 25 assert.deepEqual(cues.map((c) => c.text), Object.values(lines)); 26 Object.values(lines).forEach((text, i) => assert.equal(cueAt(cues, i + 0.5).text, text)); 27 }); 28 29 test('a .vtt is read too, and what is not a cue is passed over', () => { 30 const cues = parse('WEBVTT\n\nNOTE made by hand\n\n00:01.000 --> 00:02.5\nHello\n\nbroken --> block\nx\n\n3\n00:00:09,000 --> 00:00:08,000\nends before it starts\n'); 31 assert.deepEqual(cues, [{ start: 1, end: 2.5, text: 'Hello' }]); 32 }); 33 34 test('stamps', () => { 35 assert.equal(seconds('00:00:00,004'), 0.004); 36 assert.equal(seconds('10:00:00.5'), 36000.5); 37 assert.ok(Number.isNaN(seconds('soon'))); 38 }); 39 40 test('the cue for a moment is the one a slow search finds, for any cues and any moment', () => { 41 let seed = 11; 42 const random = () => (seed = (seed * 1103515245 + 12345) >>> 0) / 2 ** 32; 43 for (let round = 0; round < 300; round++) { 44 const cues = []; 45 let t = random() * 5; 46 for (let i = 0; i < Math.floor(random() * 40); i++) { 47 const start = t, end = start + 0.2 + random() * 5; 48 cues.push({ start, end, text: String(i) }); 49 t = end + (random() < 0.5 ? 0 : random() * 3); // back to back, or a gap 50 } 51 for (let k = 0; k < 60; k++) { 52 const at = random() * (t + 5) - 1; 53 const slow = cues.filter((c) => c.start <= at && at < c.end).pop() ?? null; 54 assert.equal(cueAt(cues, at), slow); 55 } 56 } 57 assert.equal(cueAt([], 3), null); 58 }); 59 60 test('a cue that overlaps the one after it gives way to the later one', () => { 61 const cues = [{ start: 0, end: 10, text: 'long' }, { start: 4, end: 6, text: 'short' }]; 62 assert.equal(cueAt(cues, 5).text, 'short'); 63 assert.equal(cueAt(cues, 8).text, 'long'); 64 }); 65 66 test('the time of the video is moved onto the clock of the subtitles', () => { 67 assert.equal(subtitleTime(100, 0, 1), 100); 68 assert.equal(subtitleTime(100, 12.5, 1), 87.5); // the upload has a 12.5 s intro 69 assert.ok(Math.abs(subtitleTime(3600, 0, 1.001) - 3603.6) < 1e-9); // and runs a little slow 70 }); 71 72 test('the transcript panel moves a cue time back onto the clock of the video', () => { 73 assert.equal(videoTime(100, 0, 1), 100); 74 assert.equal(videoTime(87.5, 12.5, 1), 100); // the 12.5 s intro comes back 75 assert.ok(Math.abs(videoTime(3603.6, 0, 1.001) - 3600) < 1e-9); 76 }); 77 78 test('videoTime undoes subtitleTime, and subtitleTime undoes videoTime, for many offsets and rates', () => { 79 let seed = 7; 80 const random = () => (seed = (seed * 1103515245 + 12345) >>> 0) / 2 ** 32; 81 for (let round = 0; round < 500; round++) { 82 const offset = (random() - 0.5) * 40; // seconds, either side of 0 83 const rate = 0.9 + random() * 0.2; // the panel limits rate to 0.9 .. 1.1 84 const videoT = random() * 7200; // up to two hours in 85 const subT = subtitleTime(videoT, offset, rate); 86 assert.ok(Math.abs(videoTime(subT, offset, rate) - videoT) < 1e-9); 87 assert.ok(Math.abs(subtitleTime(videoTime(subT, offset, rate), offset, rate) - subT) < 1e-9); 88 } 89 });