aboutsummaryrefslogtreecommitdiff
path: root/test/unit/undo_spec.lua
blob: 7d2120470720ca8afc718ca5b540c807b5923e0c (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
local lfs = require('lfs')
local helpers = require('test.unit.helpers')

local ffi = helpers.ffi
local cimport = helpers.cimport
local to_cstr = helpers.to_cstr
local neq = helpers.neq
local eq = helpers.eq

cimport('./src/nvim/ex_cmds_defs.h')
cimport('./src/nvim/buffer_defs.h')
local options = cimport('./src/nvim/option_defs.h')
-- TODO: remove: local vim = cimport('./src/nvim/vim.h')
local undo = cimport('./src/nvim/undo.h')
local buffer = cimport('./src/nvim/buffer.h')

local old_p_udir = options.p_udir  -- save the old value of p_udir (undodir)

-- Values expected by tests. Set in the setup function and destroyed in teardown
local file_buffer = nil
local buffer_hash = nil

describe('u_write_undo', function()
  setup(function()
    lfs.mkdir('unit-test-directory')
    lfs.chdir('unit-test-directory')
    options.p_udir = to_cstr(lfs.currentdir())  -- set p_udir to be the test dir
  end)
  
  teardown(function()
    lfs.chdir('..')
    local success, err = lfs.rmdir('unit-test-directory')
    if not success then
      print(err)  -- inform tester if directory fails to delete
    end
    options.p_udir = old_p_udir  --restore old p_udir
  end)

  before_each(function()
    -- create a new buffer
    local c_file = to_cstr('../test/unit/undo_spec.lua')
    file_buffer = buffer.buflist_new(c_file, c_file, 1, buffer.BLN_LISTED)
    file_buffer.b_u_numhead = 1 -- Pretend that the buffer has been changed

    -- TODO(christopher.waldon.dev@gmail.com): replace the 32 with UNDO_HASH_SIZE
    -- requires refactor of UNDO_HASH_SIZE into constant/enum for ffi
    --
    -- compute a hash for this undofile
    buffer_hash = ffi.new('char_u[32]')
    undo.u_compute_hash(buffer_hash)
  end)

  -- Lua wrapper for u_write_undo
  local function u_write_undo(name, forceit, buf, buf_hash)
    if name ~= nil then
      name = to_cstr(name)
    end
  
    return undo.u_write_undo(name, forceit, buf, buf_hash)
  end

  it('writes an undo file to undodir given a buffer and hash', function()
    u_write_undo(nil, false, file_buffer, buffer_hash)
    local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
    local undo_file = io.open(correct_name, "r")
    
    neq(undo_file, nil)
    local success, err = os.remove(correct_name)  -- delete the file now that we're done with it.
    if not success then
      print(err)  -- inform tester if undofile fails to delete
    end
  end)
  
  it('writes a correctly-named undo file to undodir given a name, buffer, and hash', function()
    local correct_name = "undofile.test"
    u_write_undo(correct_name, false, file_buffer, buffer_hash)
    local undo_file = io.open(correct_name, "r")
    
    neq(undo_file, nil)
    local success, err = os.remove(correct_name)  -- delete the file now that we're done with it.
    if not success then
      print(err)  -- inform tester if undofile fails to delete
    end
  end)
  
  it('does not write an undofile when the buffer has no valid undofile name', function()
    -- TODO(christopher.waldon.dev@gmail.com): Figure out how to test this.
    -- it's hard because u_get_undo_file_name() would need to return null
  end)

  it('writes the undofile with the same permissions as the original file', function()
    -- Create Test file and set permissions
    local test_file_name = "./test.file"
    local test_permission_file = io.open(test_file_name, "w")
    test_permission_file:write("testing permissions")
    test_permission_file:close()
    local test_permissions = lfs.attributes(test_file_name).permissions

    -- Create vim buffer
    local c_file = to_cstr(test_file_name)
    file_buffer = buffer.buflist_new(c_file, c_file, 1, buffer.BLN_LISTED)
    file_buffer.b_u_numhead = 1 -- Pretend that the buffer has been changed

    u_write_undo(nil, false, file_buffer, buffer_hash)
    
    -- Find out the correct name of the undofile
    local undo_file_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))

    -- Find out the permissions of the new file
    local permissions = lfs.attributes(undo_file_name).permissions
    eq(test_permissions, permissions)

    -- delete the file now that we're done with it.
    local success, err = os.remove(test_file_name)
    if not success then
      print(err)  -- inform tester if undofile fails to delete
    end
    success, err = os.remove(undo_file_name)
    if not success then
      print(err)  -- inform tester if undofile fails to delete
    end
  end)

  it('writes an undofile only readable by the user if the buffer is unnamed', function()
    local correct_permissions = "rw-------"
    local undo_file_name = "test.undo"
  
    -- Create vim buffer
    file_buffer = buffer.buflist_new(nil, nil, 1, buffer.BLN_LISTED)
    file_buffer.b_u_numhead = 1 -- Pretend that the buffer has been changed

    u_write_undo(undo_file_name, false, file_buffer, buffer_hash)
    
    -- Find out the permissions of the new file
    local permissions = lfs.attributes(undo_file_name).permissions
    eq(correct_permissions, permissions)

    -- delete the file now that we're done with it.
    local success, err = os.remove(undo_file_name)
    if not success then
      print(err)  -- inform tester if undofile fails to delete
    end
  end)

  it('forces writing undo file for :wundo! command', function()
    local file_contents = "testing permissions"
    -- Write a text file where the undofile should go
    local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
    local text_file, err = io.open(correct_name, "w")
    if err then
      pending()
    end
    text_file:write(file_contents)
    text_file:close()

    u_write_undo(nil, true, file_buffer, buffer_hash)  -- Call with forceit flag enabled

    local undo_file, undo_file_err = io.open(correct_name, "r")
    if undo_file_err then
      pending()
    end
    local undo_file_contents = undo_file:read("*a")  -- Read all

    neq(file_contents, undo_file_contents)
    local success, deletion_err = os.remove(correct_name)  -- delete the file now that we're done with it.
    if not success then
      print(deletion_err)  -- inform tester if undofile fails to delete
    end
  end)

  it('overwrites an existing undo file', function()
    u_write_undo(nil, false, file_buffer, buffer_hash)
    local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
    
    local file_last_modified = lfs.attributes(correct_name).modification

    os.execute('sleep 1s')  -- Ensure there will be some difference in timestamps
    file_buffer.b_u_numhead = 1  -- Mark it as if there are changes
    u_write_undo(nil, false, file_buffer, buffer_hash)

    local file_last_modified_2 = lfs.attributes(correct_name).modification
    
    -- print(file_last_modified, file_last_modified_2)
    neq(file_last_modified, file_last_modified_2)
    local success, err = os.remove(correct_name)  -- delete the file now that we're done with it.
    if not success then
      print(err)  -- inform tester if undofile fails to delete
    end
  end)
  
  it('does not overwrite an existing file that is not an undo file', function()
    -- TODO: write test
  end)
  
  it('does not overwrite an existing file that has the wrong permissions', function()
    -- TODO: write test
  end)
  
  it('does not write an undo file if there is no undo information for the buffer', function()
    file_buffer.b_u_numhead = 0  -- Mark it as if there is no undo information
    local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))

    local existing_file = io.open(correct_name,"r")
    if existing_file then
      existing_file:close()
      os.remove(correct_name)
    end
    u_write_undo(nil, false, file_buffer, buffer_hash)
    local undo_file = io.open(correct_name, "r")
    
    eq(undo_file, nil)
  end)
end)