" Tests for various functions. source shared.vim source check.vim source term_util.vim source screendump.vim import './vim9.vim' as v9 " Must be done first, since the alternate buffer must be unset. func Test_00_bufexists() call assert_equal(0, bufexists('does_not_exist')) call assert_equal(1, bufexists(bufnr('%'))) call assert_equal(0, bufexists(0)) new Xfoo let bn = bufnr('%') call assert_equal(1, bufexists(bn)) call assert_equal(1, bufexists('Xfoo')) call assert_equal(1, bufexists(getcwd() . '/Xfoo')) call assert_equal(1, bufexists(0)) bw call assert_equal(0, bufexists(bn)) call assert_equal(0, bufexists('Xfoo')) endfunc func Test_has() call assert_equal(1, has('eval')) call assert_equal(1, has('eval', 1)) if has('unix') call assert_equal(1, or(has('ttyin'), 1)) call assert_equal(0, and(has('ttyout'), 0)) call assert_equal(1, has('multi_byte_encoding')) call assert_equal(0, has(':tearoff')) endif call assert_equal(1, has('vcon', 1)) call assert_equal(1, has('mouse_gpm_enabled', 1)) call assert_equal(has('gui_win32') && has('menu'), has(':tearoff')) call assert_equal(0, has('nonexistent')) call assert_equal(0, has('nonexistent', 1)) " Will we ever have patch 9999? let ver = 'patch-' .. v:version / 100 .. '.' .. v:version % 100 .. '.9999' call assert_equal(0, has(ver)) " There actually isn't a patch 9.0.0, but this is more consistent. call assert_equal(1, has('patch-9.0.0')) endfunc func Test_empty() call assert_equal(1, empty('')) call assert_equal(0, empty('a')) call assert_equal(1, empty(0)) call assert_equal(1, empty(-0)) call assert_equal(0, empty(1)) call assert_equal(0, empty(-1)) call assert_equal(1, empty(0.0)) call assert_equal(1, empty(-0.0)) call assert_equal(0, empty(1.0)) call assert_equal(0, empty(-1.0)) call assert_equal(0, empty(1.0/0.0)) call assert_equal(0, empty(0.0/0.0)) call assert_equal(1, empty([])) call assert_equal(0, empty(['a'])) call assert_equal(1, empty({})) call assert_equal(0, empty({'a':1})) call assert_equal(1, empty(v:null)) call assert_equal(1, empty(v:none)) call assert_equal(1, empty(v:false)) call assert_equal(0, empty(v:true)) if has('channel') call assert_equal(1, empty(test_null_channel())) endif if has('job') call assert_equal(1, empty(test_null_job())) endif call assert_equal(0, empty(function('Test_empty'))) call assert_equal(0, empty(function('Test_empty', [0]))) call assert_fails("call empty(test_void())", ['E340:', 'E685:']) call assert_fails("call empty(test_unknown())", ['E340:', 'E685:']) endfunc func Test_err_teapot() call assert_fails('call err_teapot()', "E418: I'm a teapot") call assert_fails('call err_teapot(0)', "E418: I'm a teapot") call assert_fails('call err_teapot(v:false)', "E418: I'm a teapot") call assert_fails('call err_teapot("1")', "E503: Coffee is currently not available") call assert_fails('call err_teapot(v:true)', "E503: Coffee is currently not available") let expr = 1 call assert_fails('call err_teapot(expr)', "E503: Coffee is currently not available") endfunc func Test_test_void() call assert_fails('echo 1 == test_void()', 'E1031:') call assert_fails('echo 1.0 == test_void()', 'E1031:') call assert_fails('let x = json_encode(test_void())', ['E340:', 'E685:']) call assert_fails('let x = copy(test_void())', ['E340:', 'E685:']) call assert_fails('let x = copy([test_void()])', 'E1031:') endfunc func Test_islocked() call assert_fails('call islocked(99)', 'E475:') call assert_fails('call islocked("s: x")', 'E488:') endfunc func Test_len() call assert_equal(1, len(0)) call assert_equal(2, len(12)) call assert_equal(0, len('')) call assert_equal(2, len('ab')) call assert_equal(0, len([])) call assert_equal(0, len(test_null_list())) call assert_equal(2, len([2, 1])) call assert_equal(0, len({})) call assert_equal(0, len(test_null_dict())) call assert_equal(2, len({'a': 1, 'b': 2})) call assert_fails('call len(v:none)', 'E701:') call assert_fails('call len({-> 0})', 'E701:') endfunc func Test_max() call assert_equal(0, max([])) call assert_equal(2, max([2])) call assert_equal(2, max([1, 2])) call assert_equal(2, max([1, 2, v:null])) call assert_equal(0, max({})) call assert_equal(2, max({'a':1, 'b':2})) call assert_fails('call max(1)', 'E712:') call assert_fails('call max(v:none)', 'E712:') " check we only get one error call assert_fails('call max([#{}, [1]])', ['E728:', 'E728:']) call assert_fails('call max(#{a: {}, b: [1]})', ['E728:', 'E728:']) endfunc func Test_min() call assert_equal(0, min([])) call assert_equal(2, min([2])) call assert_equal(1, min([1, 2])) call assert_equal(0, min([1, 2, v:null])) call assert_equal(0, min({})) call assert_equal(1, min({'a':1, 'b':2})) call assert_fails('call min(1)', 'E712:') call assert_fails('call min(v:none)', 'E712:') call assert_fails('call min([1, {}])', 'E728:') " check we only get one error call assert_fails('call min([[1], #{}])', ['E745:', 'E745:']) call assert_fails('call min(#{a: [1], b: #{}})', ['E745:', 'E745:']) endfunc func Test_strwidth() for aw in ['single', 'double'] exe 'set ambiwidth=' . aw call assert_equal(0, strwidth('')) call assert_equal(1, strwidth("\t")) call assert_equal(3, strwidth('Vim')) call assert_equal(4, strwidth(1234)) call assert_equal(5, strwidth(-1234)) call assert_equal(2, strwidth('😉')) call assert_equal(17, strwidth('Eĥoŝanĝo ĉiuĵaŭde')) call assert_equal((aw == 'single') ? 6 : 7, strwidth('Straße')) call assert_fails('call strwidth({->0})', 'E729:') call assert_fails('call strwidth([])', 'E730:') call assert_fails('call strwidth({})', 'E731:') endfor call assert_equal(3, strwidth(1.2)) call v9.CheckDefAndScriptFailure(['echo strwidth(1.2)'], ['E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1']) set ambiwidth& endfunc func Test_str2nr() call assert_equal(0, str2nr('')) call assert_equal(1, str2nr('1')) call assert_equal(1, str2nr(' 1 ')) call assert_equal(1, str2nr('+1')) call assert_equal(1, str2nr('+ 1')) call assert_equal(1, str2nr(' + 1 ')) call assert_equal(-1, str2nr('-1')) call assert_equal(-1, str2nr('- 1')) call assert_equal(-1, str2nr(' - 1 ')) call assert_equal(123456789, str2nr('123456789')) call assert_equal(-123456789, str2nr('-123456789')) call assert_equal(5, str2nr('101', 2)) call assert_equal(5, '0b101'->str2nr(2)) call assert_equal(5, str2nr('0B101', 2)) call assert_equal(-5, str2nr('-101', 2)) call assert_equal(-5, str2nr('-0b101', 2)) call assert_equal(-5, str2nr('-0B101', 2)) call assert_equal(65, str2nr('101', 8)) call assert_equal(65, str2nr('0101', 8)) call assert_equal(-65, str2nr('-101', 8)) call assert_equal(-65, str2nr('-0101', 8)) call assert_equal(65, str2nr('0o101', 8)) call assert_equal(65, str2nr('0O0101', 8)) call assert_equal(-65, str2nr('-0O101', 8)) call assert_equal(-65, str2nr('-0o0101', 8)) call assert_equal(11259375, str2nr('abcdef', 16)) call assert_equal(11259375, str2nr('ABCDEF', 16)) call assert_equal(-11259375, str2nr('-ABCDEF', 16)) call assert_equal(11259375, str2nr('0xabcdef', 16)) call assert_equal(11259375, str2nr('0Xabcdef', 16)) call assert_equal(11259375, str2nr('0XABCDEF', 16)) call assert_equal(-11259375, str2nr('-0xABCDEF', 16)) call assert_equal(1, str2nr("1'000'000", 10, 0)) call assert_equal(256, str2nr("1'0000'0000", 2, 1)) call assert_equal(262144, str2nr("1'000'000", 8, 1)) call assert_equal(1000000, str2nr("1'000'000", 10, 1)) call assert_equal(1000, str2nr("1'000''000", 10, 1)) call assert_equal(65536, str2nr("1'00'00", 16, 1)) call assert_equal(0, str2nr('0x10')) call assert_equal(0, str2nr('0b10')) call assert_equal(0, str2nr('0o10')) call assert_equal(1, str2nr('12', 2)) call assert_equal(1, str2nr('18', 8)) call assert_equal(1, str2nr('1g', 16)) call assert_equal(0, str2nr(v:null)) call assert_equal(0, str2nr(v:none)) call assert_fails('call str2nr([])', 'E730:') call assert_fails('call str2nr({->2})', 'E729:') call assert_equal(1, str2nr(1.2)) call v9.CheckDefAndScriptFailure(['echo str2nr(1.2)'], ['E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1']) call assert_fails('call str2nr(10, [])', 'E745:') endfunc func Test_strftime() CheckFunction strftime " Format of strftime() depends on system. We assume " that basic formats tested here are available and " identical on all systems which support strftime(). " " The 2nd parameter of strftime() is a local time, so the output day " of strftime() can be 17 or 18, depending on timezone. call assert_match('^2017-01-1[78]$', strftime('%Y-%m-%d', 1484695512)) " call assert_match('^\d\d\d\d-\(0\d\|1[012]\)-\([012]\d\|3[01]\) \([01]\d\|2[0-3]\):[0-5]\d:\([0-5]\d\|60\)$', '%Y-%m-%d %H:%M:%S'->strftime()) call assert_fails('call strftime([])', 'E730:') call assert_fails('call strftime("%Y", [])', 'E745:') " Check that the time changes after we change the timezone " Save previous timezone value, if any if exists('$TZ') let tz = $TZ endif " Force EST and then UTC, save the current hour (24-hour clock) for each let $TZ = 'EST' | let est = strftime('%H') let $TZ = 'UTC' | let utc = strftime('%H') " Those hours should be two bytes long, and should not be the same; if they " are, a tzset(3) call may have failed somewhere call assert_equal(strlen(est), 2) call assert_equal(strlen(utc), 2) " TODO: this fails on MS-Windows if has('unix') call assert_notequal(est, utc) endif " If we cached a timezone value, put it back, otherwise clear it if exists('tz') let $TZ = tz else unlet $TZ endif endfunc func Test_strptime() CheckFunction strptime CheckNotBSD if exists('$TZ') let tz = $TZ endif let $TZ = 'UTC' call assert_equal(1484653763, strptime('%Y-%m-%d %T', '2017-01-17 11:49:23')) " Force DST and check that it's considered let $TZ = 'WINTER0SUMMER,J1,J365' call assert_equal(1484653763 - 3600, strptime('%Y-%m-%d %T', '2017-01-17 11:49:23')) call assert_fails('call strptime()', 'E119:') call assert_fails('call strptime("xxx")', 'E119:') " This fails on BSD 14 and returns " -2209078800 instead of 0 call assert_equal(0, strptime("%Y", '')) call assert_equal(0, strptime("%Y", "xxx")) if exists('tz') let $TZ = tz else unlet $TZ endif endfunc func Test_resolve_unix() CheckUnix " Xlink1 -> Xlink2 " Xlink2 -> Xlink3 silent !ln -s -f Xlink2 Xlink1 silent !ln -s -f Xlink3 Xlink2 call assert_equal('Xlink3', resolve('Xlink1')) call assert_equal('./Xlink3', resolve('./Xlink1')) call assert_equal('Xlink3/', resolve('Xlink2/')) " FIXME: these tests result in things like "Xlink2/" instead of "Xlink3/"?! "call assert_equal('Xlink3/', resolve('Xlink1/')) "call assert_equal('./Xlink3/', resolve('./Xlink1/')) "call assert_equal(getcwd() . '/Xlink3/', resolve(getcwd() . '/Xlink1/')) call assert_equal(getcwd() . '/Xlink3', resolve(getcwd() . '/Xlink1')) " Test resolve() with a symlink cycle. " Xlink1 -> Xlink2 " Xlink2 -> Xlink3 " Xlink3 -> Xlink1 silent !ln -s -f Xlink1 Xlink3 call assert_fails('call resolve("Xlink1")', 'E655:') call assert_fails('call resolve("./Xlink1")', 'E655:') call assert_fails('call resolve("Xlink2")', 'E655:') call assert_fails('call resolve("Xlink3")', 'E655:') call delete('Xlink1') call delete('Xlink2') call delete('Xlink3') silent !ln -s -f Xresolvedir//Xfile Xresolvelink call assert_equal('Xresolvedir/Xfile', resolve('Xresolvelink')) call delete('Xresolvelink') silent !ln -s -f Xlink2/ Xlink1 call assert_equal('Xlink2', 'Xlink1'->resolve()) call assert_equal('Xlink2/', resolve('Xlink1/')) call delete('Xlink1') silent !ln -s -f ./Xlink2 Xlink1 call assert_equal('Xlink2', resolve('Xlink1')) call assert_equal('./Xlink2', resolve('./Xlink1')) call delete('Xlink1') call assert_equal('/', resolve('/')) endfunc func s:normalize_fname(fname) let ret = substitute(a:fname, '\', '/', 'g') let ret = substitute(ret, '//', '/', 'g') return ret->tolower() endfunc func Test_resolve_win32() CheckMSWindows " test for shortcut file if executable('cscript') new Xresfile wq let lines =<< trim END Set fs = CreateObject("Scripting.FileSystemObject") Set ws = WScript.CreateObject("WScript.Shell") Set shortcut = ws.CreateShortcut("Xlink.lnk") shortcut.TargetPath = fs.BuildPath(ws.CurrentDirectory, "Xresfile") shortcut.Save END call writefile(lines, 'link.vbs') silent !cscript link.vbs call delete('link.vbs') call assert_equal(s:normalize_fname(getcwd() . '\Xresfile'), s:normalize_fname(resolve('./Xlink.lnk'))) call delete('Xresfile') call assert_equal(s:normalize_fname(getcwd() . '\Xresfile'), s:normalize_fname(resolve('./Xlink.lnk'))) call delete('Xlink.lnk') else echomsg 'skipped test for shortcut file' endif " remove files call delete('Xlink') call delete('Xdir', 'd') call delete('Xresfile') " test for symbolic link to a file new Xresfile wq call assert_equal('Xresfile', resolve('Xresfile')) silent !mklink Xlink Xresfile if !v:shell_error call assert_equal(s:normalize_fname(getcwd() . '\Xresfile'), s:normalize_fname(resolve('./Xlink'))) call delete('Xlink') else echomsg 'skipped test for symbolic link to a file' endif call delete('Xresfile') " test for junction to a directory call mkdir('Xdir') silent !mklink /J Xlink Xdir if !v:shell_error call assert_equal(s:normalize_fname(getcwd() . '\Xdir'), s:normalize_fname(resolve(getcwd() . '/Xlink'))) call delete('Xdir', 'd') " test for junction already removed call assert_equal(s:normalize_fname(getcwd() . '\Xlink'), s:normalize_fname(resolve(getcwd() . '/Xlink'))) call delete('Xlink') else echomsg 'skipped test for junction to a directory' call delete('Xdir', 'd') endif " test for symbolic link to a directory call mkdir('Xdir') silent !mklink /D Xlink Xdir if !v:shell_error call assert_equal(s:normalize_fname(getcwd() . '\Xdir'), s:normalize_fname(resolve(getcwd() . '/Xlink'))) call delete('Xdir', 'd') " test for symbolic link already removed call assert_equal(s:normalize_fname(getcwd() . '\Xlink'), s:normalize_fname(resolve(getcwd() . '/Xlink'))) call delete('Xlink') else echomsg 'skipped test for symbolic link to a directory' call delete('Xdir', 'd') endif " test for buffer name new Xbuffile wq silent !mklink Xlink Xbuffile if !v:shell_error edit Xlink call assert_equal('Xlink', bufname('%')) call delete('Xlink') bw! else echomsg 'skipped test for buffer name' endif call delete('Xbuffile') " test for reparse point call mkdir('Xdir') call assert_equal('Xdir', resolve('Xdir')) silent !mklink /D Xdirlink Xdir if !v:shell_error w Xdir/text.txt call assert_equal('Xdir/text.txt', resolve('Xdir/text.txt')) call assert_equal(s:normalize_fname(getcwd() . '\Xdir\text.txt'), s:normalize_fname(resolve('Xdirlink\text.txt'))) call assert_equal(s:normalize_fname(getcwd() . '\Xdir'), s:normalize_fname(resolve('Xdirlink'))) call delete('Xdirlink') else echomsg 'skipped test for reparse point' endif call delete('Xdir', 'rf') endfunc func Test_simplify() call assert_equal('', simplify('')) call assert_equal('/', simplify('/')) call assert_equal('/', simplify('/.')) call assert_equal('/', simplify('/..')) call assert_equal('/...', simplify('/...')) call assert_equal('//path', simplify('//path')) if has('unix') call assert_equal('/path', simplify('///path')) call assert_equal('/path', simplify('////path')) endif call assert_equal('./dir/file', './dir/file'->simplify()) call assert_equal('./dir/file', simplify('.///dir//file')) call assert_equal('./dir/file', simplify('./dir/./file')) call assert_equal('./file', simplify('./dir/../file')) call assert_equal('../dir/file', simplify('dir/../../dir/file')) call assert_equal('./file', simplify('dir/.././file')) call assert_equal('../dir', simplify('./../dir')) call assert_equal('..', simplify('../testdir/..')) call mkdir('Xsimpdir') call assert_equal('.', simplify('Xsimpdir/../.')) call delete('Xsimpdir', 'd') call assert_fails('call simplify({->0})', 'E729:') call assert_fails('call simplify([])', 'E730:') call assert_fails('call simplify({})', 'E731:') call assert_equal('1.2', simplify(1.2)) call v9.CheckDefAndScriptFailure(['echo simplify(1.2)'], ['E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1']) endfunc func Test_pathshorten() call assert_equal('', pathshorten('')) call assert_equal('foo', pathshorten('foo')) call assert_equal('/foo', '/foo'->pathshorten()) call assert_equal('f/', pathshorten('foo/')) call assert_equal('f/bar', pathshorten('foo/bar')) call assert_equal('f/b/foobar', 'foo/bar/foobar'->pathshorten()) call assert_equal('/f/b/foobar', pathshorten('/foo/bar/foobar')) call assert_equal('.f/bar', pathshorten('.foo/bar')) call assert_equal('~f/bar', pathshorten('~foo/bar')) call assert_equal('~.f/bar', pathshorten('~.foo/bar')) call assert_equal('.~f/bar', pathshorten('.~foo/bar')) call assert_equal('~/f/bar', pathshorten('~/foo/bar')) call assert_fails('call pathshorten([])', 'E730:') " test pathshorten with optional variable to set preferred size of shortening call assert_equal('', pathshorten('', 2)) call assert_equal('foo', pathshorten('foo', 2)) call assert_equal('/foo', pathshorten('/foo', 2)) call assert_equal('fo/', pathshorten('foo/', 2)) call assert_equal('fo/bar', pathshorten('foo/bar', 2)) call assert_equal('fo/ba/foobar', pathshorten('foo/bar/foobar', 2)) call assert_equal('/fo/ba/foobar', pathshorten('/foo/bar/foobar', 2)) call assert_equal('.fo/bar', pathshorten('.foo/bar', 2)) call assert_equal('~fo/bar', pathshorten('~foo/bar', 2)) call assert_equal('~.fo/bar', pathshorten('~.foo/bar', 2)) call assert_equal('.~fo/bar', pathshorten('.~foo/bar', 2)) call assert_equal('~/fo/bar', pathshorten('~/foo/bar', 2)) call assert_fails('call pathshorten([],2)', 'E730:') call assert_notequal('~/fo/bar', pathshorten('~/foo/bar', 3)) call assert_equal('~/foo/bar', pathshorten('~/foo/bar', 3)) call assert_equal('~/f/bar', pathshorten('~/foo/bar', 0)) endfunc func Test_strpart() call assert_equal('de', strpart('abcdefg', 3, 2)) call assert_equal('ab', strpart('abcdefg', -2, 4)) call assert_equal('abcdefg', 'abcdefg'->strpart(-2)) call assert_equal('fg', strpart('abcdefg', 5, 4)) call assert_equal('defg', strpart('abcdefg', 3)) call assert_equal('', strpart('abcdefg', 10)) call assert_fails("let s=strpart('abcdef', [])", 'E745:') call assert_equal('lép', strpart('éléphant', 2, 4)) call assert_equal('léphant', strpart('éléphant', 2)) call assert_equal('é', strpart('éléphant', 0, 1, 1)) call assert_equal('ép', strpart('éléphant', 3, 2, v:true)) call assert_equal('ó', strpart('cómposed', 1, 1, 1)) endfunc func Test_tolower() call assert_equal("", tolower("")) " Test with all printable ASCII characters. call assert_equal(' !"#$%&''()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~', \ tolower(' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~')) " Test with a few uppercase diacritics. call assert_equal("aàáâãäåāăąǎǟǡả", tolower("AÀÁÂÃÄÅĀĂĄǍǞǠẢ")) call assert_equal("bḃḇ", tolower("BḂḆ")) call assert_equal("cçćĉċč", tolower("CÇĆĈĊČ")) call assert_equal("dďđḋḏḑ", tolower("DĎĐḊḎḐ")) call assert_equal("eèéêëēĕėęěẻẽ", tolower("EÈÉÊËĒĔĖĘĚẺẼ")) call assert_equal("fḟ ", tolower("FḞ ")) call assert_equal("gĝğġģǥǧǵḡ", tolower("GĜĞĠĢǤǦǴḠ")) call assert_equal("hĥħḣḧḩ", tolower("HĤĦḢḦḨ")) call assert_equal("iìíîïĩīĭįiǐỉ", tolower("IÌÍÎÏĨĪĬĮİǏỈ")) call assert_equal("jĵ", tolower("JĴ")) call assert_equal("kķǩḱḵ", tolower("KĶǨḰḴ")) call assert_equal("lĺļľŀłḻ", tolower("LĹĻĽĿŁḺ")) call assert_equal("mḿṁ", tolower("MḾṀ")) call assert_equal("nñńņňṅṉ", tolower("NÑŃŅŇṄṈ")) call assert_equal("oòóôõöøōŏőơǒǫǭỏ", tolower("OÒÓÔÕÖØŌŎŐƠǑǪǬỎ")) call assert_equal("pṕṗ", tolower("PṔṖ")) call assert_equal("q", tolower("Q")) call assert_equal("rŕŗřṙṟ", tolower("RŔŖŘṘṞ")) call assert_equal("sśŝşšṡ", tolower("SŚŜŞŠṠ")) call assert_equal("tţťŧṫṯ", tolower("TŢŤŦṪṮ")) call assert_equal("uùúûüũūŭůűųưǔủ", tolower("UÙÚÛÜŨŪŬŮŰŲƯǓỦ")) call assert_equal("vṽ", tolower("VṼ")) call assert_equal("wŵẁẃẅẇ", tolower("WŴẀẂẄẆ")) call assert_equal("xẋẍ", tolower("XẊẌ")) call assert_equal("yýŷÿẏỳỷỹ", tolower("YÝŶŸẎỲỶỸ")) call assert_equal("zźżžƶẑẕ", tolower("ZŹŻŽƵẐẔ")) " Test with a few lowercase diacritics, which should remain unchanged. call assert_equal("aàáâãäåāăąǎǟǡả", tolower("aàáâãäåāăąǎǟǡả")) call assert_equal("bḃḇ", tolower("bḃḇ")) call assert_equal("cçćĉċč", tolower("cçćĉċč")) call assert_equal("dďđḋḏḑ", tolower("dďđḋḏḑ")) call assert_equal("eèéêëēĕėęěẻẽ", tolower("eèéêëēĕėęěẻẽ")) call assert_equal("fḟ", tolower("fḟ")) call assert_equal("gĝğġģǥǧǵḡ", tolower("gĝğġģǥǧǵḡ")) call assert_equal("hĥħḣḧḩẖ", tolower("hĥħḣḧḩẖ")) call assert_equal("iìíîïĩīĭįǐỉ", tolower("iìíîïĩīĭįǐỉ")) call assert_equal("jĵǰ", tolower("jĵǰ")) call assert_equal("kķǩḱḵ", tolower("kķǩḱḵ")) call assert_equal("lĺļľŀłḻ", tolower("lĺļľŀłḻ")) call assert_equal("mḿṁ ", tolower("mḿṁ ")) call assert_equal("nñńņňʼnṅṉ", tolower("nñńņňʼnṅṉ")) call assert_equal("oòóôõöøōŏőơǒǫǭỏ", tolower("oòóôõöøōŏőơǒǫǭỏ")) call assert_equal("pṕṗ", tolower("pṕṗ")) call assert_equal("q", tolower("q")) call assert_equal("rŕŗřṙṟ", tolower("rŕŗřṙṟ")) call assert_equal("sśŝşšṡ", tolower("sśŝşšṡ")) call assert_equal("tţťŧṫṯẗ", tolower("tţťŧṫṯẗ")) call assert_equal("uùúûüũūŭůűųưǔủ", tolower("uùúûüũūŭůűųưǔủ")) call assert_equal("vṽ", tolower("vṽ")) call assert_equal("wŵẁẃẅẇẘ", tolower("wŵẁẃẅẇẘ")) call assert_equal("ẋẍ", tolower("ẋẍ")) call assert_equal("yýÿŷẏẙỳỷỹ", tolower("yýÿŷẏẙỳỷỹ")) call assert_equal("zźżžƶẑẕ", tolower("zźżžƶẑẕ")) " According to https://twitter.com/jifa/status/625776454479970304 " Ⱥ (U+023A) and Ⱦ (U+023E) are the *only* code points to increase " in length (2 to 3 bytes) when lowercased. So let's test them. call assert_equal("ⱥ ⱦ", tolower("Ⱥ Ⱦ")) " This call to tolower with invalid utf8 sequence used to cause access to " invalid memory. call tolower("\xC0\x80\xC0") call tolower("123\xC0\x80\xC0") " Test in latin1 encoding let save_enc = &encoding set encoding=latin1 call assert_equal("abc", tolower("ABC")) let &encoding = save_enc endfunc func Test_toupper() call assert_equal("", toupper("")) " Test with all printable ASCII characters. call assert_equal(' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~', \ toupper(' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~')) " Test with a few lowercase diacritics. call assert_equal("AÀÁÂÃÄÅĀĂĄǍǞǠẢ", "aàáâãäåāăąǎǟǡả"->toupper()) call assert_equal("BḂḆ", toupper("bḃḇ")) call assert_equal("CÇĆĈĊČ", toupper("cçćĉċč")) call assert_equal("DĎĐḊḎḐ", toupper("dďđḋḏḑ")) call assert_equal("EÈÉÊËĒĔĖĘĚẺẼ", toupper("eèéêëēĕėęěẻẽ")) call assert_equal("FḞ", toupper("fḟ")) call assert_equal("GĜĞĠĢǤǦǴḠ", toupper("gĝğġģǥǧǵḡ")) call assert_equal("HĤĦḢḦḨẖ", toupper("hĥħḣḧḩẖ")) call assert_equal("IÌÍÎÏĨĪĬĮǏỈ", toupper("iìíîïĩīĭįǐỉ")) call assert_equal("JĴǰ", toupper("jĵǰ")) call assert_equal("KĶǨḰḴ", toupper("kķǩḱḵ")) call assert_equal("LĹĻĽĿŁḺ", toupper("lĺļľŀłḻ")) call assert_equal("MḾṀ ", toupper("mḿṁ ")) call assert_equal("NÑŃŅŇʼnṄṈ", toupper("nñńņňʼnṅṉ")) call assert_equal("OÒÓÔÕÖØŌŎŐƠǑǪǬỎ", toupper("oòóôõöøōŏőơǒǫǭỏ")) call assert_equal("PṔṖ", toupper("pṕṗ")) call assert_equal("Q", toupper("q")) call assert_equal("RŔŖŘṘṞ", toupper("rŕŗřṙṟ")) call assert_equal("SŚŜŞŠṠ", toupper("sśŝşšṡ")) call assert_equal("TŢŤŦṪṮẗ", toupper("tţťŧṫṯẗ")) call assert_equal("UÙÚÛÜŨŪŬŮŰŲƯǓỦ", toupper("uùúûüũūŭůűųưǔủ")) call assert_equal("VṼ", toupper("vṽ")) call assert_equal("WŴẀẂẄẆẘ", toupper("wŵẁẃẅẇẘ")) call assert_equal("ẊẌ", toupper("ẋẍ")) call assert_equal("YÝŸŶẎẙỲỶỸ", toupper("yýÿŷẏẙỳỷỹ")) call assert_equal("ZŹŻŽƵẐẔ", toupper("zźżžƶẑẕ")) " Test that uppercase diacritics, which should remain unchanged. call assert_equal("AÀÁÂÃÄÅĀĂĄǍǞǠẢ", toupper("AÀÁÂÃÄÅĀĂĄǍǞǠẢ")) call assert_equal("BḂḆ", toupper("BḂḆ")) call assert_equal("CÇĆĈĊČ", toupper("CÇĆĈĊČ")) call assert_equal("DĎĐḊḎḐ", toupper("DĎĐḊḎḐ")) call assert_equal("EÈÉÊËĒĔĖĘĚẺẼ", toupper("EÈÉÊËĒĔĖĘĚẺẼ")) call assert_equal("FḞ ", toupper("FḞ ")) call assert_equal("GĜĞĠĢǤǦǴḠ", toupper("GĜĞĠĢǤǦǴḠ")) call assert_equal("HĤĦḢḦḨ", toupper("HĤĦḢḦḨ")) call assert_equal("IÌÍÎÏĨĪĬĮİǏỈ", toupper("IÌÍÎÏĨĪĬĮİǏỈ")) call assert_equal("JĴ", toupper("JĴ")) call assert_equal("KĶǨḰḴ", toupper("KĶǨḰḴ")) call assert_equal("LĹĻĽĿŁḺ", toupper("LĹĻĽĿŁḺ")) call assert_equal("MḾṀ", toupper("MḾṀ")) call assert_equal("NÑŃŅŇṄṈ", toupper("NÑŃŅŇṄṈ")) call assert_equal("OÒÓÔÕÖØŌŎŐƠǑǪǬỎ", toupper("OÒÓÔÕÖØŌŎŐƠǑǪǬỎ")) call assert_equal("PṔṖ", toupper("PṔṖ")) call assert_equal("Q", toupper("Q")) call assert_equal("RŔŖŘṘṞ", toupper("RŔŖŘṘṞ")) call assert_equal("SŚŜŞŠṠ", toupper("SŚŜŞŠṠ")) call assert_equal("TŢŤŦṪṮ", toupper("TŢŤŦṪṮ")) call assert_equal("UÙÚÛÜŨŪŬŮŰŲƯǓỦ", toupper("UÙÚÛÜŨŪŬŮŰŲƯǓỦ")) call assert_equal("VṼ", toupper("VṼ")) call assert_equal("WŴẀẂẄẆ", toupper("WŴẀẂẄẆ")) call assert_equal("XẊẌ", toupper("XẊẌ")) call assert_equal("YÝŶŸẎỲỶỸ", toupper("YÝŶŸẎỲỶỸ")) call assert_equal("ZŹŻŽƵẐẔ", toupper("ZŹŻŽƵẐẔ")) call assert_equal("Ⱥ Ⱦ", toupper("ⱥ ⱦ")) " This call to toupper with invalid utf8 sequence used to cause access to " invalid memory. call toupper("\xC0\x80\xC0") call toupper("123\xC0\x80\xC0") " Test in latin1 encoding let save_enc = &encoding set encoding=latin1 call assert_equal("ABC", toupper("abc")) let &encoding = save_enc endfunc func Test_tr() call assert_equal('foo', tr('bar', 'bar', 'foo')) call assert_equal('zxy', 'cab'->tr('abc', 'xyz')) call assert_fails("let s=tr([], 'abc', 'def')", 'E730:') call assert_fails("let s=tr('abc', [], 'def')", 'E730:') call assert_fails("let s=tr('abc', 'abc', [])", 'E730:') call assert_fails("let s=tr('abcd', 'abcd', 'def')", 'E475:') set encoding=latin1 call assert_fails("let s=tr('abcd', 'abcd', 'def')", 'E475:') call assert_equal('hEllO', tr('hello', 'eo', 'EO')) call assert_equal('hello', tr('hello', 'xy', 'ab')) call assert_fails('call tr("abc", "123", "₁₂")', 'E475:') set encoding=utf8 endfunc " Tests for the mode() function let current_modes = '' func Save_mode() let g:current_modes = mode(0) . '-' . mode(1) return '' endfunc " Test for the mode() function func Test_mode() new call append(0, ["Blue Ball Black", "Brown Band Bowl", ""]) " Only complete from the current buffer. set complete=. noremap! =Save_mode() xnoremap call Save_mode() normal! 3G exe "normal i\\" call assert_equal('i-i', g:current_modes) " i_CTRL-P: Multiple matches exe "normal i\uBa\\\u" call assert_equal('i-ic', g:current_modes) " i_CTRL-P: Single match exe "normal iBro\\\u" call assert_equal('i-ic', g:current_modes) " i_CTRL-X exe "normal iBa\\\u" call assert_equal('i-ix', g:current_modes) " i_CTRL-X CTRL-P: Multiple matches exe "normal iBa\\\\u" call assert_equal('i-ic', g:current_modes) " i_CTRL-X CTRL-P: Single match exe "normal iBro\\\\u" call assert_equal('i-ic', g:current_modes) " i_CTRL-X CTRL-P + CTRL-P: Single match exe "normal iBro\\\\\u" call assert_equal('i-ic', g:current_modes) " i_CTRL-X CTRL-L: Multiple matches exe "normal i\\\\u" call assert_equal('i-ic', g:current_modes) " i_CTRL-X CTRL-L: Single match exe "normal iBlu\\\\u" call assert_equal('i-ic', g:current_modes) " i_CTRL-P: No match exe "normal iCom\\\u" call assert_equal('i-ic', g:current_modes) " i_CTRL-X CTRL-P: No match exe "normal iCom\\\\u" call assert_equal('i-ic', g:current_modes) " i_CTRL-X CTRL-L: No match exe "normal iabc\\\\u" call assert_equal('i-ic', g:current_modes) exe "normal R\\" call assert_equal('R-R', g:current_modes) " R_CTRL-P: Multiple matches exe "normal RBa\\\u" call assert_equal('R-Rc', g:current_modes) " R_CTRL-P: Single match exe "normal RBro\\\u" call assert_equal('R-Rc', g:current_modes) " R_CTRL-X exe "normal RBa\\\u" call assert_equal('R-Rx', g:current_modes) " R_CTRL-X CTRL-P: Multiple matches exe "normal RBa\\\\u" call assert_equal('R-Rc', g:current_modes) " R_CTRL-X CTRL-P: Single match exe "normal RBro\\\\u" call assert_equal('R-Rc', g:current_modes) " R_CTRL-X CTRL-P + CTRL-P: Single match exe "normal RBro\\\\\u" call assert_equal('R-Rc', g:current_modes) " R_CTRL-X CTRL-L: Multiple matches exe "normal R\\\\u" call assert_equal('R-Rc', g:current_modes) " R_CTRL-X CTRL-L: Single match exe "normal RBlu\\\\u" call assert_equal('R-Rc', g:current_modes) " R_CTRL-P: No match exe "normal RCom\\\u" call assert_equal('R-Rc', g:current_modes) " R_CTRL-X CTRL-P: No match exe "normal RCom\\\\u" call assert_equal('R-Rc', g:current_modes) " R_CTRL-X CTRL-L: No match exe "normal Rabc\\\\u" call assert_equal('R-Rc', g:current_modes) exe "normal gR\\" call assert_equal('R-Rv', g:current_modes) " gR_CTRL-P: Multiple matches exe "normal gRBa\\\u" call assert_equal('R-Rvc', g:current_modes) " gR_CTRL-P: Single match exe "normal gRBro\\\u" call assert_equal('R-Rvc', g:current_modes) " gR_CTRL-X exe "normal gRBa\\\u" call assert_equal('R-Rvx', g:current_modes) " gR_CTRL-X CTRL-P: Multiple matches exe "normal gRBa\\\\u" call assert_equal('R-Rvc', g:current_modes) " gR_CTRL-X CTRL-P: Single match exe "normal gRBro\\\\u" call assert_equal('R-Rvc', g:current_modes) " gR_CTRL-X CTRL-P + CTRL-P: Single match exe "normal gRBro\\\\\u" call assert_equal('R-Rvc', g:current_modes) " gR_CTRL-X CTRL-L: Multiple matches exe "normal gR\\\\u" call assert_equal('R-Rvc', g:current_modes) " gR_CTRL-X CTRL-L: Single match exe "normal gRBlu\\\\u" call assert_equal('R-Rvc', g:current_modes) " gR_CTRL-P: No match exe "normal gRCom\\\u" call assert_equal('R-Rvc', g:current_modes) " gR_CTRL-X CTRL-P: No match exe "normal gRCom\\\\u" call assert_equal('R-Rvc', g:current_modes) " gR_CTRL-X CTRL-L: No match exe "normal gRabc\\\\u" call assert_equal('R-Rvc', g:current_modes) call assert_equal('n', 0->mode()) call assert_equal('n', 1->mode()) " i_CTRL-O exe "normal i\:call Save_mode()\\" call assert_equal("n-niI", g:current_modes) " R_CTRL-O exe "normal R\:call Save_mode()\\" call assert_equal("n-niR", g:current_modes) " gR_CTRL-O exe "normal gR\:call Save_mode()\\" call assert_equal("n-niV", g:current_modes) " How to test operator-pending mode? call feedkeys("v", 'xt') call assert_equal('v', mode()) call assert_equal('v', mode(1)) call feedkeys("\V", 'xt') call assert_equal('V', mode()) call assert_equal('V', mode(1)) call feedkeys("\\", 'xt') call assert_equal("\", mode()) call assert_equal("\", mode(1)) call feedkeys("\", 'xt') call feedkeys("gh", 'xt') call assert_equal('s', mode()) call assert_equal('s', mode(1)) call feedkeys("\gH", 'xt') call assert_equal('S', mode()) call assert_equal('S', mode(1)) call feedkeys("\g\", 'xt') call assert_equal("\", mode()) call assert_equal("\", mode(1)) call feedkeys("\", 'xt') " v_CTRL-O exe "normal gh\\\" call assert_equal("v-vs", g:current_modes) exe "normal gH\\\" call assert_equal("V-Vs", g:current_modes) exe "normal g\\\\" call assert_equal("\-\s", g:current_modes) call feedkeys(":\\", 'xt') call assert_equal('c-c', g:current_modes) call feedkeys(":\\\", 'xt') call assert_equal("c-cr", g:current_modes) call feedkeys("gQ\vi\", 'xt') call assert_equal('c-cv', g:current_modes) call feedkeys("gQ\\vi\", 'xt') call assert_equal("c-cvr", g:current_modes) " Executing commands in Vim Ex mode should return "cv", never "cvr", " as Cmdline editing has already ended. call feedkeys("gQcall Save_mode()\vi\", 'xt') call assert_equal('c-cv', g:current_modes) call feedkeys("gQ\call Save_mode()\vi\", 'xt') call assert_equal('c-cv', g:current_modes) call feedkeys("Qcall Save_mode()\vi\", 'xt') call assert_equal('c-ce', g:current_modes) " Test mode in operatorfunc (it used to be Operator-pending). set operatorfunc=OperatorFunc function OperatorFunc(_) call Save_mode() endfunction execute "normal! g@l\" call assert_equal('n-n', g:current_modes) execute "normal! i\g@l\" call assert_equal('n-niI', g:current_modes) execute "normal! R\g@l\" call assert_equal('n-niR', g:current_modes) execute "normal! gR\g@l\" call assert_equal('n-niV', g:current_modes) " Test statusline updates for overstrike mode if CanRunVimInTerminal() let buf = RunVimInTerminal('', {'rows': 12}) call term_sendkeys(buf, ":set laststatus=2 statusline=%!mode(1)\") call term_sendkeys(buf, ":") call TermWait(buf) call VerifyScreenDump(buf, 'Test_mode_1', {}) call term_sendkeys(buf, "\") call TermWait(buf) call VerifyScreenDump(buf, 'Test_mode_2', {}) call StopVimInTerminal(buf) endif if has('terminal') term " Terminal-Job mode call assert_equal('t', mode()) call assert_equal('t', mode(1)) call feedkeys("\:echo \=Save_mode()\\", 'xt') call assert_equal("c-ct", g:current_modes) call feedkeys("\", 'xt') " Terminal-Normal mode call feedkeys("\N", 'xt') call assert_equal('n', mode()) call assert_equal('nt', mode(1)) call feedkeys(":echo \=Save_mode()\\", 'xt') call assert_equal("c-c", g:current_modes) call feedkeys("aexit\", 'xt') endif bwipe! unmap! xunmap set complete& set operatorfunc& delfunction OperatorFunc endfunc " Test for append() func Test_append() enew! split call assert_equal(0, append(1, [])) call assert_equal(0, append(1, test_null_list())) call assert_equal(0, append(0, ["foo"])) call assert_equal(0, append(1, [])) call assert_equal(0, append(1, test_null_list())) call assert_equal(0, append(8, [])) call assert_equal(0, append(9, test_null_list())) call assert_equal(['foo', ''], getline(1, '$')) split only undo undo " Using $ instead of '$' must give an error call assert_fails("call append($, 'foobar')", 'E116:') call assert_fails("call append({}, '')", ['E728:', 'E728:']) endfunc " Test for setline() func Test_setline() new call setline(0, ["foo"]) call setline(0, []) call setline(0, test_null_list()) call setline(1, ["bar"]) call setline(1, []) call setline(1, test_null_list()) call setline(2, []) call setline(2, test_null_list()) call setline(3, []) call setline(3, test_null_list()) call setline(2, ["baz"]) call assert_equal(['bar', 'baz'], getline(1, '$')) close! endfunc func Test_getbufvar() let bnr = bufnr('%') let b:var_num = '1234' let def_num = '5678' call assert_equal('1234', getbufvar(bnr, 'var_num')) call assert_equal('1234', getbufvar(bnr, 'var_num', def_num)) let bd = getbufvar(bnr, '') call assert_equal('1234', bd['var_num']) call assert_true(exists("bd['changedtick']")) call assert_equal(2, len(bd)) let bd2 = getbufvar(bnr, '', def_num) call assert_equal(bd, bd2) unlet b:var_num call assert_equal(def_num, getbufvar(bnr, 'var_num', def_num)) call assert_equal('', getbufvar(bnr, 'var_num')) let bd = getbufvar(bnr, '') call assert_equal(1, len(bd)) let bd = getbufvar(bnr, '',def_num) call assert_equal(1, len(bd)) call assert_equal('', getbufvar(9999, '')) call assert_equal(def_num, getbufvar(9999, '', def_num)) unlet def_num call assert_equal(0, getbufvar(bnr, '&autoindent')) call assert_equal(0, getbufvar(bnr, '&autoindent', 1)) " Set and get a buffer-local variable call setbufvar(bnr, 'bufvar_test', ['one', 'two']) call assert_equal(['one', 'two'], getbufvar(bnr, 'bufvar_test')) " Open new window with forced option values set fileformats=unix,dos new ++ff=dos ++bin ++enc=iso-8859-2 call assert_equal('dos', getbufvar(bufnr('%'), '&fileformat')) call assert_equal(1, getbufvar(bufnr('%'), '&bin')) call assert_equal('iso-8859-2', getbufvar(bufnr('%'), '&fenc')) close " Get the b: dict. let b:testvar = 'one' new let b:testvar = 'two' let thebuf = bufnr() wincmd w call assert_equal('two', getbufvar(thebuf, 'testvar')) call assert_equal('two', getbufvar(thebuf, '').testvar) bwipe! set fileformats& endfunc func Test_last_buffer_nr() call assert_equal(bufnr('$'), last_buffer_nr()) endfunc func Test_stridx() call assert_equal(-1, stridx('', 'l')) call assert_equal(0, stridx('', '')) call assert_equal(0, 'hello'->stridx('')) call assert_equal(-1, stridx('hello', 'L')) call assert_equal(2, stridx('hello', 'l', -1)) call assert_equal(2, stridx('hello', 'l', 0)) call assert_equal(2, 'hello'->stridx('l', 1)) call assert_equal(3, stridx('hello', 'l', 3)) call assert_equal(-1, stridx('hello', 'l', 4)) call assert_equal(-1, stridx('hello', 'l', 10)) call assert_equal(2, stridx('hello', 'll')) call assert_equal(-1, stridx('hello', 'hello world')) call assert_fails("let n=stridx('hello', [])", 'E730:') call assert_fails("let n=stridx([], 'l')", 'E730:') endfunc func Test_strridx() call assert_equal(-1, strridx('', 'l')) call assert_equal(0, strridx('', '')) call assert_equal(5, strridx('hello', '')) call assert_equal(-1, strridx('hello', 'L')) call assert_equal(3, 'hello'->strridx('l')) call assert_equal(3, strridx('hello', 'l', 10)) call assert_equal(3, strridx('hello', 'l', 3)) call assert_equal(2, strridx('hello', 'l', 2)) call assert_equal(-1, strridx('hello', 'l', 1)) call assert_equal(-1, strridx('hello', 'l', 0)) call assert_equal(-1, strridx('hello', 'l', -1)) call assert_equal(2, strridx('hello', 'll')) call assert_equal(-1, strridx('hello', 'hello world')) call assert_fails("let n=strridx('hello', [])", 'E730:') call assert_fails("let n=strridx([], 'l')", 'E730:') endfunc func Test_match_func() call assert_equal(4, match('testing', 'ing')) call assert_equal(4, 'testing'->match('ing', 2)) call assert_equal(-1, match('testing', 'ing', 5)) call assert_equal(-1, match('testing', 'ing', 8)) call assert_equal(1, match(['vim', 'testing', 'execute'], 'ing')) call assert_equal(-1, match(['vim', 'testing', 'execute'], 'img')) call assert_fails("let x=match('vim', [])", 'E730:') call assert_equal(3, match(['a', 'b', 'c', 'a'], 'a', 1)) call assert_equal(-1, match(['a', 'b', 'c', 'a'], 'a', 5)) call assert_equal(4, match('testing', 'ing', -1)) call assert_fails("let x=match('testing', 'ing', 0, [])", 'E745:') call assert_equal(-1, match(test_null_list(), 2)) call assert_equal(-1, match('abc', '\\%(')) endfunc func Test_matchend() call assert_equal(7, matchend('testing', 'ing')) call assert_equal(7, 'testing'->matchend('ing', 2)) call assert_equal(-1, matchend('testing', 'ing', 5)) call assert_equal(-1, matchend('testing', 'ing', 8)) call assert_equal(match(['vim', 'testing', 'execute'], 'ing'), matchend(['vim', 'testing', 'execute'], 'ing')) call assert_equal(match(['vim', 'testing', 'execute'], 'img'), matchend(['vim', 'testing', 'execute'], 'img')) endfunc func Test_matchlist() call assert_equal(['acd', 'a', '', 'c', 'd', '', '', '', '', ''], matchlist('acd', '\(a\)\?\(b\)\?\(c\)\?\(.*\)')) call assert_equal(['d', '', '', '', 'd', '', '', '', '', ''], 'acd'->matchlist('\(a\)\?\(b\)\?\(c\)\?\(.*\)', 2)) call assert_equal([], matchlist('acd', '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 4)) endfunc func Test_matchstr() call assert_equal('ing', matchstr('testing', 'ing')) call assert_equal('ing', 'testing'->matchstr('ing', 2)) call assert_equal('', matchstr('testing', 'ing', 5)) call assert_equal('', matchstr('testing', 'ing', 8)) call assert_equal('testing', matchstr(['vim', 'testing', 'execute'], 'ing')) call assert_equal('', matchstr(['vim', 'testing', 'execute'], 'img')) endfunc func Test_matchstrpos() call assert_equal(['ing', 4, 7], matchstrpos('testing', 'ing')) call assert_equal(['ing', 4, 7], 'testing'->matchstrpos('ing', 2)) call assert_equal(['', -1, -1], matchstrpos('testing', 'ing', 5)) call assert_equal(['', -1, -1], matchstrpos('testing', 'ing', 8)) call assert_equal(['ing', 1, 4, 7], matchstrpos(['vim', 'testing', 'execute'], 'ing')) call assert_equal(['', -1, -1, -1], matchstrpos(['vim', 'testing', 'execute'], 'img')) call assert_equal(['', -1, -1], matchstrpos(test_null_list(), '\a')) endfunc " Test for matchstrlist() func Test_matchstrlist() let lines =<< trim END #" Basic match call assert_equal([{'idx': 0, 'byteidx': 1, 'text': 'bout'}, \ {'idx': 1, 'byteidx': 1, 'text': 'bove'}], \ matchstrlist(['about', 'above'], 'bo.*')) #" no match call assert_equal([], matchstrlist(['about', 'above'], 'xy.*')) #" empty string call assert_equal([], matchstrlist([''], '.')) #" empty pattern call assert_equal([{'idx': 0, 'byteidx': 0, 'text': ''}], matchstrlist(['abc'], '')) #" method call call assert_equal([{'idx': 0, 'byteidx': 2, 'text': 'it'}], ['editor']->matchstrlist('ed\zsit\zeor')) #" single character matches call assert_equal([{'idx': 0, 'byteidx': 5, 'text': 'r'}], \ ['editor']->matchstrlist('r')) call assert_equal([{'idx': 0, 'byteidx': 0, 'text': 'a'}], ['a']->matchstrlist('a')) call assert_equal([{'idx': 0, 'byteidx': 0, 'text': ''}], \ matchstrlist(['foobar'], '\zs')) #" string with tabs call assert_equal([{'idx': 0, 'byteidx': 1, 'text': 'foo'}], \ matchstrlist(["\tfoobar"], 'foo')) #" string with multibyte characters call assert_equal([{'idx': 0, 'byteidx': 2, 'text': '😊😊'}], \ matchstrlist(["\t\t😊😊"], '\k\+')) #" null string call assert_equal([], matchstrlist(test_null_list(), 'abc')) call assert_equal([], matchstrlist([test_null_string()], 'abc')) call assert_equal([{'idx': 0, 'byteidx': 0, 'text': ''}], \ matchstrlist(['abc'], test_null_string())) #" sub matches call assert_equal([{'idx': 0, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}], matchstrlist(['acd'], '\(a\)\?\(b\)\?\(c\)\?\(.*\)', {'submatches': v:true})) #" null dict argument call assert_equal([{'idx': 0, 'byteidx': 0, 'text': 'vim'}], \ matchstrlist(['vim'], '\w\+', test_null_dict())) #" Error cases call assert_fails("echo matchstrlist('abc', 'a')", 'E1211: List required for argument 1') call assert_fails("echo matchstrlist(['abc'], {})", 'E1174: String required for argument 2') call assert_fails("echo matchstrlist(['abc'], '.', [])", 'E1206: Dictionary required for argument 3') call assert_fails("echo matchstrlist(['abc'], 'a', {'submatches': []})", 'E475: Invalid value for argument submatches') call assert_fails("echo matchstrlist(['abc'], '\\@=')", 'E866: (NFA regexp) Misplaced @') END call v9.CheckLegacyAndVim9Success(lines) let lines =<< trim END vim9script # non string items matchstrlist([0z10, {'a': 'x'}], 'x') END call v9.CheckSourceSuccess(lines) let lines =<< trim END vim9script def Foo() # non string items assert_equal([], matchstrlist([0z10, {'a': 'x'}], 'x')) enddef Foo() END call v9.CheckSourceFailure(lines, 'E1013: Argument 1: type mismatch, expected list but got list', 2) endfunc " Test for matchbufline() func Test_matchbufline() let lines =<< trim END #" Basic match new call setline(1, ['about', 'above', 'below']) VAR bnr = bufnr() wincmd w call assert_equal([{'lnum': 1, 'byteidx': 1, 'text': 'bout'}, \ {'lnum': 2, 'byteidx': 1, 'text': 'bove'}], \ matchbufline(bnr, 'bo.*', 1, '$')) #" multiple matches in a line call setbufline(bnr, 1, ['about about', 'above above', 'below']) call assert_equal([{'lnum': 1, 'byteidx': 1, 'text': 'bout'}, \ {'lnum': 1, 'byteidx': 7, 'text': 'bout'}, \ {'lnum': 2, 'byteidx': 1, 'text': 'bove'}, \ {'lnum': 2, 'byteidx': 7, 'text': 'bove'}], \ matchbufline(bnr, 'bo\k\+', 1, '$')) #" no match call assert_equal([], matchbufline(bnr, 'xy.*', 1, '$')) #" match on a particular line call assert_equal([{'lnum': 2, 'byteidx': 7, 'text': 'bove'}], \ matchbufline(bnr, 'bo\k\+$', 2, 2)) #" match on a particular line call assert_equal([], matchbufline(bnr, 'bo.*', 3, 3)) #" empty string call deletebufline(bnr, 1, '$') call assert_equal([], matchbufline(bnr, '.', 1, '$')) #" empty pattern call setbufline(bnr, 1, 'abc') call assert_equal([{'lnum': 1, 'byteidx': 0, 'text': ''}], \ matchbufline(bnr, '', 1, '$')) #" method call call setbufline(bnr, 1, 'editor') call assert_equal([{'lnum': 1, 'byteidx': 2, 'text': 'it'}], \ bnr->matchbufline('ed\zsit\zeor', 1, 1)) #" single character matches call assert_equal([{'lnum': 1, 'byteidx': 5, 'text': 'r'}], \ matchbufline(bnr, 'r', 1, '$')) call setbufline(bnr, 1, 'a') call assert_equal([{'lnum': 1, 'byteidx': 0, 'text': 'a'}], \ matchbufline(bnr, 'a', 1, '$')) #" zero-width match call assert_equal([{'lnum': 1, 'byteidx': 0, 'text': ''}], \ matchbufline(bnr, '\zs', 1, '$')) #" string with tabs call setbufline(bnr, 1, "\tfoobar") call assert_equal([{'lnum': 1, 'byteidx': 1, 'text': 'foo'}], \ matchbufline(bnr, 'foo', 1, '$')) #" string with multibyte characters call setbufline(bnr, 1, "\t\t😊😊") call assert_equal([{'lnum': 1, 'byteidx': 2, 'text': '😊😊'}], \ matchbufline(bnr, '\k\+', 1, '$')) #" empty buffer call deletebufline(bnr, 1, '$') call assert_equal([], matchbufline(bnr, 'abc', 1, '$')) #" Non existing buffer call setbufline(bnr, 1, 'abc') call assert_fails("echo matchbufline(5000, 'abc', 1, 1)", 'E158: Invalid buffer name: 5000') #" null string call assert_equal([{'lnum': 1, 'byteidx': 0, 'text': ''}], \ matchbufline(bnr, test_null_string(), 1, 1)) #" invalid starting line number call assert_equal([], matchbufline(bnr, 'abc', 100, 100)) #" ending line number greater than the last line call assert_equal([{'lnum': 1, 'byteidx': 0, 'text': 'abc'}], \ matchbufline(bnr, 'abc', 1, 100)) #" ending line number greater than the starting line number call setbufline(bnr, 1, ['one', 'two']) call assert_fails($"echo matchbufline({bnr}, 'abc', 2, 1)", 'E475: Invalid value for argument end_lnum') #" sub matches call deletebufline(bnr, 1, '$') call setbufline(bnr, 1, 'acd') call assert_equal([{'lnum': 1, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}], \ matchbufline(bnr, '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 1, '$', {'submatches': v:true})) #" null dict argument call assert_equal([{'lnum': 1, 'byteidx': 0, 'text': 'acd'}], \ matchbufline(bnr, '\w\+', '$', '$', test_null_dict())) #" Error cases call assert_fails("echo matchbufline([1], 'abc', 1, 1)", 'E1220: String or Number required for argument 1') call assert_fails("echo matchbufline(1, {}, 1, 1)", 'E1174: String required for argument 2') call assert_fails("echo matchbufline(1, 'abc', {}, 1)", 'E1220: String or Number required for argument 3') call assert_fails("echo matchbufline(1, 'abc', 1, {})", 'E1220: String or Number required for argument 4') call assert_fails($"echo matchbufline({bnr}, 'abc', -1, '$')", 'E475: Invalid value for argument lnum') call assert_fails($"echo matchbufline({bnr}, 'abc', 1, -1)", 'E475: Invalid value for argument end_lnum') call assert_fails($"echo matchbufline({bnr}, '\\@=', 1, 1)", 'E866: (NFA regexp) Misplaced @') call assert_fails($"echo matchbufline({bnr}, 'abc', 1, 1, {{'submatches': []}})", 'E475: Invalid value for argument submatches') :%bdelete! call assert_fails($"echo matchbufline({bnr}, 'abc', 1, '$'))", 'E681: Buffer is not loaded') END call v9.CheckLegacyAndVim9Success(lines) call assert_fails($"echo matchbufline('', 'abc', 'abc', 1)", 'E475: Invalid value for argument lnum') call assert_fails($"echo matchbufline('', 'abc', 1, 'abc')", 'E475: Invalid value for argument end_lnum') let lines =<< trim END vim9script def Foo() echo matchbufline('', 'abc', 'abc', 1) enddef Foo() END call v9.CheckSourceFailure(lines, 'E1030: Using a String as a Number: "abc"', 1) let lines =<< trim END vim9script def Foo() echo matchbufline('', 'abc', 1, 'abc') enddef Foo() END call v9.CheckSourceFailure(lines, 'E1030: Using a String as a Number: "abc"', 1) endfunc func Test_nextnonblank_prevnonblank() new insert This is a Test . call assert_equal(0, nextnonblank(-1)) call assert_equal(0, nextnonblank(0)) call assert_equal(1, nextnonblank(1)) call assert_equal(4, 2->nextnonblank()) call assert_equal(4, nextnonblank(3)) call assert_equal(4, nextnonblank(4)) call assert_equal(6, nextnonblank(5)) call assert_equal(6, nextnonblank(6)) call assert_equal(7, nextnonblank(7)) call assert_equal(0, 8->nextnonblank()) call assert_equal(0, prevnonblank(-1)) call assert_equal(0, prevnonblank(0)) call assert_equal(1, 1->prevnonblank()) call assert_equal(1, prevnonblank(2)) call assert_equal(1, prevnonblank(3)) call assert_equal(4, prevnonblank(4)) call assert_equal(4, 5->prevnonblank()) call assert_equal(6, prevnonblank(6)) call assert_equal(7, prevnonblank(7)) call assert_equal(0, prevnonblank(8)) bw! endfunc func Test_byte2line_line2byte() new set endofline call setline(1, ['a', 'bc', 'd']) set fileformat=unix call assert_equal([-1, -1, 1, 1, 2, 2, 2, 3, 3, -1], \ map(range(-1, 8), 'byte2line(v:val)')) call assert_equal([-1, -1, 1, 3, 6, 8, -1], \ map(range(-1, 5), 'line2byte(v:val)')) set fileformat=mac call assert_equal([-1, -1, 1, 1, 2, 2, 2, 3, 3, -1], \ map(range(-1, 8), 'v:val->byte2line()')) call assert_equal([-1, -1, 1, 3, 6, 8, -1], \ map(range(-1, 5), 'v:val->line2byte()')) set fileformat=dos call assert_equal([-1, -1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, -1], \ map(range(-1, 11), 'byte2line(v:val)')) call assert_equal([-1, -1, 1, 4, 8, 11, -1], \ map(range(-1, 5), 'line2byte(v:val)')) bw! set noendofline nofixendofline normal a- for ff in ["unix", "mac", "dos"] let &fileformat = ff call assert_equal(1, line2byte(1)) call assert_equal(2, line2byte(2)) " line2byte(line("$") + 1) is the buffer size plus one (as per :help line2byte). endfor set endofline& fixendofline& fileformat& bw! endfunc " Test for byteidx() using a character index func Test_byteidx() let a = '.é.' " one char of two bytes call assert_equal(0, byteidx(a, 0)) call assert_equal(1, byteidx(a, 1)) call assert_equal(3, byteidx(a, 2)) call assert_equal(4, byteidx(a, 3)) call assert_equal(-1, byteidx(a, 4)) let b = '.é.' " normal e with composing char call assert_equal(0, b->byteidx(0)) call assert_equal(1, b->byteidx(1)) call assert_equal(4, b->byteidx(2)) call assert_equal(5, b->byteidx(3)) call assert_equal(-1, b->byteidx(4)) " string with multiple composing characters let str = '-ą́-ą́' call assert_equal(0, byteidx(str, 0)) call assert_equal(1, byteidx(str, 1)) call assert_equal(6, byteidx(str, 2)) call assert_equal(7, byteidx(str, 3)) call assert_equal(12, byteidx(str, 4)) call assert_equal(-1, byteidx(str, 5)) " empty string call assert_equal(0, byteidx('', 0)) call assert_equal(-1, byteidx('', 1)) " error cases call assert_fails("call byteidx([], 0)", 'E730:') call assert_fails("call byteidx('abc', [])", 'E745:') call assert_fails("call byteidx('abc', 0, {})", ['E728:', 'E728:']) call assert_fails("call byteidx('abc', 0, -1)", ['E1023:', 'E1023:']) endfunc " Test for byteidxcomp() using a character index func Test_byteidxcomp() let a = '.é.' " one char of two bytes call assert_equal(0, byteidxcomp(a, 0)) call assert_equal(1, byteidxcomp(a, 1)) call assert_equal(3, byteidxcomp(a, 2)) call assert_equal(4, byteidxcomp(a, 3)) call assert_equal(-1, byteidxcomp(a, 4)) let b = '.é.' " normal e with composing char call assert_equal(0, b->byteidxcomp(0)) call assert_equal(1, b->byteidxcomp(1)) call assert_equal(2, b->byteidxcomp(2)) call assert_equal(4, b->byteidxcomp(3)) call assert_equal(5, b->byteidxcomp(4)) call assert_equal(-1, b->byteidxcomp(5)) " string with multiple composing characters let str = '-ą́-ą́' call assert_equal(0, byteidxcomp(str, 0)) call assert_equal(1, byteidxcomp(str, 1)) call assert_equal(2, byteidxcomp(str, 2)) call assert_equal(4, byteidxcomp(str, 3)) call assert_equal(6, byteidxcomp(str, 4)) call assert_equal(7, byteidxcomp(str, 5)) call assert_equal(8, byteidxcomp(str, 6)) call assert_equal(10, byteidxcomp(str, 7)) call assert_equal(12, byteidxcomp(str, 8)) call assert_equal(-1, byteidxcomp(str, 9)) " empty string call assert_equal(0, byteidxcomp('', 0)) call assert_equal(-1, byteidxcomp('', 1)) " error cases call assert_fails("call byteidxcomp([], 0)", 'E730:') call assert_fails("call byteidxcomp('abc', [])", 'E745:') call assert_fails("call byteidxcomp('abc', 0, {})", ['E728:', 'E728:']) call assert_fails("call byteidxcomp('abc', 0, -1)", ['E1023:', 'E1023:']) endfunc " Test for byteidx() using a UTF-16 index func Test_byteidx_from_utf16_index() " string with single byte characters let str = "abc" for i in range(3) call assert_equal(i, byteidx(str, i, v:true)) endfor call assert_equal(3, byteidx(str, 3, v:true)) call assert_equal(-1, byteidx(str, 4, v:true)) " string with two byte characters let str = "a©©b" call assert_equal(0, byteidx(str, 0, v:true)) call assert_equal(1, byteidx(str, 1, v:true)) call assert_equal(3, byteidx(str, 2, v:true)) call assert_equal(5, byteidx(str, 3, v:true)) call assert_equal(6, byteidx(str, 4, v:true)) call assert_equal(-1, byteidx(str, 5, v:true)) " string with two byte characters let str = "a😊😊b" call assert_equal(0, byteidx(str, 0, v:true)) call assert_equal(1, byteidx(str, 1, v:true)) call assert_equal(1, byteidx(str, 2, v:true)) call assert_equal(5, byteidx(str, 3, v:true)) call assert_equal(5, byteidx(str, 4, v:true)) call assert_equal(9, byteidx(str, 5, v:true)) call assert_equal(10, byteidx(str, 6, v:true)) call assert_equal(-1, byteidx(str, 7, v:true)) " string with composing characters let str = '-á-b́' call assert_equal(0, byteidx(str, 0, v:true)) call assert_equal(1, byteidx(str, 1, v:true)) call assert_equal(4, byteidx(str, 2, v:true)) call assert_equal(5, byteidx(str, 3, v:true)) call assert_equal(8, byteidx(str, 4, v:true)) call assert_equal(-1, byteidx(str, 5, v:true)) " string with multiple composing characters let str = '-ą́-ą́' call assert_equal(0, byteidx(str, 0, v:true)) call assert_equal(1, byteidx(str, 1, v:true)) call assert_equal(6, byteidx(str, 2, v:true)) call assert_equal(7, byteidx(str, 3, v:true)) call assert_equal(12, byteidx(str, 4, v:true)) call assert_equal(-1, byteidx(str, 5, v:true)) " empty string call assert_equal(0, byteidx('', 0, v:true)) call assert_equal(-1, byteidx('', 1, v:true)) " error cases call assert_fails('call byteidx(str, 0, [])', 'E745:') endfunc " Test for byteidxcomp() using a UTF-16 index func Test_byteidxcomp_from_utf16_index() " string with single byte characters let str = "abc" for i in range(3) call assert_equal(i, byteidxcomp(str, i, v:true)) endfor call assert_equal(3, byteidxcomp(str, 3, v:true)) call assert_equal(-1, byteidxcomp(str, 4, v:true)) " string with two byte characters let str = "a©©b" call assert_equal(0, byteidxcomp(str, 0, v:true)) call assert_equal(1, byteidxcomp(str, 1, v:true)) call assert_equal(3, byteidxcomp(str, 2, v:true)) call assert_equal(5, byteidxcomp(str, 3, v:true)) call assert_equal(6, byteidxcomp(str, 4, v:true)) call assert_equal(-1, byteidxcomp(str, 5, v:true)) " string with two byte characters let str = "a😊😊b" call assert_equal(0, byteidxcomp(str, 0, v:true)) call assert_equal(1, byteidxcomp(str, 1, v:true)) call assert_equal(1, byteidxcomp(str, 2, v:true)) call assert_equal(5, byteidxcomp(str, 3, v:true)) call assert_equal(5, byteidxcomp(str, 4, v:true)) call assert_equal(9, byteidxcomp(str, 5, v:true)) call assert_equal(10, byteidxcomp(str, 6, v:true)) call assert_equal(-1, byteidxcomp(str, 7, v:true)) " string with composing characters let str = '-á-b́' call assert_equal(0, byteidxcomp(str, 0, v:true)) call assert_equal(1, byteidxcomp(str, 1, v:true)) call assert_equal(2, byteidxcomp(str, 2, v:true)) call assert_equal(4, byteidxcomp(str, 3, v:true)) call assert_equal(5, byteidxcomp(str, 4, v:true)) call assert_equal(6, byteidxcomp(str, 5, v:true)) call assert_equal(8, byteidxcomp(str, 6, v:true)) call assert_equal(-1, byteidxcomp(str, 7, v:true)) call assert_fails('call byteidxcomp(str, 0, [])', 'E745:') " string with multiple composing characters let str = '-ą́-ą́' call assert_equal(0, byteidxcomp(str, 0, v:true)) call assert_equal(1, byteidxcomp(str, 1, v:true)) call assert_equal(2, byteidxcomp(str, 2, v:true)) call assert_equal(4, byteidxcomp(str, 3, v:true)) call assert_equal(6, byteidxcomp(str, 4, v:true)) call assert_equal(7, byteidxcomp(str, 5, v:true)) call assert_equal(8, byteidxcomp(str, 6, v:true)) call assert_equal(10, byteidxcomp(str, 7, v:true)) call assert_equal(12, byteidxcomp(str, 8, v:true)) call assert_equal(-1, byteidxcomp(str, 9, v:true)) " empty string call assert_equal(0, byteidxcomp('', 0, v:true)) call assert_equal(-1, byteidxcomp('', 1, v:true)) " error cases call assert_fails('call byteidxcomp(str, 0, [])', 'E745:') endfunc " Test for charidx() using a byte index func Test_charidx() let a = 'xáb́y' call assert_equal(0, charidx(a, 0)) call assert_equal(1, charidx(a, 3)) call assert_equal(2, charidx(a, 4)) call assert_equal(3, charidx(a, 7)) call assert_equal(4, charidx(a, 8)) call assert_equal(-1, charidx(a, 9)) call assert_equal(-1, charidx(a, -1)) " count composing characters call assert_equal(0, a->charidx(0, 1)) call assert_equal(2, a->charidx(2, 1)) call assert_equal(3, a->charidx(4, 1)) call assert_equal(5, a->charidx(7, 1)) call assert_equal(6, a->charidx(8, 1)) call assert_equal(-1, a->charidx(9, 1)) " empty string call assert_equal(0, charidx('', 0)) call assert_equal(-1, charidx('', 1)) call assert_equal(0, charidx('', 0, 1)) call assert_equal(-1, charidx('', 1, 1)) " error cases call assert_equal(0, charidx(test_null_string(), 0)) call assert_equal(-1, charidx(test_null_string(), 1)) call assert_fails('let x = charidx([], 1)', 'E1174:') call assert_fails('let x = charidx("abc", [])', 'E1210:') call assert_fails('let x = charidx("abc", 1, [])', 'E1212:') call assert_fails('let x = charidx("abc", 1, -1)', 'E1212:') call assert_fails('let x = charidx("abc", 1, 2)', 'E1212:') endfunc " Test for charidx() using a UTF-16 index func Test_charidx_from_utf16_index() " string with single byte characters let str = "abc" for i in range(4) call assert_equal(i, charidx(str, i, v:false, v:true)) endfor call assert_equal(-1, charidx(str, 4, v:false, v:true)) " string with two byte characters let str = "a©©b" call assert_equal(0, charidx(str, 0, v:false, v:true)) call assert_equal(1, charidx(str, 1, v:false, v:true)) call assert_equal(2, charidx(str, 2, v:false, v:true)) call assert_equal(3, charidx(str, 3, v:false, v:true)) call assert_equal(4, charidx(str, 4, v:false, v:true)) call assert_equal(-1, charidx(str, 5, v:false, v:true)) " string with four byte characters let str = "a😊😊b" call assert_equal(0, charidx(str, 0, v:false, v:true)) call assert_equal(1, charidx(str, 1, v:false, v:true)) call assert_equal(1, charidx(str, 2, v:false, v:true)) call assert_equal(2, charidx(str, 3, v:false, v:true)) call assert_equal(2, charidx(str, 4, v:false, v:true)) call assert_equal(3, charidx(str, 5, v:false, v:true)) call assert_equal(4, charidx(str, 6, v:false, v:true)) call assert_equal(-1, charidx(str, 7, v:false, v:true)) " string with composing characters let str = '-á-b́' for i in str->strcharlen()->range() call assert_equal(i, charidx(str, i, v:false, v:true)) endfor call assert_equal(4, charidx(str, 4, v:false, v:true)) call assert_equal(-1, charidx(str, 5, v:false, v:true)) for i in str->strchars()->range() call assert_equal(i, charidx(str, i, v:true, v:true)) endfor call assert_equal(6, charidx(str, 6, v:true, v:true)) call assert_equal(-1, charidx(str, 7, v:true, v:true)) " string with multiple composing characters let str = '-ą́-ą́' for i in str->strcharlen()->range() call assert_equal(i, charidx(str, i, v:false, v:true)) endfor call assert_equal(4, charidx(str, 4, v:false, v:true)) call assert_equal(-1, charidx(str, 5, v:false, v:true)) for i in str->strchars()->range() call assert_equal(i, charidx(str, i, v:true, v:true)) endfor call assert_equal(8, charidx(str, 8, v:true, v:true)) call assert_equal(-1, charidx(str, 9, v:true, v:true)) " empty string call assert_equal(0, charidx('', 0, v:false, v:true)) call assert_equal(-1, charidx('', 1, v:false, v:true)) call assert_equal(0, charidx('', 0, v:true, v:true)) call assert_equal(-1, charidx('', 1, v:true, v:true)) " error cases call assert_equal(0, charidx('', 0, v:false, v:true)) call assert_equal(-1, charidx('', 1, v:false, v:true)) call assert_equal(0, charidx('', 0, v:true, v:true)) call assert_equal(-1, charidx('', 1, v:true, v:true)) call assert_equal(0, charidx(test_null_string(), 0, v:false, v:true)) call assert_equal(-1, charidx(test_null_string(), 1, v:false, v:true)) call assert_fails('let x = charidx("abc", 1, v:false, [])', 'E1212:') call assert_fails('let x = charidx("abc", 1, v:true, [])', 'E1212:') endfunc " Test for utf16idx() using a byte index func Test_utf16idx_from_byteidx() " UTF-16 index of a string with single byte characters let str = "abc" for i in range(4) call assert_equal(i, utf16idx(str, i)) endfor call assert_equal(-1, utf16idx(str, 4)) " UTF-16 index of a string with two byte characters let str = 'a©©b' call assert_equal(0, str->utf16idx(0)) call assert_equal(1, str->utf16idx(1)) call assert_equal(1, str->utf16idx(2)) call assert_equal(2, str->utf16idx(3)) call assert_equal(2, str->utf16idx(4)) call assert_equal(3, str->utf16idx(5)) call assert_equal(4, str->utf16idx(6)) call assert_equal(-1, str->utf16idx(7)) " UTF-16 index of a string with four byte characters let str = 'a😊😊b' call assert_equal(0, utf16idx(str, 0)) call assert_equal(1, utf16idx(str, 1)) call assert_equal(1, utf16idx(str, 2)) call assert_equal(1, utf16idx(str, 3)) call assert_equal(1, utf16idx(str, 4)) call assert_equal(3, utf16idx(str, 5)) call assert_equal(3, utf16idx(str, 6)) call assert_equal(3, utf16idx(str, 7)) call assert_equal(3, utf16idx(str, 8)) call assert_equal(5, utf16idx(str, 9)) call assert_equal(6, utf16idx(str, 10)) call assert_equal(-1, utf16idx(str, 11)) " UTF-16 index of a string with composing characters let str = '-á-b́' call assert_equal(0, utf16idx(str, 0)) call assert_equal(1, utf16idx(str, 1)) call assert_equal(1, utf16idx(str, 2)) call assert_equal(1, utf16idx(str, 3)) call assert_equal(2, utf16idx(str, 4)) call assert_equal(3, utf16idx(str, 5)) call assert_equal(3, utf16idx(str, 6)) call assert_equal(3, utf16idx(str, 7)) call assert_equal(4, utf16idx(str, 8)) call assert_equal(-1, utf16idx(str, 9)) call assert_equal(0, utf16idx(str, 0, v:true)) call assert_equal(1, utf16idx(str, 1, v:true)) call assert_equal(2, utf16idx(str, 2, v:true)) call assert_equal(2, utf16idx(str, 3, v:true)) call assert_equal(3, utf16idx(str, 4, v:true)) call assert_equal(4, utf16idx(str, 5, v:true)) call assert_equal(5, utf16idx(str, 6, v:true)) call assert_equal(5, utf16idx(str, 7, v:true)) call assert_equal(6, utf16idx(str, 8, v:true)) call assert_equal(-1, utf16idx(str, 9, v:true)) " string with multiple composing characters let str = '-ą́-ą́' call assert_equal(0, utf16idx(str, 0)) call assert_equal(1, utf16idx(str, 1)) call assert_equal(1, utf16idx(str, 2)) call assert_equal(1, utf16idx(str, 3)) call assert_equal(1, utf16idx(str, 4)) call assert_equal(1, utf16idx(str, 5)) call assert_equal(2, utf16idx(str, 6)) call assert_equal(3, utf16idx(str, 7)) call assert_equal(3, utf16idx(str, 8)) call assert_equal(3, utf16idx(str, 9)) call assert_equal(3, utf16idx(str, 10)) call assert_equal(3, utf16idx(str, 11)) call assert_equal(4, utf16idx(str, 12)) call assert_equal(-1, utf16idx(str, 13)) call assert_equal(0, utf16idx(str, 0, v:true)) call assert_equal(1, utf16idx(str, 1, v:true)) call assert_equal(2, utf16idx(str, 2, v:true)) call assert_equal(2, utf16idx(str, 3, v:true)) call assert_equal(3, utf16idx(str, 4, v:true)) call assert_equal(3, utf16idx(str, 5, v:true)) call assert_equal(4, utf16idx(str, 6, v:true)) call assert_equal(5, utf16idx(str, 7, v:true)) call assert_equal(6, utf16idx(str, 8, v:true)) call assert_equal(6, utf16idx(str, 9, v:true)) call assert_equal(7, utf16idx(str, 10, v:true)) call assert_equal(7, utf16idx(str, 11, v:true)) call assert_equal(8, utf16idx(str, 12, v:true)) call assert_equal(-1, utf16idx(str, 13, v:true)) " empty string call assert_equal(0, utf16idx('', 0)) call assert_equal(-1, utf16idx('', 1)) call assert_equal(0, utf16idx('', 0, v:true)) call assert_equal(-1, utf16idx('', 1, v:true)) " error cases call assert_equal(0, utf16idx("", 0)) call assert_equal(-1, utf16idx("", 1)) call assert_equal(-1, utf16idx("abc", -1)) call assert_equal(0, utf16idx(test_null_string(), 0)) call assert_equal(-1, utf16idx(test_null_string(), 1)) call assert_fails('let l = utf16idx([], 0)', 'E1174:') call assert_fails('let l = utf16idx("ab", [])', 'E1210:') call assert_fails('let l = utf16idx("ab", 0, [])', 'E1212:') endfunc " Test for utf16idx() using a character index func Test_utf16idx_from_charidx() let str = "abc" for i in str->strcharlen()->range() call assert_equal(i, utf16idx(str, i, v:false, v:true)) endfor call assert_equal(3, utf16idx(str, 3, v:false, v:true)) call assert_equal(-1, utf16idx(str, 4, v:false, v:true)) " UTF-16 index of a string with two byte characters let str = "a©©b" for i in str->strcharlen()->range() call assert_equal(i, utf16idx(str, i, v:false, v:true)) endfor call assert_equal(4, utf16idx(str, 4, v:false, v:true)) call assert_equal(-1, utf16idx(str, 5, v:false, v:true)) " UTF-16 index of a string with four byte characters let str = "a😊😊b" call assert_equal(0, utf16idx(str, 0, v:false, v:true)) call assert_equal(1, utf16idx(str, 1, v:false, v:true)) call assert_equal(3, utf16idx(str, 2, v:false, v:true)) call assert_equal(5, utf16idx(str, 3, v:false, v:true)) call assert_equal(6, utf16idx(str, 4, v:false, v:true)) call assert_equal(-1, utf16idx(str, 5, v:false, v:true)) " UTF-16 index of a string with composing characters let str = '-á-b́' for i in str->strcharlen()->range() call assert_equal(i, utf16idx(str, i, v:false, v:true)) endfor call assert_equal(4, utf16idx(str, 4, v:false, v:true)) call assert_equal(-1, utf16idx(str, 5, v:false, v:true)) for i in str->strchars()->range() call assert_equal(i, utf16idx(str, i, v:true, v:true)) endfor call assert_equal(6, utf16idx(str, 6, v:true, v:true)) call assert_equal(-1, utf16idx(str, 7, v:true, v:true)) " string with multiple composing characters let str = '-ą́-ą́' for i in str->strcharlen()->range() call assert_equal(i, utf16idx(str, i, v:false, v:true)) endfor call assert_equal(4, utf16idx(str, 4, v:false, v:true)) call assert_equal(-1, utf16idx(str, 5, v:false, v:true)) for i in str->strchars()->range() call assert_equal(i, utf16idx(str, i, v:true, v:true)) endfor call assert_equal(8, utf16idx(str, 8, v:true, v:true)) call assert_equal(-1, utf16idx(str, 9, v:true, v:true)) " empty string call assert_equal(0, utf16idx('', 0, v:false, v:true)) call assert_equal(-1, utf16idx('', 1, v:false, v:true)) call assert_equal(0, utf16idx('', 0, v:true, v:true)) call assert_equal(-1, utf16idx('', 1, v:true, v:true)) " error cases call assert_equal(0, utf16idx(test_null_string(), 0, v:true, v:true)) call assert_equal(-1, utf16idx(test_null_string(), 1, v:true, v:true)) call assert_fails('let l = utf16idx("ab", 0, v:false, [])', 'E1212:') endfunc " Test for strutf16len() func Test_strutf16len() call assert_equal(3, strutf16len('abc')) call assert_equal(3, 'abc'->strutf16len(v:true)) call assert_equal(4, strutf16len('a©©b')) call assert_equal(4, strutf16len('a©©b', v:true)) call assert_equal(6, strutf16len('a😊😊b')) call assert_equal(6, strutf16len('a😊😊b', v:true)) call assert_equal(4, strutf16len('-á-b́')) call assert_equal(6, strutf16len('-á-b́', v:true)) call assert_equal(4, strutf16len('-ą́-ą́')) call assert_equal(8, strutf16len('-ą́-ą́', v:true)) call assert_equal(0, strutf16len('')) " error cases call assert_fails('let l = strutf16len([])', 'E1174:') call assert_fails('let l = strutf16len("a", [])', 'E1212:') call assert_equal(0, strutf16len(test_null_string())) endfunc func Test_count() let l = ['a', 'a', 'A', 'b'] call assert_equal(2, count(l, 'a')) call assert_equal(1, count(l, 'A')) call assert_equal(1, count(l, 'b')) call assert_equal(0, count(l, 'B')) call assert_equal(2, count(l, 'a', 0)) call assert_equal(1, count(l, 'A', 0)) call assert_equal(1, count(l, 'b', 0)) call assert_equal(0, count(l, 'B', 0)) call assert_equal(3, count(l, 'a', 1)) call assert_equal(3, count(l, 'A', 1)) call assert_equal(1, count(l, 'b', 1)) call assert_equal(1, count(l, 'B', 1)) call assert_equal(0, count(l, 'c', 1)) call assert_equal(1, count(l, 'a', 0, 1)) call assert_equal(2, count(l, 'a', 1, 1)) call assert_fails('call count(l, "a", 0, 10)', 'E684:') call assert_fails('call count(l, "a", [])', 'E745:') let d = {1: 'a', 2: 'a', 3: 'A', 4: 'b'} call assert_equal(2, count(d, 'a')) call assert_equal(1, count(d, 'A')) call assert_equal(1, count(d, 'b')) call assert_equal(0, count(d, 'B')) call assert_equal(2, count(d, 'a', 0)) call assert_equal(1, count(d, 'A', 0)) call assert_equal(1, count(d, 'b', 0)) call assert_equal(0, count(d, 'B', 0)) call assert_equal(3, count(d, 'a', 1)) call assert_equal(3, count(d, 'A', 1)) call assert_equal(1, count(d, 'b', 1)) call assert_equal(1, count(d, 'B', 1)) call assert_equal(0, count(d, 'c', 1)) call assert_fails('call count(d, "a", 0, 1)', 'E474:') call assert_equal(0, count("foo", "bar")) call assert_equal(1, count("foo", "oo")) call assert_equal(2, count("foo", "o")) call assert_equal(0, count("foo", "O")) call assert_equal(2, count("foo", "O", 1)) call assert_equal(2, count("fooooo", "oo")) call assert_equal(0, count("foo", "")) call assert_fails('call count(0, 0)', 'E706:') call assert_fails('call count("", "", {})', ['E728:', 'E728:']) endfunc func Test_changenr() new Xchangenr call assert_equal(0, changenr()) norm ifoo call assert_equal(1, changenr()) set undolevels=10 norm Sbar call assert_equal(2, changenr()) undo call assert_equal(1, changenr()) redo call assert_equal(2, changenr()) bw! set undolevels& endfunc func Test_filewritable() new Xfilewritable write! call assert_equal(1, filewritable('Xfilewritable')) call assert_notequal(0, setfperm('Xfilewritable', 'r--r-----')) call assert_equal(0, filewritable('Xfilewritable')) call assert_notequal(0, setfperm('Xfilewritable', 'rw-r-----')) call assert_equal(1, 'Xfilewritable'->filewritable()) call assert_equal(0, filewritable('doesnotexist')) call mkdir('Xwritedir', 'D') call assert_equal(2, filewritable('Xwritedir')) call delete('Xfilewritable') bw! endfunc func Test_Executable() if has('win32') call assert_equal(1, executable('notepad')) call assert_equal(1, 'notepad.exe'->executable()) call assert_equal(0, executable('notepad.exe.exe')) call assert_equal(0, executable('shell32.dll')) call assert_equal(0, executable('win.ini')) " get "notepad" path and remove the leading drive and sep. (ex. 'C:\') let notepadcmd = exepath('notepad.exe') let driveroot = notepadcmd[:2] let notepadcmd = notepadcmd[3:] new " check that the relative path works in / execute 'lcd' driveroot call assert_equal(1, executable(notepadcmd)) call assert_equal(driveroot .. notepadcmd, notepadcmd->exepath()) bwipe " create "notepad.bat" call mkdir('Xnotedir') let notepadbat = fnamemodify('Xnotedir/notepad.bat', ':p') call writefile([], notepadbat) new " check that the path and the pathext order is valid lcd Xnotedir let [pathext, $PATHEXT] = [$PATHEXT, '.com;.exe;.bat;.cmd'] call assert_equal(notepadbat, exepath('notepad')) let $PATHEXT = pathext " check for symbolic link execute 'silent !mklink np.bat "' .. notepadbat .. '"' call assert_equal(1, executable('./np.bat')) call assert_equal(1, executable('./np')) bwipe eval 'Xnotedir'->delete('rf') elseif has('unix') call assert_equal(1, 'cat'->executable()) call assert_equal(0, executable('nodogshere')) " get "cat" path and remove the leading / let catcmd = exepath('cat')[1:] new " check that the relative path works in / lcd / call assert_equal(1, executable(catcmd)) let result = catcmd->exepath() " when using chroot looking for sbin/cat can return bin/cat, that is OK if catcmd =~ '\' && result =~ '\' call assert_equal('/' .. substitute(catcmd, '\', 'bin', ''), result) else " /bin/cat and /usr/bin/cat may be hard linked, we could get either let result = substitute(result, '/usr/bin/cat', '/bin/cat', '') let catcmd = substitute(catcmd, 'usr/bin/cat', 'bin/cat', '') call assert_equal('/' .. catcmd, result) endif bwipe else throw 'Skipped: does not work on this platform' endif endfunc func Test_executable_windows_store_apps() CheckMSWindows " Windows Store apps install some 'decoy' .exe that require some careful " handling as they behave similarly to symlinks. let app_dir = expand("$LOCALAPPDATA\\Microsoft\\WindowsApps") if !isdirectory(app_dir) return endif let save_path = $PATH let $PATH = app_dir " Ensure executable() finds all the app .exes for entry in readdir(app_dir) if entry =~ '\.exe$' call assert_true(executable(entry)) endif endfor let $PATH = save_path endfunc func Test_executable_longname() CheckMSWindows " Create a temporary .bat file with 205 characters in the name. " Maximum length of a filename (including the path) on MS-Windows is 259 " characters. " See https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation let len = 259 - getcwd()->len() - 6 if len > 200 let len = 200 endif let fname = 'X' . repeat('あ', len) . '.bat' call writefile([], fname) call assert_equal(1, executable(fname)) call delete(fname) endfunc func Test_hostname() let hostname_vim = hostname() if has('unix') let hostname_system = systemlist('uname -n')[0] call assert_equal(hostname_vim, hostname_system) endif endfunc func Test_getpid() " getpid() always returns the same value within a vim instance. call assert_equal(getpid(), getpid()) if has('unix') call assert_equal(systemlist('echo $PPID')[0], string(getpid())) endif endfunc func Test_hlexists() call assert_equal(0, hlexists('does_not_exist')) call assert_equal(0, 'Number'->hlexists()) call assert_equal(0, highlight_exists('does_not_exist')) call assert_equal(0, highlight_exists('Number')) syntax on call assert_equal(0, hlexists('does_not_exist')) call assert_equal(1, hlexists('Number')) call assert_equal(0, highlight_exists('does_not_exist')) call assert_equal(1, highlight_exists('Number')) syntax off endfunc " Test for the col() function func Test_col() new call setline(1, 'abcdef') norm gg4|mx6|mY2| call assert_equal(2, col('.')) call assert_equal(7, col('$')) call assert_equal(2, col('v')) call assert_equal(4, col("'x")) call assert_equal(6, col("'Y")) call assert_equal(2, [1, 2]->col()) call assert_equal(7, col([1, '$'])) call assert_equal(0, col('')) call assert_equal(0, col('x')) call assert_equal(0, col([2, '$'])) call assert_equal(0, col([1, 100])) call assert_equal(0, col([1])) call assert_equal(0, col(test_null_list())) call assert_fails('let c = col({})', 'E1222:') call assert_fails('let c = col(".", [])', 'E1210:') " test for getting the visual start column func T() let g:Vcol = col('v') return '' endfunc let g:Vcol = 0 xmap T() exe "normal gg3|ve\" call assert_equal(3, g:Vcol) xunmap delfunc T " Test for the visual line start and end marks '< and '> call setline(1, ['one', 'one two', 'one two three']) "normal! ggVG call feedkeys("ggVG\", 'xt') call assert_equal(1, col("'<")) call assert_equal(14, col("'>")) " Delete the last line of the visually selected region $d call assert_notequal(14, col("'>")) " Test with 'virtualedit' set virtualedit=all call cursor(1, 10) call assert_equal(4, col('.')) set virtualedit& " Test for getting the column number in another window let winid = win_getid() new call win_execute(winid, 'normal 1G$') call assert_equal(3, col('.', winid)) call win_execute(winid, 'normal 2G') call assert_equal(8, col('$', winid)) call assert_equal(0, col('.', 5001)) bw! endfunc " Test for input() func Test_input_func() " Test for prompt with multiple lines redir => v call feedkeys(":let c = input(\"A\\nB\\nC\\n? \")\B\", 'xt') redir END call assert_equal("B", c) call assert_equal(['A', 'B', 'C'], split(v, "\n")) " Test for default value call feedkeys(":let c = input('color? ', 'red')\\", 'xt') call assert_equal('red', c) " Test for completion at the input prompt func! Tcomplete(arglead, cmdline, pos) return "item1\nitem2\nitem3" endfunc call feedkeys(":let c = input('Q? ', '', 'custom,Tcomplete')\" \ .. "\\", 'xt') delfunc Tcomplete call assert_equal('item1 item2 item3', c) " Test for using special characters as default input call feedkeys(":let c = input('name? ', \"x\\y\")\\", 'xt') call assert_equal('y', c) " Test for using text with composing characters as default input call feedkeys(":let c = input('name? ', \"ã̳\")\\", 'xt') call assert_equal('ã̳', c) " Test for using as default input call feedkeys(":let c = input('name? ', \"\\\")\x\", 'xt') call assert_equal(' x', c) call assert_fails("call input('F:', '', 'invalid')", 'E180:') call assert_fails("call input('F:', '', [])", 'E730:') endfunc " Test for the inputdialog() function func Test_inputdialog() set timeout timeoutlen=10 if has('gui_running') call assert_fails('let v=inputdialog([], "xx")', 'E730:') call assert_fails('let v=inputdialog("Q", [])', 'E730:') else call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\\", 'xt') call assert_equal('xx', v) call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\\", 'xt') call assert_equal('yy', v) endif set timeout& timeoutlen& endfunc " Test for inputlist() func Test_inputlist() call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\1\", 'tx') call assert_equal(1, c) call feedkeys(":let c = ['Select color:', '1. red', '2. green', '3. blue']->inputlist()\2\", 'tx') call assert_equal(2, c) call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\3\", 'tx') call assert_equal(3, c) " CR to cancel call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\\", 'tx') call assert_equal(0, c) " Esc to cancel call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\\", 'tx') call assert_equal(0, c) " q to cancel call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\q", 'tx') call assert_equal(0, c) " Cancel after inputting a number call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\5q", 'tx') call assert_equal(0, c) " Use backspace to delete characters in the prompt call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\1\3\2\", 'tx') call assert_equal(2, c) " Use mouse to make a selection call test_setmouse(&lines - 3, 2) call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\\", 'tx') call assert_equal(1, c) " Mouse click outside of the list call test_setmouse(&lines - 6, 2) call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\\", 'tx') call assert_equal(-2, c) call assert_fails('call inputlist("")', 'E686:') call assert_fails('call inputlist(test_null_list())', 'E686:') endfunc func Test_range_inputlist() " flush out any garbage left in the buffer while getchar(0) endwhile call feedkeys(":let result = inputlist(range(10))\1\", 'x') call assert_equal(1, result) call feedkeys(":let result = inputlist(range(3, 10))\1\", 'x') call assert_equal(1, result) unlet result endfunc func Test_balloon_show() CheckFeature balloon_eval " This won't do anything but must not crash either. call balloon_show('hi!') if !has('gui_running') call balloon_show(range(3)) call balloon_show([]) endif endfunc func Test_setbufvar_options() " This tests that aucmd_prepbuf() and aucmd_restbuf() properly restore the " window layout and cursor position. call assert_equal(1, winnr('$')) split dummy_preview resize 2 set winfixheight winfixwidth let prev_id = win_getid() wincmd j let wh = winheight(0) let dummy_buf = bufnr('dummy_buf1', v:true) call setbufvar(dummy_buf, '&buftype', 'nofile') execute 'belowright vertical split #' . dummy_buf call assert_equal(wh, winheight(0)) let dum1_id = win_getid() call setline(1, 'foo') normal! V$ call assert_equal(4, col('.')) call setbufvar('dummy_preview', '&buftype', 'nofile') call assert_equal(4, col('.')) wincmd h let wh = winheight(0) call setline(1, 'foo') normal! V$ call assert_equal(4, col('.')) let dummy_buf = bufnr('dummy_buf2', v:true) eval 'nofile'->setbufvar(dummy_buf, '&buftype') call assert_equal(4, col('.')) execute 'belowright vertical split #' . dummy_buf call assert_equal(wh, winheight(0)) bwipe! call win_gotoid(prev_id) bwipe! call win_gotoid(dum1_id) bwipe! endfunc func Test_setbufvar_keep_window_title() CheckRunVimInTerminal if !has('title') || empty(&t_ts) throw "Skipped: can't get/set title" endif let lines =<< trim END set title edit Xa.txt let g:buf = bufadd('Xb.txt') inoremap =setbufvar(g:buf, '&autoindent', 1) ?? '' END call writefile(lines, 'Xsetbufvar', 'D') let buf = RunVimInTerminal('-S Xsetbufvar', {}) call WaitForAssert({-> assert_match('Xa.txt', term_gettitle(buf))}, 1000) call term_sendkeys(buf, "i\") call TermWait(buf) call term_sendkeys(buf, "\") call TermWait(buf) call assert_match('Xa.txt', term_gettitle(buf)) call StopVimInTerminal(buf) endfunc func Test_redo_in_nested_functions() nnoremap g. :set opfunc=Operatorg@ function Operator( type, ... ) let @x = 'XXX' execute 'normal! g`[' . (a:type ==# 'line' ? 'V' : 'v') . 'g`]' . '"xp' endfunction function! Apply() 5,6normal! . endfunction new call setline(1, repeat(['some "quoted" text', 'more "quoted" text'], 3)) 1normal g.i" call assert_equal('some "XXX" text', getline(1)) 3,4normal . call assert_equal('some "XXX" text', getline(3)) call assert_equal('more "XXX" text', getline(4)) call Apply() call assert_equal('some "XXX" text', getline(5)) call assert_equal('more "XXX" text', getline(6)) bwipe! nunmap g. delfunc Operator delfunc Apply endfunc func Test_trim() call assert_equal("Testing", trim(" \t\r\r\x0BTesting \t\n\r\n\t\x0B\x0B")) call assert_equal("Testing", " \t \r\r\n\n\x0BTesting \t\n\r\n\t\x0B\x0B"->trim()) call assert_equal("RESERVE", trim("xyz \twwRESERVEzyww \t\t", " wxyz\t")) call assert_equal("wRE \tSERVEzyww", trim("wRE \tSERVEzyww")) call assert_equal("abcd\t xxxx tail", trim(" \tabcd\t xxxx tail")) call assert_equal("\tabcd\t xxxx tail", trim(" \tabcd\t xxxx tail", " ")) call assert_equal(" \tabcd\t xxxx tail", trim(" \tabcd\t xxxx tail", "abx")) call assert_equal("RESERVE", trim("你RESERVE好", "你好")) call assert_equal("您R E SER V E早", trim("你好您R E SER V E早好你你", "你好")) call assert_equal("你好您R E SER V E早好你你", trim(" \n\r\r 你好您R E SER V E早好你你 \t \x0B", )) call assert_equal("您R E SER V E早好你你 \t \x0B", trim(" 你好您R E SER V E早好你你 \t \x0B", " 你好")) call assert_equal("您R E SER V E早好你你 \t \x0B", trim(" tteesstttt你好您R E SER V E早好你你 \t \x0B ttestt", " 你好tes")) call assert_equal("您R E SER V E早好你你 \t \x0B", trim(" tteesstttt你好您R E SER V E早好你你 \t \x0B ttestt", " 你你你好好好tttsses")) call assert_equal("留下", trim("这些些不要这些留下这些", "这些不要")) call assert_equal("", trim("", "")) call assert_equal("a", trim("a", "")) call assert_equal("", trim("", "a")) call assert_equal("vim", trim(" vim ", " ", 0)) call assert_equal("vim ", trim(" vim ", " ", 1)) call assert_equal(" vim", trim(" vim ", " ", 2)) call assert_fails('eval trim(" vim ", " ", [])', 'E745:') call assert_fails('eval trim(" vim ", " ", -1)', 'E475:') call assert_fails('eval trim(" vim ", " ", 3)', 'E475:') call assert_fails('eval trim(" vim ", 0)', 'E1174:') let chars = join(map(range(1, 0x20) + [0xa0], {n -> n->nr2char()}), '') call assert_equal("x", trim(chars . "x" . chars)) call assert_equal("x", trim(chars . "x" . chars, '', 0)) call assert_equal("x" . chars, trim(chars . "x" . chars, '', 1)) call assert_equal(chars . "x", trim(chars . "x" . chars, '', 2)) call assert_fails('let c=trim([])', 'E730:') endfunc " Test for reg_recording() and reg_executing() func Test_reg_executing_and_recording() let s:reg_stat = '' func s:save_reg_stat() let s:reg_stat = reg_recording() . ':' . reg_executing() return '' endfunc new call s:save_reg_stat() call assert_equal(':', s:reg_stat) call feedkeys("qa\"=s:save_reg_stat()\pq", 'xt') call assert_equal('a:', s:reg_stat) call feedkeys("@a", 'xt') call assert_equal(':a', s:reg_stat) call feedkeys("qb@aq", 'xt') call assert_equal('b:a', s:reg_stat) call feedkeys("q\"\"=s:save_reg_stat()\pq", 'xt') call assert_equal('":', s:reg_stat) " :normal command saves and restores reg_executing let s:reg_stat = '' let @q = ":call TestFunc()\:call s:save_reg_stat()\" func TestFunc() abort normal! ia endfunc call feedkeys("@q", 'xt') call assert_equal(':q', s:reg_stat) delfunc TestFunc " getchar() command saves and restores reg_executing map W :call TestFunc() let @q = "W" let g:typed = '' let g:regs = [] func TestFunc() abort let g:regs += [reg_executing()] let g:typed = getchar(0) let g:regs += [reg_executing()] endfunc call feedkeys("@qy", 'xt') call assert_equal(char2nr("y"), g:typed) call assert_equal(['q', 'q'], g:regs) delfunc TestFunc unmap W unlet g:typed unlet g:regs " input() command saves and restores reg_executing map W :call TestFunc() let @q = "W" let g:typed = '' let g:regs = [] func TestFunc() abort let g:regs += [reg_executing()] let g:typed = '?'->input() let g:regs += [reg_executing()] endfunc call feedkeys("@qy\", 'xt') call assert_equal("y", g:typed) call assert_equal(['q', 'q'], g:regs) delfunc TestFunc unmap W unlet g:typed unlet g:regs bwipe! delfunc s:save_reg_stat unlet s:reg_stat endfunc func Test_inputsecret() map W :call TestFunc() let @q = "W" let g:typed1 = '' let g:typed2 = '' let g:regs = [] func TestFunc() abort let g:typed1 = '?'->inputsecret() let g:typed2 = inputsecret('password: ') endfunc call feedkeys("@qsomething\else\", 'xt') call assert_equal("something", g:typed1) call assert_equal("else", g:typed2) delfunc TestFunc unmap W unlet g:typed1 unlet g:typed2 endfunc func Test_getchar() call feedkeys('a', '') call assert_equal(char2nr('a'), getchar()) call assert_equal(0, getchar(0)) call assert_equal(0, getchar(1)) call feedkeys('a', '') call assert_equal('a', getcharstr()) call assert_equal('', getcharstr(0)) call assert_equal('', getcharstr(1)) call feedkeys("\", '') call assert_equal("\", getchar(0)) call assert_equal(0, getchar(0)) call setline(1, 'xxxx') call test_setmouse(1, 3) let v:mouse_win = 9 let v:mouse_winid = 9 let v:mouse_lnum = 9 let v:mouse_col = 9 call feedkeys("\", '') call assert_equal("\", getchar()) call assert_equal(1, v:mouse_win) call assert_equal(win_getid(1), v:mouse_winid) call assert_equal(1, v:mouse_lnum) call assert_equal(3, v:mouse_col) enew! endfunc func Test_libcall_libcallnr() CheckFeature libcall if has('win32') let libc = 'msvcrt.dll' elseif has('mac') let libc = 'libSystem.B.dylib' elseif executable('ldd') let libc = matchstr(split(system('ldd ' . GetVimProg())), '/libc\.so\>') endif if get(l:, 'libc', '') ==# '' " On Unix, libc.so can be in various places. if has('linux') " There is not documented but regarding the 1st argument of glibc's " dlopen an empty string and nullptr are equivalent, so using an empty " string for the 1st argument of libcall allows to call functions. let libc = '' elseif has('sun') " Set the path to libc.so according to the architecture. let test_bits = system('file ' . GetVimProg()) let test_arch = system('uname -p') if test_bits =~ '64-bit' && test_arch =~ 'sparc' let libc = '/usr/lib/sparcv9/libc.so' elseif test_bits =~ '64-bit' && test_arch =~ 'i386' let libc = '/usr/lib/amd64/libc.so' else let libc = '/usr/lib/libc.so' endif else " Unfortunately skip this test until a good way is found. return endif endif if has('win32') call assert_equal($USERPROFILE, 'USERPROFILE'->libcall(libc, 'getenv')) else call assert_equal($HOME, 'HOME'->libcall(libc, 'getenv')) endif " If function returns NULL, libcall() should return an empty string. call assert_equal('', libcall(libc, 'getenv', 'X_ENV_DOES_NOT_EXIT')) " Test libcallnr() with string and integer argument. call assert_equal(4, 'abcd'->libcallnr(libc, 'strlen')) call assert_equal(char2nr('A'), char2nr('a')->libcallnr(libc, 'toupper')) call assert_fails("call libcall(libc, 'Xdoesnotexist_', '')", ['', 'E364:']) call assert_fails("call libcallnr(libc, 'Xdoesnotexist_', '')", ['', 'E364:']) call assert_fails("call libcall('Xdoesnotexist_', 'getenv', 'HOME')", ['', 'E364:']) call assert_fails("call libcallnr('Xdoesnotexist_', 'strlen', 'abcd')", ['', 'E364:']) endfunc sandbox function Fsandbox() normal ix endfunc func Test_func_sandbox() sandbox let F = {-> 'hello'} call assert_equal('hello', F()) sandbox let F = {-> "normal ix\"->execute()} call assert_fails('call F()', 'E48:') unlet F call assert_fails('call Fsandbox()', 'E48:') delfunc Fsandbox " From a sandbox try to set a predefined variable (which cannot be modified " from a sandbox) call assert_fails('sandbox let v:lnum = 10', 'E794:') endfunc func EditAnotherFile() let word = expand('') edit Xfuncrange2 endfunc func Test_func_range_with_edit() " Define a function that edits another buffer, then call it with a range that " is invalid in that buffer. call writefile(['just one line'], 'Xfuncrange2', 'D') new eval 10->range()->setline(1) write Xfuncrange1 call assert_fails('5,8call EditAnotherFile()', 'E16:') call delete('Xfuncrange1') bwipe! endfunc func Test_func_exists_on_reload() call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists', 'D') call assert_equal(0, exists('*ExistingFunction')) source Xfuncexists call assert_equal(1, '*ExistingFunction'->exists()) " Redefining a function when reloading a script is OK. source Xfuncexists call assert_equal(1, exists('*ExistingFunction')) " But redefining in another script is not OK. call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists2', 'D') call assert_fails('source Xfuncexists2', 'E122:') " Defining a new function from the cmdline should fail if the function is " already defined call assert_fails('call feedkeys(":func ExistingFunction()\", "xt")', 'E122:') delfunc ExistingFunction call assert_equal(0, exists('*ExistingFunction')) call writefile([ \ 'func ExistingFunction()', 'echo "yes"', 'endfunc', \ 'func ExistingFunction()', 'echo "no"', 'endfunc', \ ], 'Xfuncexists') call assert_fails('source Xfuncexists', 'E122:') call assert_equal(1, exists('*ExistingFunction')) delfunc ExistingFunction endfunc " Test confirm({msg} [, {choices} [, {default} [, {type}]]]) func Test_confirm() CheckUnix CheckNotGui call feedkeys('o', 'L') let a = confirm('Press O to proceed') call assert_equal(1, a) call feedkeys('y', 'L') let a = 'Are you sure?'->confirm("&Yes\n&No") call assert_equal(1, a) call feedkeys('n', 'L') let a = confirm('Are you sure?', "&Yes\n&No") call assert_equal(2, a) " confirm() should return 0 when pressing CTRL-C. call feedkeys("\", 'L') let a = confirm('Are you sure?', "&Yes\n&No") call assert_equal(0, a) " requires another character to avoid it being seen as the start of an " escape sequence. Zero should be harmless. eval "\0"->feedkeys('L') let a = confirm('Are you sure?', "&Yes\n&No") call assert_equal(0, a) " Default choice is returned when pressing . call feedkeys("\", 'L') let a = confirm('Are you sure?', "&Yes\n&No") call assert_equal(1, a) call feedkeys("\", 'L') let a = confirm('Are you sure?', "&Yes\n&No", 2) call assert_equal(2, a) call feedkeys("\", 'L') let a = confirm('Are you sure?', "&Yes\n&No", 0) call assert_equal(0, a) " Test with the {type} 4th argument for type in ['Error', 'Question', 'Info', 'Warning', 'Generic'] call feedkeys('y', 'L') let a = confirm('Are you sure?', "&Yes\n&No\n", 1, type) call assert_equal(1, a) endfor call assert_fails('call confirm([])', 'E730:') call assert_fails('call confirm("Are you sure?", [])', 'E730:') call assert_fails('call confirm("Are you sure?", "&Yes\n&No\n", [])', 'E745:') call assert_fails('call confirm("Are you sure?", "&Yes\n&No\n", 0, [])', 'E730:') endfunc func Test_platform_name() " The system matches at most only one name. let names = ['amiga', 'bsd', 'hpux', 'linux', 'mac', 'qnx', 'sun', 'vms', 'win32', 'win32unix'] call assert_inrange(0, 1, len(filter(copy(names), 'has(v:val)'))) " Is Unix? call assert_equal(has('bsd'), has('bsd') && has('unix')) call assert_equal(has('hpux'), has('hpux') && has('unix')) call assert_equal(has('linux'), has('linux') && has('unix')) call assert_equal(has('mac'), has('mac') && has('unix')) call assert_equal(has('qnx'), has('qnx') && has('unix')) call assert_equal(has('sun'), has('sun') && has('unix')) call assert_equal(has('win32'), has('win32') && !has('unix')) call assert_equal(has('win32unix'), has('win32unix') && has('unix')) if has('unix') && executable('uname') let uname = system('uname') " GNU userland on BSD kernels (e.g., GNU/kFreeBSD) don't have BSD defined call assert_equal(uname =~? '\%(GNU/k\w\+\)\@readdir({ x -> stridx(x, 'f') != -1 }) call assert_equal(['foo.txt'], sort(files)) " Only .txt files let files = readdir('Xreaddir', { x -> x =~ '.txt$' }) call assert_equal(['bar.txt', 'foo.txt'], sort(files)) " Only .txt files with string let files = readdir('Xreaddir', 'v:val =~ ".txt$"') call assert_equal(['bar.txt', 'foo.txt'], sort(files)) " Limit to 1 result. let l = [] let files = readdir('Xreaddir', {x -> len(add(l, x)) == 2 ? -1 : 1}) call assert_equal(1, len(files)) " Nested readdir() must not crash let files = readdir('Xreaddir', 'readdir("Xreaddir", "1") != []') call sort(files)->assert_equal(['bar.txt', 'dir', 'foo.txt']) endfunc func Test_readdirex() call mkdir('Xexdir', 'R') call writefile(['foo'], 'Xexdir/foo.txt') call writefile(['barbar'], 'Xexdir/bar.txt') call mkdir('Xexdir/dir') " All results let files = readdirex('Xexdir')->map({-> v:val.name}) call assert_equal(['bar.txt', 'dir', 'foo.txt'], sort(files)) let sizes = readdirex('Xexdir')->map({-> v:val.size}) call assert_equal([0, 4, 7], sort(sizes)) " Only results containing "f" let files = 'Xexdir'->readdirex({ e -> stridx(e.name, 'f') != -1 }) \ ->map({-> v:val.name}) call assert_equal(['foo.txt'], sort(files)) " Only .txt files let files = readdirex('Xexdir', { e -> e.name =~ '.txt$' }) \ ->map({-> v:val.name}) call assert_equal(['bar.txt', 'foo.txt'], sort(files)) " Only .txt files with string let files = readdirex('Xexdir', 'v:val.name =~ ".txt$"') \ ->map({-> v:val.name}) call assert_equal(['bar.txt', 'foo.txt'], sort(files)) " Limit to 1 result. let l = [] let files = readdirex('Xexdir', {e -> len(add(l, e.name)) == 2 ? -1 : 1}) \ ->map({-> v:val.name}) call assert_equal(1, len(files)) " Nested readdirex() must not crash let files = readdirex('Xexdir', 'readdirex("Xexdir", "1") != []') \ ->map({-> v:val.name}) call sort(files)->assert_equal(['bar.txt', 'dir', 'foo.txt']) " report broken link correctly if has("unix") call writefile([], 'Xexdir/abc.txt') call system("ln -s Xexdir/abc.txt Xexdir/link") call delete('Xexdir/abc.txt') let files = readdirex('Xexdir', 'readdirex("Xexdir", "1") != []') \ ->map({-> v:val.name .. '_' .. v:val.type}) call sort(files)->assert_equal( \ ['bar.txt_file', 'dir_dir', 'foo.txt_file', 'link_link']) endif call assert_fails('call readdirex("doesnotexist")', 'E484:') endfunc func Test_readdirex_sort() CheckUnix " Skip tests on Mac OS X and Cygwin (does not allow several files with different casing) if has("osxdarwin") || has("osx") || has("macunix") || has("win32unix") throw 'Skipped: Test_readdirex_sort on systems that do not allow this using the default filesystem' endif let _collate = v:collate call mkdir('Xsortdir2', 'R') call writefile(['1'], 'Xsortdir2/README.txt') call writefile(['2'], 'Xsortdir2/Readme.txt') call writefile(['3'], 'Xsortdir2/readme.txt') " 1) default let files = readdirex('Xsortdir2')->map({-> v:val.name}) let default = copy(files) call assert_equal(['README.txt', 'Readme.txt', 'readme.txt'], files, 'sort using default') " 2) no sorting let files = readdirex('Xsortdir2', 1, #{sort: 'none'})->map({-> v:val.name}) let unsorted = copy(files) call assert_equal(['README.txt', 'Readme.txt', 'readme.txt'], sort(files), 'unsorted') call assert_fails("call readdirex('Xsortdir2', 1, #{slort: 'none'})", 'E857: Dictionary key "sort" required') " 3) sort by case (same as default) let files = readdirex('Xsortdir2', 1, #{sort: 'case'})->map({-> v:val.name}) call assert_equal(default, files, 'sort by case') " 4) sort by ignoring case let files = readdirex('Xsortdir2', 1, #{sort: 'icase'})->map({-> v:val.name}) call assert_equal(unsorted->sort('i'), files, 'sort by icase') " 5) Default Collation let collate = v:collate lang collate C let files = readdirex('Xsortdir2', 1, #{sort: 'collate'})->map({-> v:val.name}) call assert_equal(['README.txt', 'Readme.txt', 'readme.txt'], files, 'sort by C collation') " 6) Collation de_DE " Switch locale, this may not work on the CI system, if the locale isn't " available try lang collate de_DE let files = readdirex('Xsortdir2', 1, #{sort: 'collate'})->map({-> v:val.name}) call assert_equal(['readme.txt', 'Readme.txt', 'README.txt'], files, 'sort by de_DE collation') catch throw 'Skipped: de_DE collation is not available' finally exe 'lang collate' collate endtry endfunc func Test_readdir_sort() " some more cases for testing sorting for readdirex let dir = 'Xsortdir3' call mkdir(dir, 'R') call writefile(['1'], dir .. '/README.txt') call writefile(['2'], dir .. '/Readm.txt') call writefile(['3'], dir .. '/read.txt') call writefile(['4'], dir .. '/Z.txt') call writefile(['5'], dir .. '/a.txt') call writefile(['6'], dir .. '/b.txt') " 1) default let files = readdir(dir) let default = copy(files) call assert_equal(default->sort(), files, 'sort using default') " 2) sort by case (same as default) let files = readdir(dir, '1', #{sort: 'case'}) call assert_equal(default, files, 'sort using default') " 3) sort by ignoring case let files = readdir(dir, '1', #{sort: 'icase'}) call assert_equal(default->sort('i'), files, 'sort by ignoring case') " 4) collation let collate = v:collate lang collate C let files = readdir(dir, 1, #{sort: 'collate'}) call assert_equal(default->sort(), files, 'sort by C collation') exe "lang collate" collate " 5) Errors call assert_fails('call readdir(dir, 1, 1)', 'E1206:') call assert_fails('call readdir(dir, 1, #{sorta: 1})') call assert_fails('call readdir(dir, 1, test_null_dict())', 'E1297:') call assert_fails('call readdirex(dir, 1, 1)', 'E1206:') call assert_fails('call readdirex(dir, 1, #{sorta: 1})') call assert_fails('call readdirex(dir, 1, test_null_dict())', 'E1297:') " 6) ignore other values in dict let files = readdir(dir, '1', #{sort: 'c'}) call assert_equal(default, files, 'sort using default2') " Cleanup exe "lang collate" collate endfunc func Test_delete_rf() call mkdir('Xrfdir') call writefile([], 'Xrfdir/foo.txt') call writefile([], 'Xrfdir/bar.txt') call mkdir('Xrfdir/[a-1]') " issue #696 call writefile([], 'Xrfdir/[a-1]/foo.txt') call writefile([], 'Xrfdir/[a-1]/bar.txt') call assert_true(filereadable('Xrfdir/foo.txt')) call assert_true('Xrfdir/[a-1]/foo.txt'->filereadable()) call assert_equal(0, delete('Xrfdir', 'rf')) call assert_false(filereadable('Xrfdir/foo.txt')) call assert_false(filereadable('Xrfdir/[a-1]/foo.txt')) if has('unix') call mkdir('Xrfdir/Xdir2', 'p') silent !chmod 555 Xrfdir call assert_equal(-1, delete('Xrfdir/Xdir2', 'rf')) call assert_equal(-1, delete('Xrfdir', 'rf')) silent !chmod 755 Xrfdir call assert_equal(0, delete('Xrfdir', 'rf')) endif endfunc func Test_call() call assert_equal(3, call('len', [123])) call assert_equal(3, 'len'->call([123])) call assert_fails("call call('len', 123)", 'E1211:') call assert_equal(0, call('', [])) call assert_equal(0, call('len', test_null_list())) function Mylen() dict return len(self.data) endfunction let mydict = {'data': [0, 1, 2, 3], 'len': function("Mylen")} eval mydict.len->call([], mydict)->assert_equal(4) call assert_fails("call call('Mylen', [], 0)", 'E1206:') call assert_fails('call foo', 'E107:') " These once caused a crash. call call(test_null_function(), []) call call(test_null_partial(), []) call assert_fails('call test_null_function()()', 'E1192:') call assert_fails('call test_null_partial()()', 'E117:') let lines =<< trim END let Time = 'localtime' call Time() END call v9.CheckScriptFailure(lines, 'E1085:') endfunc func Test_char2nr() call assert_equal(12354, char2nr('あ', 1)) call assert_equal(120, 'x'->char2nr()) set encoding=latin1 call assert_equal(120, 'x'->char2nr()) set encoding=utf-8 endfunc func Test_charclass() call assert_equal(0, charclass(' ')) call assert_equal(1, charclass('.')) call assert_equal(2, charclass('x')) call assert_equal(3, charclass("\u203c")) " this used to crash vim call assert_equal(0, "xxx"[-1]->charclass()) endfunc func Test_eventhandler() call assert_equal(0, eventhandler()) endfunc func Test_bufadd_bufload() call assert_equal(0, bufexists('someName')) let buf = bufadd('someName') call assert_notequal(0, buf) call assert_equal(1, bufexists('someName')) call assert_equal(0, getbufvar(buf, '&buflisted')) call assert_equal(0, bufloaded(buf)) call bufload(buf) call assert_equal(1, bufloaded(buf)) call assert_equal([''], getbufline(buf, 1, '$')) let curbuf = bufnr('') eval ['some', 'text']->writefile('XotherName') let buf = 'XotherName'->bufadd() call assert_notequal(0, buf) eval 'XotherName'->bufexists()->assert_equal(1) call assert_equal(0, getbufvar(buf, '&buflisted')) call assert_equal(0, bufloaded(buf)) eval buf->bufload() call assert_equal(1, bufloaded(buf)) call assert_equal(['some', 'text'], getbufline(buf, 1, '$')) call assert_equal(curbuf, bufnr('')) let buf1 = bufadd('') let buf2 = bufadd('') call assert_notequal(0, buf1) call assert_notequal(0, buf2) call assert_notequal(buf1, buf2) call assert_equal(1, bufexists(buf1)) call assert_equal(1, bufexists(buf2)) call assert_equal(0, bufloaded(buf1)) exe 'bwipe ' .. buf1 call assert_equal(0, bufexists(buf1)) call assert_equal(1, bufexists(buf2)) exe 'bwipe ' .. buf2 call assert_equal(0, bufexists(buf2)) " When 'buftype' is "nofile" then bufload() does not read the file. " Other values too. for val in [['nofile', 0], \ ['nowrite', 1], \ ['acwrite', 1], \ ['quickfix', 0], \ ['help', 1], \ ['terminal', 0], \ ['prompt', 0], \ ['popup', 0], \ ] bwipe! XotherName let buf = bufadd('XotherName') call setbufvar(buf, '&bt', val[0]) call bufload(buf) call assert_equal(val[1] ? ['some', 'text'] : [''], getbufline(buf, 1, '$'), val[0]) endfor bwipe someName bwipe XotherName call assert_equal(0, bufexists('someName')) call delete('XotherName') endfunc func Test_state() CheckRunVimInTerminal let getstate = ":echo 'state: ' .. g:state .. '; mode: ' .. g:mode\" let lines =<< trim END call setline(1, ['one', 'two', 'three']) map ;; gg set complete=. func RunTimer() call timer_start(10, {id -> execute('let g:state = state()') .. execute('let g:mode = mode()')}) endfunc au Filetype foobar let g:state = state()|let g:mode = mode() END call writefile(lines, 'XState') let buf = RunVimInTerminal('-S XState', #{rows: 6}) " Using a ":" command Vim is busy, thus "S" is returned call term_sendkeys(buf, ":echo 'state: ' .. state() .. '; mode: ' .. mode()\") call WaitForAssert({-> assert_match('state: S; mode: n', term_getline(buf, 6))}, 1000) call term_sendkeys(buf, ":\") " Using a timer callback call term_sendkeys(buf, ":call RunTimer()\") call TermWait(buf, 25) call term_sendkeys(buf, getstate) call WaitForAssert({-> assert_match('state: c; mode: n', term_getline(buf, 6))}, 1000) " Halfway a mapping call term_sendkeys(buf, ":call RunTimer()\;") call TermWait(buf, 25) call term_sendkeys(buf, ";") call term_sendkeys(buf, getstate) call WaitForAssert({-> assert_match('state: mSc; mode: n', term_getline(buf, 6))}, 1000) " An operator is pending call term_sendkeys(buf, ":call RunTimer()\y") call TermWait(buf, 25) call term_sendkeys(buf, "y") call term_sendkeys(buf, getstate) call WaitForAssert({-> assert_match('state: oSc; mode: n', term_getline(buf, 6))}, 1000) " A register was specified call term_sendkeys(buf, ":call RunTimer()\\"r") call TermWait(buf, 25) call term_sendkeys(buf, "yy") call term_sendkeys(buf, getstate) call WaitForAssert({-> assert_match('state: oSc; mode: n', term_getline(buf, 6))}, 1000) " Insert mode completion (bit slower on Mac) call term_sendkeys(buf, ":call RunTimer()\Got\") call TermWait(buf, 25) call term_sendkeys(buf, "\") call term_sendkeys(buf, getstate) call WaitForAssert({-> assert_match('state: aSc; mode: i', term_getline(buf, 6))}, 1000) " Autocommand executing call term_sendkeys(buf, ":set filetype=foobar\") call TermWait(buf, 25) call term_sendkeys(buf, getstate) call WaitForAssert({-> assert_match('state: xS; mode: n', term_getline(buf, 6))}, 1000) " Todo: "w" - waiting for ch_evalexpr() " messages scrolled call term_sendkeys(buf, ":call RunTimer()\:echo \"one\\ntwo\\nthree\"\") call TermWait(buf, 25) call term_sendkeys(buf, "\") call term_sendkeys(buf, getstate) call WaitForAssert({-> assert_match('state: Scs; mode: r', term_getline(buf, 6))}, 1000) call StopVimInTerminal(buf) call delete('XState') endfunc func Test_range() " destructuring let [x, y] = range(2) call assert_equal([0, 1], [x, y]) " index call assert_equal(4, range(1, 10)[3]) " add() call assert_equal([0, 1, 2, 3], add(range(3), 3)) call assert_equal([0, 1, 2, [0, 1, 2]], add([0, 1, 2], range(3))) call assert_equal([0, 1, 2, [0, 1, 2]], add(range(3), range(3))) " append() new call append('.', range(5)) call assert_equal(['', '0', '1', '2', '3', '4'], getline(1, '$')) bwipe! " appendbufline() new call appendbufline(bufnr(''), '.', range(5)) call assert_equal(['0', '1', '2', '3', '4', ''], getline(1, '$')) bwipe! " call() func TwoArgs(a, b) return [a:a, a:b] endfunc call assert_equal([0, 1], call('TwoArgs', range(2))) " col() new call setline(1, ['foo', 'bar']) call assert_equal(2, col(range(1, 2))) bwipe! " complete() execute "normal! a\=[complete(col('.'), range(10)), ''][1]\" " complete_info() execute "normal! a\=[complete(col('.'), range(10)), ''][1]\\=[complete_info(range(5)), ''][1]\" " copy() call assert_equal([1, 2, 3], copy(range(1, 3))) " count() call assert_equal(0, count(range(0), 3)) call assert_equal(0, count(range(2), 3)) call assert_equal(1, count(range(5), 3)) " cursor() new call setline(1, ['aaa', 'bbb', 'ccc']) call cursor(range(1, 2)) call assert_equal([2, 1], [col('.'), line('.')]) bwipe! " deepcopy() call assert_equal([1, 2, 3], deepcopy(range(1, 3))) " empty() call assert_true(empty(range(0))) call assert_false(empty(range(2))) " execute() new call setline(1, ['aaa', 'bbb', 'ccc']) call execute(range(3)) call assert_equal(2, line('.')) bwipe! " extend() call assert_equal([1, 2, 3, 4], extend([1], range(2, 4))) call assert_equal([1, 2, 3, 4], extend(range(1, 1), range(2, 4))) call assert_equal([1, 2, 3, 4], extend(range(1, 1), [2, 3, 4])) " filter() call assert_equal([1, 3], filter(range(5), 'v:val % 2')) call assert_equal([1, 5, 7, 11, 13], filter(filter(range(15), 'v:val % 2'), 'v:val % 3')) " funcref() call assert_equal([0, 1], funcref('TwoArgs', range(2))()) " function() call assert_equal([0, 1], function('TwoArgs', range(2))()) " garbagecollect() let thelist = [1, range(2), 3] let otherlist = range(3) call test_garbagecollect_now() " get() call assert_equal(4, get(range(1, 10), 3)) call assert_equal(-1, get(range(1, 10), 42, -1)) call assert_equal(0, get(range(1, 0, 2), 0)) call assert_equal(0, get(range(0, -1, 2), 0)) call assert_equal(0, get(range(-2, -1, -2), 0)) " index() call assert_equal(1, index(range(1, 5), 2)) call assert_fails("echo index([1, 2], 1, [])", 'E745:') " insert() call assert_equal([42, 1, 2, 3, 4, 5], insert(range(1, 5), 42)) call assert_equal([42, 1, 2, 3, 4, 5], insert(range(1, 5), 42, 0)) call assert_equal([1, 42, 2, 3, 4, 5], insert(range(1, 5), 42, 1)) call assert_equal([1, 2, 3, 4, 42, 5], insert(range(1, 5), 42, 4)) call assert_equal([1, 2, 3, 4, 42, 5], insert(range(1, 5), 42, -1)) call assert_equal([1, 2, 3, 4, 5, 42], insert(range(1, 5), 42, 5)) " join() call assert_equal('0 1 2 3 4', join(range(5))) " json_encode() call assert_equal('[0,1,2,3]', json_encode(range(4))) " len() call assert_equal(0, len(range(0))) call assert_equal(2, len(range(2))) call assert_equal(5, len(range(0, 12, 3))) call assert_equal(4, len(range(3, 0, -1))) " list2str() call assert_equal('ABC', list2str(range(65, 67))) call assert_fails('let s = list2str(5)', 'E1211:') " lock() let thelist = range(5) lockvar thelist " map() call assert_equal([0, 2, 4, 6, 8], map(range(5), 'v:val * 2')) call assert_equal([3, 5, 7, 9, 11], map(map(range(5), 'v:val * 2'), 'v:val + 3')) call assert_equal([2, 6], map(filter(range(5), 'v:val % 2'), 'v:val * 2')) call assert_equal([2, 4, 8], filter(map(range(5), 'v:val * 2'), 'v:val % 3')) " match() call assert_equal(3, match(range(5), 3)) " matchaddpos() highlight MyGreenGroup ctermbg=green guibg=green call matchaddpos('MyGreenGroup', range(line('.'), line('.'))) " matchend() call assert_equal(4, matchend(range(5), '4')) call assert_equal(3, matchend(range(1, 5), '4')) call assert_equal(-1, matchend(range(1, 5), '42')) " matchstrpos() call assert_equal(['4', 4, 0, 1], matchstrpos(range(5), '4')) call assert_equal(['4', 3, 0, 1], matchstrpos(range(1, 5), '4')) call assert_equal(['', -1, -1, -1], matchstrpos(range(1, 5), '42')) " max() reverse() call assert_equal(0, max(range(0))) call assert_equal(0, max(range(10, 9))) call assert_equal(9, max(range(10))) call assert_equal(18, max(range(0, 20, 3))) call assert_equal(20, max(range(20, 0, -3))) call assert_equal(99999, max(range(100000))) call assert_equal(99999, max(range(99999, 0, -1))) call assert_equal(99999, max(reverse(range(100000)))) call assert_equal(99999, max(reverse(range(99999, 0, -1)))) " min() reverse() call assert_equal(0, min(range(0))) call assert_equal(0, min(range(10, 9))) call assert_equal(5, min(range(5, 10))) call assert_equal(5, min(range(5, 10, 3))) call assert_equal(2, min(range(20, 0, -3))) call assert_equal(0, min(range(100000))) call assert_equal(0, min(range(99999, 0, -1))) call assert_equal(0, min(reverse(range(100000)))) call assert_equal(0, min(reverse(range(99999, 0, -1)))) " remove() call assert_equal(1, remove(range(1, 10), 0)) call assert_equal(2, remove(range(1, 10), 1)) call assert_equal(9, remove(range(1, 10), 8)) call assert_equal(10, remove(range(1, 10), 9)) call assert_equal(10, remove(range(1, 10), -1)) call assert_equal([3, 4, 5], remove(range(1, 10), 2, 4)) " repeat() call assert_equal([0, 1, 2, 0, 1, 2], repeat(range(3), 2)) call assert_equal([0, 1, 2], repeat(range(3), 1)) call assert_equal([], repeat(range(3), 0)) call assert_equal([], repeat(range(5, 4), 2)) call assert_equal([], repeat(range(5, 4), 0)) " reverse() call assert_equal([2, 1, 0], reverse(range(3))) call assert_equal([0, 1, 2, 3], reverse(range(3, 0, -1))) call assert_equal([9, 8, 7, 6, 5, 4, 3, 2, 1, 0], reverse(range(10))) call assert_equal([20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10], reverse(range(10, 20))) call assert_equal([16, 13, 10], reverse(range(10, 18, 3))) call assert_equal([19, 16, 13, 10], reverse(range(10, 19, 3))) call assert_equal([19, 16, 13, 10], reverse(range(10, 20, 3))) call assert_equal([11, 14, 17, 20], reverse(range(20, 10, -3))) call assert_equal([], reverse(range(0))) " TODO: setpos() " new " call setline(1, repeat([''], bufnr(''))) " call setline(bufnr('') + 1, repeat('x', bufnr('') * 2 + 6)) " call setpos('x', range(bufnr(''), bufnr('') + 3)) " bwipe! " setreg() call setreg('a', range(3)) call assert_equal("0\n1\n2\n", getreg('a')) " settagstack() call settagstack(1, #{items : range(4)}) " sign_define() call assert_fails("call sign_define(range(5))", "E715:") call assert_fails("call sign_placelist(range(5))", "E715:") " sign_undefine() call assert_fails("call sign_undefine(range(5))", "E908:") " sign_unplacelist() call assert_fails("call sign_unplacelist(range(5))", "E715:") " sort() call assert_equal([0, 1, 2, 3, 4, 5], sort(range(5, 0, -1))) " string() call assert_equal('[0, 1, 2, 3, 4]', string(range(5))) " taglist() with 'tagfunc' func TagFunc(pattern, flags, info) return range(10) endfunc set tagfunc=TagFunc call assert_fails("call taglist('asdf')", 'E987:') set tagfunc= " term_start() if has('terminal') && has('termguicolors') call assert_fails('call term_start(range(3, 4))', 'E474:') let g:terminal_ansi_colors = range(16) if has('win32') let cmd = "cmd /c dir" else let cmd = "ls" endif call assert_fails('call term_start("' .. cmd .. '", #{term_finish: "close"' \ .. ', ansi_colors: range(16)})', 'E475:') unlet g:terminal_ansi_colors endif " type() call assert_equal(v:t_list, type(range(5))) " uniq() call assert_equal([0, 1, 2, 3, 4], uniq(range(5))) " errors call assert_fails('let x=range(2, 8, 0)', 'E726:') call assert_fails('let x=range(3, 1)', 'E727:') call assert_fails('let x=range(1, 3, -2)', 'E727:') call assert_fails('let x=range([])', 'E745:') call assert_fails('let x=range(1, [])', 'E745:') call assert_fails('let x=range(1, 4, [])', 'E745:') endfunc func Test_garbagecollect_now_fails() let v:testing = 0 call assert_fails('call test_garbagecollect_now()', 'E1142:') let v:testing = 1 endfunc func Test_echoraw() CheckScreendump " Normally used for escape codes, but let's test with a CR. let lines =<< trim END call echoraw("hello\x") END call writefile(lines, 'XTest_echoraw') let buf = RunVimInTerminal('-S XTest_echoraw', {'rows': 5, 'cols': 40}) call VerifyScreenDump(buf, 'Test_functions_echoraw', {}) " clean up call StopVimInTerminal(buf) call delete('XTest_echoraw') endfunc " Test for echo highlighting func Test_echohl() echohl Search echo 'Vim' call assert_equal('Vim', Screenline(&lines)) " TODO: How to check the highlight group used by echohl? " ScreenAttrs() returns all zeros. echohl None endfunc " Test for the eval() function func Test_eval() call assert_fails("call eval('5 a')", 'E488:') endfunc " Test for the keytrans() function func Test_keytrans() call assert_equal('', keytrans(' ')) call assert_equal('', keytrans('<')) call assert_equal('Tab>', keytrans('')) call assert_equal('', keytrans("\")) call assert_equal('', keytrans("\")) call assert_equal('', keytrans("\")) call assert_equal('', keytrans("\")) call assert_equal('', keytrans("\")) call assert_equal('', keytrans("\")) call assert_equal('', keytrans("\")) call assert_equal('', keytrans("\<*M-Space>")) call assert_equal('', "\<*M-x>"->keytrans()) call assert_equal('', "\<*C-I>"->keytrans()) call assert_equal('', "\<*S-3>"->keytrans()) call assert_equal('π', 'π'->keytrans()) call assert_equal('', "\"->keytrans()) call assert_equal('ě', 'ě'->keytrans()) call assert_equal('', "\"->keytrans()) call assert_equal('', ''->keytrans()) call assert_equal('', test_null_string()->keytrans()) call assert_fails('call keytrans(1)', 'E1174:') call assert_fails('call keytrans()', 'E119:') endfunc " Test for the nr2char() function func Test_nr2char() set encoding=latin1 call assert_equal('@', nr2char(64)) set encoding=utf8 call assert_equal('a', nr2char(97, 1)) call assert_equal('a', nr2char(97, 0)) call assert_equal("\x80\xfc\b" .. nr2char(0x100000), eval('"\"')) call assert_equal("\x80\xfc\b" .. nr2char(0x40000000), eval('"\"')) endfunc " Test for screenattr(), screenchar() and screenchars() functions func Test_screen_functions() call assert_equal(-1, screenattr(-1, -1)) call assert_equal(-1, screenchar(-1, -1)) call assert_equal([], screenchars(-1, -1)) " Run this in a separate Vim instance to avoid messing up. let after =<< trim [CODE] scriptencoding utf-8 call setline(1, '口') redraw call assert_equal(0, screenattr(1, 1)) call assert_equal(char2nr('口'), screenchar(1, 1)) call assert_equal([char2nr('口')], screenchars(1, 1)) call assert_equal('口', screenstring(1, 1)) call writefile(v:errors, 'Xresult') qall! [CODE] let encodings = ['utf-8', 'cp932', 'cp936', 'cp949', 'cp950'] if !has('win32') let encodings += ['euc-jp'] endif for enc in encodings let msg = 'enc=' .. enc if RunVim([], after, $'--clean --cmd "set encoding={enc}"') call assert_equal([], readfile('Xresult'), msg) endif call delete('Xresult') endfor endfunc " Test for getcurpos() and setpos() func Test_getcurpos_setpos() new call setline(1, ['012345678', '012345678']) normal gg6l let sp = getcurpos() normal 0 call setpos('.', sp) normal jyl call assert_equal('6', @") call assert_equal(-1, setpos('.', test_null_list())) call assert_equal(-1, setpos('.', {})) let winid = win_getid() normal G$ let pos = getcurpos() wincmd w call assert_equal(pos, getcurpos(winid)) wincmd w close! call assert_equal(getcurpos(), getcurpos(0)) call assert_equal([0, 0, 0, 0, 0], getcurpos(-1)) call assert_equal([0, 0, 0, 0, 0], getcurpos(1999)) endfunc func Test_getmousepos() enew! call setline(1, "\t\t\t1234") call test_setmouse(1, 1) call assert_equal(#{ \ screenrow: 1, \ screencol: 1, \ winid: win_getid(), \ winrow: 1, \ wincol: 1, \ line: 1, \ column: 1, \ coladd: 0, \ }, getmousepos()) call test_setmouse(1, 2) call assert_equal(#{ \ screenrow: 1, \ screencol: 2, \ winid: win_getid(), \ winrow: 1, \ wincol: 2, \ line: 1, \ column: 1, \ coladd: 1, \ }, getmousepos()) call test_setmouse(1, 8) call assert_equal(#{ \ screenrow: 1, \ screencol: 8, \ winid: win_getid(), \ winrow: 1, \ wincol: 8, \ line: 1, \ column: 1, \ coladd: 7, \ }, getmousepos()) call test_setmouse(1, 9) call assert_equal(#{ \ screenrow: 1, \ screencol: 9, \ winid: win_getid(), \ winrow: 1, \ wincol: 9, \ line: 1, \ column: 2, \ coladd: 0, \ }, getmousepos()) call test_setmouse(1, 12) call assert_equal(#{ \ screenrow: 1, \ screencol: 12, \ winid: win_getid(), \ winrow: 1, \ wincol: 12, \ line: 1, \ column: 2, \ coladd: 3, \ }, getmousepos()) call test_setmouse(1, 25) call assert_equal(#{ \ screenrow: 1, \ screencol: 25, \ winid: win_getid(), \ winrow: 1, \ wincol: 25, \ line: 1, \ column: 4, \ coladd: 0, \ }, getmousepos()) call test_setmouse(1, 28) call assert_equal(#{ \ screenrow: 1, \ screencol: 28, \ winid: win_getid(), \ winrow: 1, \ wincol: 28, \ line: 1, \ column: 7, \ coladd: 0, \ }, getmousepos()) call test_setmouse(1, 29) call assert_equal(#{ \ screenrow: 1, \ screencol: 29, \ winid: win_getid(), \ winrow: 1, \ wincol: 29, \ line: 1, \ column: 8, \ coladd: 0, \ }, getmousepos()) call test_setmouse(1, 50) call assert_equal(#{ \ screenrow: 1, \ screencol: 50, \ winid: win_getid(), \ winrow: 1, \ wincol: 50, \ line: 1, \ column: 8, \ coladd: 21, \ }, getmousepos()) " If the mouse is positioned past the last buffer line, "line" and "column" " should act like it's positioned on the last buffer line. call test_setmouse(2, 25) call assert_equal(#{ \ screenrow: 2, \ screencol: 25, \ winid: win_getid(), \ winrow: 2, \ wincol: 25, \ line: 1, \ column: 4, \ coladd: 0, \ }, getmousepos()) call test_setmouse(2, 50) call assert_equal(#{ \ screenrow: 2, \ screencol: 50, \ winid: win_getid(), \ winrow: 2, \ wincol: 50, \ line: 1, \ column: 8, \ coladd: 21, \ }, getmousepos()) 30vnew setlocal smoothscroll number call setline(1, join(range(100))) exe "normal! \" call test_setmouse(1, 5) call assert_equal(#{ \ screenrow: 1, \ screencol: 5, \ winid: win_getid(), \ winrow: 1, \ wincol: 5, \ line: 1, \ column: 27, \ coladd: 0, \ }, getmousepos()) call test_setmouse(2, 5) call assert_equal(#{ \ screenrow: 2, \ screencol: 5, \ winid: win_getid(), \ winrow: 2, \ wincol: 5, \ line: 1, \ column: 53, \ coladd: 0, \ }, getmousepos()) exe "normal! \" call test_setmouse(1, 5) call assert_equal(#{ \ screenrow: 1, \ screencol: 5, \ winid: win_getid(), \ winrow: 1, \ wincol: 5, \ line: 1, \ column: 53, \ coladd: 0, \ }, getmousepos()) call test_setmouse(2, 5) call assert_equal(#{ \ screenrow: 2, \ screencol: 5, \ winid: win_getid(), \ winrow: 2, \ wincol: 5, \ line: 1, \ column: 79, \ coladd: 0, \ }, getmousepos()) vert resize 4 call test_setmouse(2, 2) " This used to crash Vim call assert_equal(#{ \ screenrow: 2, \ screencol: 2, \ winid: win_getid(), \ winrow: 2, \ wincol: 2, \ line: 1, \ column: 53, \ coladd: 0, \ }, getmousepos()) bwipe! bwipe! endfunc func Test_getmouseshape() CheckFeature mouseshape call assert_equal('arrow', getmouseshape()) endfunc " Test for glob() func Test_glob() call assert_equal('', glob(test_null_string())) call assert_equal('', globpath(test_null_string(), test_null_string())) call assert_fails("let x = globpath(&rtp, 'syntax/c.vim', [])", 'E745:') call writefile([], 'Xglob1') call writefile([], 'XGLOB2') set wildignorecase " Sort output of glob() otherwise we end up with different " ordering depending on whether file system is case-sensitive. call assert_equal(['XGLOB2', 'Xglob1'], sort(glob('Xglob[12]', 0, 1))) " wildignorecase shall be applied even when the pattern contains no wildcards. call assert_equal('XGLOB2', glob('xglob2')) set wildignorecase& call delete('Xglob1') call delete('XGLOB2') call assert_fails("call glob('*', 0, {})", 'E728:') endfunc func Test_glob2() call mkdir('[XglobDir]', 'R') call mkdir('abc[glob]def', 'R') call writefile(['glob'], '[XglobDir]/Xglob') call writefile(['glob'], 'abc[glob]def/Xglob') if has("unix") call assert_equal([], (glob('[XglobDir]/*', 0, 1))) call assert_equal([], (glob('abc[glob]def/*', 0, 1))) call assert_equal(['[XglobDir]/Xglob'], (glob('\[XglobDir]/*', 0, 1))) call assert_equal(['abc[glob]def/Xglob'], (glob('abc\[glob]def/*', 0, 1))) elseif has("win32") let _sl=&shellslash call assert_equal([], (glob('[XglobDir]\*', 0, 1))) call assert_equal([], (glob('abc[glob]def\*', 0, 1))) call assert_equal([], (glob('\[XglobDir]\*', 0, 1))) call assert_equal([], (glob('abc\[glob]def\*', 0, 1))) set noshellslash call assert_equal(['[XglobDir]\Xglob'], (glob('[[]XglobDir]/*', 0, 1))) call assert_equal(['abc[glob]def\Xglob'], (glob('abc[[]glob]def/*', 0, 1))) set shellslash call assert_equal(['[XglobDir]/Xglob'], (glob('[[]XglobDir]/*', 0, 1))) call assert_equal(['abc[glob]def/Xglob'], (glob('abc[[]glob]def/*', 0, 1))) let &shellslash=_sl endif endfunc " Test for browse() func Test_browse() CheckFeature browse call assert_fails('call browse([], "open", "x", "a.c")', 'E745:') endfunc " Test for browsedir() func Test_browsedir() CheckFeature browse call assert_fails('call browsedir("open", [])', 'E730:') endfunc func HasDefault(msg = 'msg') return a:msg endfunc func Test_default_arg_value() call assert_equal('msg', HasDefault()) endfunc " Test for gettext() func Test_gettext() call assert_fails('call gettext(1)', 'E1174:') endfunc func Test_builtin_check() call assert_fails('let g:["trim"] = {x -> " " .. x}', 'E704:') call assert_fails('let g:.trim = {x -> " " .. x}', 'E704:') call assert_fails('let l:["trim"] = {x -> " " .. x}', 'E704:') call assert_fails('let l:.trim = {x -> " " .. x}', 'E704:') let lines =<< trim END vim9script var trim = (x) => " " .. x END call v9.CheckScriptFailure(lines, 'E704:') call assert_fails('call extend(g:, #{foo: { -> "foo" }})', 'E704:') let g:bar = 123 call extend(g:, #{bar: { -> "foo" }}, "keep") call assert_fails('call extend(g:, #{bar: { -> "foo" }}, "force")', 'E704:') unlet g:bar call assert_fails('call extend(l:, #{foo: { -> "foo" }})', 'E704:') let bar = 123 call extend(l:, #{bar: { -> "foo" }}, "keep") call assert_fails('call extend(l:, #{bar: { -> "foo" }}, "force")', 'E704:') unlet bar call assert_fails('call extend(g:, #{foo: function("extend")})', 'E704:') let g:bar = 123 call extend(g:, #{bar: function("extend")}, "keep") call assert_fails('call extend(g:, #{bar: function("extend")}, "force")', 'E704:') unlet g:bar call assert_fails('call extend(l:, #{foo: function("extend")})', 'E704:') let bar = 123 call extend(l:, #{bar: function("extend")}, "keep") call assert_fails('call extend(l:, #{bar: function("extend")}, "force")', 'E704:') unlet bar endfunc func Test_funcref_to_string() let Fn = funcref('g:Test_funcref_to_string') call assert_equal("function('g:Test_funcref_to_string')", string(Fn)) endfunc " A funcref cannot start with an underscore (except when used as a protected " class or object variable) func Test_funcref_with_underscore() " at script level let lines =<< trim END vim9script var _Fn = () => 10 END call v9.CheckSourceFailure(lines, 'E704: Funcref variable name must start with a capital: _Fn') " inside a function let lines =<< trim END vim9script def Func() var _Fn = () => 10 enddef defcompile END call v9.CheckSourceFailure(lines, 'E704: Funcref variable name must start with a capital: _Fn', 1) " as a function argument let lines =<< trim END vim9script def Func(_Fn: func) enddef defcompile END call v9.CheckSourceFailure(lines, 'E704: Funcref variable name must start with a capital: _Fn', 2) " as a lambda argument let lines =<< trim END vim9script var Fn = (_Farg: func) => 10 END call v9.CheckSourceFailure(lines, 'E704: Funcref variable name must start with a capital: _Farg', 2) endfunc " Test for isabsolutepath() func Test_isabsolutepath() call assert_false(isabsolutepath('')) call assert_false(isabsolutepath('.')) call assert_false(isabsolutepath('../Foo')) call assert_false(isabsolutepath('Foo/')) if has('win32') call assert_true(isabsolutepath('A:\')) call assert_true(isabsolutepath('A:\Foo')) call assert_true(isabsolutepath('A:/Foo')) call assert_false(isabsolutepath('A:Foo')) call assert_false(isabsolutepath('\Windows')) call assert_true(isabsolutepath('\\Server2\Share\Test\Foo.txt')) else call assert_true(isabsolutepath('/')) call assert_true(isabsolutepath('/usr/share/')) endif endfunc " Test for exepath() func Test_exepath() if has('win32') call assert_notequal(exepath('cmd'), '') let oldNoDefaultCurrentDirectoryInExePath = $NoDefaultCurrentDirectoryInExePath call writefile(['@echo off', 'echo Evil'], 'vim-test-evil.bat') let $NoDefaultCurrentDirectoryInExePath = '' call assert_notequal(exepath("vim-test-evil.bat"), '') let $NoDefaultCurrentDirectoryInExePath = '1' call assert_equal(exepath("vim-test-evil.bat"), '') let $NoDefaultCurrentDirectoryInExePath = oldNoDefaultCurrentDirectoryInExePath call delete('vim-test-evil.bat') else call assert_notequal(exepath('sh'), '') endif endfunc " Test for virtcol() func Test_virtcol() new call setline(1, "the\tquick\tbrown\tfox") norm! 4| call assert_equal(8, virtcol('.')) call assert_equal(8, virtcol('.', v:false)) call assert_equal([4, 8], virtcol('.', v:true)) let w = winwidth(0) call setline(2, repeat('a', w + 2)) let win_nosbr = win_getid() split setlocal showbreak=!! let win_sbr = win_getid() call assert_equal([w, w], virtcol([2, w], v:true, win_nosbr)) call assert_equal([w + 1, w + 1], virtcol([2, w + 1], v:true, win_nosbr)) call assert_equal([w + 2, w + 2], virtcol([2, w + 2], v:true, win_nosbr)) call assert_equal([w, w], virtcol([2, w], v:true, win_sbr)) call assert_equal([w + 3, w + 3], virtcol([2, w + 1], v:true, win_sbr)) call assert_equal([w + 4, w + 4], virtcol([2, w + 2], v:true, win_sbr)) close call assert_equal(0, virtcol('')) call assert_equal([0, 0], virtcol('', v:true)) call assert_equal(0, virtcol('.', v:false, 5001)) call assert_equal([0, 0], virtcol('.', v:true, 5001)) bwipe! endfunc func Test_delfunc_while_listing() CheckRunVimInTerminal let lines =<< trim END set nocompatible for i in range(1, 999) exe 'func ' .. 'MyFunc' .. i .. '()' endfunc endfor au CmdlineLeave : call timer_start(0, {-> execute('delfunc MyFunc622')}) END call writefile(lines, 'Xfunctionclear', 'D') let buf = RunVimInTerminal('-S Xfunctionclear', {'rows': 12}) " This was using freed memory. The height of the terminal must be so that " the next function to be listed with "j" is the one that is deleted in the " timer callback, tricky! call term_sendkeys(buf, ":func /MyFunc\") call TermWait(buf, 50) call term_sendkeys(buf, "j") call TermWait(buf, 50) call term_sendkeys(buf, "\") call StopVimInTerminal(buf) endfunc " Test for the reverse() function with a string func Test_string_reverse() let lines =<< trim END call assert_equal('', reverse(test_null_string())) for [s1, s2] in [['', ''], ['a', 'a'], ['ab', 'ba'], ['abc', 'cba'], \ ['abcd', 'dcba'], ['«-«-»-»', '»-»-«-«'], \ ['🇦', '🇦'], ['🇦🇧', '🇧🇦'], ['🇦🇧🇨', '🇨🇧🇦'], \ ['🇦«🇧-🇨»🇩', '🇩»🇨-🇧«🇦']] call assert_equal(s2, reverse(s1)) endfor END call v9.CheckLegacyAndVim9Success(lines) " test in latin1 encoding let save_enc = &encoding set encoding=latin1 call assert_equal('dcba', reverse('abcd')) let &encoding = save_enc endfunc func Test_fullcommand() " this used to crash vim call assert_equal('', fullcommand(10)) endfunc " Test for glob() with shell special patterns func Test_glob_extended_bash() CheckExecutable bash CheckNotMSWindows CheckNotMac " The default version of bash is old on macOS. let _shell = &shell set shell=bash call mkdir('Xtestglob/foo/bar/src', 'p') call writefile([], 'Xtestglob/foo/bar/src/foo.sh') call writefile([], 'Xtestglob/foo/bar/src/foo.h') call writefile([], 'Xtestglob/foo/bar/src/foo.cpp') " Sort output of glob() otherwise we end up with different " ordering depending on whether file system is case-sensitive. let expected = ['Xtestglob/foo/bar/src/foo.cpp', 'Xtestglob/foo/bar/src/foo.h'] call assert_equal(expected, sort(glob('Xtestglob/**/foo.{h,cpp}', 0, 1))) call delete('Xtestglob', 'rf') let &shell=_shell endfunc " Test for glob() with extended patterns (MS-Windows) " Vim doesn't use 'shell' to expand wildcards on MS-Windows. " Unlike bash, it doesn't support {,} expansion. func Test_glob_extended_mswin() CheckMSWindows call mkdir('Xtestglob/foo/bar/src', 'p') call writefile([], 'Xtestglob/foo/bar/src/foo.sh') call writefile([], 'Xtestglob/foo/bar/src/foo.h') call writefile([], 'Xtestglob/foo/bar/src/foo.cpp') " Sort output of glob() otherwise we end up with different " ordering depending on whether file system is case-sensitive. let expected = ['Xtestglob/foo/bar/src/foo.cpp', 'Xtestglob/foo/bar/src/foo.h', 'Xtestglob/foo/bar/src/foo.sh'] call assert_equal(expected, sort(glob('Xtestglob/**/foo.*', 0, 1))) call delete('Xtestglob', 'rf') endfunc " Tests for the slice() function. func Test_slice() let lines =<< trim END call assert_equal([1, 2, 3, 4, 5], slice(range(6), 1)) call assert_equal([2, 3, 4, 5], slice(range(6), 2)) call assert_equal([2, 3], slice(range(6), 2, 4)) call assert_equal([0, 1, 2, 3], slice(range(6), 0, 4)) call assert_equal([1, 2, 3], slice(range(6), 1, 4)) call assert_equal([1, 2, 3, 4], slice(range(6), 1, -1)) call assert_equal([1, 2], slice(range(6), 1, -3)) call assert_equal([1], slice(range(6), 1, -4)) call assert_equal([], slice(range(6), 1, -5)) call assert_equal([], slice(range(6), 1, -6)) call assert_equal(0z1122334455, slice(0z001122334455, 1)) call assert_equal(0z22334455, slice(0z001122334455, 2)) call assert_equal(0z2233, slice(0z001122334455, 2, 4)) call assert_equal(0z00112233, slice(0z001122334455, 0, 4)) call assert_equal(0z112233, slice(0z001122334455, 1, 4)) call assert_equal(0z11223344, slice(0z001122334455, 1, -1)) call assert_equal(0z1122, slice(0z001122334455, 1, -3)) call assert_equal(0z11, slice(0z001122334455, 1, -4)) call assert_equal(0z, slice(0z001122334455, 1, -5)) call assert_equal(0z, slice(0z001122334455, 1, -6)) call assert_equal('12345', slice('012345', 1)) call assert_equal('2345', slice('012345', 2)) call assert_equal('23', slice('012345', 2, 4)) call assert_equal('0123', slice('012345', 0, 4)) call assert_equal('123', slice('012345', 1, 4)) call assert_equal('1234', slice('012345', 1, -1)) call assert_equal('12', slice('012345', 1, -3)) call assert_equal('1', slice('012345', 1, -4)) call assert_equal('', slice('012345', 1, -5)) call assert_equal('', slice('012345', 1, -6)) #" Composing chars are treated as a part of the preceding base char. call assert_equal('β̳́γ̳̂δ̳̃ε̳̄ζ̳̅', 'ὰ̳β̳́γ̳̂δ̳̃ε̳̄ζ̳̅'->slice(1)) call assert_equal('γ̳̂δ̳̃ε̳̄ζ̳̅', 'ὰ̳β̳́γ̳̂δ̳̃ε̳̄ζ̳̅'->slice(2)) call assert_equal('γ̳̂δ̳̃', 'ὰ̳β̳́γ̳̂δ̳̃ε̳̄ζ̳̅'->slice(2, 4)) call assert_equal('ὰ̳β̳́γ̳̂δ̳̃', 'ὰ̳β̳́γ̳̂δ̳̃ε̳̄ζ̳̅'->slice(0, 4)) call assert_equal('β̳́γ̳̂δ̳̃', 'ὰ̳β̳́γ̳̂δ̳̃ε̳̄ζ̳̅'->slice(1, 4)) call assert_equal('β̳́γ̳̂δ̳̃ε̳̄', 'ὰ̳β̳́γ̳̂δ̳̃ε̳̄ζ̳̅'->slice(1, -1)) call assert_equal('β̳́γ̳̂', 'ὰ̳β̳́γ̳̂δ̳̃ε̳̄ζ̳̅'->slice(1, -3)) call assert_equal('β̳́', 'ὰ̳β̳́γ̳̂δ̳̃ε̳̄ζ̳̅'->slice(1, -4)) call assert_equal('', 'ὰ̳β̳́γ̳̂δ̳̃ε̳̄ζ̳̅'->slice(1, -5)) call assert_equal('', 'ὰ̳β̳́γ̳̂δ̳̃ε̳̄ζ̳̅'->slice(1, -6)) END call v9.CheckLegacyAndVim9Success(lines) call assert_equal(0, slice(v:true, 1)) endfunc " vim: shiftwidth=2 sts=2 expandtab