halkyon/halkyon_learn_curator/test/jmdict_test.dart

99 lines
3.4 KiB
Dart
Raw Normal View History

import 'dart:convert';
import 'dart:io';
import 'package:halkyon_learn_curator/src/sources/jlpt.dart';
import 'package:halkyon_learn_curator/src/sources/jmdict.dart';
import 'package:test/test.dart';
void main() {
late List<Map<String, Object?>> lines;
setUpAll(() async {
final jlpt = await readJlptLevels(Directory('test/fixtures/jlpt'));
lines = [
for (final line in await jmdictDictionary(
File('test/fixtures/jmdict-eng-sample.json')
.openRead()
.transform(utf8.decoder),
jlpt: jlpt,
).toList())
jsonDecode(line) as Map<String, Object?>,
];
});
Map<String, Object?> entry(String headword) =>
lines.skip(1).firstWhere((line) => line['headword'] == headword);
test('the header says what the file holds, and whose it is', () {
final header = lines.first;
expect(header['format'], 'halkyon-dictionary');
expect(header['formatVersion'], 1);
expect(header['source'], 'jmdict');
expect(header['sourceVersion'], '3.6.2 (2026-10-05)');
expect((header['language'], header['glossLanguage']), ('ja', 'en'));
expect(header['license'], 'CC-BY-SA-4.0');
expect(
[
for (final credit in header['credits']! as List)
(credit as Map)['name'],
],
['JMdict', 'jmdict-simplified', 'JLPT vocabulary lists'],
);
expect(lines, hasLength(7));
});
test('a word: its headword and reading, labels, and the keys a search '
'matches, in kanji, kana, romaji and its meanings', () {
final word = entry('食べる');
expect(word['id'], '1358280');
expect(word['reading'], 'たべる');
expect(word['labels'], ['common', 'jlpt:n5']);
expect(
word['keys'],
containsAll(['食べる', '喰べる', 'たべる', 'taberu', 'to eat', 'eat']),
);
// A form for searching only isn't shown.
final forms = (word['entry']! as Map)['forms']! as List;
expect([for (final form in forms) (form as Map)['text']], ['食べる']);
});
test('a word written in kana has no reading of its own; katakana is '
'searched as hiragana too', () {
final word = entry('テレビ');
expect(word.containsKey('reading'), isFalse);
expect(word['keys'], containsAll(['テレビ', 'てれび', 'terebi', 'tv']));
});
test('long vowels typed once are loose keys, found after the right '
'spellings', () {
final tokyo = entry('東京');
expect(tokyo['keys'], containsAll(['toukyou', 'toukei']));
// Its other reading, とうけい, typed with one o.
expect(tokyo['looseKeys'], ['tokei']);
// "tokyo" is a key already, its meaning in English.
expect(tokyo['keys'], contains('tokyo'));
expect(entry('食べる').containsKey('looseKeys'), isFalse);
});
test('the reading is one that belongs to the headword', () {
expect(entry('四')['reading'], 'し');
});
test("the headword is the JLPT lists' spelling, at the easiest level a "
'word is listed at', () {
final word = entry('歯磨き');
expect(word['labels'], ['common', 'jlpt:n2']);
});
test('words rank N5 first, then down the levels, then the other common '
'words, then the rest', () {
int rank(String headword) => entry(headword)['rank']! as int;
expect(rank('食べる'), lessThan(rank('歯磨き')));
expect(rank('歯磨き'), lessThan(rank('東京')));
expect(rank('東京'), lessThan(rank('〃')));
});
}