From 0a7ca4b2ed70f0f8c903a73e2a0293ef4ea7b92e Mon Sep 17 00:00:00 2001 From: Roman Tsisyk <roman@tarantool.org> Date: Tue, 20 Jun 2017 14:42:42 +0300 Subject: [PATCH] Review fixes for tuple_to_yaml() * Fix handling of encoded data * Remove \n added by libyaml * Add a test case Follow up #128 --- src/box/tuple_convert.c | 47 +++++++++++++++++++++++++---------------- test/box/tuple.result | 30 ++++++++++++++++++++++++++ test/box/tuple.test.lua | 13 +++++++++++- 3 files changed, 71 insertions(+), 19 deletions(-) diff --git a/src/box/tuple_convert.c b/src/box/tuple_convert.c index 6cb79e8013..300ca8918b 100644 --- a/src/box/tuple_convert.c +++ b/src/box/tuple_convert.c @@ -64,12 +64,13 @@ int append_output(void *arg, unsigned char *buf, size_t len) { (void) arg; - char *buf_out = region_alloc(&fiber()->gc, len); + char *buf_out = region_alloc(&fiber()->gc, len + 1); if (!buf_out) { - diag_set(OutOfMemory, len , "region_alloc", "append_output"); + diag_set(OutOfMemory, len , "region", "tuple_to_yaml"); return 0; } memcpy(buf_out, buf, len); + buf_out[len] = '\0'; return 1; } @@ -132,17 +133,19 @@ encode_array(yaml_emitter_t *emitter, const char **data) return 1; } +#define LUAYAML_TAG_PREFIX "tag:yaml.org,2002:" + static int encode_node(yaml_emitter_t *emitter, const char **data) { size_t len = 0; const char *str = ""; + size_t binlen = 0; + char *bin = NULL; yaml_char_t *tag = NULL; yaml_event_t ev; yaml_scalar_style_t style = YAML_PLAIN_SCALAR_STYLE; - int is_binary = 0; char buf[FPCONV_G_FMT_BUFSIZE]; - char *binary_encode = NULL; int type = mp_typeof(**data); switch(type) { case MP_UINT: @@ -184,16 +187,17 @@ encode_node(yaml_emitter_t *emitter, const char **data) } style = YAML_ANY_SCALAR_STYLE; /* Binary or not UTF8 */ - is_binary = 1; - binary_encode = (char *) malloc(base64_bufsize(len)); - if (binary_encode == NULL) { - diag_set(OutOfMemory, base64_bufsize(len), - "malloc", "tuple_to_yaml"); + binlen = base64_bufsize(len); + bin = (char *) malloc(binlen); + if (bin == NULL) { + diag_set(OutOfMemory, binlen, "malloc", + "tuple_to_yaml"); return 0; } - base64_encode(str, len, binary_encode, base64_bufsize(len)); - str = binary_encode; - tag = (yaml_char_t *) "binary"; + binlen = base64_encode(str, len, bin, binlen); + str = bin; + len = binlen; + tag = (yaml_char_t *) LUAYAML_TAG_PREFIX "binary"; break; case MP_BOOL: if (mp_decode_bool(data)) { @@ -206,7 +210,11 @@ encode_node(yaml_emitter_t *emitter, const char **data) break; case MP_NIL: case MP_EXT: - mp_decode_nil(data); + if (type == MP_NIL) { + mp_decode_nil(data); + } else { + mp_next(data); + } style = YAML_PLAIN_SCALAR_STYLE; str = "null"; len = 4; @@ -217,14 +225,14 @@ encode_node(yaml_emitter_t *emitter, const char **data) int rc = 1; if (!yaml_scalar_event_initialize(&ev, NULL, tag, (unsigned char *)str, - len, !is_binary, !is_binary, + len, bin == NULL, bin == NULL, style) || !yaml_emitter_emit(emitter, &ev)) { diag_set(OutOfMemory, len, "malloc", "tuple_to_yaml"); rc = 0; } - if (is_binary) - free(binary_encode); + if (bin != NULL) + free(bin); return rc; } @@ -244,8 +252,7 @@ tuple_to_yaml(const struct tuple *tuple) } yaml_emitter_set_unicode(&emitter, 1); yaml_emitter_set_indent(&emitter, 2); - yaml_emitter_set_width(&emitter, 2); - yaml_emitter_set_break(&emitter, YAML_LN_BREAK); + yaml_emitter_set_width(&emitter, INT_MAX); yaml_emitter_set_output(&emitter, &append_output, NULL); if (!yaml_stream_start_event_initialize(&ev, YAML_UTF8_ENCODING) || @@ -275,6 +282,10 @@ tuple_to_yaml(const struct tuple *tuple) diag_set(OutOfMemory, total_len, "region", "tuple_to_yaml"); return NULL; } + /* Remove trailing "\n\0" added by libyaml */ + assert(total_len > 2); + assert(buf[total_len - 1] == '\0' && buf[total_len - 2] == '\n'); + buf[total_len - 2] = '\0'; return buf; error: yaml_emitter_delete(&emitter); diff --git a/test/box/tuple.result b/test/box/tuple.result index 7f119c8235..7e0fd7b059 100644 --- a/test/box/tuple.result +++ b/test/box/tuple.result @@ -978,6 +978,36 @@ collectgarbage('collect') -- collect huge string --- - 0 ... +-- testing tostring +test_run:cmd("setopt delimiter ';'") +--- +- true +... +null = nil +t = box.tuple.new({1, -2, 1.2, -1.2}, 'x', 'y', 'z', null, true, false, + {bin = "\x08\x5c\xc2\x80\x12\x2f", + big_num = tonumber64('18446744073709551615'), + map = {key = "value"}, + double=1.0000000001, + utf8="Кудыкины горы"}); +--- +... +tostring(t); +--- +- '[[1, -2, 1.2, -1.2], ''x'', ''y'', ''z'', null, true, false, {''big_num'': 18446744073709551615, + ''double'': 1.0000000001, ''utf8'': ''Кудыкины горы'', ''bin'': !!binary CFzCgBIv, + ''map'': {''key'': ''value''}}]' +... +t; +--- +- [[1, -2, 1.2, -1.2], 'x', 'y', 'z', null, true, false, {'big_num': 18446744073709551615, + 'double': 1.0000000001, 'utf8': 'Кудыкины горы', 'bin': !!binary CFzCgBIv, 'map': { + 'key': 'value'}}] +... +test_run:cmd("setopt delimiter ''"); +--- +- true +... test_run:cmd("clear filter") --- - true diff --git a/test/box/tuple.test.lua b/test/box/tuple.test.lua index f7d700990d..a006b3f7b3 100644 --- a/test/box/tuple.test.lua +++ b/test/box/tuple.test.lua @@ -208,7 +208,6 @@ test_run:cmd("setopt delimiter ';'") t = box.tuple.new({'a','b','c','a', -1, 0, 1, 2, true, 9223372036854775807ULL, -9223372036854775807LL}); test_run:cmd("setopt delimiter ''"); - t:find('a') t:find(1, 'a') t:find('c') @@ -321,4 +320,16 @@ ffi.typeof('struct tuple') box.tuple.new(string.rep('x', 100 * 1024 * 1024)) == nil collectgarbage('collect') -- collect huge string +-- testing tostring +test_run:cmd("setopt delimiter ';'") +null = nil +t = box.tuple.new({1, -2, 1.2, -1.2}, 'x', 'y', 'z', null, true, false, + {bin = "\x08\x5c\xc2\x80\x12\x2f", + big_num = tonumber64('18446744073709551615'), + map = {key = "value"}, + double=1.0000000001, + utf8="Кудыкины горы"}); +tostring(t); +t; +test_run:cmd("setopt delimiter ''"); test_run:cmd("clear filter") -- GitLab