1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local eq = t.eq
local clear = n.clear
local api = n.api
local exc_exec = n.exc_exec
local fn = n.fn
local rmdir = n.rmdir
local write_file = t.write_file
local mkdir = t.mkdir
local testdir = 'Xtest-functional-spell-spellfile.d'
describe('spellfile', function()
before_each(function()
clear({ env = { XDG_DATA_HOME = testdir .. '/xdg_data' } })
rmdir(testdir)
mkdir(testdir)
mkdir(testdir .. '/spell')
end)
after_each(function()
rmdir(testdir)
end)
-- ┌ Magic string (#VIMSPELLMAGIC)
-- │ ┌ Spell file version (#VIMSPELLVERSION)
local spellheader = 'VIMspell\050'
it('errors out when prefcond section is truncated', function()
api.nvim_set_option_value('runtimepath', testdir, {})
-- stylua: ignore
write_file(testdir .. '/spell/en.ascii.spl',
-- ┌ Section identifier (#SN_PREFCOND)
-- │ ┌ Section flags (#SNF_REQUIRED or zero)
-- │ │ ┌ Section length (4 bytes, MSB first)
spellheader .. '\003\001\000\000\000\003'
-- ┌ Number of regexes in section (2 bytes, MSB first)
-- │ ┌ Condition length (1 byte)
-- │ │ ┌ Condition regex (missing!)
.. '\000\001\001')
api.nvim_set_option_value('spelllang', 'en', {})
eq('Vim(set):E758: Truncated spell file', exc_exec('set spell'))
end)
it('errors out when prefcond regexp contains NUL byte', function()
api.nvim_set_option_value('runtimepath', testdir, {})
-- stylua: ignore
write_file(testdir .. '/spell/en.ascii.spl',
-- ┌ Section identifier (#SN_PREFCOND)
-- │ ┌ Section flags (#SNF_REQUIRED or zero)
-- │ │ ┌ Section length (4 bytes, MSB first)
spellheader .. '\003\001\000\000\000\008'
-- ┌ Number of regexes in section (2 bytes, MSB first)
-- │ ┌ Condition length (1 byte)
-- │ │ ┌ Condition regex
-- │ │ │ ┌ End of sections marker
.. '\000\001\005ab\000cd\255'
-- ┌ LWORDTREE tree length (4 bytes)
-- │ ┌ KWORDTREE tree length (4 bytes)
-- │ │ ┌ PREFIXTREE tree length
.. '\000\000\000\000\000\000\000\000\000\000\000\000')
api.nvim_set_option_value('spelllang', 'en', {})
eq('Vim(set):E759: Format error in spell file', exc_exec('set spell'))
end)
it('errors out when region contains NUL byte', function()
api.nvim_set_option_value('runtimepath', testdir, {})
-- stylua: ignore
write_file(testdir .. '/spell/en.ascii.spl',
-- ┌ Section identifier (#SN_REGION)
-- │ ┌ Section flags (#SNF_REQUIRED or zero)
-- │ │ ┌ Section length (4 bytes, MSB first)
spellheader .. '\000\001\000\000\000\008'
-- ┌ Regions ┌ End of sections marker
.. '01234\00067\255'
-- ┌ LWORDTREE tree length (4 bytes)
-- │ ┌ KWORDTREE tree length (4 bytes)
-- │ │ ┌ PREFIXTREE tree length
.. '\000\000\000\000\000\000\000\000\000\000\000\000')
api.nvim_set_option_value('spelllang', 'en', {})
eq('Vim(set):E759: Format error in spell file', exc_exec('set spell'))
end)
it('errors out when SAL section contains NUL byte', function()
api.nvim_set_option_value('runtimepath', testdir, {})
-- stylua: ignore
write_file(testdir .. '/spell/en.ascii.spl',
-- ┌ Section identifier (#SN_SAL)
-- │ ┌ Section flags (#SNF_REQUIRED or zero)
-- │ │ ┌ Section length (4 bytes, MSB first)
spellheader .. '\005\001\000\000\000\008'
-- ┌ salflags
-- │ ┌ salcount (2 bytes, MSB first)
-- │ │ ┌ salfromlen (1 byte)
-- │ │ │ ┌ Special character
-- │ │ │ │┌ salfrom (should not contain NUL)
-- │ │ │ ││ ┌ saltolen
-- │ │ │ ││ │ ┌ salto
-- │ │ │ ││ │ │┌ End of sections marker
.. '\000\000\001\0024\000\0017\255'
-- ┌ LWORDTREE tree length (4 bytes)
-- │ ┌ KWORDTREE tree length (4 bytes)
-- │ │ ┌ PREFIXTREE tree length
.. '\000\000\000\000\000\000\000\000\000\000\000\000')
api.nvim_set_option_value('spelllang', 'en', {})
eq('Vim(set):E759: Format error in spell file', exc_exec('set spell'))
end)
it('errors out when spell header contains NUL bytes', function()
api.nvim_set_option_value('runtimepath', testdir, {})
write_file(testdir .. '/spell/en.ascii.spl', spellheader:sub(1, -3) .. '\000\000')
api.nvim_set_option_value('spelllang', 'en', {})
eq('Vim(set):E757: This does not look like a spell file', exc_exec('set spell'))
end)
it('can be set to a relative path', function()
local fname = testdir .. '/spell/spell.add'
api.nvim_set_option_value('spellfile', fname, {})
end)
it('can be set to an absolute path', function()
local fname = fn.fnamemodify(testdir .. '/spell/spell.add', ':p')
api.nvim_set_option_value('spellfile', fname, {})
end)
describe('default location', function()
it("is stdpath('data')/spell/en.utf-8.add", function()
n.command('set spell')
n.insert('abc')
n.feed('zg')
eq(
t.fix_slashes(fn.stdpath('data') .. '/spell/en.utf-8.add'),
t.fix_slashes(api.nvim_get_option_value('spellfile', {}))
)
end)
it("is not set if stdpath('data') is not writable", function()
n.command('set spell')
fn.writefile({ '' }, testdir .. '/xdg_data')
n.insert('abc')
eq("Vim(normal):E764: Option 'spellfile' is not set", exc_exec('normal! zg'))
end)
it("is not set if 'spelllang' is not set", function()
n.command('set spell spelllang=')
n.insert('abc')
eq("Vim(normal):E764: Option 'spellfile' is not set", exc_exec('normal! zg'))
end)
end)
end)
|