1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00
Files
mariadb/unittest/sql/json_reader-t.cc

277 lines
8.3 KiB
C++

/*
Copyright (c) 2026, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
#include <my_global.h>
#include <my_pthread.h>
#include <my_sys.h>
#include <stdio.h>
#include <tap.h>
/*
Unit tests for json_read_object()
*/
#include "../sql/sql_json_lib.h"
#include "../sql/sql_json_lib.cc"
#include "json_lib.h"
using namespace json_reader;
/**************************************************************************
* Nested objects/arrays parsing tests
**************************************************************************/
class Level1_struct
{
public:
char *idx_name;
};
/*
Parse a JSON object into Level1_struct.
*/
Level1_struct* parse_level1_struct(MEM_ROOT *mem_root, json_engine_t *je,
String *err_buf)
{
//const char *err_msg= "Expected an object in the indexes array";
char *str;
Read_named_member array[]= {
{"index_name", Read_string(mem_root, &str), false},
{NULL, Read_double(NULL), true}};
int rc;
rc= json_read_object(je, array, err_buf);
if (rc)
return NULL;
return new Level1_struct{str};
}
class Level2_struct
{
public:
Level1_struct *child1;
Level1_struct *child2;
};
/*
Parse JSON into Level2_struct.
Level2_struct is structure with another two structures in it.
*/
static
Level2_struct* parse_level2_struct(MEM_ROOT *mem_root,
json_engine_t *je,
String *err_buf)
{
Level1_struct *ps1;
Level1_struct *ps2;
Read_named_member memb[]=
{
{"object1",
Read_object<Level1_struct>(mem_root, &ps1, parse_level1_struct),
false
},
{"object2",
Read_object<Level1_struct>(mem_root, &ps2, parse_level1_struct),
false
},
{NULL, Read_double(NULL), true}
};
int rc;
rc= json_read_object(je, memb, err_buf);
if (rc)
return NULL;
return new Level2_struct{ps1, ps2};
}
/*
Parse a JSON object that has an array of Level1_struct objects.
*/
int parse_array_of_level1_struct(MEM_ROOT *mem_root, json_engine_t *je,
String *err_buf, const char *js_doc,
List<Level1_struct> *index_list)
{
json_scan_start(je, &my_charset_utf8mb4_bin, (const uchar *) js_doc,
(const uchar *) js_doc + strlen(js_doc));
Read_named_member array[]= {
{"indexes",
Read_object_array<Level1_struct>(mem_root, index_list,
parse_level1_struct),
true},
{NULL, Read_double(NULL), true}};
int rc= json_read_object(je, array, err_buf);
return rc;
}
void test_parse_array_of_objects(MEM_ROOT *mem_root, json_engine_t *je)
{
String err_buf;
int rc;
const char *two_elems_doc=
"{ \n"
" \"indexes\" : [ \n"
" { \n"
" \"index_name\":\"index1\" \n"
" }, \n"
" { \n"
" \"index_name\":\"index2\" \n"
" } \n"
" ] \n"
"}";
List<Level1_struct> two_elems_list;
rc= parse_array_of_level1_struct(mem_root, je, &err_buf, two_elems_doc,
&two_elems_list);
ok(!rc, "Array of two objects parsed successfully");
ok(two_elems_list.elements == 2, ".. Got two objects");
const char *no_elems_doc=
"{ \n"
" \"indexes\" : [ \n"
" ] \n"
"}";
List<Level1_struct> no_elems_list;
rc= parse_array_of_level1_struct(mem_root, je, &err_buf, no_elems_doc,
&no_elems_list);
ok(!rc, "Empty array of objects parsed successfully");
ok(two_elems_list.elements == 2, ".. Got an empty list");
}
void test_parse_nested_object(MEM_ROOT *mem_root, json_engine_t *je)
{
String err_buf;
const char *js_doc=
"{ \n"
" \"object1\" : \n"
" { \n"
" \"index_name\":\"index1\" \n"
" }, \n"
" \"object2\" : \n"
" { \n"
" \"index_name\":\"index2\" \n"
" } \n"
" } \n"
"}";
json_scan_start(je, &my_charset_utf8mb4_bin, (const uchar *) js_doc,
(const uchar *) js_doc + strlen(js_doc));
Level2_struct *data= parse_level2_struct(mem_root, je, &err_buf);
ok(data!=NULL, "Nested object successfully");
ok(!strcmp(data->child1->idx_name, "index1"), "Child object 1 is ok");
ok(!strcmp(data->child2->idx_name, "index2"), "Child object 2 is ok");
}
int main(int args, char **argv)
{
MY_INIT(argv[0]);
plan(NO_PLAN);
diag("Testing json_read_object checks");
MEM_ROOT alloc;
json_engine_t je;
int rc;
init_alloc_root(0, &alloc, 32768, 0, 0);
mem_root_dynamic_array_init(&alloc, 0, &je.stack,
sizeof(int), NULL, JSON_DEPTH_DEFAULT,
JSON_DEPTH_INC, MYF(0));
system_charset_info= &my_charset_utf8mb3_bin;
String err_buf;
/* Basic json_read_object test */
{
const char *js_doc="{ \"str_val\": \"abc\", \"double_val\": 1234.5 }";
json_scan_start(&je, &my_charset_utf8mb3_bin, (const uchar *) js_doc,
(const uchar *) js_doc + strlen(js_doc));
char *parsed_name;
double parsed_dbl;
Read_named_member array[]= {
{"str_val", Read_string(&alloc, &parsed_name), false},
{"double_val", Read_double(&parsed_dbl), false},
{NULL, Read_double(NULL), false }
};
rc= json_read_object(&je, array, &err_buf);
ok(!rc, "Basic object read");
}
/* Test that reading handles characters correctly. */
{
/* utf8mb4 character, U+1F600 Grinning Face: */
const char *field_val="\xF0\x9F\x98\x80";
const char *js_doc="{ \"str\" : \"\xF0\x9F\x98\x80\"}";
json_scan_start(&je, &my_charset_utf8mb4_bin, (const uchar *) js_doc,
(const uchar *) js_doc + strlen(js_doc));
char *str;
Read_named_member array[]= {
{"str", Read_string(&alloc, &str), false},
{NULL, Read_double(NULL), false }
};
rc= json_read_object(&je, array, &err_buf);
ok(!rc, "Success reading UTF-8 grinning face (with wchar_t > 255)");
ok(!strcmp(str, field_val), "Got correct value for grinning face");
}
diag("Test reading array-of-strings");
{
const char *js_doc="{ \"arr\" : [\"foo\", \"bar\", \"baz\"] }";
json_scan_start(&je, &my_charset_utf8mb4_bin, (const uchar *) js_doc,
(const uchar *) js_doc + strlen(js_doc));
List<char> str_array;
Read_named_member array[]= {
{"arr", Read_array_of_strings(&alloc, &str_array), false},
{NULL, Read_double(NULL), false }
};
rc= json_read_object(&je, array, &err_buf);
ok(!rc, "Success parsing 3-element array");
ok(str_array.elements == 3, "Got 3-element array");
}
{
const char *js_doc="{ \"arr\" : [] }";
json_scan_start(&je, &my_charset_utf8mb4_bin, (const uchar *) js_doc,
(const uchar *) js_doc + strlen(js_doc));
List<char> str_array;
Read_named_member array[]= {
{"arr", Read_array_of_strings(&alloc, &str_array), false},
{NULL, Read_double(NULL), false }
};
rc= json_read_object(&je, array, &err_buf);
ok(!rc, "Success parsing empty array");
ok(str_array.elements == 0, "Got an empty array");
}
test_parse_array_of_objects(&alloc, &je);
test_parse_nested_object(&alloc, &je);
free_root(&alloc, 0);
diag("Done");
my_end(MY_CHECK_ERROR);
return exit_status();
}