neovim

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

string_spec.lua (9659B)


      1 local t = require('test.testutil')
      2 local n = require('test.functional.testnvim')()
      3 
      4 local clear = n.clear
      5 local eq = t.eq
      6 local command = n.command
      7 local api = n.api
      8 local eval = n.eval
      9 local exc_exec = n.exc_exec
     10 local pcall_err = t.pcall_err
     11 local fn = n.fn
     12 local NIL = vim.NIL
     13 local source = n.source
     14 
     15 describe('string() function', function()
     16  setup(clear)
     17 
     18  describe('used to represent floating-point values', function()
     19    it('dumps NaN values', function()
     20      eq("str2float('nan')", eval("string(str2float('nan'))"))
     21    end)
     22 
     23    it('dumps infinite values', function()
     24      eq("str2float('inf')", eval("string(str2float('inf'))"))
     25      eq("-str2float('inf')", eval("string(str2float('-inf'))"))
     26    end)
     27 
     28    it('dumps regular values', function()
     29      eq('1.5', fn.string(1.5))
     30      eq('1.56e-20', fn.string(1.56000e-020))
     31      eq('0.0', eval('string(0.0)'))
     32    end)
     33 
     34    it('dumps special v: values', function()
     35      eq('v:true', eval('string(v:true)'))
     36      eq('v:false', eval('string(v:false)'))
     37      eq('v:null', eval('string(v:null)'))
     38      eq('v:true', fn.string(true))
     39      eq('v:false', fn.string(false))
     40      eq('v:null', fn.string(NIL))
     41    end)
     42 
     43    it('dumps values with at most six digits after the decimal point', function()
     44      eq('1.234568e-20', fn.string(1.23456789123456789123456789e-020))
     45      eq('1.234568', fn.string(1.23456789123456789123456789))
     46    end)
     47 
     48    it('dumps values with at most seven digits before the decimal point', function()
     49      eq('1234567.891235', fn.string(1234567.89123456789123456789))
     50      eq('1.234568e7', fn.string(12345678.9123456789123456789))
     51    end)
     52 
     53    it('dumps negative values', function()
     54      eq('-1.5', fn.string(-1.5))
     55      eq('-1.56e-20', fn.string(-1.56000e-020))
     56      eq('-1.234568e-20', fn.string(-1.23456789123456789123456789e-020))
     57      eq('-1.234568', fn.string(-1.23456789123456789123456789))
     58      eq('-1234567.891235', fn.string(-1234567.89123456789123456789))
     59      eq('-1.234568e7', fn.string(-12345678.9123456789123456789))
     60    end)
     61  end)
     62 
     63  describe('used to represent numbers', function()
     64    it('dumps regular values', function()
     65      eq('0', fn.string(0))
     66      eq('-1', fn.string(-1))
     67      eq('1', fn.string(1))
     68    end)
     69 
     70    it('dumps large values', function()
     71      eq('2147483647', fn.string(2 ^ 31 - 1))
     72      eq('-2147483648', fn.string(-2 ^ 31))
     73    end)
     74  end)
     75 
     76  describe('used to represent strings', function()
     77    it('dumps regular strings', function()
     78      eq("'test'", fn.string('test'))
     79    end)
     80 
     81    it('dumps empty strings', function()
     82      eq("''", fn.string(''))
     83    end)
     84 
     85    it("dumps strings with ' inside", function()
     86      eq("''''''''", fn.string("'''"))
     87      eq("'a''b'''''", fn.string("a'b''"))
     88      eq("'''b''''d'", fn.string("'b''d"))
     89      eq("'a''b''c''d'", fn.string("a'b'c'd"))
     90    end)
     91 
     92    it('dumps NULL strings', function()
     93      eq("''", eval('string($XXX_UNEXISTENT_VAR_XXX)'))
     94    end)
     95 
     96    it('dumps NULL lists', function()
     97      eq('[]', eval('string(v:_null_list)'))
     98    end)
     99 
    100    it('dumps NULL dictionaries', function()
    101      eq('{}', eval('string(v:_null_dict)'))
    102    end)
    103  end)
    104 
    105  describe('used to represent funcrefs', function()
    106    setup(function()
    107      source([[
    108        function Test1()
    109        endfunction
    110 
    111        function s:Test2() dict
    112        endfunction
    113 
    114        function g:Test3() dict
    115        endfunction
    116 
    117        let g:Test2_f = function('s:Test2')
    118      ]])
    119    end)
    120 
    121    it('dumps references to built-in functions', function()
    122      eq("function('function')", eval('string(function("function"))'))
    123    end)
    124 
    125    it('dumps references to user functions', function()
    126      eq("function('Test1')", eval('string(function("Test1"))'))
    127      eq("function('g:Test3')", eval('string(function("g:Test3"))'))
    128    end)
    129 
    130    it('dumps references to script functions', function()
    131      eq("function('<SNR>1_Test2')", eval('string(Test2_f)'))
    132    end)
    133 
    134    it('dumps partials with self referencing a partial', function()
    135      source([[
    136        function TestDict() dict
    137        endfunction
    138        let d = {}
    139        let TestDictRef = function('TestDict', d)
    140        let d.tdr = TestDictRef
    141      ]])
    142      eq(
    143        'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
    144        pcall_err(command, 'echo string(d.tdr)')
    145      )
    146    end)
    147 
    148    it('dumps automatically created partials', function()
    149      eq(
    150        "function('<SNR>1_Test2', {'f': function('<SNR>1_Test2')})",
    151        eval('string({"f": Test2_f}.f)')
    152      )
    153      eq(
    154        "function('<SNR>1_Test2', [1], {'f': function('<SNR>1_Test2', [1])})",
    155        eval('string({"f": function(Test2_f, [1])}.f)')
    156      )
    157    end)
    158 
    159    it('dumps manually created partials', function()
    160      eq("function('Test3', [1, 2], {})", eval('string(function("Test3", [1, 2], {}))'))
    161      eq("function('Test3', {})", eval('string(function("Test3", {}))'))
    162      eq("function('Test3', [1, 2])", eval('string(function("Test3", [1, 2]))'))
    163    end)
    164 
    165    it('does not crash or halt when dumping partials with reference cycles in self', function()
    166      api.nvim_set_var('d', { v = true })
    167      eq(
    168        [[Vim(echo):E724: unable to correctly dump variable with self-referencing container]],
    169        pcall_err(command, 'echo string(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))')
    170      )
    171    end)
    172 
    173    it('does not show errors when dumping partials referencing the same dict', function()
    174      command('let d = {}')
    175      -- Regression for “eval/typval_encode: Dump empty dict before
    176      -- checking for refcycle”, results in error.
    177      eq(
    178        "[function('tr', {}), function('tr', {})]",
    179        eval('string([function("tr", d), function("tr", d)])')
    180      )
    181      -- Regression for “eval: Work with reference cycles in partials (self)
    182      -- properly”, results in crash.
    183      eval('extend(d, {"a": 1})')
    184      eq(
    185        "[function('tr', {'a': 1}), function('tr', {'a': 1})]",
    186        eval('string([function("tr", d), function("tr", d)])')
    187      )
    188    end)
    189 
    190    it('does not crash or halt when dumping partials with reference cycles in arguments', function()
    191      api.nvim_set_var('l', {})
    192      eval('add(l, l)')
    193      -- Regression: the below line used to crash (add returns original list and
    194      -- there was error in dumping partials). Tested explicitly in
    195      -- test/unit/api/private_helpers_spec.lua.
    196      eval('add(l, function("Test1", l))')
    197      eq(
    198        [=[Vim(echo):E724: unable to correctly dump variable with self-referencing container]=],
    199        pcall_err(command, 'echo string(function("Test1", l))')
    200      )
    201    end)
    202 
    203    it(
    204      'does not crash or halt when dumping partials with reference cycles in self and arguments',
    205      function()
    206        api.nvim_set_var('d', { v = true })
    207        api.nvim_set_var('l', {})
    208        eval('add(l, l)')
    209        eval('add(l, function("Test1", l))')
    210        eval('add(l, function("Test1", d))')
    211        eq(
    212          [=[Vim(echo):E724: unable to correctly dump variable with self-referencing container]=],
    213          pcall_err(
    214            command,
    215            'echo string(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))'
    216          )
    217        )
    218      end
    219    )
    220  end)
    221 
    222  describe('used to represent lists', function()
    223    it('dumps empty list', function()
    224      eq('[]', fn.string({}))
    225    end)
    226 
    227    it('dumps nested lists', function()
    228      eq('[[[[[]]]]]', fn.string({ { { { {} } } } }))
    229    end)
    230 
    231    it('dumps nested non-empty lists', function()
    232      eq('[1, [[3, [[5], 4]], 2]]', fn.string({ 1, { { 3, { { 5 }, 4 } }, 2 } }))
    233    end)
    234 
    235    it('errors when dumping recursive lists', function()
    236      api.nvim_set_var('l', {})
    237      eval('add(l, l)')
    238      eq(
    239        'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
    240        exc_exec('echo string(l)')
    241      )
    242    end)
    243 
    244    it('dumps recursive lists despite the error', function()
    245      api.nvim_set_var('l', {})
    246      eval('add(l, l)')
    247      eq(
    248        'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
    249        pcall_err(command, 'echo string(l)')
    250      )
    251      eq(
    252        'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
    253        pcall_err(command, 'echo string([l])')
    254      )
    255    end)
    256  end)
    257 
    258  describe('used to represent dictionaries', function()
    259    it('dumps empty dict', function()
    260      eq('{}', eval('string({})'))
    261    end)
    262 
    263    it('dumps list with two same empty dictionaries, also in partials', function()
    264      command('let d = {}')
    265      eq('[{}, {}]', eval('string([d, d])'))
    266      eq("[function('tr', {}), {}]", eval('string([function("tr", d), d])'))
    267      eq("[{}, function('tr', {})]", eval('string([d, function("tr", d)])'))
    268    end)
    269 
    270    it('dumps non-empty dict', function()
    271      eq("{'t''est': 1}", fn.string({ ["t'est"] = 1 }))
    272    end)
    273 
    274    it('errors when dumping recursive dictionaries', function()
    275      api.nvim_set_var('d', { d = 1 })
    276      eval('extend(d, {"d": d})')
    277      eq(
    278        'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
    279        exc_exec('echo string(d)')
    280      )
    281    end)
    282 
    283    it('dumps recursive dictionaries despite the error', function()
    284      api.nvim_set_var('d', { d = 1 })
    285      eval('extend(d, {"d": d})')
    286      eq(
    287        'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
    288        pcall_err(command, 'echo string(d)')
    289      )
    290      eq(
    291        'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
    292        pcall_err(command, 'echo string({"out": d})')
    293      )
    294    end)
    295  end)
    296 end)