This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
stellar-stellar/deps/utable/test/unit_test_utable.cpp
2024-11-25 19:23:01 +08:00

773 lines
24 KiB
C++

#include <gtest/gtest.h>
#include "base64/b64.h"
#include "utable/utable.h"
#include "cjson/cJSON.h"
#include "mpack/mpack.h"
void test_utable_assert_arr(const struct utable *table, const char *key, int64_t expected_arr[], size_t n_expected_arr)
{
int64_t *arr = NULL;
size_t n_arr = 0;
EXPECT_EQ(utable_get_value_type(table, key), utable_value_type_integer_array);
utable_get0_integer_value_array(table, key, &arr, &n_arr);
EXPECT_EQ(n_arr, n_expected_arr);
for (size_t i = 0; i < n_arr; i++) {
EXPECT_EQ(expected_arr[i], arr[i]);
}
}
void test_utable_assert_str(const struct utable *table, const char *key, const char *expected_str)
{
char *str = NULL;
size_t str_len = 0;
EXPECT_EQ(utable_get_value_type(table, key), utable_value_type_cstring);
utable_get0_cstring_value(table, key, &str, &str_len);
EXPECT_EQ(str_len, strlen(expected_str));
EXPECT_EQ(strncmp(str, expected_str, str_len), 0);
}
void test_utable_assert_str_array(const struct utable *table, const char *key, const char **expected_str_array, size_t n_expected_str)
{
char **str_array = NULL;
size_t *str_len = NULL;
size_t n_str = 0;
EXPECT_EQ(utable_get_value_type(table, key), utable_value_type_cstring_array);
utable_get0_cstring_value_array(table, key, &str_array, &str_len, &n_str);
EXPECT_EQ(n_str, n_expected_str);
for (size_t i = 0; i < n_str; i++) {
EXPECT_EQ(str_len[i], strlen(expected_str_array[i]));
EXPECT_EQ(strncmp(str_array[i], expected_str_array[i], str_len[i]), 0);
}
}
void test_utable_assert_blob(const struct utable *table, const char *key, const char *expected_blob, size_t expected_blob_len)
{
char *blob = NULL;
size_t blob_len = 0;
EXPECT_EQ(utable_get_value_type(table, key), utable_value_type_blob);
utable_get0_blob_value(table, key, &blob, &blob_len);
EXPECT_EQ(blob_len, expected_blob_len);
EXPECT_EQ(memcmp(blob, expected_blob, blob_len), 0);
}
TEST(utable_test, new_del_when_empty)
{
struct utable *table = utable_new();
ASSERT_TRUE(table != NULL);
utable_free(table);
}
TEST(utable_test, add_1_int_and_query)
{
struct utable *table = utable_new();
int64_t int_array[] = { 1 };
utable_add_integer_array(table, "key", int_array, 1);
test_utable_assert_arr(table, "key", int_array, 1);
struct utable_stat A={};
struct utable_stat B={};
B.n_item=1;
B.n_item_size=strlen("key")+sizeof(int64_t);
B.n_integer_array=1;
B.n_integer_array_size=sizeof(int64_t);
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
}
TEST(utable_test, add_2_int_and_query)
{
struct utable *table = utable_new();
int64_t int_array[] = { 1, 2 };
utable_add_integer_array(table, "key", int_array, 2);
test_utable_assert_arr(table, "key", int_array, 2);
struct utable_stat A={};
struct utable_stat B={};
B.n_item=1;
B.n_item_size=strlen("key")+sizeof(int64_t)*2;
B.n_integer_array=1;
B.n_integer_array_size=sizeof(int64_t)*2;
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
}
TEST(utable_test, add_string_and_query)
{
struct utable *table = utable_new();
const char *str = "hello world";
utable_add_cstring(table, "key", str, strlen(str));
test_utable_assert_str(table, "key", str);
struct utable_stat A={};
struct utable_stat B={};
B.n_item=1;
B.n_item_size=strlen("key")+strlen(str);
B.n_cstring=1;
B.n_cstring_size=strlen(str);
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
}
TEST(utable_test, add_string_array_and_query)
{
struct utable *table = utable_new();
const char *str[] = {"hello world", "foo bar"};
size_t n_str=sizeof(str)/sizeof(str[0]);
size_t str_sz[] = {strlen(str[0]), strlen(str[1])};
utable_add_cstring_array(table, "key", str, str_sz, n_str);
test_utable_assert_str_array(table, "key", str, n_str);
struct utable_stat A={};
struct utable_stat B={};
B.n_item=1;
B.n_item_size=strlen("key")+str_sz[0]+str_sz[1];
B.n_cstring_array=1;
B.n_cstring_array_size=str_sz[0]+str_sz[1];
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
}
TEST(utable_test, add_blob_and_query)
{
struct utable *table = utable_new();
const char *blob = "hello world";
size_t blob_len = strlen(blob);
utable_add_blob(table, "key", blob, blob_len);
test_utable_assert_blob(table, "key", blob, blob_len);
struct utable_stat A={};
struct utable_stat B={};
B.n_item=1;
B.n_item_size=strlen("key")+blob_len;
B.n_blob=1;
B.n_blob_size=blob_len;
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
}
void test_utable_check_if_value_in_json(cJSON *tag_obj, const char *key, const std::string &value)
{
cJSON *tag_val = cJSON_GetObjectItem(tag_obj, key);
EXPECT_NE(tag_val, nullptr);
EXPECT_STREQ(tag_val->valuestring, value.c_str());
}
void test_utable_check_if_value_in_json(cJSON *tag_obj, const char *key, const char *value[], size_t n_value)
{
cJSON *tag_val = cJSON_GetObjectItem(tag_obj, key);
EXPECT_NE(tag_val, nullptr);
EXPECT_EQ(tag_val->type, cJSON_Array);
int arr_size = cJSON_GetArraySize(tag_val);
EXPECT_EQ(arr_size, n_value);
for (int i = 0; i < arr_size; i++) {
cJSON *arr_item = cJSON_GetArrayItem(tag_val, i);
EXPECT_STREQ(arr_item->valuestring, value[i]);
}
}
void test_utable_check_if_value_in_json(cJSON *tag_obj, const char *key, int64_t value[], size_t n_value)
{
cJSON *tag_val = cJSON_GetObjectItem(tag_obj, key);
EXPECT_NE(tag_val, nullptr);
EXPECT_EQ(tag_val->type, cJSON_Array);
int arr_size = cJSON_GetArraySize(tag_val);
EXPECT_EQ(arr_size, n_value);
for (int i = 0; i < arr_size; i++) {
cJSON *arr_item = cJSON_GetArrayItem(tag_val, i);
EXPECT_EQ(arr_item->valueint, value[i]);
}
}
void test_utable_check_if_value_in_json(cJSON *tag_obj, const char *key, const char *value, size_t blob_len)
{
cJSON *tag_val = cJSON_GetObjectItem(tag_obj, key);
EXPECT_NE(tag_val, nullptr);
// the tag_val is encoded in base64
size_t dec_size = 0;
unsigned char *dec = b64_decode_ex(tag_val->valuestring, strlen(tag_val->valuestring), &dec_size);
EXPECT_EQ(dec_size, blob_len);
EXPECT_EQ(memcmp(dec, value, blob_len), 0);
free(dec);
}
TEST(utable_test, export_json)
{
struct utable *table = utable_new();
int64_t int_array[] = { 1, 2 };
const char *str = "hello world";
const char *blob = "bin hello world";
const char *str_array[] = {"hello world", "foo bar"};
size_t n_str=sizeof(str_array)/sizeof(str_array[0]);
size_t str_sz[] = {strlen(str_array[0]), strlen(str_array[1])};
utable_add_integer_array(table, "key1", int_array, 2);
utable_add_cstring(table, "key2", str, strlen(str));
utable_add_blob(table, "key3", blob, strlen(blob));
utable_add_cstring_array(table, "key4", str_array, str_sz, n_str);
char *json = NULL;
size_t json_len = 0;
EXPECT_EQ(utable_json_export(table, &json, &json_len), 0);
EXPECT_NE(nullptr, json);
cJSON *root = cJSON_Parse(json);
test_utable_check_if_value_in_json(root, "key1", int_array, 2);
std::string expected_str(str);
test_utable_check_if_value_in_json(root, "key2", expected_str);
test_utable_check_if_value_in_json(root, "key3", blob, strlen(blob));
test_utable_check_if_value_in_json(root, "key4", str_array, n_str);
struct utable_stat A={};
struct utable_stat B={};
B.n_item=4;
B.n_item_size=strlen("key1")+sizeof(int64_t)*2+strlen("key2")+strlen(str)+strlen("key3")+strlen(blob)+strlen("key4")+str_sz[0]+str_sz[1];
B.n_blob=1;
B.n_blob_size=strlen(blob);
B.n_cstring=1;
B.n_cstring_size=strlen(str);
B.n_integer_array=1;
B.n_integer_array_size=sizeof(int64_t)*2;
B.n_integer=0;
B.n_integer_size=0;
B.n_cstring_array=1;
B.n_cstring_array_size=str_sz[0]+str_sz[1];
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
free(json);
cJSON_Delete(root);
}
TEST(utable_test, export_invalid_unicode_string_to_json)
{
struct utable *table = utable_new();
const char *str = "googleads.g.doublec\x86rck.net";
utable_add_cstring(table, "key2", str, strlen(str));
char *json = NULL;
size_t json_len = 0;
EXPECT_EQ(utable_json_export(table, &json, &json_len), 0);
EXPECT_NE(nullptr, json);
cJSON *root = cJSON_Parse(json);
std::string expected_str(str);
test_utable_check_if_value_in_json(root, "key2", expected_str);
struct utable_stat A={};
struct utable_stat B={};
B.n_item=1;
B.n_item_size=strlen("key2")+strlen(str);
B.n_cstring=1;
B.n_cstring_size=strlen(str);
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
free(json);
cJSON_Delete(root);
}
char *test_get_cstring_from_mpack_node(mpack_node_t node)
{
size_t len = mpack_node_strlen(node);
char *str = (char *)malloc(len + 1);
memcpy(str, mpack_node_str(node), len);
str[len] = '\0';
return str;
}
void test_utable_check_if_value_in_mpack(mpack_node_t item, const char *key, const std::string &value)
{
mpack_node_t key_node = mpack_node_map_cstr(item, "key");
mpack_node_t type_node = mpack_node_map_cstr(item, "type");
mpack_node_t value_node = mpack_node_map_cstr(item, "value");
char *key_tmp = test_get_cstring_from_mpack_node(key_node);
char *type_tmp = test_get_cstring_from_mpack_node(type_node);
char *value_tmp = test_get_cstring_from_mpack_node(value_node);
EXPECT_STREQ(key_tmp, key);
EXPECT_STREQ(type_tmp, "c_str");
EXPECT_STREQ(value_tmp, value.c_str());
free(key_tmp);
free(type_tmp);
free(value_tmp);
}
void test_utable_check_if_value_in_mpack(mpack_node_t item, const char *key, int64_t value[], size_t n_value)
{
mpack_node_t key_node = mpack_node_map_cstr(item, "key");
mpack_node_t type_node = mpack_node_map_cstr(item, "type");
mpack_node_t value_node = mpack_node_map_cstr(item, "value");
char *key_tmp = test_get_cstring_from_mpack_node(key_node);
char *type_tmp = test_get_cstring_from_mpack_node(type_node);
EXPECT_STREQ(key_tmp, key);
EXPECT_STREQ(type_tmp, "i_arr");
EXPECT_EQ(mpack_node_array_length(value_node), n_value);
for (size_t i = 0; i < n_value; i++) {
mpack_node_t tmp_v_node = mpack_node_array_at(value_node, i);
EXPECT_EQ(mpack_node_i64(tmp_v_node), value[i]);
}
free(key_tmp);
free(type_tmp);
}
void test_utable_check_if_value_in_mpack(mpack_node_t item, const char *key, const char *value, size_t blob_len)
{
mpack_node_t key_node = mpack_node_map_cstr(item, "key");
mpack_node_t type_node = mpack_node_map_cstr(item, "type");
mpack_node_t value_node = mpack_node_map_cstr(item, "value");
char *key_tmp = test_get_cstring_from_mpack_node(key_node);
char *type_tmp = test_get_cstring_from_mpack_node(type_node);
EXPECT_STREQ(key_tmp, key);
EXPECT_STREQ(type_tmp, "blob");
EXPECT_EQ(mpack_node_bin_size(value_node), blob_len);
EXPECT_EQ(memcmp(mpack_node_bin_data(value_node), value, blob_len), 0);
free(key_tmp);
free(type_tmp);
}
TEST(utable_test, DISABLED_export_mpack)
{
struct utable *table = utable_new();
int64_t int_array[] = { 1, 2 };
const char *str = "hello world";
const char *blob = "bin hello world";
utable_add_integer_array(table, "key1", int_array, 2);
utable_add_cstring(table, "key2", str, strlen(str));
utable_add_blob(table, "key3", blob, strlen(blob));
char *mpack = NULL;
size_t mpack_len = 0;
EXPECT_EQ(utable_msgpack_export(table, &mpack, &mpack_len), 0);
mpack_tree_t tree;
mpack_tree_init_data(&tree, mpack, mpack_len);
mpack_tree_parse(&tree);
mpack_node_t root = mpack_tree_root(&tree);
size_t n_item = mpack_node_array_length(root);
EXPECT_EQ(n_item, 3);
test_utable_check_if_value_in_mpack(mpack_node_array_at(root, 0), "key1", int_array, 2);
std::string expected_str(str);
test_utable_check_if_value_in_mpack(mpack_node_array_at(root, 1), "key2", expected_str);
test_utable_check_if_value_in_mpack(mpack_node_array_at(root, 2), "key3", blob, strlen(blob));
utable_free(table);
free(mpack);
mpack_tree_destroy(&tree);
}
TEST(utable_test, add_blob_then_del)
{
struct utable *table = utable_new();
const char *blob = "hello world";
size_t blob_len = strlen(blob);
utable_add_blob(table, "key", blob, blob_len);
test_utable_assert_blob(table, "key", blob, blob_len);
struct utable_stat A={};
struct utable_stat B={};
B.n_item=1;
B.n_item_size=strlen("key")+strlen(blob);
B.n_blob=1;
B.n_blob_size=strlen(blob);
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
char *value;
size_t value_len;
utable_delete(table, "key", strlen("key"));
EXPECT_EQ(utable_get0_blob_value(table, "key", &value, &value_len), -1);
EXPECT_EQ(utable_get0_cstring_value(table, "key", &value, &value_len), -1);
int64_t *value_array;
size_t n_value;
EXPECT_EQ(utable_get0_integer_value_array(table, "key", &value_array, &n_value), -1);
EXPECT_EQ(utable_get_value_type(table, "key"), utable_value_type_undefined);
struct utable_stat C={};
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &C, sizeof(struct utable_stat)), 0);
utable_free(table);
}
TEST(utable_test, add_string_array_then_del)
{
struct utable *table = utable_new();
const char *str[] = {"hello world", "foo bar"};
size_t n_str=sizeof(str)/sizeof(str[0]);
size_t str_sz[] = {strlen(str[0]), strlen(str[1])};
utable_add_cstring_array(table, "key", str, str_sz, n_str);
test_utable_assert_str_array(table, "key", str, n_str);
struct utable_stat A={};
struct utable_stat B={};
B.n_item=1;
B.n_item_size=strlen("key")+str_sz[0]+str_sz[1];
B.n_cstring_array=1;
B.n_cstring_array_size=str_sz[0]+str_sz[1];
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
char *value;
size_t value_len;
utable_delete(table, "key", strlen("key"));
EXPECT_EQ(utable_get0_blob_value(table, "key", &value, &value_len), -1);
EXPECT_EQ(utable_get0_cstring_value(table, "key", &value, &value_len), -1);
int64_t *value_array;
size_t n_value;
EXPECT_EQ(utable_get0_integer_value_array(table, "key", &value_array, &n_value), -1);
char **str_array = NULL;
size_t *str_len = NULL;
n_str = 0;
EXPECT_EQ(utable_get0_cstring_value_array(table, "key", &str_array, &str_len, &n_str), -1);
EXPECT_EQ(utable_get_value_type(table, "key"), utable_value_type_undefined);
struct utable_stat C={};
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &C, sizeof(struct utable_stat)), 0);
utable_free(table);
}
TEST(utable_test, query_on_wrong_key)
{
struct utable *table = utable_new();
char *value;
size_t value_len;
EXPECT_EQ(utable_get0_blob_value(table, "key", &value, &value_len), -1);
EXPECT_EQ(utable_get0_cstring_value(table, "key", &value, &value_len), -1);
int64_t *value_array;
size_t n_value;
EXPECT_EQ(utable_get0_integer_value_array(table, "key", &value_array, &n_value), -1);
EXPECT_EQ(utable_get_value_type(table, "key"), utable_value_type_undefined);
utable_free(table);
}
TEST(utable_test, add_on_dup_key)
{
struct utable *table = utable_new();
int64_t int_array[] = { 1, 2 };
const char *str = "hello world";
utable_add_integer_array(table, "key", int_array, 2);
utable_add_cstring(table, "key", str, strlen(str));
test_utable_assert_arr(table, "key", int_array, 2);
struct utable_stat A={};
struct utable_stat B={};
B.n_item=1;
B.n_item_size=strlen("key")+sizeof(int64_t)*2;
B.n_integer_array=1;
B.n_integer_array_size=sizeof(int64_t)*2;
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
}
TEST(utable_test, iter_and_query)
{
struct utable *table = utable_new();
int64_t int_array[] = { 1, 2 };
const char *str = "hello world";
utable_add_integer_array(table, "key1", int_array, 2);
utable_add_cstring(table, "key2", str, strlen(str));
utable_add_integer_array(table, "key3", int_array, 2);
EXPECT_STREQ(utable_next_key(table), "key1");
EXPECT_STREQ(utable_next_key(table), "key2");
EXPECT_STREQ(utable_next_key(table), "key3");
EXPECT_EQ(utable_next_key(table), nullptr);
utable_reset_iter(table);
EXPECT_STREQ(utable_next_key(table), "key1");
EXPECT_STREQ(utable_next_key(table), "key2");
EXPECT_STREQ(utable_next_key(table), "key3");
EXPECT_EQ(utable_next_key(table), nullptr);
struct utable_stat A={};
struct utable_stat B={};
B.n_item=3;
B.n_item_size=strlen("key1")+sizeof(int64_t)*2+strlen("key2")+strlen(str)+strlen("key3")+sizeof(int64_t)*2;
B.n_blob=0;
B.n_blob_size=0;
B.n_cstring=1;
B.n_cstring_size=strlen(str);
B.n_integer_array=2;
B.n_integer_array_size=sizeof(int64_t)*4;
B.n_integer=0;
B.n_integer_size=0;
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
}
TEST(utable_test, dup_empty)
{
struct utable *table = utable_new();
struct utable *dup_table = utable_duplicate(table);
EXPECT_EQ(utable_next_key(dup_table), nullptr);
utable_free(table);
utable_free(dup_table);
}
TEST(utable_test, dup_and_query)
{
struct utable *table = utable_new();
const char *str = "hello world";
utable_add_cstring(table, "key1", str, strlen(str));
int64_t int_array[] = { 1, 2 };
utable_add_integer_array(table, "key2", int_array, 2);
const char *blob = "bin hello world";
utable_add_blob(table, "key3", blob, strlen(blob));
struct utable *dup_table = utable_duplicate(table);
test_utable_assert_arr(dup_table, "key2", int_array, 2);
test_utable_assert_str(dup_table, "key1", str);
test_utable_assert_blob(dup_table, "key3", blob, strlen(blob));
struct utable_stat A={}, B={};
utable_stat(table, &A);
utable_stat(dup_table, &B);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
utable_free(dup_table);
}
TEST(utable_test, replace_8k_cstring)
{
struct utable *table = utable_new();
const char str1[] = "hello world";
char str2[8192];
memset(str2, 'B', sizeof(str2));
str2[8191] = '\0'; // make sure it's null-terminated
utable_add_cstring(table, "key1", str1, strlen(str1));
test_utable_assert_str(table, "key1", str1);
utable_delete(table, "key1", strlen("key1"));
utable_add_cstring(table, "key1", str2, strlen(str2));
test_utable_assert_str(table, "key1", str2);
struct utable_stat A={};
struct utable_stat B={};
B.n_item=1;
B.n_item_size=strlen("key1")+strlen(str2);
B.n_cstring=1;
B.n_cstring_size=strlen(str2);
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
}
TEST(utable_test, replace_cstring_1w_times)
{
struct utable *table = utable_new();
char str[4000] ;
memset(str, 'B', sizeof(str));
str[3999] = '\0'; // make sure it's null-terminated
utable_add_cstring(table, "key1", str, strlen(str));
test_utable_assert_str(table, "key1", str);
for(int i=0; i<10000; i++)
{
utable_delete(table, "key1", strlen("key1"));
utable_add_cstring(table, "key1", str, strlen(str));
}
test_utable_assert_str(table, "key1", str);
struct utable_stat A={};
struct utable_stat B={};
B.n_item=1;
B.n_item_size=strlen("key1")+strlen(str);
B.n_cstring=1;
B.n_cstring_size=strlen(str);
utable_stat(table, &A);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
printf("replace_cstring_many_times done\n");
utable_free(table);
}
TEST(utable_test, merge_empty_to_empty)
{
struct utable *table = utable_new();
struct utable *table2 = utable_new();
utable_union(table, table2);
EXPECT_EQ(utable_next_key(table), nullptr);
struct utable_stat A={}, B={};
utable_stat(table, &A);
utable_stat(table2, &B);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
utable_free(table2);
}
TEST(utable_test, merge_all_new)
{
struct utable *table = utable_new();
struct utable *table2 = utable_new();
const char *str = "hello world";
utable_add_cstring(table, "key1", str, strlen(str));
int64_t int_array[] = { 1, 2 };
utable_add_integer_array(table, "key2", int_array, 2);
const char *blob = "bin hello world";
utable_add_blob(table2, "key on tbl2", blob, strlen(blob));
utable_union(table2, table);
test_utable_assert_arr(table2, "key2", int_array, 2);
test_utable_assert_str(table2, "key1", str);
test_utable_assert_blob(table2, "key on tbl2", blob, strlen(blob));
utable_union(table, table2);
struct utable_stat A={}, B={};
utable_stat(table, &A);
utable_stat(table2, &B);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
utable_free(table2);
}
TEST(utable_test, merge_all_skip)
{
struct utable *table = utable_new();
const char *str = "hello world";
utable_add_cstring(table, "key1", str, strlen(str));
int64_t int_array[] = { 1, 2 };
utable_add_integer_array(table, "key2", int_array, 2);
struct utable *table2 = utable_duplicate(table);
utable_union(table2, table);
EXPECT_STREQ(utable_next_key(table2), "key1");
EXPECT_STREQ(utable_next_key(table2), "key2");
EXPECT_EQ(utable_next_key(table2), nullptr);
utable_free(table);
utable_free(table2);
}
TEST(utable_test, merge_some_skip_some_new)
{
struct utable *table = utable_new();
struct utable *table2 = utable_new();
const char *str = "val on tbl1";
utable_add_cstring(table, "key_share", str, strlen(str));
const char *str2 = "val on tbl2";
utable_add_cstring(table2, "key_share", str2, strlen(str2));
const char *str3 = "val on tbl1";
utable_add_cstring(table, "key1", str3, strlen(str3));
utable_union(table2, table);
test_utable_assert_str(table2, "key_share", str2);
test_utable_assert_str(table2, "key1", str3);
utable_free(table);
utable_free(table2);
}
TEST(utable_test, serialize_and_deserialize)
{
struct utable *table = utable_new();
int64_t int_array[] = { 1, 2 };
const char *str = "hello world";
const char *blob = "bin hello world";
utable_add_integer_array(table, "key1", int_array, 2);
utable_add_cstring(table, "key2", str, strlen(str));
utable_add_blob(table, "key3", blob, strlen(blob));
char *blob_out;
size_t blob_size;
utable_serialize(table, &blob_out, &blob_size);
struct utable *table2 = utable_deserialize(blob_out, blob_size);
test_utable_assert_arr(table2, "key1", int_array, 2);
test_utable_assert_str(table2, "key2", str);
test_utable_assert_blob(table2, "key3", blob, strlen(blob));
struct utable_stat A={}, B={};
utable_stat(table, &A);
utable_stat(table2, &B);
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
utable_free(table);
free(blob_out);
utable_free(table2);
}
TEST(utable_test, serialize_empty_and_deserialize)
{
struct utable *table = utable_new();
char *blob_out;
size_t blob_size;
utable_serialize(table, &blob_out, &blob_size);
struct utable *table2 = utable_deserialize(blob_out, blob_size);
ASSERT_TRUE(table2 != NULL);
ASSERT_EQ(utable_next_key(table2), nullptr);
utable_free(table);
free(blob_out);
utable_free(table2);
}
int main(int argc, char *argv[])
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}