executable_spec.lua 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. local helpers = require('test.functional.helpers')(after_each)
  2. local eq, clear, call, iswin, write_file, command =
  3. helpers.eq, helpers.clear, helpers.call, helpers.iswin, helpers.write_file,
  4. helpers.command
  5. local exc_exec = helpers.exc_exec
  6. local eval = helpers.eval
  7. describe('executable()', function()
  8. before_each(clear)
  9. it('returns 1 for commands in $PATH', function()
  10. local exe = iswin() and 'ping' or 'ls'
  11. eq(1, call('executable', exe))
  12. command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
  13. eq(1, call('executable', 'null'))
  14. eq(1, call('executable', 'true'))
  15. eq(1, call('executable', 'false'))
  16. end)
  17. it('fails for invalid values', function()
  18. for _, input in ipairs({'v:null', 'v:true', 'v:false', '{}', '[]'}) do
  19. eq('Vim(call):E928: String required', exc_exec('call executable('..input..')'))
  20. end
  21. command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
  22. for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do
  23. eq('Vim(call):E928: String required', exc_exec('call executable('..input..')'))
  24. end
  25. end)
  26. it('returns 0 for empty strings', function()
  27. eq(0, call('executable', '""'))
  28. end)
  29. it('returns 0 for non-existent files', function()
  30. eq(0, call('executable', 'no_such_file_exists_209ufq23f'))
  31. end)
  32. it('sibling to nvim binary', function()
  33. -- Some executable in build/bin/, *not* in $PATH nor CWD.
  34. local sibling_exe = 'printargs-test'
  35. -- Windows: siblings are in Nvim's "pseudo-$PATH".
  36. local expected = iswin() and 1 or 0
  37. if iswin() then
  38. eq('arg1=lemon;arg2=sky;arg3=tree;',
  39. call('system', sibling_exe..' lemon sky tree'))
  40. end
  41. eq(expected, call('executable', sibling_exe))
  42. end)
  43. describe('exec-bit', function()
  44. setup(function()
  45. clear()
  46. write_file('Xtest_not_executable', 'non-executable file')
  47. write_file('Xtest_executable', 'executable file (exec-bit set)')
  48. if not iswin() then -- N/A for Windows.
  49. call('system', {'chmod', '-x', 'Xtest_not_executable'})
  50. call('system', {'chmod', '+x', 'Xtest_executable'})
  51. end
  52. end)
  53. teardown(function()
  54. os.remove('Xtest_not_executable')
  55. os.remove('Xtest_executable')
  56. end)
  57. it('not set', function()
  58. eq(0, call('executable', 'Xtest_not_executable'))
  59. eq(0, call('executable', './Xtest_not_executable'))
  60. end)
  61. it('set, unqualified and not in $PATH', function()
  62. eq(0, call('executable', 'Xtest_executable'))
  63. end)
  64. it('set, qualified as a path', function()
  65. local expected = iswin() and 0 or 1
  66. eq(expected, call('executable', './Xtest_executable'))
  67. end)
  68. end)
  69. end)
  70. describe('executable() (Windows)', function()
  71. if not iswin() then return end -- N/A for Unix.
  72. local exts = {'bat', 'exe', 'com', 'cmd'}
  73. setup(function()
  74. for _, ext in ipairs(exts) do
  75. write_file('test_executable_'..ext..'.'..ext, '')
  76. end
  77. write_file('test_executable_zzz.zzz', '')
  78. end)
  79. teardown(function()
  80. for _, ext in ipairs(exts) do
  81. os.remove('test_executable_'..ext..'.'..ext)
  82. end
  83. os.remove('test_executable_zzz.zzz')
  84. end)
  85. it('tries default extensions on a filename if $PATHEXT is empty', function()
  86. -- Empty $PATHEXT defaults to ".com;.exe;.bat;.cmd".
  87. clear({env={PATHEXT=''}})
  88. for _,ext in ipairs(exts) do
  89. eq(1, call('executable', 'test_executable_'..ext))
  90. end
  91. eq(0, call('executable', 'test_executable_zzz'))
  92. end)
  93. it('tries default extensions on a filepath if $PATHEXT is empty', function()
  94. -- Empty $PATHEXT defaults to ".com;.exe;.bat;.cmd".
  95. clear({env={PATHEXT=''}})
  96. for _,ext in ipairs(exts) do
  97. eq(1, call('executable', '.\\test_executable_'..ext))
  98. end
  99. eq(0, call('executable', '.\\test_executable_zzz'))
  100. end)
  101. it('system([…]), jobstart([…]) use $PATHEXT #9569', function()
  102. -- Invoking `cmdscript` should find/execute `cmdscript.cmd`.
  103. eq('much success\n', call('system', {'test/functional/fixtures/cmdscript'}))
  104. assert(0 < call('jobstart', {'test/functional/fixtures/cmdscript'}))
  105. end)
  106. it('full path with extension', function()
  107. -- Some executable we can expect in the test env.
  108. local exe = 'printargs-test'
  109. local exedir = eval("fnamemodify(v:progpath, ':h')")
  110. local exepath = exedir..'/'..exe..'.exe'
  111. eq(1, call('executable', exepath))
  112. eq('arg1=lemon;arg2=sky;arg3=tree;',
  113. call('system', exepath..' lemon sky tree'))
  114. end)
  115. it('full path without extension', function()
  116. -- Some executable we can expect in the test env.
  117. local exe = 'printargs-test'
  118. local exedir = eval("fnamemodify(v:progpath, ':h')")
  119. local exepath = exedir..'/'..exe
  120. eq('arg1=lemon;arg2=sky;arg3=tree;',
  121. call('system', exepath..' lemon sky tree'))
  122. eq(1, call('executable', exepath))
  123. end)
  124. it('respects $PATHEXT when trying extensions on a filename', function()
  125. clear({env={PATHEXT='.zzz'}})
  126. for _,ext in ipairs(exts) do
  127. eq(0, call('executable', 'test_executable_'..ext))
  128. end
  129. eq(1, call('executable', 'test_executable_zzz'))
  130. end)
  131. it('respects $PATHEXT when trying extensions on a filepath', function()
  132. clear({env={PATHEXT='.zzz'}})
  133. for _,ext in ipairs(exts) do
  134. eq(0, call('executable', '.\\test_executable_'..ext))
  135. end
  136. eq(1, call('executable', '.\\test_executable_zzz'))
  137. end)
  138. it("with weird $PATHEXT", function()
  139. clear({env={PATHEXT=';'}})
  140. eq(0, call('executable', '.\\test_executable_zzz'))
  141. clear({env={PATHEXT=';;;.zzz;;'}})
  142. eq(1, call('executable', '.\\test_executable_zzz'))
  143. end)
  144. it("unqualified filename, Unix-style 'shell'", function()
  145. clear({env={PATHEXT=''}})
  146. command('set shell=sh')
  147. for _,ext in ipairs(exts) do
  148. eq(1, call('executable', 'test_executable_'..ext..'.'..ext))
  149. end
  150. eq(1, call('executable', 'test_executable_zzz.zzz'))
  151. end)
  152. it("relative path, Unix-style 'shell' (backslashes)", function()
  153. clear({env={PATHEXT=''}})
  154. command('set shell=bash.exe')
  155. for _,ext in ipairs(exts) do
  156. eq(1, call('executable', '.\\test_executable_'..ext..'.'..ext))
  157. eq(1, call('executable', './test_executable_'..ext..'.'..ext))
  158. end
  159. eq(1, call('executable', '.\\test_executable_zzz.zzz'))
  160. eq(1, call('executable', './test_executable_zzz.zzz'))
  161. end)
  162. it('unqualified filename, $PATHEXT contains dot', function()
  163. clear({env={PATHEXT='.;.zzz'}})
  164. for _,ext in ipairs(exts) do
  165. eq(1, call('executable', 'test_executable_'..ext..'.'..ext))
  166. end
  167. eq(1, call('executable', 'test_executable_zzz.zzz'))
  168. clear({env={PATHEXT='.zzz;.'}})
  169. for _,ext in ipairs(exts) do
  170. eq(1, call('executable', 'test_executable_'..ext..'.'..ext))
  171. end
  172. eq(1, call('executable', 'test_executable_zzz.zzz'))
  173. end)
  174. it('relative path, $PATHEXT contains dot (backslashes)', function()
  175. clear({env={PATHEXT='.;.zzz'}})
  176. for _,ext in ipairs(exts) do
  177. eq(1, call('executable', '.\\test_executable_'..ext..'.'..ext))
  178. eq(1, call('executable', './test_executable_'..ext..'.'..ext))
  179. end
  180. eq(1, call('executable', '.\\test_executable_zzz.zzz'))
  181. eq(1, call('executable', './test_executable_zzz.zzz'))
  182. end)
  183. it('ignores case of extension', function()
  184. clear({env={PATHEXT='.ZZZ'}})
  185. eq(1, call('executable', 'test_executable_zzz.zzz'))
  186. end)
  187. it('relative path does not search $PATH', function()
  188. clear({env={PATHEXT=''}})
  189. eq(0, call('executable', './System32/notepad.exe'))
  190. eq(0, call('executable', '.\\System32\\notepad.exe'))
  191. eq(0, call('executable', '../notepad.exe'))
  192. eq(0, call('executable', '..\\notepad.exe'))
  193. end)
  194. end)