mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-12 13:55:51 -07:00
170 lines
4.7 KiB
TypeScript
170 lines
4.7 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { buildNameTerms } from './term-building';
|
|
import type { CharacterRecord } from './types';
|
|
|
|
function characterRecord(overrides: Partial<CharacterRecord>): CharacterRecord {
|
|
return {
|
|
id: 136073,
|
|
role: 'primary',
|
|
firstNameHint: 'Chi-Yul',
|
|
fullName: 'Chi-Yul Song',
|
|
lastNameHint: 'Song',
|
|
nativeName: '송치율',
|
|
alternativeNames: [],
|
|
bloodType: '',
|
|
birthday: null,
|
|
description: '',
|
|
imageUrl: null,
|
|
age: '',
|
|
sex: '',
|
|
voiceActors: [],
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
test('buildNameTerms adds surname honorifics from Japanese localized aliases', () => {
|
|
const terms = buildNameTerms(
|
|
characterRecord({
|
|
alternativeNames: ['Isao Mabuchi (馬渕勲)', 'Chi-Yeol (송치열)'],
|
|
}),
|
|
);
|
|
|
|
assert.ok(terms.includes('馬渕勲'));
|
|
assert.ok(terms.includes('馬渕勲さん'));
|
|
assert.ok(terms.includes('馬渕'));
|
|
assert.ok(terms.includes('馬渕さん'));
|
|
assert.ok(!terms.includes('송치'));
|
|
});
|
|
|
|
test('buildNameTerms drops the disambiguator letter of a mob character name', () => {
|
|
const terms = buildNameTerms(
|
|
characterRecord({
|
|
firstNameHint: '',
|
|
lastNameHint: '',
|
|
fullName: 'Joshi A',
|
|
nativeName: '女子A',
|
|
}),
|
|
);
|
|
|
|
// ア would match every あ〜 in the subtitles; the letter is a disambiguator
|
|
// (Girl A / Girl B), not a name.
|
|
assert.ok(!terms.includes('ア'));
|
|
assert.ok(!terms.includes('アさん'));
|
|
assert.ok(terms.includes('女子A'));
|
|
assert.ok(terms.includes('ジョシア'));
|
|
});
|
|
|
|
test('buildNameTerms keeps a character whose whole name is one kana', () => {
|
|
const terms = buildNameTerms(
|
|
characterRecord({
|
|
firstNameHint: '',
|
|
lastNameHint: '',
|
|
fullName: 'A',
|
|
nativeName: 'あ',
|
|
}),
|
|
);
|
|
|
|
// The mob-label rule only judges parts a name was split into; a name the
|
|
// source gives us whole is the character's actual name.
|
|
assert.ok(terms.includes('あ'));
|
|
assert.ok(terms.includes('あさん'));
|
|
// Romanized forms are never lookup targets (the subtitles are Japanese), and
|
|
// the single-kana alias "A" transliterates to is dropped as a collision.
|
|
assert.ok(!terms.includes('A'));
|
|
assert.ok(!terms.includes('ア'));
|
|
});
|
|
|
|
test('buildNameTerms keeps a one-character name written in another script', () => {
|
|
const terms = buildNameTerms(
|
|
characterRecord({
|
|
firstNameHint: '',
|
|
lastNameHint: '',
|
|
fullName: 'Byeol',
|
|
nativeName: '별',
|
|
alternativeNames: ['Я'],
|
|
}),
|
|
);
|
|
|
|
assert.ok(terms.includes('별'));
|
|
assert.ok(terms.includes('별さん'));
|
|
assert.ok(terms.includes('Я'));
|
|
});
|
|
|
|
test('buildNameTerms yields nothing for a character whose only name is a bare letter', () => {
|
|
// Documented policy rather than an oversight: a romanized name is never a
|
|
// term on its own (the subtitles are Japanese), and the single kana a bare
|
|
// letter transliterates to would match every あ〜 in the line.
|
|
assert.deepEqual(
|
|
buildNameTerms(
|
|
characterRecord({
|
|
firstNameHint: '',
|
|
lastNameHint: '',
|
|
fullName: 'A',
|
|
nativeName: '',
|
|
}),
|
|
),
|
|
[],
|
|
);
|
|
});
|
|
|
|
test('buildNameTerms keeps one-character split parts that are not mob labels', () => {
|
|
const hangul = buildNameTerms(
|
|
characterRecord({
|
|
firstNameHint: '',
|
|
lastNameHint: '',
|
|
fullName: 'Byeol Kim',
|
|
nativeName: '별 김',
|
|
}),
|
|
);
|
|
|
|
assert.ok(hangul.includes('별'));
|
|
assert.ok(hangul.includes('김'));
|
|
|
|
const middleDot = buildNameTerms(
|
|
characterRecord({
|
|
firstNameHint: '',
|
|
lastNameHint: '',
|
|
fullName: 'A Be',
|
|
nativeName: 'ア・ベ',
|
|
}),
|
|
);
|
|
|
|
assert.ok(middleDot.includes('ア'));
|
|
assert.ok(middleDot.includes('ベ'));
|
|
});
|
|
|
|
test('buildNameTerms keeps a single-kanji name part', () => {
|
|
// The name is an alias, not the native name, so the parts come from the
|
|
// space split rather than from the native-name split.
|
|
const terms = buildNameTerms(
|
|
characterRecord({
|
|
firstNameHint: 'Sora',
|
|
lastNameHint: 'Yamada',
|
|
fullName: 'Sora Yamada',
|
|
nativeName: '',
|
|
alternativeNames: ['山田 空'],
|
|
}),
|
|
);
|
|
|
|
assert.ok(terms.includes('山田'));
|
|
assert.ok(terms.includes('空'));
|
|
});
|
|
|
|
test('buildNameTerms keeps a single supplementary-plane kanji name part', () => {
|
|
// 𠮷 (U+20BB7) is a surrogate pair: a code-unit kanji check reads only the
|
|
// high surrogate and drops the part as if it were a mob disambiguator.
|
|
const terms = buildNameTerms(
|
|
characterRecord({
|
|
firstNameHint: 'Tsukasa',
|
|
lastNameHint: 'Yoshi',
|
|
fullName: 'Tsukasa Yoshi',
|
|
nativeName: '',
|
|
alternativeNames: ['𠮷 司'],
|
|
}),
|
|
);
|
|
|
|
assert.ok(terms.includes('𠮷'));
|
|
assert.ok(terms.includes('司'));
|
|
});
|