1" Test for commands that operate on the spellfile.
2
3source shared.vim
4source check.vim
5
6CheckFeature spell
7CheckFeature syntax
8
9func Test_spell_normal()
10  new
11  call append(0, ['1 good', '2 goood', '3 goood'])
12  set spell spellfile=./Xspellfile.add spelllang=en
13  let oldlang=v:lang
14  lang C
15
16  " Test for zg
17  1
18  norm! ]s
19  call assert_equal('2 goood', getline('.'))
20  norm! zg
21  1
22  let a=execute('unsilent :norm! ]s')
23  call assert_equal('1 good', getline('.'))
24  call assert_equal('search hit BOTTOM, continuing at TOP', a[1:])
25  let cnt=readfile('./Xspellfile.add')
26  call assert_equal('goood', cnt[0])
27
28  " zg should fail in operator-pending mode
29  call assert_beeps('norm! czg')
30
31  " zg fails in visual mode when not able to get the visual text
32  call assert_beeps('norm! ggVjzg')
33  norm! V
34
35  " zg fails for a non-identifier word
36  call append(line('$'), '###')
37  call assert_fails('norm! Gzg', 'E349:')
38  $d
39
40  " Test for zw
41  2
42  norm! $zw
43  1
44  norm! ]s
45  call assert_equal('2 goood', getline('.'))
46  let cnt=readfile('./Xspellfile.add')
47  call assert_equal('#oood', cnt[0])
48  call assert_equal('goood/!', cnt[1])
49
50  " Test for :spellrare
51  spellrare rare
52  let cnt=readfile('./Xspellfile.add')
53  call assert_equal(['#oood', 'goood/!', 'rare/?'], cnt)
54
55  " Make sure :spellundo works for rare words.
56  spellundo rare
57  let cnt=readfile('./Xspellfile.add')
58  call assert_equal(['#oood', 'goood/!', '#are/?'], cnt)
59
60  " Test for zg in visual mode
61  let a=execute('unsilent :norm! V$zg')
62  call assert_equal("Word '2 goood' added to ./Xspellfile.add", a[1:])
63  1
64  norm! ]s
65  call assert_equal('3 goood', getline('.'))
66  let cnt=readfile('./Xspellfile.add')
67  call assert_equal('2 goood', cnt[3])
68  " Remove "2 good" from spellfile
69  2
70  let a=execute('unsilent norm! V$zw')
71  call assert_equal("Word '2 goood' added to ./Xspellfile.add", a[1:])
72  let cnt=readfile('./Xspellfile.add')
73  call assert_equal('2 goood/!', cnt[4])
74
75  " Test for zG
76  let a=execute('unsilent norm! V$zG')
77  call assert_match("Word '2 goood' added to .*", a)
78  let fname=matchstr(a, 'to\s\+\zs\f\+$')
79  let cnt=readfile(fname)
80  call assert_equal('2 goood', cnt[0])
81
82  " Test for zW
83  let a=execute('unsilent norm! V$zW')
84  call assert_match("Word '2 goood' added to .*", a)
85  let cnt=readfile(fname)
86  call assert_equal('# goood', cnt[0])
87  call assert_equal('2 goood/!', cnt[1])
88
89  " Test for zuW
90  let a=execute('unsilent norm! V$zuW')
91  call assert_match("Word '2 goood' removed from .*", a)
92  let cnt=readfile(fname)
93  call assert_equal('# goood', cnt[0])
94  call assert_equal('# goood/!', cnt[1])
95
96  " Test for zuG
97  let a=execute('unsilent norm! $zG')
98  call assert_match("Word 'goood' added to .*", a)
99  let cnt=readfile(fname)
100  call assert_equal('# goood', cnt[0])
101  call assert_equal('# goood/!', cnt[1])
102  call assert_equal('goood', cnt[2])
103  let a=execute('unsilent norm! $zuG')
104  let cnt=readfile(fname)
105  call assert_match("Word 'goood' removed from .*", a)
106  call assert_equal('# goood', cnt[0])
107  call assert_equal('# goood/!', cnt[1])
108  call assert_equal('#oood', cnt[2])
109  " word not found in wordlist
110  let a=execute('unsilent norm! V$zuG')
111  let cnt=readfile(fname)
112  call assert_match("", a)
113  call assert_equal('# goood', cnt[0])
114  call assert_equal('# goood/!', cnt[1])
115  call assert_equal('#oood', cnt[2])
116
117  " Test for zug
118  call delete('./Xspellfile.add')
119  2
120  let a=execute('unsilent norm! $zg')
121  let cnt=readfile('./Xspellfile.add')
122  call assert_equal('goood', cnt[0])
123  let a=execute('unsilent norm! $zug')
124  call assert_match("Word 'goood' removed from \./Xspellfile.add", a)
125  let cnt=readfile('./Xspellfile.add')
126  call assert_equal('#oood', cnt[0])
127  " word not in wordlist
128  let a=execute('unsilent norm! V$zug')
129  call assert_match('', a)
130  let cnt=readfile('./Xspellfile.add')
131  call assert_equal('#oood', cnt[0])
132
133  " Test for zuw
134  call delete('./Xspellfile.add')
135  2
136  let a=execute('unsilent norm! Vzw')
137  let cnt=readfile('./Xspellfile.add')
138  call assert_equal('2 goood/!', cnt[0])
139  let a=execute('unsilent norm! Vzuw')
140  call assert_match("Word '2 goood' removed from \./Xspellfile.add", a)
141  let cnt=readfile('./Xspellfile.add')
142  call assert_equal('# goood/!', cnt[0])
143  " word not in wordlist
144  let a=execute('unsilent norm! $zug')
145  call assert_match('', a)
146  let cnt=readfile('./Xspellfile.add')
147  call assert_equal('# goood/!', cnt[0])
148
149  " add second entry to spellfile setting
150  set spellfile=./Xspellfile.add,./Xspellfile2.add
151  call delete('./Xspellfile.add')
152  2
153  let a=execute('unsilent norm! $2zg')
154  let cnt=readfile('./Xspellfile2.add')
155  call assert_match("Word 'goood' added to ./Xspellfile2.add", a)
156  call assert_equal('goood', cnt[0])
157
158  " Test for :spellgood!
159  let temp = execute(':spe!0/0')
160  call assert_match('Invalid region', temp)
161  let spellfile = matchstr(temp, 'Invalid region nr in \zs.*\ze line \d: 0')
162  call assert_equal(['# goood', '# goood/!', '#oood', '0/0'], readfile(spellfile))
163
164  " Test for :spellrare!
165  :spellrare! raare
166  call assert_equal(['# goood', '# goood/!', '#oood', '0/0', 'raare/?'], readfile(spellfile))
167  call delete(spellfile)
168
169  " clean up
170  exe "lang" oldlang
171  call delete("./Xspellfile.add")
172  call delete("./Xspellfile2.add")
173  call delete("./Xspellfile.add.spl")
174  call delete("./Xspellfile2.add.spl")
175
176  " zux -> no-op
177  2
178  norm! $zux
179  call assert_equal([], glob('Xspellfile.add',0,1))
180  call assert_equal([], glob('Xspellfile2.add',0,1))
181
182  set spellfile= spell& spelllang&
183  bw!
184endfunc
185
186" Spell file content test. Write 'content' to the spell file prefixed by the
187" spell file header and then enable spell checking. If 'emsg' is not empty,
188" then check for error.
189func Spellfile_Test(content, emsg)
190  let splfile = './Xtest/spell/Xtest.utf-8.spl'
191  " Add the spell file header and version (VIMspell2)
192  let v = 0z56494D7370656C6C32 + a:content
193  call writefile(v, splfile, 'b')
194
195  " 'encoding' is set before each test to clear the previously loaded suggest
196  " file from memory.
197  set encoding=utf-8
198
199  set runtimepath=./Xtest
200  set spelllang=Xtest
201  if a:emsg != ''
202    call assert_fails('set spell', a:emsg)
203  else
204    " FIXME: With some invalid spellfile contents, there are no error
205    " messages. So don't know how to check for the test result.
206    set spell
207  endif
208  set nospell spelllang& rtp&
209endfunc
210
211" Test for spell file format errors.
212" The spell file format is described in spellfile.c
213func Test_spellfile_format_error()
214  let save_rtp = &rtp
215  call mkdir('Xtest/spell', 'p')
216  let splfile = './Xtest/spell/Xtest.utf-8.spl'
217
218  " empty spell file
219  call writefile([], splfile)
220  set runtimepath=./Xtest
221  set spelllang=Xtest
222  call assert_fails('set spell', 'E757:')
223  set nospell spelllang&
224
225  " invalid file ID
226  call writefile(0z56494D, splfile, 'b')
227  set runtimepath=./Xtest
228  set spelllang=Xtest
229  call assert_fails('set spell', 'E757:')
230  set nospell spelllang&
231
232  " missing version number
233  call writefile(0z56494D7370656C6C, splfile, 'b')
234  set runtimepath=./Xtest
235  set spelllang=Xtest
236  call assert_fails('set spell', 'E771:')
237  set nospell spelllang&
238
239  " invalid version number
240  call writefile(0z56494D7370656C6C7A, splfile, 'b')
241  set runtimepath=./Xtest
242  set spelllang=Xtest
243  call assert_fails('set spell', 'E772:')
244  set nospell spelllang&
245
246  " no sections
247  call Spellfile_Test(0z, 'E758:')
248
249  " missing section length
250  call Spellfile_Test(0z00, 'E758:')
251
252  " unsupported required section
253  call Spellfile_Test(0z7A0100000004, 'E770:')
254
255  " unsupported not-required section
256  call Spellfile_Test(0z7A0000000004, 'E758:')
257
258  " SN_REGION: invalid number of region names
259  call Spellfile_Test(0z0000000000FF, 'E759:')
260
261  " SN_CHARFLAGS: missing <charflagslen> length
262  call Spellfile_Test(0z010000000004, 'E758:')
263
264  " SN_CHARFLAGS: invalid <charflagslen> length
265  call Spellfile_Test(0z0100000000010201, '')
266
267  " SN_CHARFLAGS: charflagslen == 0 and folcharslen != 0
268  call Spellfile_Test(0z01000000000400000101, 'E759:')
269
270  " SN_CHARFLAGS: missing <folcharslen> length
271  call Spellfile_Test(0z01000000000100, 'E758:')
272
273  " SN_PREFCOND: invalid prefcondcnt
274  call Spellfile_Test(0z03000000000100, 'E759:')
275
276  " SN_PREFCOND: invalid condlen
277  call Spellfile_Test(0z0300000000020001, 'E759:')
278
279  " SN_REP: invalid repcount
280  call Spellfile_Test(0z04000000000100, 'E758:')
281
282  " SN_REP: missing rep
283  call Spellfile_Test(0z0400000000020004, 'E758:')
284
285  " SN_REP: zero repfromlen
286  call Spellfile_Test(0z040000000003000100, 'E759:')
287
288  " SN_REP: invalid reptolen
289  call Spellfile_Test(0z0400000000050001014101, '')
290
291  " SN_REP: zero reptolen
292  call Spellfile_Test(0z0400000000050001014100, 'E759:')
293
294  " SN_SAL: missing salcount
295  call Spellfile_Test(0z05000000000102, 'E758:')
296
297  " SN_SAL: missing salfromlen
298  call Spellfile_Test(0z050000000003080001, 'E758:')
299
300  " SN_SAL: missing saltolen
301  call Spellfile_Test(0z0500000000050400010161, 'E758:')
302
303  " SN_WORDS: non-NUL terminated word
304  call Spellfile_Test(0z0D000000000376696D, 'E758:')
305
306  " SN_WORDS: very long word
307  let v = eval('0z0D000000012C' .. repeat('41', 300))
308  call Spellfile_Test(v, 'E759:')
309
310  " SN_SOFO: missing sofofromlen
311  call Spellfile_Test(0z06000000000100, 'E758:')
312
313  " SN_SOFO: missing sofotolen
314  call Spellfile_Test(0z06000000000400016100, 'E758:')
315
316  " SN_SOFO: missing sofoto
317  call Spellfile_Test(0z0600000000050001610000, 'E759:')
318
319  " SN_SOFO: empty sofofrom and sofoto
320  call Spellfile_Test(0z06000000000400000000FF000000000000000000000000, '')
321
322  " SN_SOFO: multi-byte characters in sofofrom and sofoto
323  call Spellfile_Test(0z0600000000080002CF810002CF82FF000000000000000000000000, '')
324
325  " SN_COMPOUND: compmax is less than 2
326  call Spellfile_Test(0z08000000000101, 'E759:')
327
328  " SN_COMPOUND: missing compsylmax and other options
329  call Spellfile_Test(0z0800000000020401, 'E759:')
330
331  " SN_COMPOUND: missing compoptions
332  call Spellfile_Test(0z080000000005040101, 'E758:')
333
334  " SN_COMPOUND: missing comppattern
335  call Spellfile_Test(0z08000000000704010100000001, 'E758:')
336
337  " SN_COMPOUND: incorrect comppatlen
338  call Spellfile_Test(0z080000000007040101000000020165, 'E758:')
339
340  " SN_INFO: missing info
341  call Spellfile_Test(0z0F0000000005040101, '')
342
343  " SN_MIDWORD: missing midword
344  call Spellfile_Test(0z0200000000040102, '')
345
346  " SN_MAP: missing midword
347  call Spellfile_Test(0z0700000000040102, '')
348
349  " SN_MAP: empty map string
350  call Spellfile_Test(0z070000000000FF000000000000000000000000, '')
351
352  " SN_MAP: duplicate multibyte character
353  call Spellfile_Test(0z070000000004DC81DC81, 'E783:')
354
355  " SN_SYLLABLE: missing SYLLABLE item
356  call Spellfile_Test(0z0900000000040102, '')
357
358  " SN_SYLLABLE: More than SY_MAXLEN size
359  let v = eval('0z090000000022612F' .. repeat('62', 32))
360  call Spellfile_Test(v, '')
361
362  " LWORDTREE: missing
363  call Spellfile_Test(0zFF, 'E758:')
364
365  " LWORDTREE: missing tree node
366  call Spellfile_Test(0zFF00000004, 'E758:')
367
368  " LWORDTREE: missing tree node value
369  call Spellfile_Test(0zFF0000000402, 'E758:')
370
371  " LWORDTREE: incorrect sibling node count
372  call Spellfile_Test(0zFF00000001040000000000000000, 'E759:')
373
374  " KWORDTREE: missing tree node
375  call Spellfile_Test(0zFF0000000000000004, 'E758:')
376
377  " PREFIXTREE: missing tree node
378  call Spellfile_Test(0zFF000000000000000000000004, 'E758:')
379
380  " PREFIXTREE: incorrect prefcondnr
381  call Spellfile_Test(0zFF000000000000000000000002010200000020, 'E759:')
382
383  " PREFIXTREE: invalid nodeidx
384  call Spellfile_Test(0zFF00000000000000000000000201010000, 'E759:')
385
386  let &rtp = save_rtp
387  call delete('Xtest', 'rf')
388endfunc
389
390" Test for format errors in suggest file
391func Test_sugfile_format_error()
392  let save_rtp = &rtp
393  call mkdir('Xtest/spell', 'p')
394  let splfile = './Xtest/spell/Xtest.utf-8.spl'
395  let sugfile = './Xtest/spell/Xtest.utf-8.sug'
396
397  " create an empty spell file with a suggest timestamp
398  call writefile(0z56494D7370656C6C320B00000000080000000000000044FF000000000000000000000000, splfile, 'b')
399
400  " 'encoding' is set before each test to clear the previously loaded suggest
401  " file from memory.
402
403  " empty suggest file
404  set encoding=utf-8
405  call writefile([], sugfile)
406  set runtimepath=./Xtest
407  set spelllang=Xtest
408  set spell
409  call assert_fails("let s = spellsuggest('abc')", 'E778:')
410  set nospell spelllang&
411
412  " zero suggest version
413  set encoding=utf-8
414  call writefile(0z56494D73756700, sugfile)
415  set runtimepath=./Xtest
416  set spelllang=Xtest
417  set spell
418  call assert_fails("let s = spellsuggest('abc')", 'E779:')
419  set nospell spelllang&
420
421  " unsupported suggest version
422  set encoding=utf-8
423  call writefile(0z56494D7375671F, sugfile)
424  set runtimepath=./Xtest
425  set spelllang=Xtest
426  set spell
427  call assert_fails("let s = spellsuggest('abc')", 'E780:')
428  set nospell spelllang&
429
430  " missing suggest timestamp
431  set encoding=utf-8
432  call writefile(0z56494D73756701, sugfile)
433  set runtimepath=./Xtest
434  set spelllang=Xtest
435  set spell
436  call assert_fails("let s = spellsuggest('abc')", 'E781:')
437  set nospell spelllang&
438
439  " incorrect suggest timestamp
440  set encoding=utf-8
441  call writefile(0z56494D7375670100000000000000FF, sugfile)
442  set runtimepath=./Xtest
443  set spelllang=Xtest
444  set spell
445  call assert_fails("let s = spellsuggest('abc')", 'E781:')
446  set nospell spelllang&
447
448  " missing suggest wordtree
449  set encoding=utf-8
450  call writefile(0z56494D737567010000000000000044, sugfile)
451  set runtimepath=./Xtest
452  set spelllang=Xtest
453  set spell
454  call assert_fails("let s = spellsuggest('abc')", 'E782:')
455  set nospell spelllang&
456
457  " invalid suggest word count in SUGTABLE
458  set encoding=utf-8
459  call writefile(0z56494D7375670100000000000000440000000022, sugfile)
460  set runtimepath=./Xtest
461  set spelllang=Xtest
462  set spell
463  call assert_fails("let s = spellsuggest('abc')", 'E782:')
464  set nospell spelllang&
465
466  " missing sugline in SUGTABLE
467  set encoding=utf-8
468  call writefile(0z56494D7375670100000000000000440000000000000005, sugfile)
469  set runtimepath=./Xtest
470  set spelllang=Xtest
471  set spell
472  call assert_fails("let s = spellsuggest('abc')", 'E782:')
473  set nospell spelllang&
474
475  let &rtp = save_rtp
476  call delete('Xtest', 'rf')
477endfunc
478
479" Test for using :mkspell to create a spell file from a list of words
480func Test_wordlist_dic()
481  " duplicate encoding
482  let lines =<< trim [END]
483    # This is an example word list
484
485    /encoding=latin1
486    /encoding=latin1
487    example
488  [END]
489  call writefile(lines, 'Xwordlist.dic')
490  let output = execute('mkspell Xwordlist.spl Xwordlist.dic')
491  call assert_match('Duplicate /encoding= line ignored in Xwordlist.dic line 4: /encoding=latin1', output)
492
493  " multiple encoding for a word
494  let lines =<< trim [END]
495    example
496    /encoding=latin1
497    example
498  [END]
499  call writefile(lines, 'Xwordlist.dic')
500  let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
501  call assert_match('/encoding= line after word ignored in Xwordlist.dic line 2: /encoding=latin1', output)
502
503  " unsupported encoding for a word
504  let lines =<< trim [END]
505    /encoding=Xtest
506    example
507  [END]
508  call writefile(lines, 'Xwordlist.dic')
509  let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
510  call assert_match('Conversion in Xwordlist.dic not supported: from Xtest to utf-8', output)
511
512  " duplicate region
513  let lines =<< trim [END]
514    /regions=usca
515    /regions=usca
516    example
517  [END]
518  call writefile(lines, 'Xwordlist.dic')
519  let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
520  call assert_match('Duplicate /regions= line ignored in Xwordlist.dic line 2: regions=usca', output)
521
522  " maximum regions
523  let lines =<< trim [END]
524    /regions=uscauscauscauscausca
525    example
526  [END]
527  call writefile(lines, 'Xwordlist.dic')
528  let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
529  call assert_match('Too many regions in Xwordlist.dic line 1: uscauscauscauscausca', output)
530
531  " unsupported '/' value
532  let lines =<< trim [END]
533    /test=abc
534    example
535  [END]
536  call writefile(lines, 'Xwordlist.dic')
537  let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
538  call assert_match('/ line ignored in Xwordlist.dic line 1: /test=abc', output)
539
540  " unsupported flag
541  let lines =<< trim [END]
542    example/+
543  [END]
544  call writefile(lines, 'Xwordlist.dic')
545  let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
546  call assert_match('Unrecognized flags in Xwordlist.dic line 1: +', output)
547
548  " non-ascii word
549  call writefile(["ʀʀ"], 'Xwordlist.dic')
550  let output = execute('mkspell! -ascii Xwordlist.spl Xwordlist.dic')
551  call assert_match('Ignored 1 words with non-ASCII characters', output)
552
553  " keep case of a word
554  let lines =<< trim [END]
555    example/=
556  [END]
557  call writefile(lines, 'Xwordlist.dic')
558  let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
559  call assert_match('Compressed keep-case:', output)
560
561  call delete('Xwordlist.spl')
562  call delete('Xwordlist.dic')
563endfunc
564
565" Test for the :mkspell command
566func Test_mkspell()
567  call assert_fails('mkspell Xtest_us.spl', 'E751:')
568  call assert_fails('mkspell Xtest.spl abc', 'E484:')
569  call assert_fails('mkspell a b c d e f g h i j k', 'E754:')
570
571  " create a .aff file but not the .dic file
572  call writefile([], 'Xtest.aff')
573  call assert_fails('mkspell Xtest.spl Xtest', 'E484:')
574  call delete('Xtest.aff')
575
576  call writefile([], 'Xtest.spl')
577  call writefile([], 'Xtest.dic')
578  call assert_fails('mkspell Xtest.spl Xtest.dic', 'E13:')
579  call delete('Xtest.spl')
580  call delete('Xtest.dic')
581
582  call mkdir('Xtest.spl')
583  call assert_fails('mkspell! Xtest.spl Xtest.dic', 'E17:')
584  call delete('Xtest.spl', 'rf')
585
586  " can't write the .spl file as its directory does not exist
587  call writefile([], 'Xtest.aff')
588  call writefile([], 'Xtest.dic')
589  call assert_fails('mkspell DOES_NOT_EXIT/Xtest.spl Xtest.dic', 'E484:')
590  call delete('Xtest.aff')
591  call delete('Xtest.dic')
592
593  call assert_fails('mkspell en en_US abc_xyz', 'E755:')
594endfunc
595
596" Tests for :mkspell with a .dic and .aff file
597func Test_aff_file_format_error()
598  " FIXME: For some reason, the :mkspell command below doesn't fail on the
599  " MS-Windows CI build. Disable this test on MS-Windows for now.
600  CheckNotMSWindows
601
602  " No word count in .dic file
603  call writefile([], 'Xtest.dic')
604  call writefile([], 'Xtest.aff')
605  call assert_fails('mkspell! Xtest.spl Xtest', 'E760:')
606
607  " create a .dic file for the tests below
608  call writefile(['1', 'work'], 'Xtest.dic')
609
610  " Invalid encoding in .aff file
611  call writefile(['# comment', 'SET Xinvalidencoding'], 'Xtest.aff')
612  let output = execute('mkspell! Xtest.spl Xtest')
613  call assert_match('Conversion in Xtest.aff not supported: from xinvalidencoding', output)
614
615  " Invalid flag in .aff file
616  call writefile(['FLAG xxx'], 'Xtest.aff')
617  let output = execute('mkspell! Xtest.spl Xtest')
618  call assert_match('Invalid value for FLAG in Xtest.aff line 1: xxx', output)
619
620  " set FLAGS after using flag for an affix
621  call writefile(['SFX L Y 1', 'SFX L 0 re [^x]', 'FLAG long'], 'Xtest.aff')
622  let output = execute('mkspell! Xtest.spl Xtest')
623  call assert_match('FLAG after using flags in Xtest.aff line 3: long', output)
624
625  " INFO in affix file
626  let save_encoding = &encoding
627  call mkdir('Xrtp/spell', 'p')
628  call writefile(['1', 'work'], 'Xrtp/spell/Xtest.dic')
629  call writefile(['NAME klingon', 'VERSION 1.4', 'AUTHOR Spock'],
630        \ 'Xrtp/spell/Xtest.aff')
631  silent mkspell! Xrtp/spell/Xtest.utf-8.spl Xrtp/spell/Xtest
632  let save_rtp = &rtp
633  set runtimepath=./Xrtp
634  set spelllang=Xtest
635  set spell
636  let output = split(execute('spellinfo'), "\n")
637  call assert_equal("NAME klingon", output[1])
638  call assert_equal("VERSION 1.4", output[2])
639  call assert_equal("AUTHOR Spock", output[3])
640  let &rtp = save_rtp
641  call delete('Xrtp', 'rf')
642  set spell& spelllang& spellfile&
643  %bw!
644  " 'encoding' must be set again to clear the spell file in memory
645  let &encoding = save_encoding
646
647  " COMPOUNDFORBIDFLAG flag after PFX in an affix file
648  call writefile(['PFX L Y 1', 'PFX L 0 re x', 'COMPOUNDFLAG c', 'COMPOUNDFORBIDFLAG x'],
649        \ 'Xtest.aff')
650  let output = execute('mkspell! Xtest.spl Xtest')
651  call assert_match('Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in Xtest.aff line 4', output)
652
653  " COMPOUNDPERMITFLAG flag after PFX in an affix file
654  call writefile(['PFX L Y 1', 'PFX L 0 re x', 'COMPOUNDPERMITFLAG c'],
655        \ 'Xtest.aff')
656  let output = execute('mkspell! Xtest.spl Xtest')
657  call assert_match('Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in Xtest.aff line 3', output)
658
659  " Wrong COMPOUNDRULES flag value in an affix file
660  call writefile(['COMPOUNDRULES a'], 'Xtest.aff')
661  let output = execute('mkspell! Xtest.spl Xtest')
662  call assert_match('Wrong COMPOUNDRULES value in Xtest.aff line 1: a', output)
663
664  " Wrong COMPOUNDWORDMAX flag value in an affix file
665  call writefile(['COMPOUNDWORDMAX 0'], 'Xtest.aff')
666  let output = execute('mkspell! Xtest.spl Xtest')
667  call assert_match('Wrong COMPOUNDWORDMAX value in Xtest.aff line 1: 0', output)
668
669  " Wrong COMPOUNDMIN flag value in an affix file
670  call writefile(['COMPOUNDMIN 0'], 'Xtest.aff')
671  let output = execute('mkspell! Xtest.spl Xtest')
672  call assert_match('Wrong COMPOUNDMIN value in Xtest.aff line 1: 0', output)
673
674  " Wrong COMPOUNDSYLMAX flag value in an affix file
675  call writefile(['COMPOUNDSYLMAX 0'], 'Xtest.aff')
676  let output = execute('mkspell! Xtest.spl Xtest')
677  call assert_match('Wrong COMPOUNDSYLMAX value in Xtest.aff line 1: 0', output)
678
679  " Wrong CHECKCOMPOUNDPATTERN flag value in an affix file
680  call writefile(['CHECKCOMPOUNDPATTERN 0'], 'Xtest.aff')
681  let output = execute('mkspell! Xtest.spl Xtest')
682  call assert_match('Wrong CHECKCOMPOUNDPATTERN value in Xtest.aff line 1: 0', output)
683
684  " Duplicate affix entry in an affix file
685  call writefile(['PFX L Y 1', 'PFX L 0 re x', 'PFX L Y 1', 'PFX L 0 re x'],
686        \ 'Xtest.aff')
687  let output = execute('mkspell! Xtest.spl Xtest')
688  call assert_match('Duplicate affix in Xtest.aff line 3: L', output)
689
690  " Duplicate affix entry in an affix file
691  call writefile(['PFX L Y 1', 'PFX L Y 1'], 'Xtest.aff')
692  let output = execute('mkspell! Xtest.spl Xtest')
693  call assert_match('Unrecognized or duplicate item in Xtest.aff line 2: PFX', output)
694
695  " Different combining flags in an affix file
696  call writefile(['PFX L Y 1', 'PFX L 0 re x', 'PFX L N 1'], 'Xtest.aff')
697  let output = execute('mkspell! Xtest.spl Xtest')
698  call assert_match('Different combining flag in continued affix block in Xtest.aff line 3', output)
699
700  " Try to reuse a affix used for BAD flag
701  call writefile(['BAD x', 'PFX x Y 1', 'PFX x 0 re x'], 'Xtest.aff')
702  let output = execute('mkspell! Xtest.spl Xtest')
703  call assert_match('Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in Xtest.aff line 2: x', output)
704
705  " Trailing characters in an affix entry
706  call writefile(['PFX L Y 1 Test', 'PFX L 0 re x'], 'Xtest.aff')
707  let output = execute('mkspell! Xtest.spl Xtest')
708  call assert_match('Trailing text in Xtest.aff line 1: Test', output)
709
710  " Trailing characters in an affix entry
711  call writefile(['PFX L Y 1', 'PFX L 0 re x Test'], 'Xtest.aff')
712  let output = execute('mkspell! Xtest.spl Xtest')
713  call assert_match('Trailing text in Xtest.aff line 2: Test', output)
714
715  " Incorrect combine flag in an affix entry
716  call writefile(['PFX L X 1', 'PFX L 0 re x'], 'Xtest.aff')
717  let output = execute('mkspell! Xtest.spl Xtest')
718  call assert_match('Expected Y or N in Xtest.aff line 1: X', output)
719
720  " Invalid count for REP item
721  call writefile(['REP a'], 'Xtest.aff')
722  let output = execute('mkspell! Xtest.spl Xtest')
723  call assert_match('Expected REP(SAL) count in Xtest.aff line 1', output)
724
725  " Trailing characters in REP item
726  call writefile(['REP 1', 'REP f ph test'], 'Xtest.aff')
727  let output = execute('mkspell! Xtest.spl Xtest')
728  call assert_match('Trailing text in Xtest.aff line 2: test', output)
729
730  " Invalid count for MAP item
731  call writefile(['MAP a'], 'Xtest.aff')
732  let output = execute('mkspell! Xtest.spl Xtest')
733  call assert_match('Expected MAP count in Xtest.aff line 1', output)
734
735  " Duplicate character in a MAP item
736  call writefile(['MAP 2', 'MAP xx', 'MAP yy'], 'Xtest.aff')
737  let output = execute('mkspell! Xtest.spl Xtest')
738  call assert_match('Duplicate character in MAP in Xtest.aff line 2', output)
739
740  " Use COMPOUNDSYLMAX without SYLLABLE
741  call writefile(['COMPOUNDSYLMAX 2'], 'Xtest.aff')
742  let output = execute('mkspell! Xtest.spl Xtest')
743  call assert_match('COMPOUNDSYLMAX used without SYLLABLE', output)
744
745  " Missing SOFOTO
746  call writefile(['SOFOFROM abcdef'], 'Xtest.aff')
747  let output = execute('mkspell! Xtest.spl Xtest')
748  call assert_match('Missing SOFOTO line in Xtest.aff', output)
749
750  " Length of SOFOFROM and SOFOTO differ
751  call writefile(['SOFOFROM abcde', 'SOFOTO ABCD'], 'Xtest.aff')
752  call assert_fails('mkspell! Xtest.spl Xtest', 'E759:')
753
754  " Both SAL and SOFOFROM/SOFOTO items
755  call writefile(['SOFOFROM abcd', 'SOFOTO ABCD', 'SAL CIA X'], 'Xtest.aff')
756  let output = execute('mkspell! Xtest.spl Xtest')
757  call assert_match('Both SAL and SOFO lines in Xtest.aff', output)
758
759  " use an alphabet flag when FLAG is num
760  call writefile(['FLAG num', 'SFX L Y 1', 'SFX L 0 re [^x]'], 'Xtest.aff')
761  let output = execute('mkspell! Xtest.spl Xtest')
762  call assert_match('Flag is not a number in Xtest.aff line 2: L', output)
763
764  " use number and alphabet flag when FLAG is num
765  call writefile(['FLAG num', 'SFX 4f Y 1', 'SFX 4f 0 re [^x]'], 'Xtest.aff')
766  let output = execute('mkspell! Xtest.spl Xtest')
767  call assert_match('Affix name too long in Xtest.aff line 2: 4f', output)
768
769  " use a single character flag when FLAG is long
770  call writefile(['FLAG long', 'SFX L Y 1', 'SFX L 0 re [^x]'], 'Xtest.aff')
771  let output = execute('mkspell! Xtest.spl Xtest')
772  call assert_match('Illegal flag in Xtest.aff line 2: L', output)
773
774  " missing character in UPP entry. The character table is used only in a
775  " non-utf8 encoding
776  call writefile(['FOL abc', 'LOW abc', 'UPP A'], 'Xtest.aff')
777  let save_encoding = &encoding
778  set encoding=cp949
779  call assert_fails('mkspell! Xtest.spl Xtest', 'E761:')
780  let &encoding = save_encoding
781
782  " character range doesn't match between FOL and LOW entries
783  call writefile(["FOL \u0102bc", 'LOW abc', 'UPP ABC'], 'Xtest.aff')
784  let save_encoding = &encoding
785  set encoding=cp949
786  call assert_fails('mkspell! Xtest.spl Xtest', 'E762:')
787  let &encoding = save_encoding
788
789  " character range doesn't match between FOL and UPP entries
790  call writefile(["FOL \u0102bc", "LOW \u0102bc", 'UPP ABC'], 'Xtest.aff')
791  let save_encoding = &encoding
792  set encoding=cp949
793  call assert_fails('mkspell! Xtest.spl Xtest', 'E762:')
794  let &encoding = save_encoding
795
796  " additional characters in LOW and UPP entries
797  call writefile(["FOL ab", "LOW abc", 'UPP ABC'], 'Xtest.aff')
798  let save_encoding = &encoding
799  set encoding=cp949
800  call assert_fails('mkspell! Xtest.spl Xtest', 'E761:')
801  let &encoding = save_encoding
802
803  " missing UPP entry
804  call writefile(["FOL abc", "LOW abc"], 'Xtest.aff')
805  let save_encoding = &encoding
806  set encoding=cp949
807  let output = execute('mkspell! Xtest.spl Xtest')
808  call assert_match('Missing FOL/LOW/UPP line in Xtest.aff', output)
809  let &encoding = save_encoding
810
811  " duplicate word in the .dic file
812  call writefile(['2', 'good', 'good', 'good'], 'Xtest.dic')
813  call writefile(['NAME vim'], 'Xtest.aff')
814  let output = execute('mkspell! Xtest.spl Xtest')
815  call assert_match('First duplicate word in Xtest.dic line 3: good', output)
816  call assert_match('2 duplicate word(s) in Xtest.dic', output)
817
818  " use multiple .aff files with different values for COMPOUNDWORDMAX and
819  " MIDWORD (number and string)
820  call writefile(['1', 'world'], 'Xtest_US.dic')
821  call writefile(['1', 'world'], 'Xtest_CA.dic')
822  call writefile(["COMPOUNDWORDMAX 3", "MIDWORD '-"], 'Xtest_US.aff')
823  call writefile(["COMPOUNDWORDMAX 4", "MIDWORD '="], 'Xtest_CA.aff')
824  let output = execute('mkspell! Xtest.spl Xtest_US Xtest_CA')
825  call assert_match('COMPOUNDWORDMAX value differs from what is used in another .aff file', output)
826  call assert_match('MIDWORD value differs from what is used in another .aff file', output)
827  call delete('Xtest_US.dic')
828  call delete('Xtest_CA.dic')
829  call delete('Xtest_US.aff')
830  call delete('Xtest_CA.aff')
831
832  call delete('Xtest.dic')
833  call delete('Xtest.aff')
834  call delete('Xtest.spl')
835  call delete('Xtest.sug')
836endfunc
837
838func Test_spell_add_word()
839  set spellfile=
840  call assert_fails('spellgood abc', 'E764:')
841
842  set spellfile=Xtest.utf-8.add
843  call assert_fails('2spellgood abc', 'E765:')
844
845  edit Xtest.utf-8.add
846  call setline(1, 'sample')
847  call assert_fails('spellgood abc', 'E139:')
848  set spellfile&
849  %bw!
850endfunc
851
852func Test_spellfile_verbose()
853  call writefile(['1', 'one'], 'XtestVerbose.dic')
854  call writefile([], 'XtestVerbose.aff')
855  mkspell! XtestVerbose-utf8.spl XtestVerbose
856  set spell
857
858  " First time: the spl file should be read.
859  let a = execute('3verbose set spelllang=XtestVerbose-utf8.spl')
860  call assert_match('Reading spell file "XtestVerbose-utf8.spl"', a)
861
862  " Second time time: the spl file should not be read (already read).
863  let a = execute('3verbose set spelllang=XtestVerbose-utf8.spl')
864  call assert_notmatch('Reading spell file "XtestVerbose-utf8.spl"', a)
865
866  set spell& spelllang&
867  call delete('XtestVerbose.dic')
868  call delete('XtestVerbose.aff')
869  call delete('XtestVerbose-utf8.spl')
870endfunc
871
872" Test NOBREAK (see :help spell-NOBREAK)
873func Test_NOBREAK()
874  call writefile(['3', 'one', 'two', 'three' ], 'XtestNOBREAK.dic')
875  call writefile(['NOBREAK' ], 'XtestNOBREAK.aff')
876
877  mkspell! XtestNOBREAK-utf8.spl XtestNOBREAK
878  set spell spelllang=XtestNOBREAK-utf8.spl
879
880  call assert_equal(['', ''], spellbadword('One two three onetwo onetwothree threetwoone'))
881
882  call assert_equal(['x', 'bad'], spellbadword('x'))
883  call assert_equal(['y', 'bad'], spellbadword('yone'))
884  call assert_equal(['z', 'bad'], spellbadword('onez'))
885  call assert_equal(['zero', 'bad'], spellbadword('Onetwozerothree'))
886
887  set spell& spelllang&
888  call delete('XtestNOBREAK.dic')
889  call delete('XtestNOBREAK.aff')
890  call delete('XtestNOBREAK-utf8.spl')
891endfunc
892
893" Test CHECKCOMPOUNDPATTERN (see :help spell-CHECKCOMPOUNDPATTERN)
894func Test_spellfile_CHECKCOMPOUNDPATTERN()
895  call writefile(['4',
896        \         'one/c',
897        \         'two/c',
898        \         'three/c',
899        \         'four'], 'XtestCHECKCOMPOUNDPATTERN.dic')
900  " Forbid compound words where first word ends with 'wo' and second starts with 'on'.
901  call writefile(['CHECKCOMPOUNDPATTERN 1',
902        \         'CHECKCOMPOUNDPATTERN wo on',
903        \         'COMPOUNDFLAG c'], 'XtestCHECKCOMPOUNDPATTERN.aff')
904
905  mkspell! XtestCHECKCOMPOUNDPATTERN-utf8.spl XtestCHECKCOMPOUNDPATTERN
906  set spell spelllang=XtestCHECKCOMPOUNDPATTERN-utf8.spl
907
908  " Check valid words with and without valid compounds.
909  for goodword in ['one', 'two', 'three', 'four',
910        \          'oneone', 'onetwo',  'onethree',
911        \          'twotwo', 'twothree',
912        \          'threeone', 'threetwo', 'threethree',
913        \          'onetwothree', 'onethreetwo', 'twothreeone', 'oneoneone']
914    call assert_equal(['', ''], spellbadword(goodword), goodword)
915  endfor
916
917  " Compounds 'twoone' or 'threetwoone' should be forbidden by CHECKCOMPOUNPATTERN.
918  " 'four' does not have the 'c' flag in *.aff file so no compound.
919  " 'five' is not in the *.dic file.
920  for badword in ['five', 'onetwox',
921        \         'twoone', 'threetwoone',
922        \         'fourone', 'onefour']
923    call assert_equal([badword, 'bad'], spellbadword(badword))
924  endfor
925
926  set spell& spelllang&
927  call delete('XtestCHECKCOMPOUNDPATTERN.dic')
928  call delete('XtestCHECKCOMPOUNDPATTERN.aff')
929  call delete('XtestCHECKCOMPOUNDPATTERN-utf8.spl')
930endfunc
931
932" Test COMMON (better suggestions with common words, see :help spell-COMMON)
933func Test_spellfile_COMMON()
934  call writefile(['7',
935        \         'and',
936        \         'ant',
937        \         'end',
938        \         'any',
939        \         'tee',
940        \         'the',
941        \         'ted'], 'XtestCOMMON.dic')
942  call writefile(['COMMON the and'], 'XtestCOMMON.aff')
943
944  mkspell! XtestCOMMON-utf8.spl XtestCOMMON
945  set spell spelllang=XtestCOMMON-utf8.spl
946
947  " COMMON words 'and' and 'the' should be the top suggestions.
948  call assert_equal(['and', 'ant'], spellsuggest('anr', 2))
949  call assert_equal(['and', 'end'], spellsuggest('ond', 2))
950  call assert_equal(['the', 'ted'], spellsuggest('tha', 2))
951  call assert_equal(['the', 'tee'], spellsuggest('dhe', 2))
952
953  set spell& spelllang&
954  call delete('XtestCOMMON.dic')
955  call delete('XtestCOMMON.aff')
956  call delete('XtestCOMMON-utf8.spl')
957endfunc
958
959" Test CIRCUMFIX (see: :help spell-CIRCUMFIX)
960func Test_spellfile_CIRCUMFIX()
961  " Example taken verbatim from https://github.com/hunspell/hunspell/tree/master/tests
962  call writefile(['1',
963        \         'nagy/C	po:adj'], 'XtestCIRCUMFIX.dic')
964  call writefile(['# circumfixes: ~ obligate prefix/suffix combinations',
965        \         '# superlative in Hungarian: leg- (prefix) AND -bb (suffix)',
966        \         '',
967        \         'CIRCUMFIX X',
968        \         '',
969        \         'PFX A Y 1',
970        \         'PFX A 0 leg/X .',
971        \         '',
972        \         'PFX B Y 1',
973        \         'PFX B 0 legesleg/X .',
974        \         '',
975        \         'SFX C Y 3',
976        \         'SFX C 0 obb . is:COMPARATIVE',
977        \         'SFX C 0 obb/AX . is:SUPERLATIVE',
978        \         'SFX C 0 obb/BX . is:SUPERSUPERLATIVE'], 'XtestCIRCUMFIX.aff')
979
980  mkspell! XtestCIRCUMFIX-utf8.spl XtestCIRCUMFIX
981  set spell spelllang=XtestCIRCUMFIX-utf8.spl
982
983  " From https://catalog.ldc.upenn.edu/docs/LDC2008T01/acta04.pdf:
984  " Hungarian       English
985  " ---------       -------
986  " nagy            great
987  " nagyobb         greater
988  " legnagyobb      greatest
989  " legeslegnagyob  most greatest
990  call assert_equal(['', ''], spellbadword('nagy nagyobb legnagyobb legeslegnagyobb'))
991
992  for badword in ['legnagy', 'legeslegnagy', 'legobb', 'legeslegobb']
993    call assert_equal([badword, 'bad'], spellbadword(badword))
994  endfor
995
996  set spell& spelllang&
997  call delete('XtestCIRCUMFIX.dic')
998  call delete('XtestCIRCUMFIX.aff')
999  call delete('XtestCIRCUMFIX-utf8.spl')
1000endfunc
1001
1002" When 'spellfile' is not set, adding a new good word will automatically set
1003" the 'spellfile'
1004func Test_init_spellfile()
1005  let save_rtp = &rtp
1006  let save_encoding = &encoding
1007  call mkdir('Xrtp/spell', 'p')
1008  call writefile(['vim'], 'Xrtp/spell/Xtest.dic')
1009  silent mkspell Xrtp/spell/Xtest.utf-8.spl Xrtp/spell/Xtest.dic
1010  set runtimepath=./Xrtp
1011  set spelllang=Xtest
1012  set spell
1013  silent spellgood abc
1014  call assert_equal('./Xrtp/spell/Xtest.utf-8.add', &spellfile)
1015  call assert_equal(['abc'], readfile('Xrtp/spell/Xtest.utf-8.add'))
1016  call assert_true(filereadable('Xrtp/spell/Xtest.utf-8.spl'))
1017  set spell& spelllang& spellfile&
1018  call delete('Xrtp', 'rf')
1019  let &encoding = save_encoding
1020  let &rtp = save_rtp
1021  %bw!
1022endfunc
1023
1024" Test for the 'mkspellmem' option
1025func Test_mkspellmem_opt()
1026  call assert_fails('set mkspellmem=1000', 'E474:')
1027  call assert_fails('set mkspellmem=1000,', 'E474:')
1028  call assert_fails('set mkspellmem=1000,50', 'E474:')
1029  call assert_fails('set mkspellmem=1000,50,', 'E474:')
1030  call assert_fails('set mkspellmem=1000,50,10,', 'E474:')
1031  call assert_fails('set mkspellmem=1000,50,0', 'E474:')
1032endfunc
1033
1034" vim: shiftwidth=2 sts=2 expandtab
1035