aboutsummaryrefslogtreecommitdiff
path: root/test/functional/ex_cmds/cd_spec.lua
blob: 0f95f2aca454f28080ef2b15e86888ce1b31aacc (plain) (blame)
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
-- Specs for :cd, :tcd, :lcd and getcwd()

local t = require('test.testutil')
local n = require('test.functional.testnvim')()

local eq = t.eq
local call = n.call
local clear = n.clear
local command = n.command
local exc_exec = n.exc_exec
local pathsep = n.get_pathsep()
local skip = t.skip
local is_os = t.is_os
local mkdir = t.mkdir

-- These directories will be created for testing
local directories = {
  tab = 'Xtest-functional-ex_cmds-cd_spec.tab', -- Tab
  window = 'Xtest-functional-ex_cmds-cd_spec.window', -- Window
  global = 'Xtest-functional-ex_cmds-cd_spec.global', -- New global
}

-- Shorthand writing to get the current working directory
local cwd = function(...)
  return call('getcwd', ...)
end -- effective working dir
local wcwd = function()
  return cwd(0)
end -- window dir
local tcwd = function()
  return cwd(-1, 0)
end -- tab dir

-- Same, except these tell us if there is a working directory at all
local lwd = function(...)
  return call('haslocaldir', ...)
end -- effective working dir
local wlwd = function()
  return lwd(0)
end -- window dir
local tlwd = function()
  return lwd(-1, 0)
end -- tab dir
--local glwd = function() return eval('haslocaldir(-1, -1)') end  -- global dir

-- Test both the `cd` and `chdir` variants
for _, cmd in ipairs { 'cd', 'chdir' } do
  describe(':' .. cmd, function()
    before_each(function()
      clear()
      for _, d in pairs(directories) do
        mkdir(d)
      end
      directories.start = cwd()
    end)

    after_each(function()
      for _, d in pairs(directories) do
        vim.uv.fs_rmdir(d)
      end
    end)

    describe('using explicit scope', function()
      it('for window', function()
        local globalDir = directories.start
        local globalwin = call('winnr')
        local tabnr = call('tabpagenr')

        -- Everything matches globalDir to start
        eq(globalDir, cwd(globalwin))
        eq(globalDir, cwd(globalwin, tabnr))
        eq(0, lwd(globalwin))
        eq(0, lwd(globalwin, tabnr))

        command('bot split')
        local localwin = call('winnr')
        -- Initial window is still using globalDir
        eq(globalDir, cwd(localwin))
        eq(globalDir, cwd(localwin, tabnr))
        eq(0, lwd(globalwin))
        eq(0, lwd(globalwin, tabnr))

        command('silent l' .. cmd .. ' ' .. directories.window)
        -- From window with local dir, the original window
        -- is still reporting the global dir
        eq(globalDir, cwd(globalwin))
        eq(globalDir, cwd(globalwin, tabnr))
        eq(0, lwd(globalwin))
        eq(0, lwd(globalwin, tabnr))

        -- Window with local dir reports as such
        eq(globalDir .. pathsep .. directories.window, cwd(localwin))
        eq(globalDir .. pathsep .. directories.window, cwd(localwin, tabnr))
        eq(1, lwd(localwin))
        eq(1, lwd(localwin, tabnr))

        command('tabnew')
        -- From new tab page, original window reports global dir
        eq(globalDir, cwd(globalwin, tabnr))
        eq(0, lwd(globalwin, tabnr))

        -- From new tab page, local window reports as such
        eq(globalDir .. pathsep .. directories.window, cwd(localwin, tabnr))
        eq(1, lwd(localwin, tabnr))
      end)

      it('for tab page', function()
        local globalDir = directories.start
        local globaltab = call('tabpagenr')

        -- Everything matches globalDir to start
        eq(globalDir, cwd(-1, 0))
        eq(globalDir, cwd(-1, globaltab))
        eq(0, lwd(-1, 0))
        eq(0, lwd(-1, globaltab))

        command('tabnew')
        command('silent t' .. cmd .. ' ' .. directories.tab)
        local localtab = call('tabpagenr')

        -- From local tab page, original tab reports globalDir
        eq(globalDir, cwd(-1, globaltab))
        eq(0, lwd(-1, globaltab))

        -- new tab reports local
        eq(globalDir .. pathsep .. directories.tab, cwd(-1, 0))
        eq(globalDir .. pathsep .. directories.tab, cwd(-1, localtab))
        eq(1, lwd(-1, 0))
        eq(1, lwd(-1, localtab))

        command('tabnext')
        -- From original tab page, local reports as such
        eq(globalDir .. pathsep .. directories.tab, cwd(-1, localtab))
        eq(1, lwd(-1, localtab))
      end)
    end)

    describe('getcwd(-1, -1)', function()
      it('works', function()
        eq(directories.start, cwd(-1, -1))
        eq(0, lwd(-1, -1))
      end)

      it('works with tab-local pwd', function()
        command('silent t' .. cmd .. ' ' .. directories.tab)
        eq(directories.start, cwd(-1, -1))
        eq(0, lwd(-1, -1))
      end)

      it('works with window-local pwd', function()
        command('silent l' .. cmd .. ' ' .. directories.window)
        eq(directories.start, cwd(-1, -1))
        eq(0, lwd(-1, -1))
      end)
    end)

    describe('Local directory gets inherited', function()
      it('by tabs', function()
        local globalDir = directories.start

        -- Create a new tab and change directory
        command('tabnew')
        command('silent t' .. cmd .. ' ' .. directories.tab)
        eq(globalDir .. pathsep .. directories.tab, tcwd())

        -- Create a new tab and verify it has inherited the directory
        command('tabnew')
        eq(globalDir .. pathsep .. directories.tab, tcwd())

        -- Change tab and change back, verify that directories are correct
        command('tabnext')
        eq(globalDir, tcwd())
        command('tabprevious')
        eq(globalDir .. pathsep .. directories.tab, tcwd())
      end)
    end)

    it('works', function()
      local globalDir = directories.start
      -- Create a new tab first and verify that is has the same working dir
      command('tabnew')
      eq(globalDir, cwd())
      eq(globalDir, tcwd()) -- has no tab-local directory
      eq(0, tlwd())
      eq(globalDir, wcwd()) -- has no window-local directory
      eq(0, wlwd())

      -- Change tab-local working directory and verify it is different
      command('silent t' .. cmd .. ' ' .. directories.tab)
      eq(globalDir .. pathsep .. directories.tab, cwd())
      eq(cwd(), tcwd()) -- working directory matches tab directory
      eq(1, tlwd())
      eq(cwd(), wcwd()) -- still no window-directory
      eq(0, wlwd())

      -- Create a new window in this tab to test `:lcd`
      command('new')
      eq(1, tlwd()) -- Still tab-local working directory
      eq(0, wlwd()) -- Still no window-local working directory
      eq(globalDir .. pathsep .. directories.tab, cwd())
      command('silent l' .. cmd .. ' ../' .. directories.window)
      eq(globalDir .. pathsep .. directories.window, cwd())
      eq(globalDir .. pathsep .. directories.tab, tcwd())
      eq(1, wlwd())

      -- Verify the first window still has the tab local directory
      command('wincmd w')
      eq(globalDir .. pathsep .. directories.tab, cwd())
      eq(globalDir .. pathsep .. directories.tab, tcwd())
      eq(0, wlwd()) -- No window-local directory

      -- Change back to initial tab and verify working directory has stayed
      command('tabnext')
      eq(globalDir, cwd())
      eq(0, tlwd())
      eq(0, wlwd())

      -- Verify global changes don't affect local ones
      command('silent ' .. cmd .. ' ' .. directories.global)
      eq(globalDir .. pathsep .. directories.global, cwd())
      command('tabnext')
      eq(globalDir .. pathsep .. directories.tab, cwd())
      eq(globalDir .. pathsep .. directories.tab, tcwd())
      eq(0, wlwd()) -- Still no window-local directory in this window

      -- Unless the global change happened in a tab with local directory
      command('silent ' .. cmd .. ' ..')
      eq(globalDir, cwd())
      eq(0, tlwd())
      eq(0, wlwd())
      -- Which also affects the first tab
      command('tabnext')
      eq(globalDir, cwd())

      -- But not in a window with its own local directory
      command('tabnext | wincmd w')
      eq(globalDir .. pathsep .. directories.window, cwd())
      eq(0, tlwd())
      eq(globalDir .. pathsep .. directories.window, wcwd())
    end)
  end)
end

-- Test legal parameters for 'getcwd' and 'haslocaldir'
for _, cmd in ipairs { 'getcwd', 'haslocaldir' } do
  describe(cmd .. '()', function()
    before_each(function()
      clear()
    end)

    -- Test invalid argument types
    local err474 = 'Vim(call):E474: Invalid argument'
    it('fails on string', function()
      eq(err474, exc_exec('call ' .. cmd .. '("some string")'))
    end)
    it('fails on float', function()
      eq(err474, exc_exec('call ' .. cmd .. '(1.0)'))
    end)
    it('fails on list', function()
      eq(err474, exc_exec('call ' .. cmd .. '([1, 2])'))
    end)
    it('fails on dictionary', function()
      eq(err474, exc_exec('call ' .. cmd .. '({"key": "value"})'))
    end)
    it('fails on funcref', function()
      eq(err474, exc_exec('call ' .. cmd .. '(function("tr"))'))
    end)

    -- Test invalid numbers
    it('fails on number less than -1', function()
      eq(err474, exc_exec('call ' .. cmd .. '(-2)'))
    end)
    local err5001 = 'Vim(call):E5001: Higher scope cannot be -1 if lower scope is >= 0.'
    it('fails on -1 if previous arg is >=0', function()
      eq(err5001, exc_exec('call ' .. cmd .. '(0, -1)'))
    end)

    -- Test wrong number of arguments
    local err118 = 'Vim(call):E118: Too many arguments for function: ' .. cmd
    it('fails to parse more than one argument', function()
      eq(err118, exc_exec('call ' .. cmd .. '(0, 0, 0)'))
    end)
  end)
end

describe('getcwd()', function()
  before_each(function()
    clear()
    mkdir(directories.global)
  end)

  after_each(function()
    n.rmdir(directories.global)
  end)

  it('returns empty string if working directory does not exist', function()
    skip(is_os('win'))
    command('cd ' .. directories.global)
    command("call delete('../" .. directories.global .. "', 'd')")
    eq('', n.eval('getcwd()'))
  end)

  it("works with 'autochdir' after local directory was set (#9892)", function()
    local curdir = cwd()
    command('lcd ' .. directories.global)
    command('lcd -')
    command('set autochdir')
    command('edit ' .. directories.global .. '/foo')
    eq(curdir .. pathsep .. directories.global, cwd())
    eq(curdir, wcwd())
    call('mkdir', 'bar')
    command('edit ' .. 'bar/foo')
    eq(curdir .. pathsep .. directories.global .. pathsep .. 'bar', cwd())
    eq(curdir, wcwd())
    command('lcd ..')
    eq(curdir .. pathsep .. directories.global, cwd())
    eq(curdir .. pathsep .. directories.global, wcwd())
    command('edit')
    eq(curdir .. pathsep .. directories.global .. pathsep .. 'bar', cwd())
    eq(curdir .. pathsep .. directories.global, wcwd())
  end)
end)