test/book-subtitles.test.ts (5954 bytes)
1 import fc from 'fast-check'; 2 import { describe, expect, it } from 'vitest'; 3 import { 4 keepMakeStatus, 5 resultName, 6 srtName, 7 subreadConcerns, 8 subtitlesOnOpen, 9 } from '../src/book-subtitles'; 10 11 describe('keepMakeStatus', () => { 12 it('removes the SubRead result of the book before', () => { 13 // The finding: "15 cues, language en, 97% ..." of book A stayed in the 14 // menu when book B opened. 15 expect(keepMakeStatus('B', null, null)).toBe(false); 16 }); 17 18 it('removes the wait of the book before: its job does not start', () => { 19 expect(keepMakeStatus('B', null, 'A')).toBe(false); 20 }); 21 22 it('keeps the status of the job that runs: it tells why the button is off', () => { 23 expect(keepMakeStatus('B', 'A', null)).toBe(true); 24 expect(keepMakeStatus('A', 'A', null)).toBe(true); 25 }); 26 27 it('keeps the wait of the book that opens again', () => { 28 expect(keepMakeStatus('A', null, 'A')).toBe(true); 29 }); 30 }); 31 32 describe('srtName', () => { 33 it('puts .srt in place of .pdf', () => { 34 expect(srtName('sample-eng-2p.pdf')).toBe('sample-eng-2p.srt'); 35 expect(srtName('Neko.PDF')).toBe('Neko.srt'); 36 expect(srtName('吾輩は猫である.pdf')).toBe('吾輩は猫である.srt'); 37 }); 38 39 it('adds .srt to a name without .pdf at the end', () => { 40 expect(srtName('book')).toBe('book.srt'); 41 expect(srtName('a.pdf.txt')).toBe('a.pdf.txt.srt'); 42 }); 43 }); 44 45 describe('subtitlesOnOpen', () => { 46 const eng = 'sample-eng-2p.pdf|4053'; 47 const jpn = 'sample-jpn.pdf|20410'; 48 49 it('loads the saved subtitles of the book, else clears', () => { 50 expect(subtitlesOnOpen(undefined, jpn, true)).toBe('load'); 51 expect(subtitlesOnOpen(undefined, jpn, false)).toBe('clear'); 52 }); 53 54 it('does not keep the subtitles of another book', () => { 55 // The web finding: the cues of the English book stayed on the Japanese book. 56 expect(subtitlesOnOpen(eng, jpn, false)).toBe('clear'); 57 expect(subtitlesOnOpen(eng, jpn, true)).toBe('load'); 58 }); 59 60 it('keeps subtitles that were loaded while no book was open, for the book that opens', () => { 61 expect(subtitlesOnOpen(null, jpn, false)).toBe('keep'); 62 expect(subtitlesOnOpen(null, jpn, true)).toBe('keep'); 63 }); 64 65 it('keeps the subtitles of the same book', () => { 66 expect(subtitlesOnOpen(jpn, jpn, true)).toBe('keep'); 67 expect(subtitlesOnOpen(jpn, jpn, false)).toBe('keep'); 68 }); 69 }); 70 71 describe('resultName', () => { 72 it('is the FNV-1a hash of the book key', () => { 73 // The test vectors of FNV-1a (32 bit). 74 expect(resultName('')).toBe('subread-811c9dc5.srt'); 75 expect(resultName('a')).toBe('subread-e40c292c.srt'); 76 expect(resultName('foobar')).toBe('subread-bf9cf968.srt'); 77 }); 78 79 it('tells apart two Japanese books that the plugin would both call "_"', () => { 80 const neko = resultName('吾輩は猫である.pdf|204800'); 81 const botchan = resultName('坊っちゃん.pdf|204800'); 82 expect(neko).not.toBe(botchan); 83 expect(resultName('吾輩は猫である.pdf|204801')).not.toBe(neko); 84 }); 85 86 it('gives a name that the plugin keeps as it is, the same for the same key', () => { 87 fc.assert( 88 fc.property(fc.string({ unit: 'binary' }), (key) => { 89 const name = resultName(key); 90 expect(name).toMatch(/^subread-[0-9a-f]{8}\.srt$/); 91 expect(resultName(key)).toBe(name); 92 }), 93 ); 94 }); 95 }); 96 97 describe('subreadConcerns', () => { 98 const file = { name: 'sample-eng-2p.srt', source: 'file' as const }; 99 100 it('asks for the phone case: no speech, language km, match rate 1, over a loaded file', () => { 101 expect( 102 subreadConcerns({ 103 requested: 'auto', 104 ocrLang: 'eng', 105 language: 'km', 106 matchRate: 1, 107 loaded: file, 108 }), 109 ).toEqual([ 110 'They replace sample-eng-2p.srt, the subtitles that you loaded.', 111 'SubRead found the language "km", not "en".', 112 ]); 113 }); 114 115 it('loads at once a good result over no subtitles or over an earlier SubRead result', () => { 116 const good = { requested: 'auto', ocrLang: 'jpn', language: 'ja', matchRate: 0.97 }; 117 expect(subreadConcerns(good)).toEqual([]); 118 const earlier = { name: 'neko.srt', source: 'subread' as const }; 119 expect(subreadConcerns({ ...good, loaded: earlier })).toEqual([]); 120 }); 121 122 it('compares the found language with the requested one', () => { 123 expect(subreadConcerns({ requested: 'ja', ocrLang: 'eng', language: 'ja' })).toEqual([]); 124 expect(subreadConcerns({ requested: 'ja', ocrLang: 'jpn', language: 'en' })).toEqual([ 125 'SubRead found the language "en", not "ja".', 126 ]); 127 }); 128 129 it('takes the language of the book from the OCR language when the request is auto', () => { 130 const both = { requested: 'auto', ocrLang: 'jpn+eng' }; 131 expect(subreadConcerns({ ...both, language: 'en' })).toEqual([]); 132 expect(subreadConcerns({ ...both, language: 'ja' })).toEqual([]); 133 expect(subreadConcerns({ ...both, language: 'km' })).toEqual([ 134 'SubRead found the language "km", not "ja" or "en".', 135 ]); 136 const vertical = { requested: 'auto', ocrLang: 'jpn_vert', language: 'ja' }; 137 expect(subreadConcerns(vertical)).toEqual([]); 138 expect(subreadConcerns({ requested: 'auto', ocrLang: 'eng', language: 'en-US' })).toEqual([]); 139 }); 140 141 it('does not ask about a language or a match rate that SubRead does not tell', () => { 142 expect(subreadConcerns({ requested: 'ja', ocrLang: 'jpn', language: null })).toEqual([]); 143 expect(subreadConcerns({ requested: 'ja', ocrLang: 'jpn', language: '' })).toEqual([]); 144 expect(subreadConcerns({ requested: 'ja', ocrLang: 'jpn', matchRate: -1 })).toEqual([]); 145 }); 146 147 it('asks when less than 80% of the lines are found in the book', () => { 148 expect(subreadConcerns({ requested: 'en', ocrLang: 'eng', matchRate: 0.42 })).toEqual([ 149 'SubRead found only 42% of the lines in the book.', 150 ]); 151 expect(subreadConcerns({ requested: 'en', ocrLang: 'eng', matchRate: 0.8 })).toEqual([]); 152 }); 153 });