#include #include #include #include #include #include "doc_binary.hpp" using nlohmann::json; using smartbotic::db::doc_binary::Doc; using smartbotic::db::doc_binary::encode; using smartbotic::db::doc_binary::decode; using smartbotic::db::doc_binary::get_field; using smartbotic::db::doc_binary::to_json_text; namespace { void check(bool cond, const char* msg) { if (!cond) { std::cerr << "FAIL: " << msg << "\n"; std::abort(); } } void roundtrip(const json& j, const char* label) { auto doc = encode(j); auto back = decode(doc); check(back == j, label); } void test_default_doc_is_empty() { Doc d; check(d.empty(), "default-constructed Doc is empty"); check(d.root() == nullptr, "empty Doc has null root"); auto back = decode(d); check(back.is_null(), "decoding empty Doc returns null"); } void test_primitives_roundtrip() { roundtrip(json(nullptr), "null"); roundtrip(json(true), "true"); roundtrip(json(false), "false"); roundtrip(json(0), "int zero"); roundtrip(json(42), "int 42"); roundtrip(json(-7), "negative int"); roundtrip(json(9223372036854775807LL), "int64 max"); roundtrip(json(3.14), "double"); roundtrip(json("hello"), "string"); roundtrip(json(""), "empty string"); } void test_collections_roundtrip() { roundtrip(json::array(), "empty array"); roundtrip(json::object(), "empty object"); roundtrip(json::array({1, 2, 3}), "int array"); roundtrip(json::array({1, "two", 3.0, true, nullptr}), "mixed array"); roundtrip(json({{"k", "v"}, {"n", 1}}), "small object"); } void test_zoe_shape_roundtrip() { json zoe = { {"_id", "doc-1"}, {"_created_at", 1731628800123LL}, {"name", "Zoe"}, {"tags", json::array({"hot", "pinned"})}, {"_vector", json::array({0.1, -0.2, 0.3, 0.4})}, {"meta", {{"flag", true}, {"score", 0.93}}}, }; roundtrip(zoe, "Zoe-shape"); } void test_unicode_roundtrip() { roundtrip( json({{"hu", "Árvíztűrő tükörfúrógép"}, {"emoji", "🚀"}}), "unicode strings"); } void test_get_field_present() { json j = {{"name", "Zoe"}, {"count", 42}, {"flag", true}}; auto doc = encode(j); auto name = get_field(doc, "name"); check(name.has_value(), "name present"); check(name->get() == "Zoe", "name value"); auto count = get_field(doc, "count"); check(count.has_value(), "count present"); check(count->get() == 42, "count value"); auto flag = get_field(doc, "flag"); check(flag.has_value(), "flag present"); check(flag->get() == true, "flag value"); } void test_get_field_missing() { json j = {{"name", "Zoe"}}; auto doc = encode(j); auto absent = get_field(doc, "nonexistent"); check(!absent.has_value(), "missing field returns nullopt"); } void test_get_field_on_non_object() { auto doc = encode(json::array({1, 2, 3})); auto v = get_field(doc, "anything"); check(!v.has_value(), "get_field on array returns nullopt"); } void test_get_field_on_empty() { Doc d; auto v = get_field(d, "anything"); check(!v.has_value(), "get_field on empty Doc returns nullopt"); } void test_to_json_text_roundtrip() { json j = {{"a", 1}, {"b", "two"}, {"c", json::array({1, 2})}}; auto doc = encode(j); std::string text = to_json_text(doc); json parsed = json::parse(text); check(parsed == j, "to_json_text round-trips through nlohmann::json::parse"); } void test_to_json_text_empty() { Doc d; check(to_json_text(d) == "null", "to_json_text of empty Doc is \"null\""); } void test_doc_is_move_only() { auto d1 = encode(json({{"a", 1}})); check(!d1.empty(), "encoded doc not empty"); Doc d2 = std::move(d1); check(d1.empty(), "moved-from Doc is empty"); check(!d2.empty(), "moved-to Doc holds the data"); auto field = get_field(d2, "a"); check(field.has_value() && field->get() == 1, "moved Doc still readable"); } } // namespace int main() { test_default_doc_is_empty(); test_primitives_roundtrip(); test_collections_roundtrip(); test_zoe_shape_roundtrip(); test_unicode_roundtrip(); test_get_field_present(); test_get_field_missing(); test_get_field_on_non_object(); test_get_field_on_empty(); test_to_json_text_roundtrip(); test_to_json_text_empty(); test_doc_is_move_only(); std::cout << "test_doc_binary: all passed\n"; return 0; }