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> 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, ]; }); Map 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 are found typed once', () { expect(entry('東京')['keys'], containsAll(['toukyou', 'tokyo'])); }); 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('〃'))); }); }