aboutsummaryrefslogtreecommitdiff
path: root/test/unit/os/fs.moon
blob: 44dd3a123ea4bd5ca54ce98268fbb2d29f8b411f (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
323
324
325
326
327
328
329
330
331
332
333
{:cimport, :cppimport, :internalize, :eq, :neq, :ffi, :lib, :cstr, :to_cstr} = require 'test.unit.helpers'
require 'lfs'
require 'bit'

-- fs = cimport './src/os/os.h'
-- remove these statements once 'cimport' is working properly for misc1.h
fs = lib
ffi.cdef [[
enum OKFAIL {
  OK = 1, FAIL = 0
};
enum BOOLEAN {
  TRUE = 1, FALSE = 0
};
int os_dirname(char_u *buf, int len);
int os_isdir(char_u * name);
int is_executable(char_u *name);
int os_can_exe(char_u *name);
int32_t os_getperm(char_u *name);
int os_setperm(char_u *name, long perm);
int os_file_exists(const char_u *name);
]]

-- import constants parsed by ffi
{:OK, :FAIL} = lib
{:TRUE, :FALSE} = lib

cppimport 'sys/stat.h'

describe 'fs function', ->
  setup ->
    lfs.mkdir 'unit-test-directory'
    (io.open 'unit-test-directory/test.file', 'w').close!

    -- Since the tests are executed, they are called by an executable. We use
    -- that executable for several asserts.
    export absolute_executable = arg[0]

    -- Split absolute_executable into a directory and the actual file name for
    -- later usage.
    export directory, executable_name = string.match(absolute_executable, '^(.*)/(.*)$')

  teardown ->
    os.remove 'unit-test-directory/test.file'
    lfs.rmdir 'unit-test-directory'

  describe 'os_dirname', ->
    os_dirname = (buf, len) ->
      fs.os_dirname buf, len

    before_each ->
      export len = (string.len lfs.currentdir!) + 1
      export buf = cstr len, ''

    it 'returns OK and writes current directory into the buffer if it is large
    enough', ->
      eq OK, (os_dirname buf, len)
      eq lfs.currentdir!, (ffi.string buf)

    -- What kind of other failing cases are possible?
    it 'returns FAIL if the buffer is too small', ->
      buf = cstr (len-1), ''
      eq FAIL, (os_dirname buf, (len-1))

  describe 'os_full_dir_name', ->
    ffi.cdef 'int os_full_dir_name(char *directory, char *buffer, int len);'

    os_full_dir_name = (directory, buffer, len) ->
      directory = to_cstr directory
      fs.os_full_dir_name directory, buffer, len

    before_each ->
      -- Create empty string buffer which will contain the resulting path.
      export len = (string.len lfs.currentdir!) + 22
      export buffer = cstr len, ''

    it 'returns the absolute directory name of a given relative one', ->
      result = os_full_dir_name '..', buffer, len
      eq OK, result
      old_dir = lfs.currentdir!
      lfs.chdir '..'
      expected = lfs.currentdir!
      lfs.chdir old_dir
      eq expected, (ffi.string buffer)

    it 'returns the current directory name if the given string is empty', ->
      eq OK, (os_full_dir_name '', buffer, len)
      eq lfs.currentdir!, (ffi.string buffer)

    it 'fails if the given directory does not exist', ->
      eq FAIL, os_full_dir_name('does_not_exist', buffer, len)

    it 'works with a normal relative dir', ->
      result = os_full_dir_name('unit-test-directory', buffer, len)
      eq lfs.currentdir! .. '/unit-test-directory', (ffi.string buffer)
      eq OK, result

  describe 'os_get_absolute_path', ->
    ffi.cdef 'int os_get_absolute_path(char *fname, char *buf, int len, int force);'

    os_get_absolute_path = (filename, buffer, length, force) ->
      filename = to_cstr filename
      fs.os_get_absolute_path filename, buffer, length, force

    before_each ->
      -- Create empty string buffer which will contain the resulting path.
      export len = (string.len lfs.currentdir!) + 33
      export buffer = cstr len, ''

    it 'fails if given filename contains non-existing directory', ->
      force_expansion = 1
      result = os_get_absolute_path 'non_existing_dir/test.file', buffer, len, force_expansion
      eq FAIL, result

    it 'concatenates given filename if it does not contain a slash', ->
      force_expansion = 1
      result = os_get_absolute_path 'test.file', buffer, len, force_expansion
      expected = lfs.currentdir! .. '/test.file'
      eq expected, (ffi.string buffer)
      eq OK, result

    it 'concatenates given filename if it is a directory but does not contain a
    slash', ->
      force_expansion = 1
      result = os_get_absolute_path '..', buffer, len, force_expansion
      expected = lfs.currentdir! .. '/..'
      eq expected, (ffi.string buffer)
      eq OK, result

    -- Is it possible for every developer to enter '..' directory while running
    -- the unit tests? Which other directory would be better?
    it 'enters given directory (instead of just concatenating the strings) if
    possible and if path contains a slash', ->
      force_expansion = 1
      result = os_get_absolute_path '../test.file', buffer, len, force_expansion
      old_dir = lfs.currentdir!
      lfs.chdir '..'
      expected = lfs.currentdir! .. '/test.file'
      lfs.chdir old_dir
      eq expected, (ffi.string buffer)
      eq OK, result

    it 'just copies the path if it is already absolute and force=0', ->
      force_expansion = 0
      absolute_path = '/absolute/path'
      result = os_get_absolute_path absolute_path, buffer, len, force_expansion
      eq absolute_path, (ffi.string buffer)
      eq OK, result

    it 'fails when the path is relative to HOME', ->
      force_expansion = 1
      absolute_path = '~/home.file'
      result = os_get_absolute_path absolute_path, buffer, len, force_expansion
      eq FAIL, result

    it 'works with some "normal" relative path with directories', ->
      force_expansion = 1
      result = os_get_absolute_path 'unit-test-directory/test.file', buffer, len, force_expansion
      eq OK, result
      eq lfs.currentdir! .. '/unit-test-directory/test.file', (ffi.string buffer)

    it 'does not modify the given filename', ->
      force_expansion = 1
      filename = to_cstr 'unit-test-directory/test.file'
      -- Don't use the wrapper here but pass a cstring directly to the c
      -- function.
      result = fs.os_get_absolute_path filename, buffer, len, force_expansion
      eq lfs.currentdir! .. '/unit-test-directory/test.file', (ffi.string buffer)
      eq 'unit-test-directory/test.file', (ffi.string filename)
      eq OK, result

  describe 'append_path', ->
    ffi.cdef 'int append_path(char *path, char *to_append, int max_len);'

    it 'joins given paths with a slash', ->
     path = cstr 100, 'path1'
     to_append = to_cstr 'path2'
     eq OK, (fs.append_path path, to_append, 100)
     eq "path1/path2", (ffi.string path)

    it 'joins given paths without adding an unnecessary slash', ->
     path = cstr 100, 'path1/'
     to_append = to_cstr 'path2'
     eq OK, fs.append_path path, to_append, 100
     eq "path1/path2", (ffi.string path)

    it 'fails if there is not enough space left for to_append', ->
      path = cstr 11, 'path1/'
      to_append = to_cstr 'path2'
      eq FAIL, (fs.append_path path, to_append, 11)

    it 'does not append a slash if to_append is empty', ->
      path = cstr 6, 'path1'
      to_append = to_cstr ''
      eq OK, (fs.append_path path, to_append, 6)
      eq 'path1', (ffi.string path)

    it 'does not append unnecessary dots', ->
      path = cstr 6, 'path1'
      to_append = to_cstr '.'
      eq OK, (fs.append_path path, to_append, 6)
      eq 'path1', (ffi.string path)

    it 'copies to_append to path, if path is empty', ->
      path = cstr 7, ''
      to_append = to_cstr '/path2'
      eq OK, (fs.append_path path, to_append, 7)
      eq '/path2', (ffi.string path)

  describe 'os_is_absolute_path', ->
    ffi.cdef 'int os_is_absolute_path(char *fname);'

    os_is_absolute_path = (filename) ->
      filename = to_cstr filename
      fs.os_is_absolute_path filename

    it 'returns true if filename starts with a slash', ->
      eq OK, os_is_absolute_path '/some/directory/'

    it 'returns true if filename starts with a tilde', ->
      eq OK, os_is_absolute_path '~/in/my/home~/directory'

    it 'returns false if filename starts not with slash nor tilde', ->
      eq FAIL, os_is_absolute_path 'not/in/my/home~/directory'

  describe 'os_isdir', ->
    os_isdir = (name) ->
      fs.os_isdir (to_cstr name)

    it 'returns false if an empty string is given', ->
      eq FALSE, (os_isdir '')

    it 'returns false if a nonexisting directory is given', ->
      eq FALSE, (os_isdir 'non-existing-directory')

    it 'returns false if a nonexisting absolute directory is given', ->
      eq FALSE, (os_isdir '/non-existing-directory')

    it 'returns false if an existing file is given', ->
      eq FALSE, (os_isdir 'unit-test-directory/test.file')

    it 'returns true if the current directory is given', ->
      eq TRUE, (os_isdir '.')

    it 'returns true if the parent directory is given', ->
      eq TRUE, (os_isdir '..')

    it 'returns true if an arbitrary directory is given', ->
      eq TRUE, (os_isdir 'unit-test-directory')

    it 'returns true if an absolute directory is given', ->
      eq TRUE, (os_isdir directory)

  describe 'os_can_exe', ->
    os_can_exe = (name) ->
      fs.os_can_exe (to_cstr name)

    it 'returns false when given a directory', ->
      eq FALSE, (os_can_exe './unit-test-directory')

    it 'returns false when given a regular file without executable bit set', ->
      eq FALSE, (os_can_exe 'unit-test-directory/test.file')

    it 'returns false when the given file does not exists', ->
      eq FALSE, (os_can_exe 'does-not-exist.file')

    it 'returns true when given an executable inside $PATH', ->
      eq TRUE, (os_can_exe executable_name)

    it 'returns true when given an executable relative to the current dir', ->
      old_dir = lfs.currentdir!
      lfs.chdir directory
      relative_executable = './' .. executable_name
      eq TRUE, (os_can_exe relative_executable)
      lfs.chdir old_dir

  describe 'file permissions', ->
    os_getperm = (filename) ->
      perm = fs.os_getperm (to_cstr filename)
      tonumber perm

    os_setperm = (filename, perm) ->
      fs.os_setperm (to_cstr filename), perm

    bit_set = (number, check_bit) ->
      if 0 == (bit.band number, check_bit) then false else true

    set_bit = (number, to_set) ->
      return bit.bor number, to_set

    unset_bit = (number, to_unset) ->
      return bit.band number, (bit.bnot to_unset)

    describe 'os_getperm', ->
      it 'returns -1 when the given file does not exist', ->
        eq -1, (os_getperm 'non-existing-file')

      it 'returns a perm > 0 when given an existing file', -> 
        assert.is_true (os_getperm 'unit-test-directory') > 0

      it 'returns S_IRUSR when the file is readable', ->
        perm = os_getperm 'unit-test-directory'
        assert.is_true (bit_set perm, ffi.C.kS_IRUSR)

    describe 'os_setperm', ->
      it 'can set and unset the executable bit of a file', ->
        perm = os_getperm 'unit-test-directory/test.file'

        perm = unset_bit perm, ffi.C.kS_IXUSR
        eq OK, (os_setperm 'unit-test-directory/test.file', perm)

        perm = os_getperm 'unit-test-directory/test.file'
        assert.is_false (bit_set perm, ffi.C.kS_IXUSR)

        perm = set_bit perm, ffi.C.kS_IXUSR
        eq OK, os_setperm 'unit-test-directory/test.file', perm

        perm = os_getperm 'unit-test-directory/test.file'
        assert.is_true (bit_set perm, ffi.C.kS_IXUSR)

      it 'fails if given file does not exist', ->
        perm = ffi.C.kS_IXUSR
        eq FAIL, (os_setperm 'non-existing-file', perm)

  describe 'os_file_exists', ->
    os_file_exists = (filename) ->
      fs.os_file_exists (to_cstr filename)

    it 'returns FALSE when given a non-existing file', ->
      eq FALSE, (os_file_exists 'non-existing-file')

    it 'returns TRUE when given an existing file', ->
      eq TRUE, (os_file_exists 'unit-test-directory/test.file')