neovim

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

statusline_spec.lua (12911B)


      1 local t = require('test.unit.testutil')
      2 local itp = t.gen_itp(it)
      3 
      4 local to_cstr = t.to_cstr
      5 local get_str = t.ffi.string
      6 local eq = t.eq
      7 local NULL = t.NULL
      8 
      9 local buffer = t.cimport('./src/nvim/buffer.h')
     10 local globals = t.cimport('./src/nvim/globals.h')
     11 local stl = t.cimport('./src/nvim/statusline.h')
     12 local grid = t.cimport('./src/nvim/grid.h')
     13 
     14 describe('build_stl_str_hl', function()
     15  local buffer_byte_size = 120
     16  local STL_INITIAL_ITEMS = 20
     17  local output_buffer = ''
     18 
     19  -- This function builds the statusline
     20  --
     21  -- @param arg Optional arguments are:
     22  --    .pat The statusline format string
     23  --    .fillchar The fill character used in the statusline
     24  --    .maximum_cell_count The number of cells available in the statusline
     25  local function build_stl_str_hl(arg)
     26    output_buffer = to_cstr(string.rep(' ', buffer_byte_size))
     27 
     28    local pat = arg.pat or ''
     29    local fillchar = arg.fillchar or ' '
     30    local maximum_cell_count = arg.maximum_cell_count or buffer_byte_size
     31    if type(fillchar) == type('') then
     32      fillchar = grid.schar_from_str(fillchar)
     33    end
     34 
     35    return stl.build_stl_str_hl(
     36      globals.curwin,
     37      output_buffer,
     38      buffer_byte_size,
     39      to_cstr(pat),
     40      -1,
     41      0,
     42      fillchar,
     43      maximum_cell_count,
     44      NULL,
     45      NULL,
     46      NULL,
     47      NULL
     48    )
     49  end
     50 
     51  -- Use this function to simplify testing the comparison between
     52  --  the format string and the resulting statusline.
     53  --
     54  -- @param description The description of what the test should be doing
     55  -- @param statusline_cell_count The number of cells available in the statusline
     56  -- @param input_stl The format string for the statusline
     57  -- @param expected_stl The expected result string for the statusline
     58  --
     59  -- @param arg Options can be placed in an optional dict as the last parameter
     60  --    .expected_cell_count The expected number of cells build_stl_str_hl will return
     61  --    .expected_byte_length The expected byte length of the string (defaults to byte length of expected_stl)
     62  --    .file_name The name of the file to be tested (useful in %f type tests)
     63  --    .fillchar The character that will be used to fill any 'extra' space in the stl
     64  local function statusline_test(description, statusline_cell_count, input_stl, expected_stl, arg)
     65    -- arg is the optional parameter
     66    -- so we either fill in option with arg or an empty dict
     67    local option = arg or {}
     68 
     69    local fillchar = option.fillchar or ' '
     70    local expected_cell_count = option.expected_cell_count or statusline_cell_count
     71    local expected_byte_length = option.expected_byte_length or #expected_stl
     72 
     73    itp(description, function()
     74      if option.file_name then
     75        buffer.setfname(globals.curbuf, to_cstr(option.file_name), NULL, 1)
     76      else
     77        buffer.setfname(globals.curbuf, nil, NULL, 1)
     78      end
     79 
     80      local result_cell_count = build_stl_str_hl {
     81        pat = input_stl,
     82        maximum_cell_count = statusline_cell_count,
     83        fillchar = fillchar,
     84      }
     85 
     86      eq(expected_stl, get_str(output_buffer, expected_byte_length))
     87      eq(expected_cell_count, result_cell_count)
     88    end)
     89  end
     90 
     91  -- expression testing
     92  statusline_test('Should expand expression', 2, '%!expand(20+1)', '21')
     93  statusline_test('Should expand broken expression to itself', 11, '%!expand(20+1', 'expand(20+1')
     94 
     95  -- file name testing
     96  statusline_test('should print no file name', 10, '%f', '[No Name]', { expected_cell_count = 9 })
     97  statusline_test(
     98    'should print the relative file name',
     99    30,
    100    '%f',
    101    'test/unit/buffer_spec.lua',
    102    { file_name = 'test/unit/buffer_spec.lua', expected_cell_count = 25 }
    103  )
    104  statusline_test(
    105    'should print the full file name',
    106    40,
    107    '%F',
    108    '/test/unit/buffer_spec.lua',
    109    { file_name = '/test/unit/buffer_spec.lua', expected_cell_count = 26 }
    110  )
    111 
    112  -- fillchar testing
    113  statusline_test(
    114    'should handle `!` as a fillchar',
    115    10,
    116    'abcde%=',
    117    'abcde!!!!!',
    118    { fillchar = '!' }
    119  )
    120  statusline_test(
    121    'should handle `~` as a fillchar',
    122    10,
    123    '%=abcde',
    124    '~~~~~abcde',
    125    { fillchar = '~' }
    126  )
    127  statusline_test(
    128    'should put fillchar `!` in between text',
    129    10,
    130    'abc%=def',
    131    'abc!!!!def',
    132    { fillchar = '!' }
    133  )
    134  statusline_test(
    135    'should put fillchar `~` in between text',
    136    10,
    137    'abc%=def',
    138    'abc~~~~def',
    139    { fillchar = '~' }
    140  )
    141  statusline_test(
    142    'should put fillchar `━` in between text',
    143    10,
    144    'abc%=def',
    145    'abc━━━━def',
    146    { fillchar = '━' }
    147  )
    148  statusline_test(
    149    'should handle zero-fillchar as a space',
    150    10,
    151    'abcde%=',
    152    'abcde     ',
    153    { fillchar = 0 }
    154  )
    155  statusline_test(
    156    'should print the tail file name',
    157    80,
    158    '%t',
    159    'buffer_spec.lua',
    160    { file_name = 'test/unit/buffer_spec.lua', expected_cell_count = 15 }
    161  )
    162 
    163  -- standard text testing
    164  statusline_test(
    165    'should copy plain text',
    166    80,
    167    'this is a test',
    168    'this is a test',
    169    { expected_cell_count = 14 }
    170  )
    171 
    172  -- line number testing
    173  statusline_test('should print the buffer number', 80, '%n', '1', { expected_cell_count = 1 })
    174  statusline_test(
    175    'should print the current line number in the buffer',
    176    80,
    177    '%l',
    178    '0',
    179    { expected_cell_count = 1 }
    180  )
    181  statusline_test(
    182    'should print the number of lines in the buffer',
    183    80,
    184    '%L',
    185    '1',
    186    { expected_cell_count = 1 }
    187  )
    188 
    189  -- truncation testing
    190  statusline_test(
    191    'should truncate when standard text pattern is too long',
    192    10,
    193    '0123456789abcde',
    194    '<6789abcde'
    195  )
    196  statusline_test('should truncate when using =', 10, 'abcdef%=ghijkl', 'abcdef<jkl')
    197  statusline_test(
    198    'should truncate centered text when using ==',
    199    10,
    200    'abcde%=gone%=fghij',
    201    'abcde<ghij'
    202  )
    203  statusline_test('should respect the `<` marker', 10, 'abc%<defghijkl', 'abc<ghijkl')
    204  statusline_test(
    205    'should truncate at `<` with one `=`, test 1',
    206    10,
    207    'abc%<def%=ghijklmno',
    208    'abc<jklmno'
    209  )
    210  statusline_test(
    211    'should truncate at `<` with one `=`, test 2',
    212    10,
    213    'abcdef%=ghijkl%<mno',
    214    'abcdefghi>'
    215  )
    216  statusline_test(
    217    'should truncate at `<` with one `=`, test 3',
    218    10,
    219    'abc%<def%=ghijklmno',
    220    'abc<jklmno'
    221  )
    222  statusline_test('should truncate at `<` with one `=`, test 4', 10, 'abc%<def%=ghij', 'abcdefghij')
    223  statusline_test(
    224    'should truncate at `<` with one `=`, test 4',
    225    10,
    226    'abc%<def%=ghijk',
    227    'abc<fghijk'
    228  )
    229 
    230  statusline_test(
    231    'should truncate at `<` with many `=`, test 4',
    232    10,
    233    'ab%<cdef%=g%=h%=ijk',
    234    'ab<efghijk'
    235  )
    236 
    237  statusline_test('should truncate at the first `<`', 10, 'abc%<def%<ghijklm', 'abc<hijklm')
    238 
    239  statusline_test('should ignore trailing %', 3, 'abc%', 'abc')
    240 
    241  -- alignment testing with fillchar
    242  local function statusline_test_align(
    243    description,
    244    statusline_cell_count,
    245    input_stl,
    246    expected_stl,
    247    arg
    248  )
    249    arg = arg or {}
    250    statusline_test(
    251      description .. ' without fillchar',
    252      statusline_cell_count,
    253      input_stl,
    254      expected_stl:gsub('%~', ' '),
    255      arg
    256    )
    257    arg.fillchar = '!'
    258    statusline_test(
    259      description .. ' with fillchar `!`',
    260      statusline_cell_count,
    261      input_stl,
    262      expected_stl:gsub('%~', '!'),
    263      arg
    264    )
    265    arg.fillchar = '━'
    266    statusline_test(
    267      description .. ' with fillchar `━`',
    268      statusline_cell_count,
    269      input_stl,
    270      expected_stl:gsub('%~', '━'),
    271      arg
    272    )
    273  end
    274 
    275  statusline_test_align('should right align when using =', 20, 'neo%=vim', 'neo~~~~~~~~~~~~~~vim')
    276  statusline_test_align(
    277    'should, when possible, center text when using %=text%=',
    278    20,
    279    'abc%=neovim%=def',
    280    'abc~~~~neovim~~~~def'
    281  )
    282  statusline_test_align(
    283    'should handle uneven spacing in the buffer when using %=text%=',
    284    20,
    285    'abc%=neo_vim%=def',
    286    'abc~~~neo_vim~~~~def'
    287  )
    288  statusline_test_align(
    289    'should have equal spaces even with non-equal sides when using =',
    290    20,
    291    'foobar%=test%=baz',
    292    'foobar~~~test~~~~baz'
    293  )
    294  statusline_test_align(
    295    'should have equal spaces even with longer right side when using =',
    296    20,
    297    'a%=test%=longtext',
    298    'a~~~test~~~~longtext'
    299  )
    300  statusline_test_align(
    301    'should handle an empty left side when using ==',
    302    20,
    303    '%=test%=baz',
    304    '~~~~~~test~~~~~~~baz'
    305  )
    306  statusline_test_align(
    307    'should handle an empty right side when using ==',
    308    20,
    309    'foobar%=test%=',
    310    'foobar~~~~~test~~~~~'
    311  )
    312  statusline_test_align(
    313    'should handle consecutive empty ==',
    314    20,
    315    '%=%=test%=',
    316    '~~~~~~~~~~test~~~~~~'
    317  )
    318  statusline_test_align('should handle an = alone', 20, '%=', '~~~~~~~~~~~~~~~~~~~~')
    319  statusline_test_align(
    320    'should right align text when it is alone with =',
    321    20,
    322    '%=foo',
    323    '~~~~~~~~~~~~~~~~~foo'
    324  )
    325  statusline_test_align(
    326    'should left align text when it is alone with =',
    327    20,
    328    'foo%=',
    329    'foo~~~~~~~~~~~~~~~~~'
    330  )
    331 
    332  statusline_test_align(
    333    'should approximately center text when using %=text%=',
    334    21,
    335    'abc%=neovim%=def',
    336    'abc~~~~neovim~~~~~def'
    337  )
    338  statusline_test_align(
    339    'should completely fill the buffer when using %=text%=',
    340    21,
    341    'abc%=neo_vim%=def',
    342    'abc~~~~neo_vim~~~~def'
    343  )
    344  statusline_test_align(
    345    'should have equal spacing even with non-equal sides when using =',
    346    21,
    347    'foobar%=test%=baz',
    348    'foobar~~~~test~~~~baz'
    349  )
    350  statusline_test_align(
    351    'should have equal spacing even with longer right side when using =',
    352    21,
    353    'a%=test%=longtext',
    354    'a~~~~test~~~~longtext'
    355  )
    356  statusline_test_align(
    357    'should handle an empty left side when using ==',
    358    21,
    359    '%=test%=baz',
    360    '~~~~~~~test~~~~~~~baz'
    361  )
    362  statusline_test_align(
    363    'should handle an empty right side when using ==',
    364    21,
    365    'foobar%=test%=',
    366    'foobar~~~~~test~~~~~~'
    367  )
    368 
    369  statusline_test_align(
    370    'should quadrant the text when using 3 %=',
    371    40,
    372    'abcd%=n%=eovim%=ef',
    373    'abcd~~~~~~~~~n~~~~~~~~~eovim~~~~~~~~~~ef'
    374  )
    375  statusline_test_align(
    376    'should work well with %t',
    377    40,
    378    '%t%=right_aligned',
    379    'buffer_spec.lua~~~~~~~~~~~~right_aligned',
    380    { file_name = 'test/unit/buffer_spec.lua' }
    381  )
    382  statusline_test_align(
    383    'should work well with %t and regular text',
    384    40,
    385    'l%=m_l %t m_r%=r',
    386    'l~~~~~~~m_l buffer_spec.lua m_r~~~~~~~~r',
    387    { file_name = 'test/unit/buffer_spec.lua' }
    388  )
    389  statusline_test_align(
    390    'should work well with %=, %t, %L, and %l',
    391    40,
    392    '%t %= %L %= %l',
    393    'buffer_spec.lua ~~~~~~~~~ 1 ~~~~~~~~~~ 0',
    394    { file_name = 'test/unit/buffer_spec.lua' }
    395  )
    396 
    397  statusline_test_align(
    398    'should quadrant the text when using 3 %=',
    399    41,
    400    'abcd%=n%=eovim%=ef',
    401    'abcd~~~~~~~~~n~~~~~~~~~eovim~~~~~~~~~~~ef'
    402  )
    403  statusline_test_align(
    404    'should work well with %t',
    405    41,
    406    '%t%=right_aligned',
    407    'buffer_spec.lua~~~~~~~~~~~~~right_aligned',
    408    { file_name = 'test/unit/buffer_spec.lua' }
    409  )
    410  statusline_test_align(
    411    'should work well with %t and regular text',
    412    41,
    413    'l%=m_l %t m_r%=r',
    414    'l~~~~~~~~m_l buffer_spec.lua m_r~~~~~~~~r',
    415    { file_name = 'test/unit/buffer_spec.lua' }
    416  )
    417  statusline_test_align(
    418    'should work well with %=, %t, %L, and %l',
    419    41,
    420    '%t %= %L %= %l',
    421    'buffer_spec.lua ~~~~~~~~~~ 1 ~~~~~~~~~~ 0',
    422    { file_name = 'test/unit/buffer_spec.lua' }
    423  )
    424 
    425  statusline_test_align(
    426    'should work with 10 %=',
    427    50,
    428    'aaaa%=b%=c%=d%=e%=fg%=hi%=jk%=lmnop%=qrstuv%=wxyz',
    429    'aaaa~~b~~c~~d~~e~~fg~~hi~~jk~~lmnop~~qrstuv~~~wxyz'
    430  )
    431 
    432  -- stl item testing
    433  local tabline = ''
    434  for i = 1, 1000 do
    435    tabline = tabline .. (i % 2 == 0 and '%#TabLineSel#' or '%#TabLineFill#') .. tostring(i % 2)
    436  end
    437  statusline_test('should handle a large amount of any items', 20, tabline, '<1010101010101010101') -- Should not show any error
    438  statusline_test(
    439    'should handle a larger amount of = than stl initial item',
    440    20,
    441    ('%='):rep(STL_INITIAL_ITEMS * 5),
    442    '                    '
    443  ) -- Should not show any error
    444  statusline_test(
    445    'should handle many extra characters',
    446    20,
    447    'a' .. ('a'):rep(STL_INITIAL_ITEMS * 5),
    448    '<aaaaaaaaaaaaaaaaaaa'
    449  ) -- Does not show any error
    450  statusline_test(
    451    'should handle many extra characters and flags',
    452    20,
    453    'a' .. ('%=a'):rep(STL_INITIAL_ITEMS * 2),
    454    'a<aaaaaaaaaaaaaaaaaa'
    455  ) -- Should not show any error
    456 
    457  -- multi-byte testing
    458  statusline_test('should handle multibyte characters', 10, 'Ĉ%=x', 'Ĉ        x')
    459  statusline_test(
    460    'should handle multibyte characters and different fillchars',
    461    10,
    462    'Ą%=mid%=end',
    463    'Ą@mid@@end',
    464    { fillchar = '@' }
    465  )
    466 
    467  -- escaping % testing
    468  statusline_test('should handle escape of %', 4, 'abc%%', 'abc%')
    469  statusline_test('case where escaped % does not fit', 3, 'abc%%abcabc', '<bc')
    470  statusline_test('escaped % is first', 1, '%%', '%')
    471 end)