neovim

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

health_spec.lua (17657B)


      1 local t = require('test.testutil')
      2 local n = require('test.functional.testnvim')()
      3 local Screen = require('test.functional.ui.screen')
      4 
      5 local clear = n.clear
      6 local curbuf_contents = n.curbuf_contents
      7 local command = n.command
      8 local eq, matches = t.eq, t.matches
      9 local getcompletion = n.fn.getcompletion
     10 local insert = n.insert
     11 local exec_lua = n.exec_lua
     12 local source = n.source
     13 local assert_alive = n.assert_alive
     14 local fn = n.fn
     15 local api = n.api
     16 
     17 describe(':checkhealth', function()
     18  it('detects invalid $VIMRUNTIME', function()
     19    clear({
     20      env = { VIMRUNTIME = 'bogus' },
     21    })
     22    local status, err = pcall(command, 'checkhealth')
     23    eq(false, status)
     24    eq('Invalid $VIMRUNTIME: bogus', string.match(err, 'Invalid.*'))
     25  end)
     26 
     27  it("detects invalid 'runtimepath'", function()
     28    clear()
     29    command('set runtimepath=bogus')
     30    local status, err = pcall(command, 'checkhealth')
     31    eq(false, status)
     32    eq("Invalid 'runtimepath'", string.match(err, 'Invalid.*'))
     33  end)
     34 
     35  it('detects invalid $VIM', function()
     36    clear()
     37    -- Do this after startup, otherwise it just breaks $VIMRUNTIME.
     38    command("let $VIM='zub'")
     39    command('checkhealth vim.health')
     40    matches('ERROR $VIM .* zub', curbuf_contents())
     41  end)
     42 
     43  it('getcompletion()', function()
     44    clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } }
     45 
     46    eq('vim.deprecated', getcompletion('vim', 'checkhealth')[1])
     47    eq('vim.provider', getcompletion('vim.prov', 'checkhealth')[1])
     48    eq('vim.lsp', getcompletion('vim.ls', 'checkhealth')[1])
     49 
     50    -- "test_plug/health/init.lua" should complete as "test_plug", not "test_plug.health". #30342
     51    eq({
     52      'test_plug',
     53      'test_plug.full_render',
     54      'test_plug.submodule',
     55      'test_plug.submodule_empty',
     56      'test_plug.success1',
     57      'test_plug.success2',
     58    }, getcompletion('test_plug', 'checkhealth'))
     59  end)
     60 
     61  it('completion checks for vim.health._complete() return type #28456', function()
     62    clear()
     63    exec_lua([[vim.health._complete = function() return 1 end]])
     64    eq({}, getcompletion('', 'checkhealth'))
     65    exec_lua([[vim.health._complete = function() return { 1 } end]])
     66    eq({}, getcompletion('', 'checkhealth'))
     67    assert_alive()
     68  end)
     69 
     70  it('cmdline completion works with multiple args #35054', function()
     71    clear()
     72    n.feed(':checkhealth vim.ls<Tab>')
     73    eq('checkhealth vim.lsp', fn.getcmdline())
     74    n.feed(' vim.prov<Tab>')
     75    eq('checkhealth vim.lsp vim.provider', fn.getcmdline())
     76  end)
     77 
     78  it('vim.g.health', function()
     79    clear {
     80      args_rm = { '-u' },
     81      args = { '--clean', '+set runtimepath+=test/functional/fixtures' },
     82    }
     83    command("let g:health = {'style':'float'}")
     84    command('checkhealth lsp')
     85    eq(
     86      'editor',
     87      exec_lua([[
     88      return vim.api.nvim_win_get_config(0).relative
     89    ]])
     90    )
     91    matches('health%.lua:%d+>$', fn.maparg('q', 'n', false, false))
     92 
     93    -- gO should not close the :checkhealth floating window. #34784
     94    command('checkhealth full_render')
     95    local win = api.nvim_get_current_win()
     96    api.nvim_win_set_cursor(win, { 5, 1 })
     97    n.feed('gO')
     98    eq(true, api.nvim_win_is_valid(win))
     99    eq('qf', api.nvim_get_option_value('filetype', { buf = 0 }))
    100  end)
    101 
    102  it("vim.provider works with a misconfigured 'shell'", function()
    103    clear()
    104    command([[set shell=echo\ WRONG!!!]])
    105    command('let g:loaded_perl_provider = 0')
    106    command('let g:loaded_python3_provider = 0')
    107    command('checkhealth vim.provider')
    108    eq(nil, string.match(curbuf_contents(), 'WRONG!!!'))
    109  end)
    110 end)
    111 
    112 describe('vim.health', function()
    113  before_each(function()
    114    clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } }
    115  end)
    116 
    117  describe(':checkhealth', function()
    118    it('report_xx() renders correctly', function()
    119      command('checkhealth full_render')
    120      n.expect([[
    121 
    122      ==============================================================================
    123      test_plug.full_render:                                              1 ⚠️  1 
    124 
    125      report 1 ~
    126      -  OK life is fine
    127      - ⚠️ WARNING no what installed
    128        - ADVICE:
    129          - pip what
    130          - make what
    131 
    132      report 2 ~
    133      - stuff is stable
    134      -  ERROR why no hardcopy
    135        - ADVICE:
    136          - :help |:hardcopy|
    137          - :help |:TOhtml|
    138      ]])
    139    end)
    140 
    141    it('user FileType handler can modify report', function()
    142      -- Define a FileType autocmd that removes emoji chars.
    143      source [[
    144        autocmd FileType checkhealth :set modifiable | silent! %s/\v( ?[^\x00-\x7F])//g
    145        checkhealth full_render
    146      ]]
    147      n.expect([[
    148 
    149      ==============================================================================
    150      test_plug.full_render:                                              1  1
    151 
    152      report 1 ~
    153      - OK life is fine
    154      - WARNING no what installed
    155        - ADVICE:
    156          - pip what
    157          - make what
    158 
    159      report 2 ~
    160      - stuff is stable
    161      - ERROR why no hardcopy
    162        - ADVICE:
    163          - :help |:hardcopy|
    164          - :help |:TOhtml|
    165      ]])
    166    end)
    167 
    168    it('concatenates multiple reports', function()
    169      command('checkhealth success1 success2 test_plug')
    170      n.expect([[
    171 
    172        ==============================================================================
    173        test_plug:                                                                  
    174 
    175        report 1 ~
    176        -  OK everything is fine
    177 
    178        report 2 ~
    179        -  OK nothing to see here
    180 
    181        ==============================================================================
    182        test_plug.success1:                                                         
    183 
    184        report 1 ~
    185        -  OK everything is fine
    186 
    187        report 2 ~
    188        -  OK nothing to see here
    189 
    190        ==============================================================================
    191        test_plug.success2:                                                         
    192 
    193        another 1 ~
    194        -  OK ok
    195        ]])
    196    end)
    197 
    198    it('lua plugins submodules', function()
    199      command('checkhealth test_plug.submodule')
    200      n.expect([[
    201 
    202        ==============================================================================
    203        test_plug.submodule:                                                        
    204 
    205        report 1 ~
    206        -  OK everything is fine
    207 
    208        report 2 ~
    209        -  OK nothing to see here
    210        ]])
    211    end)
    212 
    213    it('... including empty reports', function()
    214      command('checkhealth test_plug.submodule_empty')
    215      n.expect([[
    216 
    217      ==============================================================================
    218      test_plug.submodule_empty:                                                1 
    219 
    220      -  ERROR The healthcheck report for "test_plug.submodule_empty" plugin is empty.
    221      ]])
    222    end)
    223 
    224    it('highlights OK, ERROR', function()
    225      local screen = Screen.new(50, 12)
    226      screen:set_default_attr_ids({
    227        h1 = { reverse = true },
    228        h2 = { foreground = tonumber('0x6a0dad') },
    229        Ok = { foreground = Screen.colors.LightGreen },
    230        Error = { foreground = Screen.colors.Red },
    231        Done = { foreground = Screen.colors.NvimDarkGreen },
    232        Bar = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGrey },
    233      })
    234      command('checkhealth foo success1')
    235      command('set nofoldenable nowrap laststatus=0')
    236      screen:expect {
    237        grid = [[
    238        ^                                                  |
    239        {Bar:                                                  }|
    240        {h1:foo:                                              }|
    241                                                          |
    242        - ❌ {Error:ERROR} No healthcheck found for "foo" plugin. |
    243                                                          |
    244        {Bar:                                                  }|
    245        {h1:test_plug.success1:                               }|
    246                                                          |
    247        {h2:report 1}                                          |
    248        - ✅ {Ok:OK} everything is fine                        |
    249        {Done:checkhealth}: checks done                          |
    250      ]],
    251      }
    252    end)
    253 
    254    it('gracefully handles invalid healthcheck', function()
    255      command('checkhealth non_existent_healthcheck')
    256      -- luacheck: ignore 613
    257      n.expect([[
    258 
    259        ==============================================================================
    260        non_existent_healthcheck:                                                 1 
    261 
    262        -  ERROR No healthcheck found for "non_existent_healthcheck" plugin.
    263        ]])
    264    end)
    265 
    266    it('does not use vim.health as a healthcheck', function()
    267      -- vim.health is not a healthcheck
    268      command('checkhealth vim')
    269      n.expect([[
    270      ERROR: No healthchecks found.]])
    271    end)
    272 
    273    it('nested lua/ directory', function()
    274      command('checkhealth lua')
    275      n.expect([[
    276 
    277      ==============================================================================
    278      test_plug.lua:                                                              
    279 
    280      nested lua/ directory ~
    281      -  OK everything is ok
    282      ]])
    283    end)
    284 
    285    it('&rtp can contain nested path (by packadd)', function()
    286      -- re-add to ensure this appears before new nested rtp
    287      command([[set runtimepath-=test/functional/fixtures]])
    288      command([[set runtimepath+=test/functional/fixtures]])
    289      command('set packpath+=test/functional/fixtures')
    290      -- set rtp+=test/functional/fixtures/pack/foo/opt/healthy
    291      command('packadd healthy')
    292      command('checkhealth nest')
    293      n.expect([[
    294 
    295      ==============================================================================
    296      nest:                                                                       
    297 
    298      healthy pack ~
    299      -  OK healthy ok
    300      ]])
    301    end)
    302  end)
    303 end)
    304 
    305 describe(':checkhealth window', function()
    306  before_each(function()
    307    clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } }
    308    command('set nofoldenable nowrap laststatus=0')
    309  end)
    310 
    311  it('opens directly if no buffer created', function()
    312    local screen = Screen.new(50, 12, { ext_multigrid = true })
    313    screen:set_default_attr_ids {
    314      h1 = { reverse = true },
    315      h2 = { foreground = tonumber('0x6a0dad') },
    316      Done = { foreground = Screen.colors.NvimDarkGreen },
    317      [1] = { foreground = Screen.colors.Blue, bold = true },
    318      [14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray },
    319      [32] = { foreground = Screen.colors.PaleGreen2 },
    320    }
    321    command('checkhealth success1')
    322    screen:expect {
    323      grid = [[
    324    ## grid 1
    325      [2:--------------------------------------------------]|*11
    326      [3:--------------------------------------------------]|
    327    ## grid 2
    328      ^                                                  |
    329      {14:                                                  }|
    330      {14:                            }                      |
    331      {h1:test_plug.                                        }|
    332      {h1:success1:                                         }|
    333      {h1:                ✅}                                |
    334                                                        |
    335      {h2:report 1}                                          |
    336      - ✅ {32:OK} everything is fine                        |
    337                                                        |
    338      {h2:report 2}                                          |
    339    ## grid 3
    340      {Done:checkhealth}: checks done                          |
    341    ]],
    342    }
    343  end)
    344 
    345  local function test_health_vsplit(left, emptybuf, mods)
    346    local screen = Screen.new(50, 20, { ext_multigrid = true })
    347    screen:set_default_attr_ids {
    348      h1 = { reverse = true },
    349      h2 = { foreground = tonumber('0x6a0dad') },
    350      Done = { foreground = Screen.colors.NvimDarkGreen },
    351      [1] = { foreground = Screen.colors.Blue, bold = true },
    352      [14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray },
    353      [32] = { foreground = Screen.colors.PaleGreen2 },
    354    }
    355    if not emptybuf then
    356      insert('hello')
    357    end
    358    command(mods .. ' checkhealth success1')
    359    screen:expect(
    360      ([[
    361    ## grid 1
    362      %s
    363      [3:--------------------------------------------------]|
    364    ## grid 2
    365      %s                   |
    366      {1:~                       }|*18
    367    ## grid 3
    368      {Done:checkhealth}: checks done                          |
    369    ## grid 4
    370      ^                         |
    371      {14:                         }|*3
    372      {14:   }                      |
    373      {h1:test_plug.               }|
    374      {h1:success1:                }|
    375      {h1:                         }|
    376      {h1:                ✅}       |
    377                               |
    378      {h2:report 1}                 |
    379      -  {32:OK} everything is    |
    380      fine                     |
    381                               |
    382      {h2:report 2}                 |
    383      -  {32:OK} nothing to see   |
    384      here                     |
    385                               |
    386      {1:~                        }|
    387    ]]):format(
    388        left and '[4:-------------------------]│[2:------------------------]|*19'
    389          or '[2:------------------------]│[4:-------------------------]|*19',
    390        emptybuf and '     ' or 'hello'
    391      )
    392    )
    393  end
    394 
    395  for _, mods in ipairs({ 'vertical', 'leftabove vertical', 'topleft vertical' }) do
    396    it(('opens in left vsplit window with :%s and no buffer created'):format(mods), function()
    397      test_health_vsplit(true, true, mods)
    398    end)
    399    it(('opens in left vsplit window with :%s and non-empty buffer'):format(mods), function()
    400      test_health_vsplit(true, false, mods)
    401    end)
    402  end
    403 
    404  for _, mods in ipairs({ 'rightbelow vertical', 'botright vertical' }) do
    405    it(('opens in right vsplit window with :%s and no buffer created'):format(mods), function()
    406      test_health_vsplit(false, true, mods)
    407    end)
    408    it(('opens in right vsplit window with :%s and non-empty buffer'):format(mods), function()
    409      test_health_vsplit(false, false, mods)
    410    end)
    411  end
    412 
    413  local function test_health_split(top, emptybuf, mods)
    414    local screen = Screen.new(50, 25, { ext_multigrid = true })
    415    screen._default_attr_ids = nil
    416    if not emptybuf then
    417      insert('hello')
    418    end
    419    command(mods .. ' checkhealth success1')
    420    screen:expect(
    421      ([[
    422    ## grid 1
    423 %s
    424      [3:--------------------------------------------------]|
    425    ## grid 2
    426      %s                                             |
    427      ~                                                 |*10
    428    ## grid 3
    429      checkhealth: checks done                          |
    430    ## grid 4
    431      ^                                                  |
    432                                                        |*2
    433      test_plug.                                        |
    434      success1:                                         |
    435                                                      |
    436                                                        |
    437      report 1                                          |
    438      -  OK everything is fine                        |
    439                                                        |
    440      report 2                                          |
    441      -  OK nothing to see here                       |
    442    ]]):format(
    443        top
    444            and [[
    445      [4:--------------------------------------------------]|*12
    446      health:// [-]                                     |
    447      [2:--------------------------------------------------]|*11]]
    448          or ([[
    449      [2:--------------------------------------------------]|*11
    450      [No Name] %s                                     |
    451      [4:--------------------------------------------------]|*12]]):format(
    452            emptybuf and '   ' or '[+]'
    453          ),
    454        emptybuf and '     ' or 'hello'
    455      )
    456    )
    457  end
    458 
    459  for _, mods in ipairs({ 'horizontal', 'leftabove', 'topleft' }) do
    460    it(('opens in top split window with :%s and no buffer created'):format(mods), function()
    461      test_health_split(true, true, mods)
    462    end)
    463    it(('opens in top split window with :%s and non-empty buffer'):format(mods), function()
    464      test_health_split(true, false, mods)
    465    end)
    466  end
    467 
    468  for _, mods in ipairs({ 'rightbelow', 'botright' }) do
    469    it(('opens in bottom split window with :%s and no buffer created'):format(mods), function()
    470      test_health_split(false, true, mods)
    471    end)
    472    it(('opens in bottom split window with :%s and non-empty buffer'):format(mods), function()
    473      test_health_split(false, false, mods)
    474    end)
    475  end
    476 
    477  it('opens in tab', function()
    478    -- create an empty buffer called "my_buff"
    479    api.nvim_create_buf(false, true)
    480    command('file my_buff')
    481    command('checkhealth success1')
    482    -- define a function that collects all buffers in each tab
    483    -- returns a dict like {tab1 = ["buf1", "buf2"], tab2 = ["buf3"]}
    484    source([[
    485        function CollectBuffersPerTab()
    486                let buffs = {}
    487                for i in range(tabpagenr('$'))
    488                  let key = 'tab' . (i + 1)
    489                  let value = []
    490                  for j in tabpagebuflist(i + 1)
    491                    call add(value, bufname(j))
    492                  endfor
    493                  let buffs[key] = value
    494                endfor
    495                return buffs
    496        endfunction
    497    ]])
    498    local buffers_per_tab = fn.CollectBuffersPerTab()
    499    eq(buffers_per_tab, { tab1 = { 'my_buff' }, tab2 = { 'health://' } })
    500  end)
    501 end)