neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

uv_spec.lua (7578B)


      1 -- Test suite for testing interactions with API bindings
      2 local t = require('test.testutil')
      3 local n = require('test.functional.testnvim')()
      4 local Screen = require('test.functional.ui.screen')
      5 
      6 local fn = n.fn
      7 local api = n.api
      8 local clear = n.clear
      9 local sleep = vim.uv.sleep
     10 local feed = n.feed
     11 local eq = t.eq
     12 local eval = n.eval
     13 local matches = t.matches
     14 local exec_lua = n.exec_lua
     15 local retry = t.retry
     16 
     17 before_each(clear)
     18 
     19 describe('vim.uv', function()
     20  it('version', function()
     21    assert(fn.luaeval('vim.uv.version()') >= 72961, 'libuv version too old')
     22    matches('(%d+)%.(%d+)%.(%d+)', fn.luaeval('vim.uv.version_string()'))
     23  end)
     24 
     25  it('timer', function()
     26    exec_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {})
     27 
     28    local code = function()
     29      local touch = 0
     30      local function wait(ms)
     31        local this = coroutine.running()
     32        assert(this)
     33        local timer = assert(vim.uv.new_timer())
     34        timer:start(
     35          ms,
     36          0,
     37          vim.schedule_wrap(function()
     38            timer:close()
     39            touch = touch + 1
     40            coroutine.resume(this)
     41            touch = touch + 1
     42            assert(touch == 3)
     43            vim.api.nvim_set_var('coroutine_cnt_1', touch)
     44          end)
     45        )
     46        coroutine.yield()
     47        touch = touch + 1
     48        return touch
     49      end
     50      coroutine.wrap(function()
     51        local touched = wait(10)
     52        assert(touched == touch)
     53        vim.api.nvim_set_var('coroutine_cnt', touched)
     54      end)()
     55    end
     56 
     57    eq(0, api.nvim_get_var('coroutine_cnt'))
     58    exec_lua(code)
     59    retry(2, nil, function()
     60      sleep(50)
     61      eq(2, api.nvim_get_var('coroutine_cnt'))
     62    end)
     63    eq(3, api.nvim_get_var('coroutine_cnt_1'))
     64  end)
     65 
     66  it('is API safe', function()
     67    local screen = Screen.new(50, 10)
     68    screen:set_default_attr_ids({
     69      [1] = { bold = true, foreground = Screen.colors.Blue1 },
     70      [2] = { bold = true, reverse = true },
     71      [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
     72      [4] = { bold = true, foreground = Screen.colors.SeaGreen4 },
     73      [5] = { bold = true },
     74    })
     75 
     76    -- deferred API functions are disabled, as their safety can't be guaranteed
     77    exec_lua([[
     78      local timer = vim.uv.new_timer()
     79      timer:start(20, 0, function ()
     80        _G.is_fast = vim.in_fast_event()
     81        timer:close()
     82        vim.api.nvim_set_var("valid", true)
     83        vim.api.nvim_command("echomsg 'howdy'")
     84      end)
     85    ]])
     86 
     87    screen:expect([[
     88                                                        |
     89      {2:                                                  }|
     90      {3:Lua callback:}                                     |
     91      {3:[string "<nvim>"]:5: E5560: nvim_set_var must not }|
     92      {3:be called in a fast event context}                 |
     93      {3:stack traceback:}                                  |
     94      {3:        [C]: in function 'nvim_set_var'}           |
     95      {3:        [string "<nvim>"]:5: in function <[string }|
     96      {3:"<nvim>"]:2>}                                      |
     97      {4:Press ENTER or type command to continue}^           |
     98    ]])
     99    feed('<cr>')
    100    eq(false, eval("get(g:, 'valid', v:false)"))
    101    eq(true, exec_lua('return _G.is_fast'))
    102 
    103    -- callbacks can be scheduled to be executed in the main event loop
    104    -- where the entire API is available
    105    exec_lua(function()
    106      local timer = assert(vim.uv.new_timer())
    107      timer:start(
    108        20,
    109        0,
    110        vim.schedule_wrap(function()
    111          _G.is_fast = vim.in_fast_event()
    112          timer:close()
    113          vim.api.nvim_set_var('valid', true)
    114          vim.api.nvim_command("echomsg 'howdy'")
    115        end)
    116      )
    117    end)
    118 
    119    screen:expect([[
    120      ^                                                  |
    121      {1:~                                                 }|*8
    122      howdy                                             |
    123    ]])
    124    eq(true, eval("get(g:, 'valid', v:false)"))
    125    eq(false, exec_lua('return _G.is_fast'))
    126 
    127    -- fast (not deferred) API functions are allowed to be called directly
    128    exec_lua(function()
    129      local timer = assert(vim.uv.new_timer())
    130      timer:start(20, 0, function()
    131        timer:close()
    132        -- input is queued for processing after the callback returns
    133        vim.api.nvim_input('isneaky')
    134        _G.mode = vim.api.nvim_get_mode()
    135      end)
    136    end)
    137    screen:expect([[
    138      sneaky^                                            |
    139      {1:~                                                 }|*8
    140      {5:-- INSERT --}                                      |
    141    ]])
    142    eq({ blocking = false, mode = 'n' }, exec_lua('return _G.mode'))
    143 
    144    exec_lua(function()
    145      local timer = assert(vim.uv.new_timer())
    146      timer:start(20, 0, function()
    147        _G.is_fast = vim.in_fast_event()
    148        timer:close()
    149        _G.value = vim.fn.has('nvim-0.5')
    150        _G.unvalue = vim.fn.has('python3')
    151      end)
    152    end)
    153 
    154    screen:expect({ any = [[{3:Vim:E5560: Vimscript function must not be called i}]] })
    155    feed('<cr>')
    156    eq({ 1, nil }, exec_lua('return {_G.value, _G.unvalue}'))
    157  end)
    158 
    159  it("is equal to require('luv')", function()
    160    eq(true, exec_lua("return vim.uv == require('luv')"))
    161  end)
    162 
    163  it('non-string error() #32595', function()
    164    local screen = Screen.new(50, 10)
    165    exec_lua(function()
    166      local timer = assert(vim.uv.new_timer())
    167      timer:start(0, 0, function()
    168        timer:close()
    169        error(nil)
    170      end)
    171    end)
    172    local s = [[
    173                                                        |
    174      {1:~                                                 }|*5
    175      {3:                                                  }|
    176      {9:Lua callback:}                                     |
    177      {9:[NULL]}                                            |
    178      {6:Press ENTER or type command to continue}^           |
    179    ]]
    180    screen:expect(s)
    181    feed('<cr>')
    182    n.assert_alive()
    183    screen:expect([[
    184      ^                                                  |
    185      {1:~                                                 }|*8
    186                                                        |
    187    ]])
    188    exec_lua(function()
    189      vim.uv.fs_stat('non-existent-file', function()
    190        error(nil)
    191      end)
    192    end)
    193    screen:expect(s)
    194    feed('<cr>')
    195    n.assert_alive()
    196  end)
    197 
    198  it("doesn't crash on async callbacks throwing nil error", function()
    199    local screen = Screen.new(50, 4)
    200 
    201    exec_lua(function()
    202      _G.idle = vim.uv.new_idle()
    203      _G.idle:start(function()
    204        _G.idle:stop()
    205        error()
    206      end)
    207    end)
    208 
    209    screen:expect([[
    210      {3:                                                  }|
    211      {9:Lua callback:}                                     |
    212      {9:[NULL]}                                            |
    213      {6:Press ENTER or type command to continue}^           |
    214    ]])
    215    feed('<cr>')
    216 
    217    exec_lua(function()
    218      _G.idle:close()
    219    end)
    220  end)
    221 
    222  it("doesn't crash on async callbacks throwing object as an error", function()
    223    local screen = Screen.new(50, 4)
    224 
    225    exec_lua(function()
    226      _G.idle = vim.uv.new_idle()
    227      _G.idle:start(function()
    228        _G.idle:stop()
    229        error(_G.idle) -- userdata with __tostring method
    230      end)
    231    end)
    232 
    233    screen:expect([[
    234      {3:                                                  }|
    235      {9:Lua callback:}                                     |
    236      {9:uv_idle_t: 0x{MATCH:%w+}}{MATCH: +}|
    237      {6:Press ENTER or type command to continue}^           |
    238    ]])
    239    feed('<cr>')
    240 
    241    exec_lua(function()
    242      _G.idle:close()
    243    end)
    244  end)
    245 end)