spellchecker.test.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import {
  2. getWordsFromLine,
  3. buildSpellCheckResult,
  4. Word,
  5. } from '@/features/source-editor/extensions/spelling/spellchecker'
  6. import { expect } from 'chai'
  7. import { EditorView } from '@codemirror/view'
  8. import { IgnoredWords } from '@/features/dictionary/ignored-words'
  9. import { LaTeXLanguage } from '@/features/source-editor/languages/latex/latex-language'
  10. import { LanguageSupport } from '@codemirror/language'
  11. const extensions = [new LanguageSupport(LaTeXLanguage)]
  12. describe('SpellChecker', function () {
  13. describe('getWordsFromLine', function () {
  14. let lang: string, ignoredWords: IgnoredWords
  15. beforeEach(function () {
  16. /* Note: ignore the word 'test' */
  17. lang = 'en'
  18. ignoredWords = new Set([]) as unknown as IgnoredWords
  19. })
  20. it('should get words from a line', function () {
  21. const view = new EditorView({
  22. doc: 'Hello test one two',
  23. extensions,
  24. })
  25. const line = view.state.doc.line(1)
  26. const words = getWordsFromLine(view, line, ignoredWords, lang)
  27. expect(words).to.deep.equal([
  28. { text: 'Hello', from: 0, to: 5, lineNumber: 1, lang: 'en' },
  29. { text: 'test', from: 6, to: 10, lineNumber: 1, lang: 'en' },
  30. { text: 'one', from: 11, to: 14, lineNumber: 1, lang: 'en' },
  31. { text: 'two', from: 15, to: 18, lineNumber: 1, lang: 'en' },
  32. ])
  33. })
  34. it('should ignore words in ignoredWords', function () {
  35. ignoredWords = new Set(['test']) as unknown as IgnoredWords
  36. const view = new EditorView({
  37. doc: 'Hello test one two',
  38. extensions,
  39. })
  40. const line = view.state.doc.line(1)
  41. const words = getWordsFromLine(view, line, ignoredWords, lang)
  42. expect(words).to.deep.equal([
  43. { text: 'Hello', from: 0, to: 5, lineNumber: 1, lang: 'en' },
  44. { text: 'one', from: 11, to: 14, lineNumber: 1, lang: 'en' },
  45. { text: 'two', from: 15, to: 18, lineNumber: 1, lang: 'en' },
  46. ])
  47. })
  48. it('should get no words from an empty line', function () {
  49. const view = new EditorView({
  50. doc: ' ',
  51. extensions,
  52. })
  53. const line = view.state.doc.line(1)
  54. const words = getWordsFromLine(view, line, ignoredWords, lang)
  55. expect(words).to.deep.equal([])
  56. })
  57. it('should ignore content of some commands in the text', function () {
  58. const view = new EditorView({
  59. doc: '\\usepackage[foo]{ bar } seven eight',
  60. extensions,
  61. })
  62. const line = view.state.doc.line(1)
  63. const words = getWordsFromLine(view, line, ignoredWords, lang)
  64. expect(words).to.deep.equal([
  65. { text: 'seven', from: 24, to: 29, lineNumber: 1, lang: 'en' },
  66. { text: 'eight', from: 30, to: 35, lineNumber: 1, lang: 'en' },
  67. ])
  68. })
  69. it('should ignore command names in the text', function () {
  70. const view = new EditorView({
  71. doc: '\\foo nine \\bar ten \\baz[]{}',
  72. extensions,
  73. })
  74. const line = view.state.doc.line(1)
  75. const words = getWordsFromLine(view, line, ignoredWords, lang)
  76. expect(words).to.deep.equal([
  77. { text: 'nine', from: 5, to: 9, lineNumber: 1, lang: 'en' },
  78. { text: 'ten', from: 15, to: 18, lineNumber: 1, lang: 'en' },
  79. ])
  80. })
  81. })
  82. describe('buildSpellCheckResult', function () {
  83. it('should build an empty result', function () {
  84. const knownMisspelledWords: Word[] = []
  85. const unknownWords: Word[] = []
  86. const misspellings: { index: number; suggestions: string[] }[] = []
  87. const result = buildSpellCheckResult(
  88. knownMisspelledWords,
  89. unknownWords,
  90. misspellings
  91. )
  92. expect(result).to.deep.equal({
  93. cacheAdditions: [],
  94. misspelledWords: [],
  95. })
  96. })
  97. it('should build a realistic result', function () {
  98. const _makeWord = (text: string, suggestions?: string[]) => {
  99. const word = new Word({
  100. text,
  101. from: 0,
  102. to: 0,
  103. lineNumber: 0,
  104. lang: 'xx',
  105. })
  106. if (suggestions != null) {
  107. word.suggestions = suggestions
  108. }
  109. return word
  110. }
  111. // We know this word is misspelled
  112. const knownMisspelledWords = [_makeWord('fff', ['food', 'fleece'])]
  113. // These words we didn't know
  114. const unknownWords = [
  115. _makeWord('aaa'),
  116. _makeWord('bbb'),
  117. _makeWord('ccc'),
  118. _makeWord('ddd'),
  119. ]
  120. // These are the suggestions we got back from the backend
  121. const misspellings = [
  122. { index: 1, suggestions: ['box', 'bass'] },
  123. { index: 3, suggestions: ['docs', 'dance'] },
  124. ]
  125. // Build the result structure
  126. const result = buildSpellCheckResult(
  127. knownMisspelledWords,
  128. unknownWords,
  129. misspellings
  130. )
  131. expect(result).to.have.keys('cacheAdditions', 'misspelledWords')
  132. // Check cache additions
  133. expect(result.cacheAdditions.map(([k, v]) => [k.text, v])).to.deep.equal([
  134. // Put these in cache as known misspellings
  135. ['bbb', ['box', 'bass']],
  136. ['ddd', ['docs', 'dance']],
  137. // Put these in cache as known-correct
  138. ['aaa', true],
  139. ['ccc', true],
  140. ])
  141. // Check misspellings
  142. expect(
  143. result.misspelledWords.map(w => [w.text, w.suggestions])
  144. ).to.deep.equal([
  145. // Words in the payload that we now know were misspelled
  146. ['bbb', ['box', 'bass']],
  147. ['ddd', ['docs', 'dance']],
  148. // Word we already knew was misspelled, preserved here
  149. ['fff', ['food', 'fleece']],
  150. ])
  151. })
  152. })
  153. })