obsidian-sample-plugin/src/custom-sort/matchers.spec.ts

409 lines
12 KiB
TypeScript

import {
getNormalizedNumber,
getNormalizedRomanNumber,
prependWithZeros,
romanToIntStr,
NumberRegexStr,
CompoundNumberDotRegexStr,
CompoundNumberDashRegexStr,
RomanNumberRegexStr,
CompoundRomanNumberDotRegexStr,
CompoundRomanNumberDashRegexStr,
WordInASCIIRegexStr,
WordInAnyLanguageRegexStr
} from "./matchers";
import {SortingSpecProcessor} from "./sorting-spec-processor";
describe('Plain numbers regexp', () => {
let regexp: RegExp;
beforeEach(() => {
regexp = new RegExp('^' + NumberRegexStr, 'i');
});
it.each([
['', null],
[' ', null],
[' 1', '1'], // leading spaces are swallowed
['-1', null],
['1', '1'],
['1a', '1'],
['3580', '3580'],
['9', '9'],
['7328964783268794325496783', '7328964783268794325496783']
])('%s => %s', (s: string, out: string | null) => {
const match: RegExpMatchArray | null = s.match(regexp)
if (out) {
expect(match).not.toBeNull()
expect(match?.[1]).toBe(out)
} else {
expect(match).toBeNull()
}
})
})
describe('Plain compound numbers regexp (dot)', () => {
let regexp: RegExp;
beforeEach(() => {
regexp = new RegExp('^' + CompoundNumberDotRegexStr, 'i');
});
it.each([
['', null],
[' ', null],
[' 1', '1'], // leading spaces are swallowed
['-1', null],
['1', '1'],
['1a', '1'],
['3580', '3580'],
['9', '9'],
['7328964783268794325496783', '7328964783268794325496783'],
['9.', '9'],
['5.2', '5.2'],
['5.-2', '5'],
['12. 34', '12'],
['.12 .34', null],
['56.78.000.1', '56.78.000.1'],
['56.78.000.1 ', '56.78.000.1'],
['56.78.000.1abc', '56.78.000.1'],
['56.78.-.1abc', '56.78'],
['56.78-.1abc', '56.78'],
])('%s => %s', (s: string, out: string | null) => {
const match: RegExpMatchArray | null = s.match(regexp)
if (out) {
expect(match).not.toBeNull()
expect(match?.[1]).toBe(out)
} else {
expect(match).toBeNull()
}
})
})
describe('Plain compound numbers regexp (dash)', () => {
let regexp: RegExp;
beforeEach(() => {
regexp = new RegExp('^' + CompoundNumberDashRegexStr, 'i');
});
it.each([
['', null],
[' ', null],
[' 1', '1'], // leading spaces are swallowed
['.1', null],
['1', '1'],
['1a', '1'],
['3580', '3580'],
['9', '9'],
['7328964783268794325496783', '7328964783268794325496783'],
['9-', '9'],
['5-2', '5-2'],
['5-.2', '5'],
['12- 34', '12'],
['-12 -34', null],
['56-78-000-1', '56-78-000-1'],
['56-78-000-1 ', '56-78-000-1'],
['56-78-000-1abc', '56-78-000-1'],
['56-78-.-1abc', '56-78'],
['56-78.-1abc', '56-78'],
])('%s => %s', (s: string, out: string | null) => {
const match: RegExpMatchArray | null = s.match(regexp)
if (out) {
expect(match).not.toBeNull()
expect(match?.[1]).toBe(out)
} else {
expect(match).toBeNull()
}
})
})
describe('Plain Roman numbers regexp', () => {
let regexp: RegExp;
beforeEach(() => {
regexp = new RegExp('^' + RomanNumberRegexStr, 'i');
});
it.each([
['', null],
[' ', null],
[' i', 'i'], // leading spaces are swallowed
['-i', null],
['i', 'i'],
['ia', 'i'],
['mdclxv', 'mdclxv'],
['iiiii', 'iiiii'],
['viviviv794325496783', 'viviviv']
])('%s => %s', (s: string, out: string | null) => {
const match: RegExpMatchArray | null = s.match(regexp)
if (out) {
expect(match).not.toBeNull()
expect(match?.[1]).toBe(out)
} else {
expect(match).toBeNull()
}
})
})
describe('Roman compound numbers regexp (dot)', () => {
let regexp: RegExp;
beforeEach(() => {
regexp = new RegExp('^' + CompoundRomanNumberDotRegexStr, 'i');
});
it.each([
['', null],
[' ', null],
[' I', 'I'], // leading spaces are swallowed
['.I', null],
['v', 'v'],
['va', 'v'],
['vava ', 'v'],
['ix', 'ix'],
['mclv96783', 'mclv'],
['C.', 'C'],
['v.ii', 'v.ii'],
['xx.-x', 'xx'],
['xx.x', 'xx.x'],
['iv- v', 'iv'],
['.12 .34', null],
['vv.mc.lx.i', 'vv.mc.lx.i'],
['mcm.m.mmm.l ', 'mcm.m.mmm.l'],
['iv.I.DDD.Iabc', 'iv.I.DDD.I'],
['xiii.viii.-.1abc', 'xiii.viii'],
['xvx.d-.iabc', 'xvx.d'],
['xvx.d..iabc', 'xvx.d'],
])('%s => %s', (s: string, out: string | null) => {
const match: RegExpMatchArray | null = s.match(regexp)
if (out) {
expect(match).not.toBeNull()
expect(match?.[1]).toBe(out)
} else {
expect(match).toBeNull()
}
})
})
describe('Roman compound numbers regexp (dash)', () => {
let regexp: RegExp;
beforeEach(() => {
regexp = new RegExp('^' + CompoundRomanNumberDashRegexStr, 'i');
});
it.each([
['', null],
[' ', null],
[' I', 'I'], // leading spaces are swallowed
['.I', null],
['v', 'v'],
['va', 'v'],
['vava ', 'v'],
['ix', 'ix'],
['mclv96783', 'mclv'],
['C-', 'C'],
['v-ii', 'v-ii'],
['xx.-x', 'xx'],
['xx.x', 'xx'],
['iv- v', 'iv'],
['-12 -34', null],
['vv-mc-lx-i', 'vv-mc-lx-i'],
['mcm-m-mmm-l ', 'mcm-m-mmm-l'],
['iv-I-DDD-Iabc', 'iv-I-DDD-I'],
['xiii-viii-.-1abc', 'xiii-viii'],
['xvx-d.-iabc', 'xvx-d'],
['xvx-d--iabc', 'xvx-d']
])('%s => %s', (s: string, out: string | null) => {
const match: RegExpMatchArray | null = s.match(regexp)
if (out) {
expect(match).not.toBeNull()
expect(match?.[1]).toBe(out)
} else {
expect(match).toBeNull()
}
})
})
describe('ASCII word regexp', () => {
let regexp: RegExp;
beforeEach(() => {
regexp = new RegExp('^' + WordInASCIIRegexStr, 'i');
});
it.each([
['', null],
[' ', null],
[' I', null], // leading spaces are not swallowed
['I ', 'I'], // trailing spaces are swallowed
['Abc', 'Abc'],
['Sun', 'Sun'],
['Hello123', 'Hello'],
['John_', 'John'],
['Title.', 'Title'],
['Deutschstäder', 'Deutschst'],
['ItalianoàèéìòùÈ', 'Italiano'],
['PolskićśńĄł', 'Polski']
])('%s => %s', (s: string, out: string | null) => {
const match: RegExpMatchArray | null = s.match(regexp)
if (out) {
expect(match).not.toBeNull()
expect(match?.[1]).toBe(out)
} else {
expect(match).toBeNull()
}
})
})
describe('Unicode word regexp', () => {
let regexp: RegExp;
beforeEach(() => {
regexp = new RegExp('^' + WordInAnyLanguageRegexStr, 'ui');
});
it.each([
['', null],
[' ', null],
[' I', null], // leading spaces are not swallowed
['I ', 'I'], // trailing characters are ignored in unit test
['Abc', 'Abc'],
['Sun', 'Sun'],
['Hello123', 'Hello'],
['John_', 'John'],
['Title.', 'Title'],
['Deutschstäder_', 'Deutschstäder'],
['ItalianoàèéìòùÈ', 'ItalianoàèéìòùÈ'],
['PolskićśńĄł', 'PolskićśńĄł']
])('%s => %s', (s: string, out: string | null) => {
const match: RegExpMatchArray | null = s.match(regexp)
if (out) {
expect(match).not.toBeNull()
expect(match?.[1]).toBe(out)
} else {
expect(match).toBeNull()
}
})
})
describe('prependWithZeros', () => {
const Length = 5;
it('should add leading zeros to empty string', () => {
const s = prependWithZeros('', Length);
expect(s).toBe('00000')
})
it('should add leading zeros to shorter string', () => {
const s = prependWithZeros('12', Length);
expect(s).toBe('00012')
})
it('should not add leading zeros to sufficient string', () => {
const s = prependWithZeros('12345', Length);
expect(s).toBe('12345')
})
it('should not add leading zeros to longer string', () => {
const s = prependWithZeros('12345678', Length);
expect(s).toBe('12345678')
})
})
describe('getNormalizedNumber', () => {
const LEN = 5;
const params = [
['', '00000000//', null],
['1', '00000001//', undefined],
['000', '00000000//', ' '],
['000', '00000000//', ''],
['1234567890123', '1234567890123//', ''],
['1234567890123456789012345', '1234567890123456789012345//', ''], // No conversion to number should happen
// Compound numbers - dot
['1', '00000001//', '.'],
['1 .1', '0000001 |00000001//', '.'], // Invalid case, Regexp on matcher in the caller should guard against this
['1. 1', '00000001|000000 1//', '.'], // Invalid case, Regexp on matcher in the caller should guard against this
['1..1', '00000001|00000001//', '.'], // Edge case, consecutive separators treated as one
['1.2', '00000001|00000002//', '.'],
['1.2.', '00000001|00000002//', '.'], // Edge case, trailing dangling separator is swallowed
['1.2.3', '00000001|00000002|00000003//', '.'],
['44.2314325423432.4', '00000044|2314325423432|00000004//', '.'],
['0.0.0.0.', '00000000|00000000|00000000|00000000//', '.'], // Edge case, trailing dangling separator is swallowed
['0.0.0.0', '00000000|00000000|00000000|00000000//', '.'],
['0.0-0.0', '00000000|000000-0|00000000//', '.'], // Invalid case, Regexp on matcher in the caller should guard against this
// Compound numbers - dash
['1', '00000001//', '-'],
['1 -1', '0000001 |00000001//', '-'], // Invalid case, Regexp on matcher in the caller should guard against this
['1- 1', '00000001|000000 1//', '-'], // Invalid case, Regexp on matcher in the caller should guard against this
['1--1', '00000001|00000001//', '-'], // Edge case, consecutive separators treated as one
['1-2', '00000001|00000002//', '-'],
['1-2-', '00000001|00000002//', '-'], // Edge case, trailing dangling separator is swallowed
['1-2-3', '00000001|00000002|00000003//', '-'],
['44-2314325423432-4', '00044|2314325423432|00004//', '-5'],
['0-7-0-0-', '00000000|00000007|00000000|00000000//', '-'], // // Edge case, trailing dangling separator is swallowed
['0-0.3-0', '00000|000.3|00000//', '-5'],
];
it.each(params)('>%s< should become %s (sep >%s<)', (s: string, out: string, separator?: string) => {
if (separator === '-5') {
expect(getNormalizedNumber(s, '-', LEN)).toBe(out)
} else {
expect(getNormalizedNumber(s, separator)).toBe(out)
}
})
})
describe('romanToIntStr', () => {
const params = [
['', '0'],
['I', '1'],
['II', '2'],
['III', '3'],
['IIII', '4'],
['IIIII', '5'],
['iv', '4'],
['v', '5'],
['vi', '6'],
['vii', '7'],
['viii', '8'],
['iX', '9'],
['x', '10'],
['XI', '11'],
['L', '50'],
['C', '100'],
['d', '500'],
['M', '1000'],
// formally correct, unused
['iv', '4'],
['iiv', '5'],
['iiiv', '6'],
['iiiiv', '7'],
['iiiiiv', '8'],
['12345', '0'],
];
it.each(params)('>%s< should be %s', (s: string, out: string) => {
expect(romanToIntStr(s)).toBe(out)
})
})
describe('getNormalizedRomanNumber', () => {
const LEN = 5
const params = [
['', '00000//', null],
['1', '00000//', undefined],
['000', '00000//', ' '],
['000', '00000//', ''],
['1234567890123//', '00000//', ''],
['00123', '00000//', ''],
['1234567890123456789012345//', '00000//', ''], // No conversion to number should happen
// Compound numbers - dot
['i', '00001//', '.'],
['ii .ii', '00002|00002//', '.'], // Invalid case, Regexp on matcher in the caller should guard against this
['iv. vi', '00004|00006//', '.'], // Invalid case, Regexp on matcher in the caller should guard against this
['X..C', '00010|00100//', '.'], // Edge case, consecutive separators treated as one
['C.M', '00100|01000//', '.'],
['I.II.', '00001|00002//', '.'], // Edge case, trailing dangling separator is swallowed
['i.i.iv', '00001|00001|00004//', '.'],
['MCMLXX.2314325423432.CM', '01970|00000|00900//', '.'],
['0.0.0.0.', '00000|00000|00000|00000//', '.'], // Edge case, trailing dangling separator is swallowed
['L.l.M.iiii', '00050|00050|01000|00004//', '.'],
['v.v-v.v', '00005|00010|00005//', '.'], // Invalid case, Regexp on matcher in the caller should guard against this
// Compound numbers - dash
['i', '00001//', '-'],
['ii -ii', '00002|00002//', '-'], // Invalid case, Regexp on matcher in the caller should guard against this
['iv- vi', '00004|00006//', '-'], // Invalid case, Regexp on matcher in the caller should guard against this
['X--C', '00010|00100//', '-'], // Edge case, consecutive separators treated as one
['C-M', '00100|01000//', '-'],
['I-II-', '00001|00002//', '-'], // Edge case, trailing dangling separator is swallowed
['i-i-iv', '00001|00001|00004//', '-'],
['MCMLXX-2314325423432-CM', '01970|00000|00900//', '-'],
['0-0-0-0-', '00000|00000|00000|00000//', '-'], // Edge case, trailing dangling separator is swallowed
['L-l-M-iiii', '00050|00050|01000|00004//', '-'],
['v-v.v-v', '00005|00010|00005//', '-'], // Invalid case, Regexp on matcher in the caller should guard against this
];
it.each(params)('>%s< should become %s (sep >%s<)', (s: string, out: string, separator?: string) => {
expect(getNormalizedRomanNumber(s, separator, LEN)).toBe(out)
})
})