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)