neovim

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

msgpack_spec.lua (29696B)


      1 local t = require('test.testutil')
      2 local n = require('test.functional.testnvim')()
      3 
      4 local clear = n.clear
      5 local api = n.api
      6 local eq = t.eq
      7 local nvim_eval = n.eval
      8 local nvim_command = n.command
      9 local exc_exec = n.exc_exec
     10 local ok = t.ok
     11 local NIL = vim.NIL
     12 
     13 describe('autoload/msgpack.vim', function()
     14  setup(function()
     15    clear { args = { '-u', 'NORC' } }
     16  end)
     17 
     18  local sp = function(typ, val)
     19    return ('{"_TYPE": v:msgpack_types.%s, "_VAL": %s}'):format(typ, val)
     20  end
     21  local mapsp = function(...)
     22    local val = ''
     23    for i = 1, (select('#', ...) / 2) do
     24      val = ('%s[%s,%s],'):format(val, select(i * 2 - 1, ...), select(i * 2, ...))
     25    end
     26    return sp('map', '[' .. val .. ']')
     27  end
     28 
     29  local nan = -(1.0 / 0.0 - 1.0 / 0.0)
     30  local inf = 1.0 / 0.0
     31  local minus_inf = -(1.0 / 0.0)
     32 
     33  describe('function msgpack#equal', function()
     34    local msgpack_eq = function(expected, a, b)
     35      eq(expected, nvim_eval(('msgpack#equal(%s, %s)'):format(a, b)))
     36      if a ~= b then
     37        eq(expected, nvim_eval(('msgpack#equal(%s, %s)'):format(b, a)))
     38      end
     39    end
     40    it('compares raw integers correctly', function()
     41      msgpack_eq(1, '1', '1')
     42      msgpack_eq(0, '1', '0')
     43    end)
     44    it('compares integer specials correctly', function()
     45      msgpack_eq(1, sp('integer', '[-1, 1, 0, 0]'), sp('integer', '[-1, 1, 0, 0]'))
     46      msgpack_eq(0, sp('integer', '[-1, 1, 0, 0]'), sp('integer', '[ 1, 1, 0, 0]'))
     47    end)
     48    it('compares integer specials with raw integer correctly', function()
     49      msgpack_eq(1, sp('integer', '[-1, 0, 0, 1]'), '-1')
     50      msgpack_eq(0, sp('integer', '[-1, 0, 0, 1]'), '1')
     51      msgpack_eq(0, sp('integer', '[ 1, 0, 0, 1]'), '-1')
     52      msgpack_eq(1, sp('integer', '[ 1, 0, 0, 1]'), '1')
     53    end)
     54    it('compares integer with float correctly', function()
     55      msgpack_eq(0, '0', '0.0')
     56    end)
     57    it('compares raw binaries correctly', function()
     58      msgpack_eq(1, '"abc\\ndef"', '"abc\\ndef"')
     59      msgpack_eq(0, '"abc\\ndef"', '"abc\\nghi"')
     60    end)
     61    it('compares string specials correctly', function()
     62      msgpack_eq(1, sp('string', '["abc\\n", "def"]'), sp('string', '["abc\\n", "def"]'))
     63      msgpack_eq(0, sp('string', '["abc", "def"]'), sp('string', '["abc\\n", "def"]'))
     64      msgpack_eq(1, sp('string', '["abc", "def"]'), '"abc\\ndef"')
     65      msgpack_eq(1, '"abc\\ndef"', sp('string', '["abc", "def"]'))
     66    end)
     67    it('compares ext specials correctly', function()
     68      msgpack_eq(1, sp('ext', '[1, ["", "ac"]]'), sp('ext', '[1, ["", "ac"]]'))
     69      msgpack_eq(0, sp('ext', '[2, ["", "ac"]]'), sp('ext', '[1, ["", "ac"]]'))
     70      msgpack_eq(0, sp('ext', '[1, ["", "ac"]]'), sp('ext', '[1, ["", "abc"]]'))
     71    end)
     72    it('compares raw maps correctly', function()
     73      msgpack_eq(1, '{"a": 1, "b": 2}', '{"b": 2, "a": 1}')
     74      msgpack_eq(1, '{}', '{}')
     75      msgpack_eq(0, '{}', '{"a": 1}')
     76      msgpack_eq(0, '{"a": 2}', '{"a": 1}')
     77      msgpack_eq(0, '{"a": 1}', '{"b": 1}')
     78      msgpack_eq(0, '{"a": 1}', '{"a": 1, "b": 1}')
     79      msgpack_eq(0, '{"a": 1, "b": 1}', '{"b": 1}')
     80    end)
     81    it('compares map specials correctly', function()
     82      msgpack_eq(1, mapsp(), mapsp())
     83      msgpack_eq(
     84        1,
     85        mapsp(mapsp('1', '1'), mapsp('1', '1')),
     86        mapsp(mapsp('1', '1'), mapsp('1', '1'))
     87      )
     88      msgpack_eq(0, mapsp(), mapsp('1', '1'))
     89      msgpack_eq(
     90        0,
     91        mapsp(mapsp('1', '1'), mapsp('1', '1')),
     92        mapsp(sp('string', '[""]'), mapsp('1', '1'))
     93      )
     94      msgpack_eq(
     95        0,
     96        mapsp(mapsp('1', '1'), mapsp('1', '1')),
     97        mapsp(mapsp('2', '1'), mapsp('1', '1'))
     98      )
     99      msgpack_eq(
    100        0,
    101        mapsp(mapsp('1', '1'), mapsp('1', '1')),
    102        mapsp(mapsp('1', '2'), mapsp('1', '1'))
    103      )
    104      msgpack_eq(
    105        0,
    106        mapsp(mapsp('1', '1'), mapsp('1', '1')),
    107        mapsp(mapsp('1', '1'), mapsp('2', '1'))
    108      )
    109      msgpack_eq(
    110        0,
    111        mapsp(mapsp('1', '1'), mapsp('1', '1')),
    112        mapsp(mapsp('1', '1'), mapsp('1', '2'))
    113      )
    114      msgpack_eq(
    115        1,
    116        mapsp(mapsp('2', '1'), mapsp('1', '1'), mapsp('1', '1'), mapsp('1', '1')),
    117        mapsp(mapsp('1', '1'), mapsp('1', '1'), mapsp('2', '1'), mapsp('1', '1'))
    118      )
    119    end)
    120    it('compares map specials with raw maps correctly', function()
    121      msgpack_eq(1, mapsp(), '{}')
    122      msgpack_eq(1, mapsp(sp('string', '["1"]'), '1'), '{"1": 1}')
    123      msgpack_eq(1, mapsp(sp('string', '["1"]'), sp('integer', '[1, 0, 0, 1]')), '{"1": 1}')
    124      msgpack_eq(0, mapsp(sp('integer', '[1, 0, 0, 1]'), sp('string', '["1"]')), '{1: "1"}')
    125      msgpack_eq(1, mapsp('"1"', sp('integer', '[1, 0, 0, 1]')), '{"1": 1}')
    126      msgpack_eq(0, mapsp(sp('string', '["1"]'), '1', sp('string', '["2"]'), '2'), '{"1": 1}')
    127      msgpack_eq(0, mapsp(sp('string', '["1"]'), '1'), '{"1": 1, "2": 2}')
    128    end)
    129    it('compares raw arrays correctly', function()
    130      msgpack_eq(1, '[]', '[]')
    131      msgpack_eq(0, '[]', '[1]')
    132      msgpack_eq(1, '[1]', '[1]')
    133      msgpack_eq(1, '[[[1]]]', '[[[1]]]')
    134      msgpack_eq(0, '[[[2]]]', '[[[1]]]')
    135    end)
    136    it('compares array specials correctly', function()
    137      msgpack_eq(1, sp('array', '[]'), sp('array', '[]'))
    138      msgpack_eq(0, sp('array', '[]'), sp('array', '[1]'))
    139      msgpack_eq(1, sp('array', '[1]'), sp('array', '[1]'))
    140      msgpack_eq(1, sp('array', '[[[1]]]'), sp('array', '[[[1]]]'))
    141      msgpack_eq(0, sp('array', '[[[1]]]'), sp('array', '[[[2]]]'))
    142    end)
    143    it('compares array specials with raw arrays correctly', function()
    144      msgpack_eq(1, sp('array', '[]'), '[]')
    145      msgpack_eq(0, sp('array', '[]'), '[1]')
    146      msgpack_eq(1, sp('array', '[1]'), '[1]')
    147      msgpack_eq(1, sp('array', '[[[1]]]'), '[[[1]]]')
    148      msgpack_eq(0, sp('array', '[[[1]]]'), '[[[2]]]')
    149    end)
    150    it('compares raw floats correctly', function()
    151      msgpack_eq(1, '0.0', '0.0')
    152      msgpack_eq(1, '(1.0/0.0-1.0/0.0)', '(1.0/0.0-1.0/0.0)')
    153      -- both (1.0/0.0-1.0/0.0) and -(1.0/0.0-1.0/0.0) now return
    154      -- str2float('nan'). ref: @18d1ba3422d
    155      msgpack_eq(1, '(1.0/0.0-1.0/0.0)', '-(1.0/0.0-1.0/0.0)')
    156      msgpack_eq(1, '-(1.0/0.0-1.0/0.0)', '-(1.0/0.0-1.0/0.0)')
    157      msgpack_eq(1, '1.0/0.0', '1.0/0.0')
    158      msgpack_eq(1, '-(1.0/0.0)', '-(1.0/0.0)')
    159      msgpack_eq(1, '0.0', '0.0')
    160      msgpack_eq(0, '0.0', '1.0')
    161      msgpack_eq(0, '0.0', '(1.0/0.0-1.0/0.0)')
    162      msgpack_eq(0, '0.0', '1.0/0.0')
    163      msgpack_eq(0, '0.0', '-(1.0/0.0)')
    164      msgpack_eq(0, '1.0/0.0', '-(1.0/0.0)')
    165      msgpack_eq(0, '(1.0/0.0-1.0/0.0)', '-(1.0/0.0)')
    166      msgpack_eq(0, '(1.0/0.0-1.0/0.0)', '1.0/0.0')
    167    end)
    168    it('compares float specials with raw floats correctly', function()
    169      msgpack_eq(1, sp('float', '0.0'), '0.0')
    170      msgpack_eq(1, sp('float', '(1.0/0.0-1.0/0.0)'), '(1.0/0.0-1.0/0.0)')
    171      msgpack_eq(1, sp('float', '(1.0/0.0-1.0/0.0)'), '-(1.0/0.0-1.0/0.0)')
    172      msgpack_eq(1, sp('float', '-(1.0/0.0-1.0/0.0)'), '(1.0/0.0-1.0/0.0)')
    173      msgpack_eq(1, sp('float', '-(1.0/0.0-1.0/0.0)'), '-(1.0/0.0-1.0/0.0)')
    174      msgpack_eq(1, sp('float', '1.0/0.0'), '1.0/0.0')
    175      msgpack_eq(1, sp('float', '-(1.0/0.0)'), '-(1.0/0.0)')
    176      msgpack_eq(1, sp('float', '0.0'), '0.0')
    177      msgpack_eq(0, sp('float', '0.0'), '1.0')
    178      msgpack_eq(0, sp('float', '0.0'), '(1.0/0.0-1.0/0.0)')
    179      msgpack_eq(0, sp('float', '0.0'), '1.0/0.0')
    180      msgpack_eq(0, sp('float', '0.0'), '-(1.0/0.0)')
    181      msgpack_eq(0, sp('float', '1.0/0.0'), '-(1.0/0.0)')
    182      msgpack_eq(0, sp('float', '(1.0/0.0-1.0/0.0)'), '-(1.0/0.0)')
    183      msgpack_eq(0, sp('float', '(1.0/0.0-1.0/0.0)'), '1.0/0.0')
    184    end)
    185    it('compares float specials correctly', function()
    186      msgpack_eq(1, sp('float', '0.0'), sp('float', '0.0'))
    187      msgpack_eq(1, sp('float', '(1.0/0.0-1.0/0.0)'), sp('float', '(1.0/0.0-1.0/0.0)'))
    188      msgpack_eq(1, sp('float', '1.0/0.0'), sp('float', '1.0/0.0'))
    189      msgpack_eq(1, sp('float', '-(1.0/0.0)'), sp('float', '-(1.0/0.0)'))
    190      msgpack_eq(1, sp('float', '0.0'), sp('float', '0.0'))
    191      msgpack_eq(0, sp('float', '0.0'), sp('float', '1.0'))
    192      msgpack_eq(0, sp('float', '0.0'), sp('float', '(1.0/0.0-1.0/0.0)'))
    193      msgpack_eq(0, sp('float', '0.0'), sp('float', '1.0/0.0'))
    194      msgpack_eq(0, sp('float', '0.0'), sp('float', '-(1.0/0.0)'))
    195      msgpack_eq(0, sp('float', '1.0/0.0'), sp('float', '-(1.0/0.0)'))
    196      msgpack_eq(0, sp('float', '(1.0/0.0-1.0/0.0)'), sp('float', '-(1.0/0.0)'))
    197      msgpack_eq(1, sp('float', '(1.0/0.0-1.0/0.0)'), sp('float', '-(1.0/0.0-1.0/0.0)'))
    198      msgpack_eq(1, sp('float', '-(1.0/0.0-1.0/0.0)'), sp('float', '-(1.0/0.0-1.0/0.0)'))
    199      msgpack_eq(0, sp('float', '(1.0/0.0-1.0/0.0)'), sp('float', '1.0/0.0'))
    200    end)
    201    it('compares boolean specials correctly', function()
    202      msgpack_eq(1, sp('boolean', '1'), sp('boolean', '1'))
    203      msgpack_eq(0, sp('boolean', '1'), sp('boolean', '0'))
    204    end)
    205    it('compares nil specials correctly', function()
    206      msgpack_eq(1, sp('nil', '1'), sp('nil', '0'))
    207    end)
    208    it('compares nil, boolean and integer values with each other correctly', function()
    209      msgpack_eq(0, sp('boolean', '1'), '1')
    210      msgpack_eq(0, sp('boolean', '1'), sp('nil', '0'))
    211      msgpack_eq(0, sp('boolean', '1'), sp('nil', '1'))
    212      msgpack_eq(0, sp('boolean', '0'), sp('nil', '0'))
    213      msgpack_eq(0, sp('boolean', '0'), '0')
    214      msgpack_eq(0, sp('boolean', '0'), sp('integer', '[1, 0, 0, 0]'))
    215      msgpack_eq(0, sp('boolean', '0'), sp('integer', '[1, 0, 0, 1]'))
    216      msgpack_eq(0, sp('boolean', '1'), sp('integer', '[1, 0, 0, 1]'))
    217      msgpack_eq(0, sp('nil', '0'), sp('integer', '[1, 0, 0, 0]'))
    218      msgpack_eq(0, sp('nil', '0'), '0')
    219    end)
    220  end)
    221 
    222  describe('function msgpack#is_int', function()
    223    it('works', function()
    224      eq(1, nvim_eval('msgpack#is_int(1)'))
    225      eq(1, nvim_eval('msgpack#is_int(-1)'))
    226      eq(1, nvim_eval(('msgpack#is_int(%s)'):format(sp('integer', '[1, 0, 0, 1]'))))
    227      eq(1, nvim_eval(('msgpack#is_int(%s)'):format(sp('integer', '[-1, 0, 0, 1]'))))
    228      eq(0, nvim_eval(('msgpack#is_int(%s)'):format(sp('float', '0.0'))))
    229      eq(0, nvim_eval(('msgpack#is_int(%s)'):format(sp('boolean', '0'))))
    230      eq(0, nvim_eval(('msgpack#is_int(%s)'):format(sp('nil', '0'))))
    231      eq(0, nvim_eval('msgpack#is_int("")'))
    232    end)
    233  end)
    234 
    235  describe('function msgpack#is_uint', function()
    236    it('works', function()
    237      eq(1, nvim_eval('msgpack#is_uint(1)'))
    238      eq(0, nvim_eval('msgpack#is_uint(-1)'))
    239      eq(1, nvim_eval(('msgpack#is_uint(%s)'):format(sp('integer', '[1, 0, 0, 1]'))))
    240      eq(0, nvim_eval(('msgpack#is_uint(%s)'):format(sp('integer', '[-1, 0, 0, 1]'))))
    241      eq(0, nvim_eval(('msgpack#is_uint(%s)'):format(sp('float', '0.0'))))
    242      eq(0, nvim_eval(('msgpack#is_uint(%s)'):format(sp('boolean', '0'))))
    243      eq(0, nvim_eval(('msgpack#is_uint(%s)'):format(sp('nil', '0'))))
    244      eq(0, nvim_eval('msgpack#is_uint("")'))
    245    end)
    246  end)
    247 
    248  describe('function msgpack#strftime', function()
    249    it('works', function()
    250      local epoch = os.date('%Y-%m-%dT%H:%M:%S', 0)
    251      eq(epoch, nvim_eval('msgpack#strftime("%Y-%m-%dT%H:%M:%S", 0)'))
    252      eq(
    253        epoch,
    254        nvim_eval(
    255          ('msgpack#strftime("%%Y-%%m-%%dT%%H:%%M:%%S", %s)'):format(sp('integer', '[1, 0, 0, 0]'))
    256        )
    257      )
    258    end)
    259  end)
    260 
    261  describe('function msgpack#strptime', function()
    262    it('works', function()
    263      for _, v in ipairs({ 0, 10, 100000, 204, 1000000000 }) do
    264        local time = os.date('%Y-%m-%dT%H:%M:%S', v)
    265        eq(v, nvim_eval('msgpack#strptime("%Y-%m-%dT%H:%M:%S", ' .. '"' .. time .. '")'))
    266      end
    267    end)
    268  end)
    269 
    270  describe('function msgpack#type', function()
    271    local type_eq = function(expected, val)
    272      eq(expected, nvim_eval(('msgpack#type(%s)'):format(val)))
    273    end
    274 
    275    it('works for special dictionaries', function()
    276      type_eq('string', sp('string', '[""]'))
    277      type_eq('ext', sp('ext', '[1, [""]]'))
    278      type_eq('array', sp('array', '[]'))
    279      type_eq('map', sp('map', '[]'))
    280      type_eq('integer', sp('integer', '[1, 0, 0, 0]'))
    281      type_eq('float', sp('float', '0.0'))
    282      type_eq('boolean', sp('boolean', '0'))
    283      type_eq('nil', sp('nil', '0'))
    284    end)
    285 
    286    it('works for regular values', function()
    287      type_eq('string', '""')
    288      type_eq('array', '[]')
    289      type_eq('map', '{}')
    290      type_eq('integer', '1')
    291      type_eq('float', '0.0')
    292      type_eq('float', '(1.0/0.0)')
    293      type_eq('float', '-(1.0/0.0)')
    294      type_eq('float', '(1.0/0.0-1.0/0.0)')
    295    end)
    296  end)
    297 
    298  describe('function msgpack#special_type', function()
    299    local sp_type_eq = function(expected, val)
    300      eq(expected, nvim_eval(('msgpack#special_type(%s)'):format(val)))
    301    end
    302 
    303    it('works for special dictionaries', function()
    304      sp_type_eq('string', sp('string', '[""]'))
    305      sp_type_eq('ext', sp('ext', '[1, [""]]'))
    306      sp_type_eq('array', sp('array', '[]'))
    307      sp_type_eq('map', sp('map', '[]'))
    308      sp_type_eq('integer', sp('integer', '[1, 0, 0, 0]'))
    309      sp_type_eq('float', sp('float', '0.0'))
    310      sp_type_eq('boolean', sp('boolean', '0'))
    311      sp_type_eq('nil', sp('nil', '0'))
    312    end)
    313 
    314    it('works for regular values', function()
    315      sp_type_eq(0, '""')
    316      sp_type_eq(0, '[]')
    317      sp_type_eq(0, '{}')
    318      sp_type_eq(0, '1')
    319      sp_type_eq(0, '0.0')
    320      sp_type_eq(0, '(1.0/0.0)')
    321      sp_type_eq(0, '-(1.0/0.0)')
    322      sp_type_eq(0, '(1.0/0.0-1.0/0.0)')
    323    end)
    324  end)
    325 
    326  describe('function msgpack#string', function()
    327    local string_eq = function(expected, val)
    328      eq(expected, nvim_eval(('msgpack#string(%s)'):format(val)))
    329    end
    330 
    331    it('works for special dictionaries', function()
    332      string_eq('""', sp('string', '[""]'))
    333      string_eq('"\\n"', sp('string', '["", ""]'))
    334      string_eq('"ab\\0c\\nde"', sp('string', '["ab\\nc", "de"]'))
    335      string_eq('+(2)""', sp('ext', '[2, [""]]'))
    336      string_eq('+(2)"\\n"', sp('ext', '[2, ["", ""]]'))
    337      string_eq('+(2)"ab\\0c\\nde"', sp('ext', '[2, ["ab\\nc", "de"]]'))
    338      string_eq('[]', sp('array', '[]'))
    339      string_eq('[[[[{}]]]]', sp('array', '[[[[{}]]]]'))
    340      string_eq('{}', sp('map', '[]'))
    341      string_eq('{2: 10}', sp('map', '[[2, 10]]'))
    342      string_eq(
    343        '{{1: 1}: {1: 1}, {2: 1}: {1: 1}}',
    344        mapsp(mapsp('2', '1'), mapsp('1', '1'), mapsp('1', '1'), mapsp('1', '1'))
    345      )
    346      string_eq(
    347        '{{1: 1}: {1: 1}, {2: 1}: {1: 1}}',
    348        mapsp(mapsp('1', '1'), mapsp('1', '1'), mapsp('2', '1'), mapsp('1', '1'))
    349      )
    350      string_eq(
    351        '{[1, 2, {{1: 2}: 1}]: [1, 2, {{1: 2}: 1}]}',
    352        mapsp(
    353          ('[1, 2, %s]'):format(mapsp(mapsp('1', '2'), '1')),
    354          ('[1, 2, %s]'):format(mapsp(mapsp('1', '2'), '1'))
    355        )
    356      )
    357      string_eq('0x0000000000000000', sp('integer', '[1, 0, 0, 0]'))
    358      string_eq('-0x0000000100000000', sp('integer', '[-1, 0, 2, 0]'))
    359      string_eq('0x123456789abcdef0', sp('integer', '[ 1, 0,  610839793, 448585456]'))
    360      string_eq('-0x123456789abcdef0', sp('integer', '[-1, 0,  610839793, 448585456]'))
    361      string_eq('0xf23456789abcdef0', sp('integer', '[ 1, 3, 1684581617, 448585456]'))
    362      string_eq('-0x723456789abcdef0', sp('integer', '[-1, 1, 1684581617, 448585456]'))
    363      string_eq('0.0', sp('float', '0.0'))
    364      string_eq('inf', sp('float', '(1.0/0.0)'))
    365      string_eq('-inf', sp('float', '-(1.0/0.0)'))
    366      string_eq('nan', sp('float', '(1.0/0.0-1.0/0.0)'))
    367      string_eq('nan', sp('float', '-(1.0/0.0-1.0/0.0)'))
    368      string_eq('FALSE', sp('boolean', '0'))
    369      string_eq('TRUE', sp('boolean', '1'))
    370      string_eq('NIL', sp('nil', '0'))
    371    end)
    372 
    373    it('works for regular values', function()
    374      string_eq('""', '""')
    375      string_eq('"\\n"', '"\\n"')
    376      string_eq('[]', '[]')
    377      string_eq('[[[{}]]]', '[[[{}]]]')
    378      string_eq('{}', '{}')
    379      string_eq('{"2": 10}', '{2: 10}')
    380      string_eq('{"2": [{}]}', '{2: [{}]}')
    381      string_eq('1', '1')
    382      string_eq('0.0', '0.0')
    383      string_eq('inf', '(1.0/0.0)')
    384      string_eq('-inf', '-(1.0/0.0)')
    385      string_eq('nan', '(1.0/0.0-1.0/0.0)')
    386      string_eq('nan', '-(1.0/0.0-1.0/0.0)')
    387    end)
    388 
    389    it('works for special v: values like v:true', function()
    390      string_eq('TRUE', 'v:true')
    391      string_eq('FALSE', 'v:false')
    392      string_eq('NIL', 'v:null')
    393    end)
    394  end)
    395 
    396  describe('function msgpack#deepcopy', function()
    397    it('works for special dictionaries', function()
    398      nvim_command('let sparr = ' .. sp('array', '[[[]]]'))
    399      nvim_command('let spmap = ' .. mapsp('"abc"', '[[]]'))
    400      nvim_command('let spint = ' .. sp('integer', '[1, 0, 0, 0]'))
    401      nvim_command('let spflt = ' .. sp('float', '1.0'))
    402      nvim_command('let spext = ' .. sp('ext', '[2, ["abc", "def"]]'))
    403      nvim_command('let spstr = ' .. sp('string', '["abc", "def"]'))
    404      nvim_command('let spbln = ' .. sp('boolean', '0'))
    405      nvim_command('let spnil = ' .. sp('nil', '0'))
    406 
    407      nvim_command('let sparr2 = msgpack#deepcopy(sparr)')
    408      nvim_command('let spmap2 = msgpack#deepcopy(spmap)')
    409      nvim_command('let spint2 = msgpack#deepcopy(spint)')
    410      nvim_command('let spflt2 = msgpack#deepcopy(spflt)')
    411      nvim_command('let spext2 = msgpack#deepcopy(spext)')
    412      nvim_command('let spstr2 = msgpack#deepcopy(spstr)')
    413      nvim_command('let spbln2 = msgpack#deepcopy(spbln)')
    414      nvim_command('let spnil2 = msgpack#deepcopy(spnil)')
    415 
    416      eq('array', nvim_eval('msgpack#type(sparr2)'))
    417      eq('map', nvim_eval('msgpack#type(spmap2)'))
    418      eq('integer', nvim_eval('msgpack#type(spint2)'))
    419      eq('float', nvim_eval('msgpack#type(spflt2)'))
    420      eq('ext', nvim_eval('msgpack#type(spext2)'))
    421      eq('string', nvim_eval('msgpack#type(spstr2)'))
    422      eq('boolean', nvim_eval('msgpack#type(spbln2)'))
    423      eq('nil', nvim_eval('msgpack#type(spnil2)'))
    424 
    425      nvim_command('call add(sparr._VAL, 0)')
    426      nvim_command('call add(sparr._VAL[0], 0)')
    427      nvim_command('call add(sparr._VAL[0][0], 0)')
    428      nvim_command('call add(spmap._VAL, [0, 0])')
    429      nvim_command('call add(spmap._VAL[0][1], 0)')
    430      nvim_command('call add(spmap._VAL[0][1][0], 0)')
    431      nvim_command('let spint._VAL[1] = 1')
    432      nvim_command('let spflt._VAL = 0.0')
    433      nvim_command('let spext._VAL[0] = 3')
    434      nvim_command('let spext._VAL[1][0] = "gh"')
    435      nvim_command('let spstr._VAL[0] = "gh"')
    436      nvim_command('let spbln._VAL = 1')
    437      nvim_command('let spnil._VAL = 1')
    438 
    439      eq({ _TYPE = {}, _VAL = { { {} } } }, nvim_eval('sparr2'))
    440      eq({ _TYPE = {}, _VAL = { { 'abc', { {} } } } }, nvim_eval('spmap2'))
    441      eq({ _TYPE = {}, _VAL = { 1, 0, 0, 0 } }, nvim_eval('spint2'))
    442      eq({ _TYPE = {}, _VAL = 1.0 }, nvim_eval('spflt2'))
    443      eq({ _TYPE = {}, _VAL = { 2, { 'abc', 'def' } } }, nvim_eval('spext2'))
    444      eq({ _TYPE = {}, _VAL = { 'abc', 'def' } }, nvim_eval('spstr2'))
    445      eq({ _TYPE = {}, _VAL = 0 }, nvim_eval('spbln2'))
    446      eq({ _TYPE = {}, _VAL = 0 }, nvim_eval('spnil2'))
    447 
    448      nvim_command('let sparr._TYPE = []')
    449      nvim_command('let spmap._TYPE = []')
    450      nvim_command('let spint._TYPE = []')
    451      nvim_command('let spflt._TYPE = []')
    452      nvim_command('let spext._TYPE = []')
    453      nvim_command('let spstr._TYPE = []')
    454      nvim_command('let spbln._TYPE = []')
    455      nvim_command('let spnil._TYPE = []')
    456 
    457      eq('array', nvim_eval('msgpack#special_type(sparr2)'))
    458      eq('map', nvim_eval('msgpack#special_type(spmap2)'))
    459      eq('integer', nvim_eval('msgpack#special_type(spint2)'))
    460      eq('float', nvim_eval('msgpack#special_type(spflt2)'))
    461      eq('ext', nvim_eval('msgpack#special_type(spext2)'))
    462      eq('string', nvim_eval('msgpack#special_type(spstr2)'))
    463      eq('boolean', nvim_eval('msgpack#special_type(spbln2)'))
    464      eq('nil', nvim_eval('msgpack#special_type(spnil2)'))
    465    end)
    466 
    467    it('works for regular values', function()
    468      nvim_command('let arr = [[[]]]')
    469      nvim_command('let map = {1: {}}')
    470      nvim_command('let int = 1')
    471      nvim_command('let flt = 2.0')
    472      nvim_command('let bin = "abc"')
    473 
    474      nvim_command('let arr2 = msgpack#deepcopy(arr)')
    475      nvim_command('let map2 = msgpack#deepcopy(map)')
    476      nvim_command('let int2 = msgpack#deepcopy(int)')
    477      nvim_command('let flt2 = msgpack#deepcopy(flt)')
    478      nvim_command('let bin2 = msgpack#deepcopy(bin)')
    479 
    480      eq('array', nvim_eval('msgpack#type(arr2)'))
    481      eq('map', nvim_eval('msgpack#type(map2)'))
    482      eq('integer', nvim_eval('msgpack#type(int2)'))
    483      eq('float', nvim_eval('msgpack#type(flt2)'))
    484      eq('string', nvim_eval('msgpack#type(bin2)'))
    485 
    486      nvim_command('call add(arr, 0)')
    487      nvim_command('call add(arr[0], 0)')
    488      nvim_command('call add(arr[0][0], 0)')
    489      nvim_command('let map.a = 1')
    490      nvim_command('let map.1.a = 1')
    491      nvim_command('let int = 2')
    492      nvim_command('let flt = 3.0')
    493      nvim_command('let bin = ""')
    494 
    495      eq({ { {} } }, nvim_eval('arr2'))
    496      eq({ ['1'] = {} }, nvim_eval('map2'))
    497      eq(1, nvim_eval('int2'))
    498      eq(2.0, nvim_eval('flt2'))
    499      eq('abc', nvim_eval('bin2'))
    500    end)
    501 
    502    it('works for special v: values like v:true', function()
    503      api.nvim_set_var('true', true)
    504      api.nvim_set_var('false', false)
    505      api.nvim_set_var('nil', NIL)
    506 
    507      nvim_command('let true2 = msgpack#deepcopy(true)')
    508      nvim_command('let false2 = msgpack#deepcopy(false)')
    509      nvim_command('let nil2 = msgpack#deepcopy(nil)')
    510 
    511      eq(true, api.nvim_get_var('true'))
    512      eq(false, api.nvim_get_var('false'))
    513      eq(NIL, api.nvim_get_var('nil'))
    514    end)
    515  end)
    516 
    517  describe('function msgpack#eval', function()
    518    local eval_eq = function(expected_type, expected_val, str, ...)
    519      nvim_command(
    520        ("let g:__val = msgpack#eval('%s', %s)"):format(str:gsub("'", "''"), select(1, ...) or '{}')
    521      )
    522      eq(expected_type, nvim_eval('msgpack#type(g:__val)'))
    523      local expected_val_full = expected_val
    524      if
    525        not (({ float = true, integer = true })[expected_type] and type(expected_val) ~= 'table')
    526        and expected_type ~= 'array'
    527      then
    528        expected_val_full = { _TYPE = {}, _VAL = expected_val_full }
    529      end
    530      if expected_val_full == expected_val_full then
    531        eq(expected_val_full, nvim_eval('g:__val'))
    532      else -- NaN
    533        local nvim_nan = tostring(nvim_eval('g:__val'))
    534        -- -NaN is a hardware-specific detail, there's no need to test for it.
    535        -- Accept ether 'nan' or '-nan' as the response.
    536        ok(nvim_nan == 'nan' or nvim_nan == '-nan')
    537      end
    538      nvim_command('unlet g:__val')
    539    end
    540 
    541    it('correctly loads strings', function()
    542      eval_eq('string', { 'abcdef' }, '="abcdef"')
    543      eval_eq('string', { 'abc', 'def' }, '="abc\\ndef"')
    544      eval_eq('string', { 'abc\ndef' }, '="abc\\0def"')
    545      eval_eq('string', { '\nabc\ndef\n' }, '="\\0abc\\0def\\0"')
    546      eval_eq('string', { 'abc\n\n\ndef' }, '="abc\\0\\0\\0def"')
    547      eval_eq('string', { 'abc\n', '\ndef' }, '="abc\\0\\n\\0def"')
    548      eval_eq('string', { 'abc', '', '', 'def' }, '="abc\\n\\n\\ndef"')
    549      eval_eq('string', { 'abc', '', '', 'def', '' }, '="abc\\n\\n\\ndef\\n"')
    550      eval_eq('string', { '', 'abc', '', '', 'def' }, '="\\nabc\\n\\n\\ndef"')
    551      eval_eq('string', { '' }, '=""')
    552      eval_eq('string', { '"' }, '="\\""')
    553      eval_eq('string', { 'py3 print(sys.version_info)' }, '="py3 print(sys.version_info)"')
    554    end)
    555 
    556    it('correctly loads ext values', function()
    557      eval_eq('ext', { 0, { 'abcdef' } }, '+(0)"abcdef"')
    558      eval_eq('ext', { 0, { 'abc', 'def' } }, '+(0)"abc\\ndef"')
    559      eval_eq('ext', { 0, { 'abc\ndef' } }, '+(0)"abc\\0def"')
    560      eval_eq('ext', { 0, { '\nabc\ndef\n' } }, '+(0)"\\0abc\\0def\\0"')
    561      eval_eq('ext', { 0, { 'abc\n\n\ndef' } }, '+(0)"abc\\0\\0\\0def"')
    562      eval_eq('ext', { 0, { 'abc\n', '\ndef' } }, '+(0)"abc\\0\\n\\0def"')
    563      eval_eq('ext', { 0, { 'abc', '', '', 'def' } }, '+(0)"abc\\n\\n\\ndef"')
    564      eval_eq('ext', { 0, { 'abc', '', '', 'def', '' } }, '+(0)"abc\\n\\n\\ndef\\n"')
    565      eval_eq('ext', { 0, { '', 'abc', '', '', 'def' } }, '+(0)"\\nabc\\n\\n\\ndef"')
    566      eval_eq('ext', { 0, { '' } }, '+(0)""')
    567      eval_eq('ext', { 0, { '"' } }, '+(0)"\\""')
    568 
    569      eval_eq('ext', { -1, { 'abcdef' } }, '+(-1)"abcdef"')
    570      eval_eq('ext', { -1, { 'abc', 'def' } }, '+(-1)"abc\\ndef"')
    571      eval_eq('ext', { -1, { 'abc\ndef' } }, '+(-1)"abc\\0def"')
    572      eval_eq('ext', { -1, { '\nabc\ndef\n' } }, '+(-1)"\\0abc\\0def\\0"')
    573      eval_eq('ext', { -1, { 'abc\n\n\ndef' } }, '+(-1)"abc\\0\\0\\0def"')
    574      eval_eq('ext', { -1, { 'abc\n', '\ndef' } }, '+(-1)"abc\\0\\n\\0def"')
    575      eval_eq('ext', { -1, { 'abc', '', '', 'def' } }, '+(-1)"abc\\n\\n\\ndef"')
    576      eval_eq('ext', { -1, { 'abc', '', '', 'def', '' } }, '+(-1)"abc\\n\\n\\ndef\\n"')
    577      eval_eq('ext', { -1, { '', 'abc', '', '', 'def' } }, '+(-1)"\\nabc\\n\\n\\ndef"')
    578      eval_eq('ext', { -1, { '' } }, '+(-1)""')
    579      eval_eq('ext', { -1, { '"' } }, '+(-1)"\\""')
    580 
    581      eval_eq(
    582        'ext',
    583        { 42, { 'py3 print(sys.version_info)' } },
    584        '+(42)"py3 print(sys.version_info)"'
    585      )
    586    end)
    587 
    588    it('correctly loads floats', function()
    589      eval_eq('float', inf, 'inf')
    590      eval_eq('float', minus_inf, '-inf')
    591      eval_eq('float', nan, 'nan')
    592      eval_eq('float', 1.0e10, '1.0e10')
    593      eval_eq('float', 1.0e10, '1.0e+10')
    594      eval_eq('float', -1.0e10, '-1.0e+10')
    595      eval_eq('float', 1.0, '1.0')
    596      eval_eq('float', -1.0, '-1.0')
    597      eval_eq('float', 1.0e-10, '1.0e-10')
    598      eval_eq('float', -1.0e-10, '-1.0e-10')
    599    end)
    600 
    601    it('correctly loads integers', function()
    602      eval_eq('integer', 10, '10')
    603      eval_eq('integer', -10, '-10')
    604      eval_eq('integer', { 1, 0, 610839793, 448585456 }, ' 0x123456789ABCDEF0')
    605      eval_eq('integer', { -1, 0, 610839793, 448585456 }, '-0x123456789ABCDEF0')
    606      eval_eq('integer', { 1, 3, 1684581617, 448585456 }, ' 0xF23456789ABCDEF0')
    607      eval_eq('integer', { -1, 1, 1684581617, 448585456 }, '-0x723456789ABCDEF0')
    608      eval_eq('integer', { 1, 0, 0, 0x100 }, '0x100')
    609      eval_eq('integer', { -1, 0, 0, 0x100 }, '-0x100')
    610 
    611      eval_eq('integer', ('a'):byte(), "'a'")
    612      eval_eq('integer', 0xAB, "'«'")
    613      eval_eq('integer', 0, "'\\0'")
    614      eval_eq('integer', 10246567, "'\\10246567'")
    615    end)
    616 
    617    it('correctly loads constants', function()
    618      eval_eq('boolean', 1, 'TRUE')
    619      eval_eq('boolean', 0, 'FALSE')
    620      eval_eq('nil', 0, 'NIL')
    621      eval_eq('nil', 0, 'NIL', '{"NIL": 1, "nan": 2, "T": 3}')
    622      eval_eq('float', nan, 'nan', '{"NIL": "1", "nan": "2", "T": "3"}')
    623      eval_eq('integer', 3, 'T', '{"NIL": "1", "nan": "2", "T": "3"}')
    624      eval_eq(
    625        'integer',
    626        { 1, 0, 0, 0 },
    627        'T',
    628        ('{"NIL": "1", "nan": "2", "T": \'%s\'}'):format(sp('integer', '[1, 0, 0, 0]'))
    629      )
    630    end)
    631 
    632    it('correctly loads maps', function()
    633      eval_eq('map', {}, '{}')
    634      eval_eq(
    635        'map',
    636        { { { _TYPE = {}, _VAL = { { 1, 2 } } }, { _TYPE = {}, _VAL = { { 3, 4 } } } } },
    637        '{{1: 2}: {3: 4}}'
    638      )
    639      eval_eq(
    640        'map',
    641        { { { _TYPE = {}, _VAL = { { 1, 2 } } }, { _TYPE = {}, _VAL = { { 3, 4 } } } }, { 1, 2 } },
    642        '{{1: 2}: {3: 4}, 1: 2}'
    643      )
    644 
    645      eval_eq('map', {
    646        {
    647          {
    648            _TYPE = {},
    649            _VAL = {
    650              { { _TYPE = {}, _VAL = { 'py3 print(sys.version_info)' } }, 2 },
    651            },
    652          },
    653          { _TYPE = {}, _VAL = { { 3, 4 } } },
    654        },
    655        { 1, 2 },
    656      }, '{{"py3 print(sys.version_info)": 2}: {3: 4}, 1: 2}')
    657    end)
    658 
    659    it('correctly loads arrays', function()
    660      eval_eq('array', {}, '[]')
    661      eval_eq('array', { 1 }, '[1]')
    662      eval_eq('array', { { _TYPE = {}, _VAL = 1 } }, '[TRUE]')
    663      eval_eq(
    664        'array',
    665        { { { _TYPE = {}, _VAL = { { 1, 2 } } } }, { _TYPE = {}, _VAL = { { 3, 4 } } } },
    666        '[[{1: 2}], {3: 4}]'
    667      )
    668 
    669      eval_eq(
    670        'array',
    671        { { _TYPE = {}, _VAL = { 'py3 print(sys.version_info)' } } },
    672        '["py3 print(sys.version_info)"]'
    673      )
    674    end)
    675 
    676    it('errors out when needed', function()
    677      eq('empty:Parsed string is empty', exc_exec('call msgpack#eval("", {})'))
    678      eq('unknown:Invalid non-space character: ^', exc_exec('call msgpack#eval("^", {})'))
    679      eq(
    680        "char-invalid:Invalid integer character literal format: ''",
    681        exc_exec('call msgpack#eval("\'\'", {})')
    682      )
    683      eq(
    684        "char-invalid:Invalid integer character literal format: 'ab'",
    685        exc_exec('call msgpack#eval("\'ab\'", {})')
    686      )
    687      eq(
    688        "char-invalid:Invalid integer character literal format: '",
    689        exc_exec('call msgpack#eval("\'", {})')
    690      )
    691      eq('"-invalid:Invalid string: "', exc_exec('call msgpack#eval("\\"", {})'))
    692      eq('"-invalid:Invalid string: ="', exc_exec('call msgpack#eval("=\\"", {})'))
    693      eq('"-invalid:Invalid string: +(0)"', exc_exec('call msgpack#eval("+(0)\\"", {})'))
    694      eq(
    695        '0.-nodigits:Decimal dot must be followed by digit(s): .e1',
    696        exc_exec('call msgpack#eval("0.e1", {})')
    697      )
    698      eq(
    699        '0x-long:Must have at most 16 hex digits: FEDCBA98765432100',
    700        exc_exec('call msgpack#eval("0xFEDCBA98765432100", {})')
    701      )
    702      eq('0x-empty:Must have number after 0x: ', exc_exec('call msgpack#eval("0x", {})'))
    703      eq('name-unknown:Unknown name FOO: FOO', exc_exec('call msgpack#eval("FOO", {})'))
    704 
    705      eq(
    706        'name-unknown:Unknown name py3: py3 print(sys.version_info)',
    707        exc_exec('call msgpack#eval("py3 print(sys.version_info)", {})')
    708      )
    709      eq('name-unknown:Unknown name o: o', exc_exec('call msgpack#eval("-info", {})'))
    710    end)
    711  end)
    712 end)