2024-04-20 08:44:13 -07:00
|
|
|
local t = require('test.testutil')
|
|
|
|
local n = require('test.functional.testnvim')()
|
|
|
|
|
|
|
|
local clear = n.clear
|
2024-04-08 02:03:20 -07:00
|
|
|
local eq = t.eq
|
2024-04-20 08:44:13 -07:00
|
|
|
local command = n.command
|
|
|
|
local api = n.api
|
|
|
|
local eval = n.eval
|
|
|
|
local exc_exec = n.exc_exec
|
2024-04-08 02:03:20 -07:00
|
|
|
local pcall_err = t.pcall_err
|
2024-04-20 08:44:13 -07:00
|
|
|
local fn = n.fn
|
2024-01-12 04:28:20 -07:00
|
|
|
local NIL = vim.NIL
|
2024-04-20 08:44:13 -07:00
|
|
|
local source = n.source
|
2015-12-25 16:01:47 -07:00
|
|
|
|
|
|
|
describe('string() function', function()
|
|
|
|
before_each(clear)
|
|
|
|
|
|
|
|
describe('used to represent floating-point values', function()
|
|
|
|
it('dumps NaN values', function()
|
|
|
|
eq("str2float('nan')", eval("string(str2float('nan'))"))
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps infinite values', function()
|
|
|
|
eq("str2float('inf')", eval("string(str2float('inf'))"))
|
|
|
|
eq("-str2float('inf')", eval("string(str2float('-inf'))"))
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps regular values', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('1.5', fn.string(1.5))
|
|
|
|
eq('1.56e-20', fn.string(1.56000e-020))
|
2015-12-25 16:01:47 -07:00
|
|
|
eq('0.0', eval('string(0.0)'))
|
|
|
|
end)
|
|
|
|
|
2016-01-30 15:25:00 -07:00
|
|
|
it('dumps special v: values', function()
|
|
|
|
eq('v:true', eval('string(v:true)'))
|
|
|
|
eq('v:false', eval('string(v:false)'))
|
|
|
|
eq('v:null', eval('string(v:null)'))
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('v:true', fn.string(true))
|
|
|
|
eq('v:false', fn.string(false))
|
|
|
|
eq('v:null', fn.string(NIL))
|
2016-01-30 15:25:00 -07:00
|
|
|
end)
|
|
|
|
|
2015-12-25 16:01:47 -07:00
|
|
|
it('dumps values with at most six digits after the decimal point', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('1.234568e-20', fn.string(1.23456789123456789123456789e-020))
|
|
|
|
eq('1.234568', fn.string(1.23456789123456789123456789))
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps values with at most seven digits before the decimal point', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('1234567.891235', fn.string(1234567.89123456789123456789))
|
|
|
|
eq('1.234568e7', fn.string(12345678.9123456789123456789))
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps negative values', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('-1.5', fn.string(-1.5))
|
|
|
|
eq('-1.56e-20', fn.string(-1.56000e-020))
|
|
|
|
eq('-1.234568e-20', fn.string(-1.23456789123456789123456789e-020))
|
|
|
|
eq('-1.234568', fn.string(-1.23456789123456789123456789))
|
|
|
|
eq('-1234567.891235', fn.string(-1234567.89123456789123456789))
|
|
|
|
eq('-1.234568e7', fn.string(-12345678.9123456789123456789))
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
end)
|
|
|
|
|
|
|
|
describe('used to represent numbers', function()
|
|
|
|
it('dumps regular values', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('0', fn.string(0))
|
|
|
|
eq('-1', fn.string(-1))
|
|
|
|
eq('1', fn.string(1))
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps large values', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('2147483647', fn.string(2 ^ 31 - 1))
|
|
|
|
eq('-2147483648', fn.string(-2 ^ 31))
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
end)
|
|
|
|
|
|
|
|
describe('used to represent strings', function()
|
|
|
|
it('dumps regular strings', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq("'test'", fn.string('test'))
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps empty strings', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq("''", fn.string(''))
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it("dumps strings with ' inside", function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq("''''''''", fn.string("'''"))
|
|
|
|
eq("'a''b'''''", fn.string("a'b''"))
|
|
|
|
eq("'''b''''d'", fn.string("'b''d"))
|
|
|
|
eq("'a''b''c''d'", fn.string("a'b'c'd"))
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
2016-04-03 18:53:07 -07:00
|
|
|
|
|
|
|
it('dumps NULL strings', function()
|
|
|
|
eq("''", eval('string($XXX_UNEXISTENT_VAR_XXX)'))
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps NULL lists', function()
|
|
|
|
eq('[]', eval('string(v:_null_list)'))
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps NULL dictionaries', function()
|
|
|
|
eq('{}', eval('string(v:_null_dict)'))
|
|
|
|
end)
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
describe('used to represent funcrefs', function()
|
|
|
|
before_each(function()
|
2016-08-20 12:24:34 -07:00
|
|
|
source([[
|
2015-12-25 16:01:47 -07:00
|
|
|
function Test1()
|
|
|
|
endfunction
|
|
|
|
|
2017-01-03 12:51:29 -07:00
|
|
|
function s:Test2() dict
|
2015-12-25 16:01:47 -07:00
|
|
|
endfunction
|
|
|
|
|
2017-01-03 12:51:29 -07:00
|
|
|
function g:Test3() dict
|
2015-12-25 16:01:47 -07:00
|
|
|
endfunction
|
|
|
|
|
|
|
|
let g:Test2_f = function('s:Test2')
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps references to built-in functions', function()
|
|
|
|
eq("function('function')", eval('string(function("function"))'))
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps references to user functions', function()
|
|
|
|
eq("function('Test1')", eval('string(function("Test1"))'))
|
|
|
|
eq("function('g:Test3')", eval('string(function("g:Test3"))'))
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps references to script functions', function()
|
|
|
|
eq("function('<SNR>1_Test2')", eval('string(Test2_f)'))
|
|
|
|
end)
|
2016-12-25 13:29:35 -07:00
|
|
|
|
|
|
|
it('dumps partials with self referencing a partial', function()
|
|
|
|
source([[
|
|
|
|
function TestDict() dict
|
|
|
|
endfunction
|
|
|
|
let d = {}
|
|
|
|
let TestDictRef = function('TestDict', d)
|
|
|
|
let d.tdr = TestDictRef
|
|
|
|
]])
|
2021-09-19 02:29:37 -07:00
|
|
|
eq(
|
|
|
|
'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
|
|
|
|
pcall_err(command, 'echo string(d.tdr)')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2016-12-25 13:29:35 -07:00
|
|
|
end)
|
2017-01-03 12:51:29 -07:00
|
|
|
|
|
|
|
it('dumps automatically created partials', function()
|
|
|
|
eq(
|
|
|
|
"function('<SNR>1_Test2', {'f': function('<SNR>1_Test2')})",
|
|
|
|
eval('string({"f": Test2_f}.f)')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2017-01-03 12:51:29 -07:00
|
|
|
eq(
|
|
|
|
"function('<SNR>1_Test2', [1], {'f': function('<SNR>1_Test2', [1])})",
|
|
|
|
eval('string({"f": function(Test2_f, [1])}.f)')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2017-01-03 12:51:29 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps manually created partials', function()
|
|
|
|
eq("function('Test3', [1, 2], {})", eval('string(function("Test3", [1, 2], {}))'))
|
|
|
|
eq("function('Test3', {})", eval('string(function("Test3", {}))'))
|
|
|
|
eq("function('Test3', [1, 2])", eval('string(function("Test3", [1, 2]))'))
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('does not crash or halt when dumping partials with reference cycles in self', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_set_var('d', { v = true })
|
2021-09-19 02:29:37 -07:00
|
|
|
eq(
|
|
|
|
[[Vim(echo):E724: unable to correctly dump variable with self-referencing container]],
|
|
|
|
pcall_err(command, 'echo string(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2017-01-03 12:51:29 -07:00
|
|
|
end)
|
|
|
|
|
refactor(api)!: rename Dictionary => Dict
In the api_info() output:
:new|put =map(filter(api_info().functions, '!has_key(v:val,''deprecated_since'')'), 'v:val')
...
{'return_type': 'ArrayOf(Integer, 2)', 'name': 'nvim_win_get_position', 'method': v:true, 'parameters': [['Window', 'window']], 'since': 1}
The `ArrayOf(Integer, 2)` return type didn't break clients when we added
it, which is evidence that clients don't use the `return_type` field,
thus renaming Dictionary => Dict in api_info() is not (in practice)
a breaking change.
2024-09-19 22:34:50 -07:00
|
|
|
it('does not show errors when dumping partials referencing the same dict', function()
|
2017-01-06 13:52:31 -07:00
|
|
|
command('let d = {}')
|
refactor(api)!: rename Dictionary => Dict
In the api_info() output:
:new|put =map(filter(api_info().functions, '!has_key(v:val,''deprecated_since'')'), 'v:val')
...
{'return_type': 'ArrayOf(Integer, 2)', 'name': 'nvim_win_get_position', 'method': v:true, 'parameters': [['Window', 'window']], 'since': 1}
The `ArrayOf(Integer, 2)` return type didn't break clients when we added
it, which is evidence that clients don't use the `return_type` field,
thus renaming Dictionary => Dict in api_info() is not (in practice)
a breaking change.
2024-09-19 22:34:50 -07:00
|
|
|
-- Regression for “eval/typval_encode: Dump empty dict before
|
2017-01-06 13:52:31 -07:00
|
|
|
-- checking for refcycle”, results in error.
|
|
|
|
eq(
|
|
|
|
"[function('tr', {}), function('tr', {})]",
|
|
|
|
eval('string([function("tr", d), function("tr", d)])')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2017-01-06 13:52:31 -07:00
|
|
|
-- Regression for “eval: Work with reference cycles in partials (self)
|
|
|
|
-- properly”, results in crash.
|
|
|
|
eval('extend(d, {"a": 1})')
|
|
|
|
eq(
|
|
|
|
"[function('tr', {'a': 1}), function('tr', {'a': 1})]",
|
|
|
|
eval('string([function("tr", d), function("tr", d)])')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2017-01-06 13:52:31 -07:00
|
|
|
end)
|
|
|
|
|
2017-01-03 12:51:29 -07:00
|
|
|
it('does not crash or halt when dumping partials with reference cycles in arguments', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_set_var('l', {})
|
2017-01-03 12:51:29 -07:00
|
|
|
eval('add(l, l)')
|
|
|
|
-- Regression: the below line used to crash (add returns original list and
|
|
|
|
-- there was error in dumping partials). Tested explicitly in
|
2024-04-08 02:03:20 -07:00
|
|
|
-- test/unit/api/private_t_spec.lua.
|
2017-01-03 12:51:29 -07:00
|
|
|
eval('add(l, function("Test1", l))')
|
2021-09-19 02:29:37 -07:00
|
|
|
eq(
|
|
|
|
[=[Vim(echo):E724: unable to correctly dump variable with self-referencing container]=],
|
|
|
|
pcall_err(command, 'echo string(function("Test1", l))')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2017-01-03 12:51:29 -07:00
|
|
|
end)
|
2024-01-02 18:09:18 -07:00
|
|
|
|
2017-01-03 12:51:29 -07:00
|
|
|
it(
|
|
|
|
'does not crash or halt when dumping partials with reference cycles in self and arguments',
|
|
|
|
function()
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_set_var('d', { v = true })
|
|
|
|
api.nvim_set_var('l', {})
|
2017-01-03 12:51:29 -07:00
|
|
|
eval('add(l, l)')
|
|
|
|
eval('add(l, function("Test1", l))')
|
|
|
|
eval('add(l, function("Test1", d))')
|
2021-09-19 02:29:37 -07:00
|
|
|
eq(
|
|
|
|
[=[Vim(echo):E724: unable to correctly dump variable with self-referencing container]=],
|
|
|
|
pcall_err(
|
|
|
|
command,
|
|
|
|
'echo string(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))'
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2021-09-19 02:29:37 -07:00
|
|
|
)
|
2017-01-03 12:51:29 -07:00
|
|
|
end
|
|
|
|
)
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
describe('used to represent lists', function()
|
|
|
|
it('dumps empty list', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('[]', fn.string({}))
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps nested lists', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('[[[[[]]]]]', fn.string({ { { { {} } } } }))
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps nested non-empty lists', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('[1, [[3, [[5], 4]], 2]]', fn.string({ 1, { { 3, { { 5 }, 4 } }, 2 } }))
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('errors when dumping recursive lists', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_set_var('l', {})
|
2015-12-25 16:01:47 -07:00
|
|
|
eval('add(l, l)')
|
|
|
|
eq(
|
|
|
|
'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
|
|
|
|
exc_exec('echo string(l)')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps recursive lists despite the error', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_set_var('l', {})
|
2015-12-25 16:01:47 -07:00
|
|
|
eval('add(l, l)')
|
2021-09-19 02:29:37 -07:00
|
|
|
eq(
|
|
|
|
'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
|
|
|
|
pcall_err(command, 'echo string(l)')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2021-09-19 02:29:37 -07:00
|
|
|
eq(
|
|
|
|
'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
|
|
|
|
pcall_err(command, 'echo string([l])')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
end)
|
|
|
|
|
|
|
|
describe('used to represent dictionaries', function()
|
refactor(api)!: rename Dictionary => Dict
In the api_info() output:
:new|put =map(filter(api_info().functions, '!has_key(v:val,''deprecated_since'')'), 'v:val')
...
{'return_type': 'ArrayOf(Integer, 2)', 'name': 'nvim_win_get_position', 'method': v:true, 'parameters': [['Window', 'window']], 'since': 1}
The `ArrayOf(Integer, 2)` return type didn't break clients when we added
it, which is evidence that clients don't use the `return_type` field,
thus renaming Dictionary => Dict in api_info() is not (in practice)
a breaking change.
2024-09-19 22:34:50 -07:00
|
|
|
it('dumps empty dict', function()
|
2015-12-25 16:01:47 -07:00
|
|
|
eq('{}', eval('string({})'))
|
|
|
|
end)
|
|
|
|
|
2017-01-06 13:52:31 -07:00
|
|
|
it('dumps list with two same empty dictionaries, also in partials', function()
|
|
|
|
command('let d = {}')
|
|
|
|
eq('[{}, {}]', eval('string([d, d])'))
|
|
|
|
eq("[function('tr', {}), {}]", eval('string([function("tr", d), d])'))
|
|
|
|
eq("[{}, function('tr', {})]", eval('string([d, function("tr", d)])'))
|
|
|
|
end)
|
|
|
|
|
refactor(api)!: rename Dictionary => Dict
In the api_info() output:
:new|put =map(filter(api_info().functions, '!has_key(v:val,''deprecated_since'')'), 'v:val')
...
{'return_type': 'ArrayOf(Integer, 2)', 'name': 'nvim_win_get_position', 'method': v:true, 'parameters': [['Window', 'window']], 'since': 1}
The `ArrayOf(Integer, 2)` return type didn't break clients when we added
it, which is evidence that clients don't use the `return_type` field,
thus renaming Dictionary => Dict in api_info() is not (in practice)
a breaking change.
2024-09-19 22:34:50 -07:00
|
|
|
it('dumps non-empty dict', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq("{'t''est': 1}", fn.string({ ["t'est"] = 1 }))
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('errors when dumping recursive dictionaries', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_set_var('d', { d = 1 })
|
2015-12-25 16:01:47 -07:00
|
|
|
eval('extend(d, {"d": d})')
|
|
|
|
eq(
|
|
|
|
'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
|
|
|
|
exc_exec('echo string(d)')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('dumps recursive dictionaries despite the error', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_set_var('d', { d = 1 })
|
2015-12-25 16:01:47 -07:00
|
|
|
eval('extend(d, {"d": d})')
|
2021-09-19 02:29:37 -07:00
|
|
|
eq(
|
|
|
|
'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
|
|
|
|
pcall_err(command, 'echo string(d)')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2021-09-19 02:29:37 -07:00
|
|
|
eq(
|
|
|
|
'Vim(echo):E724: unable to correctly dump variable with self-referencing container',
|
|
|
|
pcall_err(command, 'echo string({"out": d})')
|
2024-01-02 18:09:18 -07:00
|
|
|
)
|
2015-12-25 16:01:47 -07:00
|
|
|
end)
|
|
|
|
end)
|
|
|
|
end)
|