UNPKG

versification

Version:

A library for parsing Paratext's vrs files.

499 lines (392 loc) 18.7 kB
import {expect} from 'chai'; import Versification from '../src/Versification' import * as testData from './testData.js'; import VerseRef from '../src/VerseRef'; describe('Versification', () => { describe('Comment lines', () => { it('single meaningless comment line', () => { const v = new Versification('#hello world'); expect(v.name).to.be.empty; expect(v.books()).to.be.empty; }); it('single name comment line', () => { const v = new Versification('# Versification "Septuagint"'); expect(v.name).to.be.equal('Septuagint'); }); it('single name comment line, with leading spaces', () => { const v = new Versification(' # Versification "Septuagint"'); expect(v.name).to.be.equal('Septuagint'); }); it('multiple comment lines', () => { const v = new Versification(`# Versification "Original" # Version=1.200`); expect(v.name).to.be.equal('Original'); }); it('duplicate name comment lines - second one is ignored', () => { const v = new Versification(`# Versification "Original" # Versification "Septuagint"`); expect(v.name).to.be.equal('Original'); }); }) describe('chapter / verse definitions', () => { it('Genesis line', () => { const testLine = 'GEN 1:31 2:25 3:24 4:26 5:32 6:22'; const v = new Versification(testLine); expect(v.books()).to.have.lengthOf(2); expect(v.books()[0]).to.be.undefined; expect(v.books()[1]).to.have.lengthOf(7); expect(v.books()[1][0]).to.be.undefined; expect(v.books()[1][1]).to.be.equal(31); expect(v.books()[1][2]).to.be.equal(25); }) it('Exodus line', () => { const testLine = 'EXO 1:22 2:25 3:22 4:31'; const v = new Versification(testLine); expect(v.books()).to.have.lengthOf(3); expect(v.books()[0]).to.be.undefined; expect(v.books()[1]).to.be.undefined; expect(v.books()[2]).to.have.lengthOf(5); expect(v.books()[2][0]).to.be.undefined; expect(v.books()[2][1]).to.be.equal(22); expect(v.books()[2][2]).to.be.equal(25); }) it('Overrides - subsequent lines override previous lines', () => { const testLine = `GEN 1:31 2:25 3:24 4:26 5:32 6:22 GEN 1:30`; const v = new Versification(testLine); expect(v.books()).to.have.lengthOf(2); expect(v.books()[0]).to.be.undefined; expect(v.books()[1]).to.have.lengthOf(7); expect(v.books()[1][0]).to.be.undefined; expect(v.books()[1][1]).to.be.equal(30); expect(v.books()[1][2]).to.be.equal(25); }); }) describe('standard mappings', () => { it('single verse mapping', () => { const testLine = `GEN 31:55 = GEN 32:1`; const v = new Versification(testLine); expect(v.mappings()).to.have.lengthOf(1); expect(v.mappings()[0][0].toString()).to.be.equal('GEN 31:55'); expect(v.mappings()[0][1].toString()).to.be.equal('GEN 32:1'); }); it('whole chapter mapping', () => { const testLine = `PSA 3:0-8 = PSA 3:1-9`; const v = new Versification(testLine); expect(v.mappings()).to.have.lengthOf(9); expect(v.mappings()[0][0].toString()).to.be.equal('PSA 3:0'); expect(v.mappings()[0][1].toString()).to.be.equal('PSA 3:1'); expect(v.mappings()[8][0].toString()).to.be.equal('PSA 3:8'); expect(v.mappings()[8][1].toString()).to.be.equal('PSA 3:9'); }); it('invalid reverse range mapping - ignores the range part', () => { const testLine = `PSA 3:0-2 = PSA 3:2-0`; const v = new Versification(testLine); expect(v.mappings()).to.have.lengthOf(3); expect(v.mappings()[0][0].toString()).to.be.equal('PSA 3:0'); expect(v.mappings()[0][1].toString()).to.be.equal('PSA 3:2'); expect(v.mappings()[1][0].toString()).to.be.equal('PSA 3:1'); expect(v.mappings()[1][1].toString()).to.be.equal('PSA 3:2'); expect(v.mappings()[2][0].toString()).to.be.equal('PSA 3:2'); expect(v.mappings()[2][1].toString()).to.be.equal('PSA 3:2'); }); }); describe('one to many mapping', () => { it('two verse references -> one verse reference', () => { const testLine = `#! &ACT 19:40-41 = ACT 19:40`; const v = new Versification(testLine); expect(v.mappings()).to.have.lengthOf(2); expect(v.mappings()[0][0].toString()).to.be.equal('ACT 19:40'); expect(v.mappings()[0][1].toString()).to.be.equal('ACT 19:40'); expect(v.mappings()[1][0].toString()).to.be.equal('ACT 19:41'); expect(v.mappings()[1][1].toString()).to.be.equal('ACT 19:40'); }); }); describe('excluded verses', () => { it('no excluded verses', () => { const v = new Versification(''); expect(v.excludedVerses()).to.have.lengthOf(0); expect(v.excludedVerses(1)).to.have.lengthOf(0); expect(v.excludedVerses(1, 1)).to.have.lengthOf(0); }); it('Single excluded verse', () => { const testLine = `-EXO 25:6`; const v = new Versification(testLine); expect(v.excludedVerses()).to.have.lengthOf(1); expect(v.excludedVerses()).to.contain(2025006); }); it('multiple excluded verses', () => { const testLine = `-EXO 25:6 -MAT 1:1`; const v = new Versification(testLine); expect(v.excludedVerses()).to.have.lengthOf(2); expect(v.excludedVerses()).to.contain(2025006); expect(v.excludedVerses()).to.contain(40001001); }); it('duplicate excluded verses', () => { const testLine = `-EXO 25:6 -EXO 25:6`; const v = new Versification(testLine); expect(v.excludedVerses()).to.have.lengthOf(1); expect(v.excludedVerses()).to.contain(2025006); }); it('invalid bookcode data - ignored', () => { const testLine = `-bookcodedoesnotexist 25:99`; const v = new Versification(testLine); expect(v.excludedVerses()).to.have.lengthOf(0); }); it('filtered by book', () => { const testLine = `-EXO 25:6 -MAT 1:1`; const v = new Versification(testLine); expect(v.excludedVerses(2)).to.have.lengthOf(1); expect(v.excludedVerses(40)).to.have.lengthOf(1); expect(v.excludedVerses(3)).to.have.lengthOf(0); expect(v.excludedVerses(2)).to.contain(2025006); expect(v.excludedVerses(40)).to.contain(40001001); }); it('filtered by book and chapter', () => { const testLine = `-EXO 25:6 -MAT 1:1`; const v = new Versification(testLine); expect(v.excludedVerses(2, 25)).to.have.lengthOf(1); expect(v.excludedVerses(2, 24)).to.have.lengthOf(0); expect(v.excludedVerses(40, 1)).to.have.lengthOf(1); expect(v.excludedVerses(40, 2)).to.have.lengthOf(0); expect(v.excludedVerses(2, 25)).to.contain(2025006); expect(v.excludedVerses(40, 1)).to.contain(40001001); }); }); describe('verse segment', () => { it('no verse segments', () => { const v = new Versification(''); expect(Object.keys(v.verseSegments())).to.have.lengthOf(0); expect(Object.keys(v.verseSegments(1))).to.have.lengthOf(0); expect(Object.keys(v.verseSegments(1, 1))).to.have.lengthOf(0); }); it('single verses segmented', () => { // This line means that for Gen 9:2 the following exists: // \v 2, \v 2a, \v 2b, \v 2c, ... // If there was no '-' then, just \v 2a, \v 2b, \v 2c, ... would exist. const testLine = `#! *GEN 9:2,-,a,b,c,d,e,f`; const v = new Versification(testLine); expect(Object.keys(v.verseSegments())).to.have.lengthOf(1); expect(v.verseSegments()[1009002]).to.be.eql(['', 'a', 'b', 'c', 'd', 'e', 'f']); }); it('verse segment, unknown book - ignored', () => { const testLine = `#! *abc 9:2,-,a,b,c,d,e,f`; const v = new Versification(testLine); expect(Object.keys(v.verseSegments())).to.have.lengthOf(0); }); it('filtered by book', () => { const testLine = `#! *GEN 9:2,-,a,b,c,d,e,f`; const v = new Versification(testLine); expect(Object.keys(v.verseSegments(1))).to.have.lengthOf(1); expect(Object.keys(v.verseSegments(40))).to.have.lengthOf(0); expect(v.verseSegments(1)[1009002]).to.be.eql(['', 'a', 'b', 'c', 'd', 'e', 'f']); }); it('filtered by book and chapter', () => { const testLine = `#! *GEN 9:2,-,a,b,c,d,e,f`; const v = new Versification(testLine); expect(Object.keys(v.verseSegments(1, 9))).to.have.lengthOf(1); expect(Object.keys(v.verseSegments(1, 10))).to.have.lengthOf(0); expect(v.verseSegments(1, 9)[1009002]).to.be.eql(['', 'a', 'b', 'c', 'd', 'e', 'f']); }); }); describe('sample data', () => { it('original sample', () => { const v = new Versification(testData.original); expect(v.books()).to.have.lengthOf(41, "MAT is the last book in sample data"); expect(v.books()[40]).to.have.lengthOf(29, "28 chapters (1 based index)"); }); it('english sample', () => { const v = new Versification(testData.eng); expect(v.books()).to.have.lengthOf(41, "MAT is the last book in sample data"); expect(v.books()[40]).to.have.lengthOf(29, "28 chapters (1 based index)"); expect(v.mappings()).to.have.lengthOf(1151) }); }); describe('changeVersification', () => { it('PSA 3:2 with undefined versification to original', () => { const originalVersification = new Versification(testData.original); const verseRef = VerseRef.parse("PSA 3:2"); // @ts-ignore - verseRef won't be undefined. const updatedVerseRef = originalVersification.changeVersification(verseRef); expect(updatedVerseRef?.toString()).to.be.equal('PSA 3:2'); expect(updatedVerseRef.versification()).to.be.equal(originalVersification); }) it('PSA 3:2 English to Original - Changes to PSA 3:3 (as PSA 3 heading counts a verse 1)', () => { const englishVersification = new Versification(testData.eng); const originalVersification = new Versification(testData.original); const verseRef = VerseRef.parse("PSA 3:2", englishVersification); expect(verseRef).to.not.be.null; // @ts-ignore - verseRef won't be undefined. const updatedVerseRef = originalVersification.changeVersification(verseRef); expect(updatedVerseRef?.toString()).to.be.equal('PSA 3:3'); expect(verseRef?.toString()).to.be.equal('PSA 3:2'); }); it('PSA 3:3 Original to English - Changes to PSA 3:2', () => { const englishVersification = new Versification(testData.eng); const originalVersification = new Versification(testData.original); const verseRef = VerseRef.parse("PSA 3:3", originalVersification); expect(verseRef).to.not.be.null; // @ts-ignore - verseRef won't be undefined. const updatedVerseRef = englishVersification.changeVersification(verseRef); expect(updatedVerseRef?.toString()).to.be.equal('PSA 3:2'); expect(verseRef?.toString()).to.be.equal('PSA 3:3'); }); it('PSA 3:2 English to Custom (Which matches English versification for PSA 3)', () => { const englishVersification = new Versification(testData.eng); const customVersification = new Versification(testData.myCustom); const verseRef = VerseRef.parse("PSA 3:2", englishVersification); expect(verseRef).to.not.be.null; // @ts-ignore - verseRef won't be undefined. const updatedVerseRef = customVersification.changeVersification(verseRef); expect(updatedVerseRef?.toString()).to.be.equal('PSA 3:2'); expect(verseRef?.toString()).to.be.equal('PSA 3:2'); }); it('PSA 3:2-3 English to Original - changes to PSA 3:3-4', () => { const englishVersification = new Versification(testData.eng); const originalVersification = new Versification(testData.original); const verseRef = VerseRef.parse("PSA 3:2-3", englishVersification); expect(verseRef).to.not.be.null; // @ts-ignore - verseRef won't be undefined. const updatedVerseRef = originalVersification.changeVersification(verseRef); expect(updatedVerseRef?.toString()).to.be.equal('PSA 3:3-4'); expect(updatedVerseRef?.versification().name).to.be.equal(originalVersification.name); expect(verseRef?.toString()).to.be.equal('PSA 3:2-3'); }); it('PSA 3:3-4 Original to English - changes to PSA 3:2-3', () => { const englishVersification = new Versification(testData.eng); const originalVersification = new Versification(testData.original); const verseRef = VerseRef.parse("PSA 3:3-4", originalVersification); expect(verseRef).to.not.be.null; // @ts-ignore - verseRef won't be undefined. const updatedVerseRef = englishVersification.changeVersification(verseRef); expect(updatedVerseRef?.toString()).to.be.equal('PSA 3:2-3'); expect(updatedVerseRef?.versification().name).to.be.equal(englishVersification.name); expect(verseRef?.toString()).to.be.equal('PSA 3:3-4'); }); it('MAT 2:6 English to LXX (I know this does not make sense :) ) (regression test)', () => { const englishVersification = new Versification(testData.eng); const lxxVersification = new Versification(testData.lxx); const verseRef = VerseRef.parse("MAT 2:6", englishVersification); expect(verseRef).to.not.be.null; // @ts-ignore - verseRef won't be undefined. const updatedVerseRef = lxxVersification.changeVersification(verseRef); expect(updatedVerseRef?.toString()).to.be.equal('MAT 2:6'); }); it('PSA 151:1 LXX to English - does not exist in target project', () => { const englishVersification = new Versification(testData.eng); const lxxVersification = new Versification(testData.lxx); const verseRef = VerseRef.parse("PSA 151:1", lxxVersification); expect(verseRef).to.not.be.null; // @ts-ignore - verseRef won't be undefined. const updatedVerseRef = englishVersification.changeVersification(verseRef); expect(updatedVerseRef?.toString()).to.be.equal('PSA 151:1'); }); it('English to English - returns same verseRef instance', () => { const englishVersification = new Versification(testData.eng); const verseRef = VerseRef.parse("MAT 2:6", englishVersification); // @ts-ignore - verseRef won't be undefined. const newVerseRef = englishVersification.changeVersification(verseRef); expect(verseRef).to.be.equal(newVerseRef, "Should be same instance as versification was the same"); }) it('null - returns null', () => { const englishVersification = new Versification(testData.eng); // @ts-ignore - testing non typesafe invokes (js) expect(englishVersification.changeVersification(null)).to.be.null; }); }); describe('nameToFileName', () => { [ ['English', 'eng'], ['English-f421fe261da7624f0405a602838bbed467f5fdb2abcdefff', 'eng'], ['Original-3f0f2b0426e1457e8e496834aaa30fce00000002abcdefff', 'org'], ['Septuagint', 'lxx'], ['Russian Protestant', 'rsc'], ['RussianProtestant-64f96631883240818dc01c345e58a1bff75e18e1abcdefff', 'rsc'], ['Vulgate', 'vul'], ].forEach(x => it(`${x[0]} => ${x[1]}`, () => { expect(Versification.nameToFileName(x[0])).to.be.equal(x[1]); })); }); describe('bookIdToNumber', () => { [ ['GEN', 1], ['MAT', 40] ].forEach(x => it(`${x[0]} => ${x[1]}`, () => { expect(Versification.bookIdToNumber('' + x[0])).to.be.equal(x[1]); })); }); describe('equals', () => { it('same name - considered equal', () => { const a = new Versification(`# Versification "Original" # Version=1.200`); const b = new Versification(`# Versification "Original" # Version=1.200`); expect(a.equals(b)).to.true; }); it('different name - considered different', () => { const a = new Versification(`# Versification "Original" # Version=1.200`); const b = new Versification(`# Versification "English" # Version=1.200`); expect(a.equals(b)).to.false; }); }); });