rizin/test/unit/test_sdb_diff.c
Anton Angelov 95f94ae258
refactor: SwissTable implementation for ht (#5860)
* Add ht benchmarks
* Initial implementation
* Finalize native per-group lookup support
* Lookup SSE2 implementation
* Improve hashing
* Add support for custom elem_size
* Avoid double h2 hashing when reserving slot
* Make custom elem_size support conditional
* Fix issues with bitwise and default lookup implementations
* Implement deletion trick optimization
* Track growth_size instead of deleted_slots
* Refactor SDB to access ht via API instead of internals
* Modify SDB tests which rely on hashtable order
* Fix SDB build warnings
* Fix bug with finding next power of two
* foreach_kv to return a bool result
* Change SDB diff order expected by serialize_analysis unit test
* Fix bug in the bitwise lookup implementation
* Remove second call to rz_core_init() which causes memory leaks
* Update some regression tests to accept reordered output
* Adapt ht clear to new implementation
* Use fini_kv_pair and fix 1 potential leak on malloc failure
* Fix cmd/types test after merge
* Avoid second call to calsize_key and avoid iter leaks on malloc failure
* Improve hash distribution
* Extend benchmark suite
* Fix bug with string hashing
* Branchless write to mirrored ctrl bytes
* Simplify string hash and remove potential UB
* Move RZ_PREFETCH macro to rz_types.h
* Add SSE2 discovery in Meson
* Forward SDB string hash function to ht string hash
* Try to revert test_cpu_profiles() to avoid relying on a baked SDB file
* Revert SDB/CDB hash function change
* Fix SDB reference to HT hash function instead of CDB hash
* Change calloc to malloc
* Avoid storing/checking key_len and key_value if they are ut64
* Improve string hash function
* Rename default hash functions
* Improve bench code
* linter.yml: set clang-path to point to llvm-18
2026-03-02 12:31:35 +08:00

258 lines
6.2 KiB
C

// SPDX-FileCopyrightText: pancake <pancake@nopcode.org>
// SPDX-License-Identifier: MIT
#include <sdb.h>
#include "minunit.h"
// #define SAVE_FILES
static Sdb *test_sdb_new(const char *file) {
#ifdef SAVE_FILES
Sdb *r = sdb_new(NULL, file, 0);
// sdb_disk_create (r);
#else
Sdb *r = sdb_new0();
#endif
sdb_set(r, "some", "stuff");
sdb_set(r, "and", "even");
sdb_set(r, "more", "stuff");
sdb_ns(r, "emptyns", true);
Sdb *test_ns = sdb_ns(r, "test", true);
sdb_set(test_ns, "a", "123");
sdb_set(test_ns, "b", "test");
sdb_set(test_ns, "c", "hello");
Sdb *subspace_ns = sdb_ns(test_ns, "subspace", true);
sdb_set(subspace_ns, "some", "values");
sdb_set(subspace_ns, "are", "saved");
sdb_set(subspace_ns, "here", "lol");
return r;
}
static void test_sdb_free(Sdb *sdb) {
if (!sdb) {
return;
}
#ifdef SAVE_FILES
sdb_sync(sdb); // sdb_disk_finish (sdb);
#endif
sdb_free(sdb);
}
typedef struct {
char buf[2048];
size_t buf_len;
} Ctx;
void diff_cb(const SdbDiff *diff, void *user) {
Ctx *ctx = user;
int r = sdb_diff_format(ctx->buf + ctx->buf_len, sizeof(ctx->buf) - ctx->buf_len, diff);
if (r >= 0) {
ctx->buf_len += r;
if (ctx->buf_len >= sizeof(ctx->buf)) {
ctx->buf_len = sizeof(ctx->buf) - 1;
}
if (ctx->buf_len < sizeof(ctx->buf) + 1) {
ctx->buf[ctx->buf_len++] = '\n';
ctx->buf[ctx->buf_len] = '\0';
}
}
}
static bool diff_str(Sdb *a, Sdb *b, char **diff) {
Ctx ctx = { 0 };
bool eq = sdb_diff(a, b, diff ? diff_cb : NULL, diff ? &ctx : NULL);
if (diff) {
*diff = strdup(ctx.buf);
}
return eq;
}
bool test_sdb_diff_equal_empty() {
Sdb *a = sdb_new0();
Sdb *b = sdb_new0();
mu_assert("equal db (no diff)", diff_str(a, b, NULL));
char *diff;
mu_assert("equal db (diff)", diff_str(a, b, &diff));
mu_assert_streq(diff, "", "equal db diff");
free(diff);
test_sdb_free(a);
test_sdb_free(b);
mu_end;
}
bool test_sdb_diff_equal() {
Sdb *a = test_sdb_new("equal_a.sdb");
Sdb *b = test_sdb_new("equal_b.sdb");
mu_assert("equal db (no diff)", diff_str(a, b, NULL));
char *diff;
mu_assert("equal db (diff)", diff_str(a, b, &diff));
mu_assert_streq(diff, "", "equal db diff");
free(diff);
test_sdb_free(a);
test_sdb_free(b);
mu_end;
}
bool test_sdb_diff_ns_empty() {
Sdb *a = test_sdb_new("ns_empty_a.sdb");
Sdb *b = test_sdb_new("ns_empty_b.sdb");
sdb_ns_unset(b, "emptyns", NULL);
mu_assert("empty ns removed (no diff)", !diff_str(a, b, NULL));
char *diff;
mu_assert("empty ns removed (diff)", !diff_str(a, b, &diff));
mu_assert_streq(diff, "-NS emptyns\n", "empty ns removed diff");
free(diff);
mu_assert("empty ns added (no diff)", !diff_str(b, a, NULL));
mu_assert("empty ns added (diff)", !diff_str(b, a, &diff));
mu_assert_streq(diff, "+NS emptyns\n", "empty ns added diff");
free(diff);
test_sdb_free(a);
test_sdb_free(b);
mu_end;
}
bool test_sdb_diff_ns() {
Sdb *a = test_sdb_new("ns_a.sdb");
Sdb *b = test_sdb_new("ns_b.sdb");
sdb_ns_unset(b, "test", NULL);
mu_assert("ns removed (no diff)", !diff_str(a, b, NULL));
char *diff;
mu_assert("ns removed (diff)", !diff_str(a, b, &diff));
mu_assert_streq(diff,
"-NS test\n"
"-NS test/subspace\n"
"- test/subspace/are=saved\n"
"- test/subspace/some=values\n"
"- test/subspace/here=lol\n"
"- test/b=test\n"
"- test/a=123\n"
"- test/c=hello\n",
"ns removed diff");
free(diff);
mu_assert("ns added (no diff)", !diff_str(b, a, NULL));
mu_assert("ns added (diff)", !diff_str(b, a, &diff));
mu_assert_streq(diff,
"+NS test\n"
"+NS test/subspace\n"
"+ test/subspace/are=saved\n"
"+ test/subspace/some=values\n"
"+ test/subspace/here=lol\n"
"+ test/b=test\n"
"+ test/a=123\n"
"+ test/c=hello\n",
"ns added diff");
free(diff);
test_sdb_free(a);
test_sdb_free(b);
mu_end;
}
bool test_sdb_diff_ns_sub() {
Sdb *a = test_sdb_new("ns_sub_a.sdb");
Sdb *b = test_sdb_new("ns_sub_b.sdb");
sdb_ns_unset(sdb_ns(b, "test", 0), "subspace", NULL);
mu_assert("sub ns removed (no diff)", !diff_str(a, b, NULL));
char *diff;
mu_assert("sub ns removed (diff)", !diff_str(a, b, &diff));
mu_assert_streq(diff,
"-NS test/subspace\n"
"- test/subspace/are=saved\n"
"- test/subspace/some=values\n"
"- test/subspace/here=lol\n",
"sub ns removed diff");
free(diff);
mu_assert("sub ns added (no diff)", !diff_str(b, a, NULL));
mu_assert("sub ns added (diff)", !diff_str(b, a, &diff));
mu_assert_streq(diff,
"+NS test/subspace\n"
"+ test/subspace/are=saved\n"
"+ test/subspace/some=values\n"
"+ test/subspace/here=lol\n",
"sub ns added diff");
free(diff);
test_sdb_free(a);
test_sdb_free(b);
mu_end;
}
bool test_sdb_diff_kv() {
Sdb *a = test_sdb_new("kv_a.sdb");
Sdb *b = test_sdb_new("kv_b.sdb");
sdb_unset(b, "more");
sdb_unset(sdb_ns(b, "test", false), "a");
mu_assert("kv removed (no diff)", !diff_str(a, b, NULL));
char *diff;
mu_assert("kv removed (diff)", !diff_str(a, b, &diff));
mu_assert_streq(diff,
"- test/a=123\n"
"- more=stuff\n",
"ns removed diff");
free(diff);
mu_assert("kv added (no diff)", !diff_str(b, a, NULL));
mu_assert("kv added (diff)", !diff_str(b, a, &diff));
mu_assert_streq(diff,
"+ test/a=123\n"
"+ more=stuff\n",
"ns added diff");
free(diff);
test_sdb_free(a);
test_sdb_free(b);
mu_end;
}
bool test_sdb_diff_kv_value() {
Sdb *a = test_sdb_new("kv_value_a.sdb");
Sdb *b = test_sdb_new("kv_value_b.sdb");
sdb_set(b, "more", "cowbell");
sdb_set(sdb_ns(b, "test", false), "a", "reaper");
mu_assert("kv value changed (no diff)", !diff_str(a, b, NULL));
char *diff;
mu_assert("kv value changed (diff)", !diff_str(a, b, &diff));
mu_assert_streq(diff,
"- test/a=123\n"
"+ test/a=reaper\n"
"- more=stuff\n"
"+ more=cowbell\n",
"ns value changed diff");
free(diff);
test_sdb_free(a);
test_sdb_free(b);
mu_end;
}
int all_tests() {
mu_run_test(test_sdb_diff_equal_empty);
mu_run_test(test_sdb_diff_equal);
mu_run_test(test_sdb_diff_ns_empty);
mu_run_test(test_sdb_diff_ns);
mu_run_test(test_sdb_diff_ns_sub);
mu_run_test(test_sdb_diff_kv);
mu_run_test(test_sdb_diff_kv_value);
return tests_passed != tests_run;
}
int main(int argc, char **argv) {
// Sdb *sdb = test_sdb_new();
// sdb_query (sdb, "*");
// sdb_query (sdb, "***");
// test_sdb_free (sdb);
// return 0;
return all_tests();
}