kana.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import { test } from 'uvu';
  2. import * as assert from 'uvu/assert';
  3. import { normalizeInput, KanaInputState } from '../src/kana';
  4. import { TransitionResult } from '../src/state';
  5. function testInput(input: string, line: string) {
  6. const inputState = new KanaInputState(line);
  7. let kanaCount = 0;
  8. inputState.map((_, m) => {
  9. m.addObserver((result, meta) => {
  10. if (m.isFinished()) {
  11. kanaCount += meta;
  12. }
  13. assert.is(
  14. result,
  15. TransitionResult.SUCCESS,
  16. `Expected ${input} to match ${line}`
  17. );
  18. });
  19. });
  20. for (const c of input.split('')) {
  21. inputState.handleInput(c);
  22. }
  23. assert.ok(inputState.isFinished(), `Expected inputState to be finished`);
  24. assert.is(
  25. kanaCount,
  26. line.length,
  27. `Expected ${line.length} boundaries, got ${kanaCount}`
  28. );
  29. }
  30. function testFail(input: string, line: string) {
  31. const inputState = new KanaInputState(line);
  32. let fail = false;
  33. inputState.map((_, m) => {
  34. m.addObserver((result, _boundary) => {
  35. fail =
  36. fail ||
  37. result === TransitionResult.FAILED ||
  38. result === TransitionResult.SKIPPED;
  39. });
  40. });
  41. for (const c of input.split('')) {
  42. inputState.handleInput(c);
  43. }
  44. fail = fail || !inputState.isFinished();
  45. assert.ok(fail, `Expected ${input} to fail on ${line}`);
  46. }
  47. function testSkip(input: string, line: string, expectedSkips: number) {
  48. const inputState = new KanaInputState(line);
  49. let kanaCount = 0;
  50. let skipCount = 0;
  51. inputState.map((_, m) => {
  52. m.addObserver((result, meta) => {
  53. if (result === TransitionResult.SKIPPED) {
  54. kanaCount += meta;
  55. skipCount += 1;
  56. } else if (result === TransitionResult.SUCCESS) {
  57. kanaCount += meta;
  58. } else {
  59. assert.unreachable(`Expected ${input} to match ${line}`);
  60. }
  61. });
  62. });
  63. for (const c of input.split('')) {
  64. inputState.handleInput(c);
  65. }
  66. assert.ok(inputState.isFinished(), `Expected inputState to be finished`);
  67. assert.is(
  68. kanaCount,
  69. line.length,
  70. `Expected ${line.length} boundaries, got ${kanaCount}`
  71. );
  72. assert.is(skipCount, expectedSkips, `Expected skip count to match`);
  73. }
  74. test('normalizeInput', () => {
  75. assert.is(normalizeInput('ABCdef'), 'abcdef');
  76. assert.is(normalizeInput('フェスティバル'), 'ふぇすてぃばる');
  77. assert.is(normalizeInput('  '), ' ');
  78. });
  79. test('multiple romanization single kana', () => {
  80. testInput('si', 'し');
  81. testInput('shi', 'し');
  82. testInput('ji', 'じ');
  83. testInput('zi', 'じ');
  84. testInput('ti', 'ち');
  85. testInput('chi', 'ち');
  86. testInput('tu', 'つ');
  87. testInput('tsu', 'つ');
  88. testInput('fu', 'ふ');
  89. testInput('hu', 'ふ');
  90. });
  91. test('multiple romanization double kana', () => {
  92. testInput('sha', 'しゃ');
  93. testInput('sya', 'しゃ');
  94. // testInput('shilya', 'しゃ');
  95. // testInput('silya', 'しゃ');
  96. testInput('cha', 'ちゃ');
  97. testInput('tya', 'ちゃ');
  98. // testInput('chilya', 'ちゃ');
  99. // testInput('tilya', 'ちゃ');
  100. testInput('ja', 'じゃ');
  101. testInput('jya', 'じゃ');
  102. testInput('zya', 'じゃ');
  103. // testInput('jilya', 'じゃ');
  104. // testInput('zilya', 'じゃ');
  105. testInput('fe', 'ふぇ');
  106. // testInput('fule', 'ふぇ');
  107. });
  108. test('small tsu', () => {
  109. testInput('katto', 'カット');
  110. testInput('kaltsuto', 'かっと');
  111. testInput('kaltuto', 'かっと');
  112. testInput('ejji', 'エッジ');
  113. testInput('ezzi', 'エッジ');
  114. testInput('extuji', 'エッジ');
  115. testInput('extsuzi', 'エッジ');
  116. testInput('hassha', 'はっしゃ');
  117. testInput('hassya', 'はっしゃ');
  118. testInput('haltusha', 'はっしゃ');
  119. testInput('haltusya', 'はっしゃ');
  120. });
  121. test('nn', () => {
  122. testInput('nn', 'ん');
  123. testInput('nna', 'んあ');
  124. testFail('na', 'んあ');
  125. testInput('nda', 'んだ');
  126. testInput('nnda', 'んだ');
  127. testFail('nnnda', 'んだ');
  128. testInput('nnnda', 'んんだ');
  129. testInput('nnnnda', 'んんだ');
  130. testFail('nya', 'んにゃ');
  131. testFail('nnya', 'んにゃ');
  132. testInput('nnnya', 'んにゃ');
  133. });
  134. test('skipping', () => {
  135. testSkip('a', 'は', 1);
  136. testSkip('hao', 'はろ', 1);
  137. testSkip('hro', 'はろ', 1);
  138. });
  139. test.run();