refactor(typval)!: remove distinction of binary and nonbinary strings

This is a breaking change which will make refactor of typval and shada
code a lot easier. In particular, code that would use or check for
v:msgpack_types.binary in the wild would be broken. This appears to be
rarely used in existing plugins.

Also some cases where v:msgpack_type.string would be used to represent a
binary string of "string" type, we use a BLOB instead, which is
vimscripts native type for binary blobs, and already was used for BIN
formats when necessary.

msgpackdump(msgpackparse(data)) no longer preserves the distinction
of BIN and STR strings. This is very common behavior for
language-specific msgpack bindings. Nvim uses msgpack as a tool to
serialize its data. Nvim is not a tool to bit-perfectly manipulate
arbitrary msgpack data out in the wild.

The changed tests should indicate how behavior changes in various edge
cases.
This commit is contained in:
bfredl 2024-06-25 15:33:47 +02:00
parent 9e436251de
commit bda63d5b97
19 changed files with 137 additions and 269 deletions

View File

@ -361,7 +361,7 @@ endfunction
let s:MSGPACK_STANDARD_TYPES = {
\type(0): 'integer',
\type(0.0): 'float',
\type(''): 'binary',
\type(''): 'string',
\type([]): 'array',
\type({}): 'map',
\type(v:true): 'boolean',
@ -412,9 +412,15 @@ endfunction
""
" Dump |msgpack-special-dict| that represents a string. If any additional
" parameter is given then it dumps binary string.
function s:msgpack_dump_string(v, ...) abort
let ret = [a:0 ? '"' : '="']
for v in a:v._VAL
function s:msgpack_dump_string(v) abort
if type(a:v) == type({})
let val = a:v
else
let val = {'_VAL': split(a:v, "\n", 1)}
end
let ret = ['"']
for v in val._VAL
call add(
\ret,
\substitute(
@ -426,16 +432,6 @@ function s:msgpack_dump_string(v, ...) abort
return join(ret, '')
endfunction
""
" Dump binary string.
function s:msgpack_dump_binary(v) abort
if type(a:v) == type({})
return s:msgpack_dump_string(a:v, 1)
else
return s:msgpack_dump_string({'_VAL': split(a:v, "\n", 1)}, 1)
endif
endfunction
""
" Dump array value.
function s:msgpack_dump_array(v) abort
@ -449,7 +445,7 @@ function s:msgpack_dump_map(v) abort
let ret = ['{']
if msgpack#special_type(a:v) is 0
for [k, v] in items(a:v)
let ret += [s:msgpack_dump_string({'_VAL': split(k, "\n", 1)}),
let ret += [s:msgpack_dump_string({'_VAL': split(k, "\n")}),
\': ',
\msgpack#string(v),
\', ']
@ -479,7 +475,7 @@ endfunction
" Dump extension value.
function s:msgpack_dump_ext(v) abort
return printf('+(%i)%s', a:v._VAL[0],
\s:msgpack_dump_string({'_VAL': a:v._VAL[1]}, 1))
\s:msgpack_dump_string({'_VAL': a:v._VAL[1]}))
endfunction
""
@ -619,9 +615,7 @@ function msgpack#eval(s, special_objs) abort
throw '"-invalid:Invalid string: ' . s
endif
call add(expr, '{''_TYPE'': v:msgpack_types.')
if empty(match[1])
call add(expr, 'binary')
elseif match[1] is# '='
if empty(match[1]) || match[1] is# '='
call add(expr, 'string')
else
call add(expr, 'ext')
@ -772,7 +766,7 @@ function msgpack#equal(a, b)
let a = aspecial is 0 ? a:a : a:a._VAL
let b = bspecial is 0 ? a:b : a:b._VAL
return msgpack#equal(a, b)
elseif atype is# 'binary'
elseif atype is# 'string'
let a = (aspecial is 0 ? split(a:a, "\n", 1) : a:a._VAL)
let b = (bspecial is 0 ? split(a:b, "\n", 1) : a:b._VAL)
return a ==# b
@ -787,13 +781,17 @@ function msgpack#equal(a, b)
" Non-special mapping cannot have non-string keys
return 0
endif
if (empty(k._VAL)
\|| k._VAL ==# [""]
\|| !empty(filter(copy(k._VAL), 'stridx(v:val, "\n") != -1')))
" Non-special mapping cannot have zero byte in key or an empty key
return 0
if type(k) == type({})
if (empty(k._VAL)
\|| k._VAL ==# [""]
\|| !empty(filter(copy(k._VAL), 'stridx(v:val, "\n") != -1')))
" Non-special mapping cannot have zero byte in key or an empty key
return 0
endif
let kstr = join(k._VAL, "\n")
else
let kstr = k
endif
let kstr = join(k._VAL, "\n")
if !has_key(akeys, kstr)
" Protects from both missing and duplicate keys
return 0

View File

@ -230,7 +230,7 @@ function s:shada_check_type(type, val) abort
return 0
elseif a:type is# 'bin'
" Binary string without zero bytes
if type isnot# 'binary'
if type isnot# 'string'
return 'Expected binary string'
elseif (type(a:val) == type({})
\&& !empty(filter(copy(a:val._VAL), 'stridx(v:val, "\n") != -1')))
@ -247,7 +247,7 @@ function s:shada_check_type(type, val) abort
if type isnot# 'array'
return 'Expected array value'
elseif !empty(filter(copy(type(a:val) == type({}) ? a:val._VAL : a:val),
\'msgpack#type(v:val) isnot# "binary"'))
\'msgpack#type(v:val) isnot# "string"'))
return 'Expected array of binary strings'
else
for element in (type(a:val) == type({}) ? a:val._VAL : a:val)

View File

@ -5152,12 +5152,7 @@ msgpackparse({data}) *msgpackparse()*
C parser does not support such values.
float |Float|. This value cannot possibly appear in
|msgpackparse()| output.
string |readfile()|-style list of strings. This value will
appear in |msgpackparse()| output if string contains
zero byte or if string is a mapping key and mapping is
being represented as special dictionary for other
reasons.
binary |String|, or |Blob| if binary string contains zero
string |String|, or |Blob| if binary string contains zero
byte. This value cannot appear in |msgpackparse()|
output since blobs were introduced.
array |List|. This value cannot appear in |msgpackparse()|

View File

@ -50,6 +50,12 @@ EDITOR
• |hl-CurSearch| now behaves the same as Vim and no longer updates on every
cursor movement.
VIM SCRIPT
• |v:msgpack_types| has the type "binary" removed. |msgpackparse()| no longer
treats BIN, STR and FIXSTR as separate types. Any of these is returned as a
string if possible, or a |blob| if the value contained embedded NUL:s.
EVENTS
• TODO

View File

@ -6177,12 +6177,7 @@ function vim.fn.msgpackdump(list, type) end
--- C parser does not support such values.
--- float |Float|. This value cannot possibly appear in
--- |msgpackparse()| output.
--- string |readfile()|-style list of strings. This value will
--- appear in |msgpackparse()| output if string contains
--- zero byte or if string is a mapping key and mapping is
--- being represented as special dictionary for other
--- reasons.
--- binary |String|, or |Blob| if binary string contains zero
--- string |String|, or |Blob| if binary string contains zero
--- byte. This value cannot appear in |msgpackparse()|
--- output since blobs were introduced.
--- array |List|. This value cannot appear in |msgpackparse()|

View File

@ -7,7 +7,9 @@
#include "nvim/api/private/converter.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ascii_defs.h"
#include "nvim/assert_defs.h"
#include "nvim/eval/decode.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
@ -302,15 +304,11 @@ void object_to_vim_take_luaref(Object *obj, typval_T *tv, bool take_luaref, Erro
tv->vval.v_float = obj->data.floating;
break;
case kObjectTypeString:
tv->v_type = VAR_STRING;
if (obj->data.string.data == NULL) {
tv->vval.v_string = NULL;
} else {
tv->vval.v_string = xmemdupz(obj->data.string.data,
obj->data.string.size);
}
case kObjectTypeString: {
String s = obj->data.string;
*tv = decode_string(s.data, s.size, false, false);
break;
}
case kObjectTypeArray: {
list_T *const list = tv_list_alloc((ptrdiff_t)obj->data.array.size);

View File

@ -331,7 +331,6 @@ static const char *const msgpack_type_names[] = {
[kMPInteger] = "integer",
[kMPFloat] = "float",
[kMPString] = "string",
[kMPBinary] = "binary",
[kMPArray] = "array",
[kMPMap] = "map",
[kMPExt] = "ext",
@ -342,7 +341,6 @@ const list_T *eval_msgpack_type_lists[] = {
[kMPInteger] = NULL,
[kMPFloat] = NULL,
[kMPString] = NULL,
[kMPBinary] = NULL,
[kMPArray] = NULL,
[kMPMap] = NULL,
[kMPExt] = NULL,

View File

@ -7444,12 +7444,7 @@ M.funcs = {
C parser does not support such values.
float |Float|. This value cannot possibly appear in
|msgpackparse()| output.
string |readfile()|-style list of strings. This value will
appear in |msgpackparse()| output if string contains
zero byte or if string is a mapping key and mapping is
being represented as special dictionary for other
reasons.
binary |String|, or |Blob| if binary string contains zero
string |String|, or |Blob| if binary string contains zero
byte. This value cannot appear in |msgpackparse()|
output since blobs were introduced.
array |List|. This value cannot appear in |msgpackparse()|

View File

@ -247,45 +247,29 @@ list_T *decode_create_map_special_dict(typval_T *const ret_tv, const ptrdiff_t l
///
/// @param[in] s String to decode.
/// @param[in] len String length.
/// @param[in] hasnul Whether string has NUL byte, not or it was not yet
/// determined.
/// @param[in] binary Determines decode type if string has NUL bytes.
/// If true convert string to VAR_BLOB, otherwise to the
/// kMPString special type.
/// @param[in] force_blob whether string always should be decoded as a blob,
/// or only when embedded NUL bytes were present
/// @param[in] s_allocated If true, then `s` was allocated and can be saved in
/// a returned structure. If it is not saved there, it
/// will be freed.
///
/// @return Decoded string.
typval_T decode_string(const char *const s, const size_t len, const TriState hasnul,
const bool binary, const bool s_allocated)
typval_T decode_string(const char *const s, const size_t len, bool force_blob,
const bool s_allocated)
FUNC_ATTR_WARN_UNUSED_RESULT
{
assert(s != NULL || len == 0);
const bool really_hasnul = (hasnul == kNone
? ((s != NULL) && (memchr(s, NUL, len) != NULL))
: (bool)hasnul);
if (really_hasnul) {
const bool use_blob = force_blob || ((s != NULL) && (memchr(s, NUL, len) != NULL));
if (use_blob) {
typval_T tv;
tv.v_lock = VAR_UNLOCKED;
if (binary) {
tv_blob_alloc_ret(&tv);
ga_concat_len(&tv.vval.v_blob->bv_ga, s, len);
blob_T *b = tv_blob_alloc_ret(&tv);
if (s_allocated) {
b->bv_ga.ga_data = (void *)s;
b->bv_ga.ga_len = (int)len;
b->bv_ga.ga_maxlen = (int)len;
} else {
list_T *const list = tv_list_alloc(kListLenMayKnow);
tv_list_ref(list);
create_special_dict(&tv, kMPString,
(typval_T){ .v_type = VAR_LIST,
.v_lock = VAR_UNLOCKED,
.vval = { .v_list = list } });
const int elw_ret = encode_list_write((void *)list, s, len);
if (s_allocated) {
xfree((void *)s);
}
if (elw_ret == -1) {
tv_clear(&tv);
return (typval_T) { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED };
}
ga_concat_len(&b->bv_ga, s, len);
}
return tv;
}
@ -405,7 +389,6 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
char *str = xmalloc(len + 1);
int fst_in_pair = 0;
char *str_end = str;
bool hasnul = false;
#define PUT_FST_IN_PAIR(fst_in_pair, str_end) \
do { \
if ((fst_in_pair) != 0) { \
@ -426,9 +409,6 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
uvarnumber_T ch;
vim_str2nr(ubuf, NULL, NULL,
STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4, true, NULL);
if (ch == 0) {
hasnul = true;
}
if (SURROGATE_HI_START <= ch && ch <= SURROGATE_HI_END) {
PUT_FST_IN_PAIR(fst_in_pair, str_end);
fst_in_pair = (int)ch;
@ -476,10 +456,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
PUT_FST_IN_PAIR(fst_in_pair, str_end);
#undef PUT_FST_IN_PAIR
*str_end = NUL;
typval_T obj = decode_string(str, (size_t)(str_end - str), hasnul ? kTrue : kFalse, false, true);
if (obj.v_type == VAR_UNKNOWN) {
goto parse_json_string_fail;
}
typval_T obj = decode_string(str, (size_t)(str_end - str), false, true);
POP(obj, obj.v_type != VAR_STRING);
goto parse_json_string_ret;
parse_json_string_fail:
@ -982,18 +959,8 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
};
break;
case MSGPACK_OBJECT_STR:
*rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kTrue, false,
false);
if (rettv->v_type == VAR_UNKNOWN) {
return FAIL;
}
break;
case MSGPACK_OBJECT_BIN:
*rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kNone, true,
false);
if (rettv->v_type == VAR_UNKNOWN) {
return FAIL;
}
*rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, false, false);
break;
case MSGPACK_OBJECT_ARRAY: {
list_T *const list = tv_list_alloc((ptrdiff_t)mobj.via.array.size);
@ -1016,7 +983,8 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
}
case MSGPACK_OBJECT_MAP: {
for (size_t i = 0; i < mobj.via.map.size; i++) {
if (mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR
if ((mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR
&& mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_BIN)
|| mobj.via.map.ptr[i].key.via.str.size == 0
|| memchr(mobj.via.map.ptr[i].key.via.str.ptr, NUL,
mobj.via.map.ptr[i].key.via.str.size) != NULL) {

View File

@ -776,8 +776,7 @@ bool encode_check_json_key(const typval_T *const tv)
const dictitem_T *val_di;
if ((type_di = tv_dict_find(spdict, S_LEN("_TYPE"))) == NULL
|| type_di->di_tv.v_type != VAR_LIST
|| (type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPString]
&& type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPBinary])
|| type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPString]
|| (val_di = tv_dict_find(spdict, S_LEN("_VAL"))) == NULL
|| val_di->di_tv.v_type != VAR_LIST) {
return false;

View File

@ -501,9 +501,7 @@ static int TYPVAL_ENCODE_CONVERT_ONE_VALUE(
}
TYPVAL_ENCODE_CONV_FLOAT(tv, val_di->di_tv.vval.v_float);
break;
case kMPString:
case kMPBinary: {
const bool is_string = ((MessagePackType)i == kMPString);
case kMPString: {
if (val_di->di_tv.v_type != VAR_LIST) {
goto _convert_one_value_regular_dict;
}
@ -513,11 +511,7 @@ static int TYPVAL_ENCODE_CONVERT_ONE_VALUE(
&buf)) {
goto _convert_one_value_regular_dict;
}
if (is_string) {
TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len);
} else {
TYPVAL_ENCODE_CONV_STRING(tv, buf, len);
}
TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len);
xfree(buf);
break;
}

View File

@ -9,7 +9,6 @@ typedef enum {
kMPInteger,
kMPFloat,
kMPString,
kMPBinary,
kMPArray,
kMPMap,
kMPExt,

View File

@ -219,12 +219,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
if (cur.special) {
list_T *const kv_pair = tv_list_alloc(2);
typval_T s_tv = decode_string(s, len, kTrue, false, false);
if (s_tv.v_type == VAR_UNKNOWN) {
ret = false;
tv_list_unref(kv_pair);
continue;
}
typval_T s_tv = decode_string(s, len, true, false);
tv_list_append_owned_tv(kv_pair, s_tv);
// Value: not populated yet, need to create list item to push.
@ -280,10 +275,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
case LUA_TSTRING: {
size_t len;
const char *s = lua_tolstring(lstate, -1, &len);
*cur.tv = decode_string(s, len, kNone, true, false);
if (cur.tv->v_type == VAR_UNKNOWN) {
ret = false;
}
*cur.tv = decode_string(s, len, false, false);
break;
}
case LUA_TNUMBER: {

View File

@ -1571,9 +1571,9 @@ describe('API', function()
eq(val2, request('vim_del_var', 'lua'))
end)
it('truncates values with NULs in them', function()
it('preserves values with NULs in them', function()
api.nvim_set_var('xxx', 'ab\0cd')
eq('ab', api.nvim_get_var('xxx'))
eq('ab\000cd', api.nvim_get_var('xxx'))
end)
end)

View File

@ -72,9 +72,9 @@ describe('luaeval()', function()
end)
it('are successfully converted to special dictionaries in table keys', function()
command([[let d = luaeval('{["\0"]=1}')]])
eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n'}}, 1}}}, api.nvim_get_var('d'))
eq({_TYPE={}, _VAL={{'\000', 1}}}, api.nvim_get_var('d'))
eq(1, fn.eval('d._TYPE is v:msgpack_types.map'))
eq(1, fn.eval('d._VAL[0][0]._TYPE is v:msgpack_types.string'))
eq(eval('v:t_blob'), fn.eval('type(d._VAL[0][0])'))
end)
it('are successfully converted to blobs from a list', function()
command([[let l = luaeval('{"abc", "a\0b", "c\0d", "def"}')]])
@ -125,11 +125,11 @@ describe('luaeval()', function()
local level = 30
eq(nested_by_level[level].o, fn.luaeval(nested_by_level[level].s))
eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}},
eq({_TYPE={}, _VAL={{'\000\n\000', '\000\n\000\000'}}},
fn.luaeval([[{['\0\n\0']='\0\n\0\0'}]]))
eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._TYPE is v:msgpack_types.map]]))
eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][0]._TYPE is v:msgpack_types.string]]))
eq({nested={{_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}}}},
eq(eval("v:t_blob"), eval([[type(luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][0])]]))
eq({nested={{_TYPE={}, _VAL={{'\000\n\000', '\000\n\000\000'}}}}},
fn.luaeval([[{nested={{['\0\n\0']='\0\n\0\0'}}}]]))
end)
@ -177,12 +177,10 @@ describe('luaeval()', function()
end
it('correctly passes special dictionaries', function()
eq({0, '\000\n\000'}, luaevalarg(sp('binary', '["\\n", "\\n"]')))
eq({0, '\000\n\000'}, luaevalarg(sp('string', '["\\n", "\\n"]')))
eq({0, true}, luaevalarg(sp('boolean', 1)))
eq({0, false}, luaevalarg(sp('boolean', 0)))
eq({0, NIL}, luaevalarg(sp('nil', 0)))
eq({0, {[""]=""}}, luaevalarg(mapsp(sp('binary', '[""]'), '""')))
eq({0, {[""]=""}}, luaevalarg(mapsp(sp('string', '[""]'), '""')))
end)

View File

@ -58,23 +58,11 @@ describe('autoload/msgpack.vim', function()
msgpack_eq(1, '"abc\\ndef"', '"abc\\ndef"')
msgpack_eq(0, '"abc\\ndef"', '"abc\\nghi"')
end)
it('compares binary specials correctly', function()
msgpack_eq(1, sp('binary', '["abc\\n", "def"]'), sp('binary', '["abc\\n", "def"]'))
msgpack_eq(0, sp('binary', '["abc", "def"]'), sp('binary', '["abc\\n", "def"]'))
end)
it('compares binary specials with raw binaries correctly', function()
msgpack_eq(1, sp('binary', '["abc", "def"]'), '"abc\\ndef"')
msgpack_eq(0, sp('binary', '["abc", "def"]'), '"abcdef"')
end)
it('compares string specials correctly', function()
msgpack_eq(1, sp('string', '["abc\\n", "def"]'), sp('string', '["abc\\n", "def"]'))
msgpack_eq(0, sp('string', '["abc", "def"]'), sp('string', '["abc\\n", "def"]'))
end)
it('compares string specials with binary correctly', function()
msgpack_eq(0, sp('string', '["abc\\n", "def"]'), sp('binary', '["abc\\n", "def"]'))
msgpack_eq(0, sp('string', '["abc", "def"]'), '"abc\\ndef"')
msgpack_eq(0, sp('binary', '["abc\\n", "def"]'), sp('string', '["abc\\n", "def"]'))
msgpack_eq(0, '"abc\\ndef"', sp('string', '["abc", "def"]'))
msgpack_eq(1, sp('string', '["abc", "def"]'), '"abc\\ndef"')
msgpack_eq(1, '"abc\\ndef"', sp('string', '["abc", "def"]'))
end)
it('compares ext specials correctly', function()
msgpack_eq(1, sp('ext', '[1, ["", "ac"]]'), sp('ext', '[1, ["", "ac"]]'))
@ -92,20 +80,16 @@ describe('autoload/msgpack.vim', function()
end)
it('compares map specials correctly', function()
msgpack_eq(1, mapsp(), mapsp())
msgpack_eq(1, mapsp(sp('binary', '[""]'), '""'), mapsp(sp('binary', '[""]'), '""'))
msgpack_eq(
1,
mapsp(mapsp('1', '1'), mapsp('1', '1')),
mapsp(mapsp('1', '1'), mapsp('1', '1'))
)
msgpack_eq(0, mapsp(), mapsp('1', '1'))
msgpack_eq(0, mapsp(sp('binary', '["a"]'), '""'), mapsp(sp('binary', '[""]'), '""'))
msgpack_eq(0, mapsp(sp('binary', '[""]'), '"a"'), mapsp(sp('binary', '[""]'), '""'))
msgpack_eq(0, mapsp(sp('binary', '["a"]'), '"a"'), mapsp(sp('binary', '[""]'), '""'))
msgpack_eq(
0,
mapsp(mapsp('1', '1'), mapsp('1', '1')),
mapsp(sp('binary', '[""]'), mapsp('1', '1'))
mapsp(sp('string', '[""]'), mapsp('1', '1'))
)
msgpack_eq(
0,
@ -138,7 +122,7 @@ describe('autoload/msgpack.vim', function()
msgpack_eq(1, mapsp(sp('string', '["1"]'), '1'), '{"1": 1}')
msgpack_eq(1, mapsp(sp('string', '["1"]'), sp('integer', '[1, 0, 0, 1]')), '{"1": 1}')
msgpack_eq(0, mapsp(sp('integer', '[1, 0, 0, 1]'), sp('string', '["1"]')), '{1: "1"}')
msgpack_eq(0, mapsp('"1"', sp('integer', '[1, 0, 0, 1]')), '{"1": 1}')
msgpack_eq(1, mapsp('"1"', sp('integer', '[1, 0, 0, 1]')), '{"1": 1}')
msgpack_eq(0, mapsp(sp('string', '["1"]'), '1', sp('string', '["2"]'), '2'), '{"1": 1}')
msgpack_eq(0, mapsp(sp('string', '["1"]'), '1'), '{"1": 1, "2": 2}')
end)
@ -290,7 +274,6 @@ describe('autoload/msgpack.vim', function()
it('works for special dictionaries', function()
type_eq('string', sp('string', '[""]'))
type_eq('binary', sp('binary', '[""]'))
type_eq('ext', sp('ext', '[1, [""]]'))
type_eq('array', sp('array', '[]'))
type_eq('map', sp('map', '[]'))
@ -301,7 +284,7 @@ describe('autoload/msgpack.vim', function()
end)
it('works for regular values', function()
type_eq('binary', '""')
type_eq('string', '""')
type_eq('array', '[]')
type_eq('map', '{}')
type_eq('integer', '1')
@ -319,7 +302,6 @@ describe('autoload/msgpack.vim', function()
it('works for special dictionaries', function()
sp_type_eq('string', sp('string', '[""]'))
sp_type_eq('binary', sp('binary', '[""]'))
sp_type_eq('ext', sp('ext', '[1, [""]]'))
sp_type_eq('array', sp('array', '[]'))
sp_type_eq('map', sp('map', '[]'))
@ -347,12 +329,9 @@ describe('autoload/msgpack.vim', function()
end
it('works for special dictionaries', function()
string_eq('=""', sp('string', '[""]'))
string_eq('="\\n"', sp('string', '["", ""]'))
string_eq('="ab\\0c\\nde"', sp('string', '["ab\\nc", "de"]'))
string_eq('""', sp('binary', '[""]'))
string_eq('"\\n"', sp('binary', '["", ""]'))
string_eq('"ab\\0c\\nde"', sp('binary', '["ab\\nc", "de"]'))
string_eq('""', sp('string', '[""]'))
string_eq('"\\n"', sp('string', '["", ""]'))
string_eq('"ab\\0c\\nde"', sp('string', '["ab\\nc", "de"]'))
string_eq('+(2)""', sp('ext', '[2, [""]]'))
string_eq('+(2)"\\n"', sp('ext', '[2, ["", ""]]'))
string_eq('+(2)"ab\\0c\\nde"', sp('ext', '[2, ["ab\\nc", "de"]]'))
@ -397,8 +376,8 @@ describe('autoload/msgpack.vim', function()
string_eq('[]', '[]')
string_eq('[[[{}]]]', '[[[{}]]]')
string_eq('{}', '{}')
string_eq('{="2": 10}', '{2: 10}')
string_eq('{="2": [{}]}', '{2: [{}]}')
string_eq('{"2": 10}', '{2: 10}')
string_eq('{"2": [{}]}', '{2: [{}]}')
string_eq('1', '1')
string_eq('0.0', '0.0')
string_eq('inf', '(1.0/0.0)')
@ -422,7 +401,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('let spflt = ' .. sp('float', '1.0'))
nvim_command('let spext = ' .. sp('ext', '[2, ["abc", "def"]]'))
nvim_command('let spstr = ' .. sp('string', '["abc", "def"]'))
nvim_command('let spbin = ' .. sp('binary', '["abc", "def"]'))
nvim_command('let spbln = ' .. sp('boolean', '0'))
nvim_command('let spnil = ' .. sp('nil', '0'))
@ -432,7 +410,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('let spflt2 = msgpack#deepcopy(spflt)')
nvim_command('let spext2 = msgpack#deepcopy(spext)')
nvim_command('let spstr2 = msgpack#deepcopy(spstr)')
nvim_command('let spbin2 = msgpack#deepcopy(spbin)')
nvim_command('let spbln2 = msgpack#deepcopy(spbln)')
nvim_command('let spnil2 = msgpack#deepcopy(spnil)')
@ -442,7 +419,6 @@ describe('autoload/msgpack.vim', function()
eq('float', nvim_eval('msgpack#type(spflt2)'))
eq('ext', nvim_eval('msgpack#type(spext2)'))
eq('string', nvim_eval('msgpack#type(spstr2)'))
eq('binary', nvim_eval('msgpack#type(spbin2)'))
eq('boolean', nvim_eval('msgpack#type(spbln2)'))
eq('nil', nvim_eval('msgpack#type(spnil2)'))
@ -457,7 +433,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('let spext._VAL[0] = 3')
nvim_command('let spext._VAL[1][0] = "gh"')
nvim_command('let spstr._VAL[0] = "gh"')
nvim_command('let spbin._VAL[0] = "gh"')
nvim_command('let spbln._VAL = 1')
nvim_command('let spnil._VAL = 1')
@ -467,7 +442,6 @@ describe('autoload/msgpack.vim', function()
eq({ _TYPE = {}, _VAL = 1.0 }, nvim_eval('spflt2'))
eq({ _TYPE = {}, _VAL = { 2, { 'abc', 'def' } } }, nvim_eval('spext2'))
eq({ _TYPE = {}, _VAL = { 'abc', 'def' } }, nvim_eval('spstr2'))
eq({ _TYPE = {}, _VAL = { 'abc', 'def' } }, nvim_eval('spbin2'))
eq({ _TYPE = {}, _VAL = 0 }, nvim_eval('spbln2'))
eq({ _TYPE = {}, _VAL = 0 }, nvim_eval('spnil2'))
@ -477,7 +451,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('let spflt._TYPE = []')
nvim_command('let spext._TYPE = []')
nvim_command('let spstr._TYPE = []')
nvim_command('let spbin._TYPE = []')
nvim_command('let spbln._TYPE = []')
nvim_command('let spnil._TYPE = []')
@ -487,7 +460,6 @@ describe('autoload/msgpack.vim', function()
eq('float', nvim_eval('msgpack#special_type(spflt2)'))
eq('ext', nvim_eval('msgpack#special_type(spext2)'))
eq('string', nvim_eval('msgpack#special_type(spstr2)'))
eq('binary', nvim_eval('msgpack#special_type(spbin2)'))
eq('boolean', nvim_eval('msgpack#special_type(spbln2)'))
eq('nil', nvim_eval('msgpack#special_type(spnil2)'))
end)
@ -509,7 +481,7 @@ describe('autoload/msgpack.vim', function()
eq('map', nvim_eval('msgpack#type(map2)'))
eq('integer', nvim_eval('msgpack#type(int2)'))
eq('float', nvim_eval('msgpack#type(flt2)'))
eq('binary', nvim_eval('msgpack#type(bin2)'))
eq('string', nvim_eval('msgpack#type(bin2)'))
nvim_command('call add(arr, 0)')
nvim_command('call add(arr[0], 0)')
@ -566,21 +538,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('unlet g:__val')
end
it('correctly loads binary strings', function()
eval_eq('binary', { 'abcdef' }, '"abcdef"')
eval_eq('binary', { 'abc', 'def' }, '"abc\\ndef"')
eval_eq('binary', { 'abc\ndef' }, '"abc\\0def"')
eval_eq('binary', { '\nabc\ndef\n' }, '"\\0abc\\0def\\0"')
eval_eq('binary', { 'abc\n\n\ndef' }, '"abc\\0\\0\\0def"')
eval_eq('binary', { 'abc\n', '\ndef' }, '"abc\\0\\n\\0def"')
eval_eq('binary', { 'abc', '', '', 'def' }, '"abc\\n\\n\\ndef"')
eval_eq('binary', { 'abc', '', '', 'def', '' }, '"abc\\n\\n\\ndef\\n"')
eval_eq('binary', { '', 'abc', '', '', 'def' }, '"\\nabc\\n\\n\\ndef"')
eval_eq('binary', { '' }, '""')
eval_eq('binary', { '"' }, '"\\""')
eval_eq('binary', { 'py3 print(sys.version_info)' }, '"py3 print(sys.version_info)"')
end)
it('correctly loads strings', function()
eval_eq('string', { 'abcdef' }, '="abcdef"')
eval_eq('string', { 'abc', 'def' }, '="abc\\ndef"')

View File

@ -68,7 +68,7 @@ describe('autoload/shada.vim', function()
endfor
return ret
elseif type(a:val) == type('')
return {'_TYPE': v:msgpack_types.binary, '_VAL': split(a:val, "\n", 1)}
return {'_TYPE': v:msgpack_types.string, '_VAL': split(a:val, "\n", 1)}
else
return a:val
endif
@ -253,8 +253,7 @@ describe('autoload/shada.vim', function()
' + sm magic value "TRUE"',
' # Expected integer',
' + so offset value "TRUE"',
' # Expected binary string',
' + sp pattern ="abc"',
' + sp pattern "abc"',
},
([[ [{'type': 1, 'timestamp': 0, 'data': {
'sm': 'TRUE',
@ -267,7 +266,7 @@ describe('autoload/shada.vim', function()
'n': -0x40,
'l': -10,
'c': 'abc',
'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]},
'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@ -276,15 +275,14 @@ describe('autoload/shada.vim', function()
' % Key Description Value',
' # Expected no NUL bytes',
' + f file name "abc\\0def"',
' # Expected array of binary strings',
' + rc contents ["abc", ="abc"]',
' + rc contents ["abc", "abc"]',
' # Expected integer',
' + rt type "ABC"',
},
([[ [{'type': 1, 'timestamp': 0, 'data': {
'rt': 'ABC',
'rc': ["abc", {'_TYPE': v:msgpack_types.string, '_VAL': ["abc"]}],
'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]},
'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@ -295,7 +293,7 @@ describe('autoload/shada.vim', function()
' + rc contents ["abc", "a\\nd\\0"]',
},
([[ [{'type': 1, 'timestamp': 0, 'data': {
'rc': ["abc", {'_TYPE': v:msgpack_types.binary, '_VAL': ["a", "d\n"]}],
'rc': ["abc", {'_TYPE': v:msgpack_types.string, '_VAL': ["a", "d\n"]}],
}}] ]]):gsub('\n', '')
)
end)
@ -468,7 +466,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'Replacement string with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
' = {="a": [10]}',
' = {"a": [10]}',
}, { { type = 3, timestamp = 0, data = { a = { 10 } } } })
sd2strings_eq(
{
@ -498,7 +496,7 @@ describe('autoload/shada.vim', function()
' - :s replacement string "abc\\0def"',
},
([[ [{'type': 3, 'timestamp': 0, 'data': [
{'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]},
{'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@ -508,7 +506,7 @@ describe('autoload/shada.vim', function()
' - :s replacement string "abc\\ndef"',
},
([[ [{'type': 3, 'timestamp': 0, 'data': [
{'_TYPE': v:msgpack_types.binary, '_VAL': ["abc", "def"]},
{'_TYPE': v:msgpack_types.string, '_VAL': ["abc", "def"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@ -519,7 +517,7 @@ describe('autoload/shada.vim', function()
' - 0',
},
([[ [{'type': 3, 'timestamp': 0, 'data': [
{'_TYPE': v:msgpack_types.binary, '_VAL': ["abc", "def"]},
{'_TYPE': v:msgpack_types.string, '_VAL': ["abc", "def"]},
0,
]}] ]]):gsub('\n', '')
)
@ -529,7 +527,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'History entry with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
' = {="a": [10]}',
' = {"a": [10]}',
}, { { type = 4, timestamp = 0, data = { a = { 10 } } } })
sd2strings_eq(
{
@ -682,7 +680,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 4, 'timestamp': 0, 'data': [
4,
{'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]},
{'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@ -909,7 +907,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'Variable with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
' = {="a": [10]}',
' = {"a": [10]}',
}, { { type = 6, timestamp = 0, data = { a = { 10 } } } })
sd2strings_eq(
{
@ -941,7 +939,7 @@ describe('autoload/shada.vim', function()
' # Expected more elements in list',
},
([[ [{'type': 6, 'timestamp': 0, 'data': [
{'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
{'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@ -952,7 +950,7 @@ describe('autoload/shada.vim', function()
' # Expected more elements in list',
},
([[ [{'type': 6, 'timestamp': 0, 'data': [
{'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]},
{'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@ -963,7 +961,7 @@ describe('autoload/shada.vim', function()
' - value NIL',
},
([[ [{'type': 6, 'timestamp': 0, 'data': [
{'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]},
{'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]},
{'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]},
]}] ]]):gsub('\n', '')
)
@ -976,7 +974,7 @@ describe('autoload/shada.vim', function()
' - NIL',
},
([[ [{'type': 6, 'timestamp': 0, 'data': [
{'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]},
{'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]},
{'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]},
{'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]},
]}] ]]):gsub('\n', '')
@ -1041,7 +1039,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 7, 'timestamp': 0, 'data': {
'n': -10,
'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@ -1174,7 +1172,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 8, 'timestamp': 0, 'data': {
'n': -10,
'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@ -1237,7 +1235,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'Buffer list with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
' = {="a": [10]}',
' = {"a": [10]}',
}, { { type = 9, timestamp = 0, data = { a = { 10 } } } })
sd2strings_eq({
'Buffer list with timestamp ' .. epoch .. ':',
@ -1247,7 +1245,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
' = [{="a": 10}, []]',
' = [{"a": 10}, []]',
}, { { type = 9, timestamp = 0, data = { { a = 10 }, {} } } })
sd2strings_eq({
'Buffer list with timestamp ' .. epoch .. ':',
@ -1322,7 +1320,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 9, 'timestamp': 0, 'data': [
{'f': 10},
{'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}},
{'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}},
]}] ]]):gsub('\n', '')
)
end)
@ -1385,7 +1383,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 10, 'timestamp': 0, 'data': {
'n': -10,
'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@ -1504,7 +1502,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 11, 'timestamp': 0, 'data': {
'n': -10,
'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@ -1616,7 +1614,7 @@ describe('autoload/shada.vim', function()
timestamp = 0,
data = {
c = 'abc',
f = { '!binary', { 'abc\ndef' } },
f = { '!string', { 'abc\ndef' } },
l = -10,
n = -64,
rc = '10',
@ -1711,7 +1709,7 @@ describe('autoload/shada.vim', function()
timestamp = 0,
data = {
c = 'abc',
f = { '!binary', { 'abc\ndef' } },
f = { '!string', { 'abc\ndef' } },
l = -10,
n = -64,
rc = '10',
@ -1892,7 +1890,7 @@ describe('autoload/shada.vim', function()
} } }, {
'Replacement string with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
' = {="a": [10]}',
' = {"a": [10]}',
})
strings2sd_eq({ { type = 3, timestamp = 0, data = {} } }, {
'Replacement string with timestamp ' .. epoch .. ':',
@ -1934,7 +1932,7 @@ describe('autoload/shada.vim', function()
} } }, {
'History entry with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
' = {="a": [10]}',
' = {"a": [10]}',
})
strings2sd_eq({ { type = 4, timestamp = 0, data = {} } }, {
'History entry with timestamp ' .. epoch .. ':',
@ -2184,7 +2182,7 @@ describe('autoload/shada.vim', function()
} } }, {
'Variable with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
' = {="a": [10]}',
' = {"a": [10]}',
})
strings2sd_eq({ { type = 6, timestamp = 0, data = {} } }, {
'Variable with timestamp ' .. epoch .. ':',
@ -2315,7 +2313,7 @@ describe('autoload/shada.vim', function()
} } }, {
'Buffer list with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
' = {="a": [10]}',
' = {"a": [10]}',
})
strings2sd_eq(
{ { type = 9, timestamp = 0, data = {
@ -2325,7 +2323,7 @@ describe('autoload/shada.vim', function()
{
'Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
' = [{="a": 10}, []]',
' = [{"a": 10}, []]',
}
)
strings2sd_eq({ { type = 9, timestamp = 0, data = {
@ -2421,7 +2419,7 @@ describe('autoload/shada.vim', function()
timestamp = 0,
data = {
{ f = 10 },
{ f = { '!binary', { '\n' } } },
{ f = { '!string', { '\n' } } },
},
},
}, {
@ -2955,7 +2953,7 @@ describe('ftplugin/shada.vim', function()
' - :s replacement string "abc\\ndef"',
' Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
'= [{="a": 10}, []]',
'= [{"a": 10}, []]',
' Buffer list with timestamp ' .. epoch .. ':',
' % Key Description Value',
' # Expected binary string',
@ -2992,7 +2990,7 @@ describe('ftplugin/shada.vim', function()
' - :s replacement string "abc\\ndef"',
'Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
' = [{="a": 10}, []]',
' = [{"a": 10}, []]',
'Buffer list with timestamp ' .. epoch .. ':',
' % Key Description Value',
' # Expected binary string',
@ -3083,7 +3081,7 @@ describe('syntax/shada.vim', function()
' - :s replacement string DEBUG',
'Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
' = [{="a": +(10)"ac\\0df\\ngi\\"tt\\.", TRUE: FALSE}, [NIL, +(-10)""]]',
' = [{"a": +(10)"ac\\0df\\ngi\\"tt\\.", TRUE: FALSE}, [NIL, +(-10)""]]',
'Buffer list with timestamp ' .. epoch .. ':',
' % Key Description Value',
'',
@ -3119,8 +3117,8 @@ describe('syntax/shada.vim', function()
{1: -} {4::s replacement string} {1:DEBUG} |
{1:Buffer list} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: |
{4: # Expected array of maps} |
= {1:[{="}{3:a}{1:":} {1:+(}{5:10}{1:)"}{3:ac}{6:\0}{3:df}{6:\n}{3:gi}{6:\"}{3:tt\.}{1:",} {1:TRUE:} {1:FALSE},} {1:[NIL,} {1:+(}{5:-}|
{5:10}{1:)""]]} |
= {1:[{"}{3:a}{1:":} {1:+(}{5:10}{1:)"}{3:ac}{6:\0}{3:df}{6:\n}{3:gi}{6:\"}{3:tt\.}{1:",} {1:TRUE:} {1:FALSE},} {1:[NIL,} {1:+(}{5:-1}|
{5:0}{1:)""]]} |
{1:Buffer list} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: |
{2: % Key Description Value} |
|
@ -3464,7 +3462,6 @@ describe('syntax/shada.vim', function()
{ { 'ShaDaEntryRawMsgpack' }, ' = ' },
{ { 'ShaDaMsgpackArray', 'ShaDaMsgpackArrayBraces' }, '[' },
{ { 'ShaDaMsgpackArray', 'ShaDaMsgpackMap', 'ShaDaMsgpackMapBraces' }, '{' },
{ { 'ShaDaMsgpackArray', 'ShaDaMsgpackMap', 'ShaDaMsgpackString' }, '=' },
{
{
'ShaDaMsgpackArray',

View File

@ -502,9 +502,9 @@ describe('json_decode() function', function()
end
it('parses strings with NUL properly', function()
sp_decode_eq({ _TYPE = 'string', _VAL = { '\n' } }, '"\\u0000"')
sp_decode_eq({ _TYPE = 'string', _VAL = { '\n', '\n' } }, '"\\u0000\\n\\u0000"')
sp_decode_eq({ _TYPE = 'string', _VAL = { '\n«\n' } }, '"\\u0000\\u00AB\\u0000"')
sp_decode_eq('\000', '"\\u0000"')
sp_decode_eq('\000\n\000', '"\\u0000\\n\\u0000"')
sp_decode_eq('\000«\000', '"\\u0000\\u00AB\\u0000"')
end)
it('parses dictionaries with duplicate keys to special maps', function()
@ -580,14 +580,8 @@ describe('json_decode() function', function()
end)
it('parses dictionaries with keys with NUL bytes to special maps', function()
sp_decode_eq(
{ _TYPE = 'map', _VAL = { { { _TYPE = 'string', _VAL = { 'a\n', 'b' } }, 4 } } },
'{"a\\u0000\\nb": 4}'
)
sp_decode_eq(
{ _TYPE = 'map', _VAL = { { { _TYPE = 'string', _VAL = { 'a\n', 'b', '' } }, 4 } } },
'{"a\\u0000\\nb\\n": 4}'
)
sp_decode_eq({ _TYPE = 'map', _VAL = { { 'a\000\nb', 4 } } }, '{"a\\u0000\\nb": 4}')
sp_decode_eq({ _TYPE = 'map', _VAL = { { 'a\000\nb\n', 4 } } }, '{"a\\u0000\\nb\\n": 4}')
sp_decode_eq({
_TYPE = 'map',
_VAL = {
@ -595,10 +589,7 @@ describe('json_decode() function', function()
{ 'a', 1 },
{ 'c', 4 },
{ 'd', 2 },
{
{ _TYPE = 'string', _VAL = { '\n' } },
4,
},
{ '\000', 4 },
},
}, '{"b": 3, "a": 1, "c": 4, "d": 2, "\\u0000": 4}')
end)
@ -738,22 +729,11 @@ describe('json_encode() function', function()
eq('{"\\u0000": 1}', eval('json_encode(todump)'))
end)
it('can dump generic mapping with BIN special key and NUL', function()
command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n"]}')
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
eq('{"\\u0000": 1}', eval('json_encode(todump)'))
end)
it('can dump STR special mapping with NUL and NL', function()
command('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n", ""]}')
eq('"\\u0000\\n"', eval('json_encode(todump)'))
end)
it('can dump BIN special mapping with NUL and NL', function()
command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n", ""]}')
eq('"\\u0000\\n"', eval('json_encode(todump)'))
end)
it('cannot dump special ext mapping', function()
command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
eq('Vim(call):E474: Unable to convert EXT string to JSON', exc_exec('call json_encode(todump)'))

View File

@ -371,13 +371,14 @@ describe('msgpack*() functions', function()
eq(1, eval('dumped ==# dumped2'))
end)
it('can restore and dump STR string with zero byte', function()
it('can restore and dump STR string contents with zero byte', function()
command('let dumped = ["\\xA1\\n"]')
command('let parsed = msgpackparse(dumped)')
command('let dumped2 = msgpackdump(parsed)')
eq({ { _TYPE = {}, _VAL = { '\n' } } }, eval('parsed'))
eq(1, eval('parsed[0]._TYPE is v:msgpack_types.string'))
eq(1, eval('dumped ==# dumped2'))
eq({ '\000' }, eval('parsed'))
eq(eval('v:t_blob'), eval('type(parsed[0])'))
-- type is not preserved: prefer BIN for binary contents
eq(0, eval('dumped ==# dumped2'))
end)
it('can restore and dump BIN string with NL', function()
@ -428,9 +429,8 @@ describe('msgpackparse() function', function()
parse_eq({ true }, { '\195' })
end)
it('restores FIXSTR as special dict', function()
parse_eq({ { _TYPE = {}, _VAL = { 'ab' } } }, { '\162ab' })
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.string'))
it('restores FIXSTR as string', function()
parse_eq({ 'ab' }, { '\162ab' })
end)
it('restores BIN 8 as string', function()
@ -442,9 +442,8 @@ describe('msgpackparse() function', function()
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.ext'))
end)
it('restores MAP with BIN key as special dictionary', function()
parse_eq({ { _TYPE = {}, _VAL = { { 'a', '' } } } }, { '\129\196\001a\196\n' })
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
it('restores MAP with BIN key as ordinary dictionary', function()
parse_eq({ { a = '' } }, { '\129\196\001a\196\n' })
end)
it('restores MAP with duplicate STR keys as special dictionary', function()
@ -455,14 +454,14 @@ describe('msgpackparse() function', function()
{
_TYPE = {},
_VAL = {
{ { _TYPE = {}, _VAL = { 'a' } }, '' },
{ { _TYPE = {}, _VAL = { 'a' } }, '' },
{ 'a', '' },
{ 'a', '' },
},
},
}, eval('parsed'))
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
eq(1, eval('g:parsed[0]._VAL[0][0]._TYPE is v:msgpack_types.string'))
eq(1, eval('g:parsed[0]._VAL[1][0]._TYPE is v:msgpack_types.string'))
eq(eval('v:t_string'), eval('type(g:parsed[0]._VAL[0][0])'))
eq(eval('v:t_string'), eval('type(g:parsed[0]._VAL[1][0])'))
end)
it('restores MAP with MAP key as special dictionary', function()
@ -802,7 +801,7 @@ describe('msgpackdump() function', function()
it('can dump NULL string', function()
dump_eq({ '\196\n' }, '[$XXX_UNEXISTENT_VAR_XXX]')
dump_eq({ '\196\n' }, '[{"_TYPE": v:msgpack_types.binary, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]')
dump_eq({ '\196\n' }, '[v:_null_blob]')
dump_eq({ '\160' }, '[{"_TYPE": v:msgpack_types.string, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]')
end)