From 5174fc25698cff33b03b5746bf1742e417988f7d Mon Sep 17 00:00:00 2001 From: Marcos Magueta Date: Fri, 5 Jun 2026 21:40:44 -0300 Subject: Project C interface, reroute FOL plan enums & format --- test/VM.cpp | 159 ++++++++++++++++++++++++++++-------------------------------- 1 file changed, 75 insertions(+), 84 deletions(-) (limited to 'test/VM.cpp') diff --git a/test/VM.cpp b/test/VM.cpp index f4ce453..7e61da6 100644 --- a/test/VM.cpp +++ b/test/VM.cpp @@ -21,48 +21,45 @@ // --------------------------------------------------------------------------- // Stores a tuple in the backend and updates the Relation object's Merkle root. -static void store_tuple(nt::InMemoryBackend& backend, - nt::ObjectManager& objects, - const std::vector& path, - std::vector attrs) -{ +static void store_tuple(nt::InMemoryBackend& backend, nt::ObjectManager& objects, + const std::vector& path, std::vector attrs) { auto bytes = nt::TupleCodec::Serialize(attrs); - auto hash = backend.Put(std::move(bytes)); + auto hash = backend.Put(std::move(bytes)); auto* entry = objects.Find(path); - if (!entry) return; + if (!entry) + return; auto* rel = dynamic_cast(entry->object.get()); - if (!rel) return; + if (!rel) + return; auto hash_bin = nt::hex_to_bin(hash); - rel->merkle_root = nt::Merkle::Insert(backend, rel->merkle_root, - hash_bin, hash_bin); + rel->merkle_root = + nt::Merkle::Insert(backend, rel->merkle_root, hash_bin, hash_bin); } -static std::unique_ptr make_relation_type() -{ +static std::unique_ptr make_relation_type() { auto t = std::make_unique(); - t->label = RELATION; + t->label = RELATION; t->disposable = false; - t->methods = { OPEN, CLOSE }; + t->methods = {OPEN, CLOSE}; return t; } // Generator for eq[A, B]: returns one tuple when A == B, nothing otherwise. // Treats both args as integers when parseable, strings otherwise. -static std::unique_ptr make_eq_type() -{ +static std::unique_ptr make_eq_type() { auto t = std::make_unique(); - t->label = EPHEMERAL_RELATION; - t->disposable = false; - t->methods = { OPEN, CLOSE }; + t->label = EPHEMERAL_RELATION; + t->disposable = false; + t->methods = {OPEN, CLOSE}; t->cardinality = nt::ObjectManager::ephemeral_object_type::Cardinality::AlephZero; - t->generator = [](const std::vector& args, - std::size_t offset, - std::size_t limit) -> std::vector - { - if (args.size() < 2 || offset > 0 || limit == 0) return {}; - if (args[0] != args[1]) return {}; - return { nt::Tuple({ { "left", args[0] }, { "right", args[1] } }) }; + t->generator = [](const std::vector& args, std::size_t offset, + std::size_t limit) -> std::vector { + if (args.size() < 2 || offset > 0 || limit == 0) + return {}; + if (args[0] != args[1]) + return {}; + return {nt::Tuple({{"left", args[0]}, {"right", args[1]}})}; }; return t; } @@ -71,16 +68,15 @@ static std::unique_ptr make_eq_type() // Fixture: shared manager stack // --------------------------------------------------------------------------- -struct Fixture -{ - nt::InMemoryBackend backend; - nt::ObjectManager objects; +struct Fixture { + nt::InMemoryBackend backend; + nt::ObjectManager objects; nt::PermissionsManager permissions; - nt::IdentityManager identities; - nt::LifecycleManager lifecycles { objects, backend }; - nt::NamespaceReferenceManager references { objects, backend }; - nt::HandlerManager handler { objects, permissions, identities, lifecycles, references }; - nt::CursorManager cursors { backend, &lifecycles, &objects }; + nt::IdentityManager identities; + nt::LifecycleManager lifecycles{objects, backend}; + nt::NamespaceReferenceManager references{objects, backend}; + nt::HandlerManager handler{objects, permissions, identities, lifecycles, references}; + nt::CursorManager cursors{backend, &lifecycles, &objects}; int conn = 1; }; @@ -88,14 +84,13 @@ struct Fixture // Tests // --------------------------------------------------------------------------- -TEST_CASE("SCAN returns all tuples from a stored relation", "[scan]") -{ +TEST_CASE("SCAN returns all tuples from a stored relation", "[scan]") { Fixture f; - const std::vector path = { "relations", "villager" }; + const std::vector path = {"relations", "villager"}; f.objects.Register(path, std::make_unique(), make_relation_type()); - store_tuple(f.backend, f.objects, path, { { "name", "John" }, { "age", "30" } }); - store_tuple(f.backend, f.objects, path, { { "name", "Peter" }, { "age", "25" } }); + store_tuple(f.backend, f.objects, path, {{"name", "John"}, {"age", "30"}}); + store_tuple(f.backend, f.objects, path, {{"name", "Peter"}, {"age", "25"}}); auto* handle = f.handler.Open(path, &f.conn); REQUIRE(handle != nullptr); @@ -104,12 +99,13 @@ TEST_CASE("SCAN returns all tuples from a stored relation", "[scan]") REQUIRE(cursor != nullptr); nt::PlanNode plan; - plan.op = nt::PlanNode::Op::SCAN; + plan.op = nt::FOL_OPERATION_SCAN; plan.scan_cursor = cursor; nt::VM vm(f.cursors); int count = 0; - while (vm.Next(&plan)) ++count; + while (vm.Next(&plan)) + ++count; REQUIRE(count == 2); @@ -117,25 +113,21 @@ TEST_CASE("SCAN returns all tuples from a stored relation", "[scan]") f.handler.Close(handle); } -TEST_CASE("JOIN filters a stored relation with eq ephemeral", "[join]") -{ +TEST_CASE("JOIN filters a stored relation with eq ephemeral", "[join]") { Fixture f; - const std::vector people_path = { "relations", "people" }; - const std::vector eq_path = { "builtins", "eq" }; + const std::vector people_path = {"relations", "people"}; + const std::vector eq_path = {"builtins", "eq"}; // Register stored relation: people(name, age) - f.objects.Register(people_path, - std::make_unique(), + f.objects.Register(people_path, std::make_unique(), make_relation_type()); - store_tuple(f.backend, f.objects, people_path, { { "name", "John" }, { "age", "30" } }); - store_tuple(f.backend, f.objects, people_path, { { "name", "Peter" }, { "age", "25" } }); - store_tuple(f.backend, f.objects, people_path, { { "name", "Jude" }, { "age", "25" } }); + store_tuple(f.backend, f.objects, people_path, {{"name", "John"}, {"age", "30"}}); + store_tuple(f.backend, f.objects, people_path, {{"name", "Peter"}, {"age", "25"}}); + store_tuple(f.backend, f.objects, people_path, {{"name", "Jude"}, {"age", "25"}}); // Register ephemeral eq relation - f.objects.Register(eq_path, - std::make_unique(), - make_eq_type()); + f.objects.Register(eq_path, std::make_unique(), make_eq_type()); // Open handles and cursors auto* people_handle = f.handler.Open(people_path, &f.conn); @@ -143,8 +135,8 @@ TEST_CASE("JOIN filters a stored relation with eq ephemeral", "[join]") auto* eq_handle = f.handler.Open(eq_path, &f.conn); REQUIRE(eq_handle != nullptr); - auto* people_rel = dynamic_cast( - f.objects.Find(people_path)->object.get()); + auto* people_rel = + dynamic_cast(f.objects.Find(people_path)->object.get()); auto* people_cursor = f.cursors.Open(people_handle, people_rel->merkle_root); REQUIRE(people_cursor != nullptr); auto* eq_cursor = f.cursors.Open(eq_handle); // EPHEMERAL: starts exhausted, JOIN resets @@ -152,24 +144,23 @@ TEST_CASE("JOIN filters a stored relation with eq ephemeral", "[join]") // Plan: JOIN( SCAN(people), SCAN(eq[ Var("age"), Const("25") ]) ) nt::PlanNode right; - right.op = nt::PlanNode::Op::SCAN; + right.op = nt::FOL_OPERATION_SCAN; right.scan_cursor = eq_cursor; - right.scan_args = { nt::PathArg::Var("age"), nt::PathArg::Const("25") }; + right.scan_args = {nt::PathArg::Var("age"), nt::PathArg::Const("25")}; nt::PlanNode left; - left.op = nt::PlanNode::Op::SCAN; + left.op = nt::FOL_OPERATION_SCAN; left.scan_cursor = people_cursor; nt::PlanNode root; - root.op = nt::PlanNode::Op::JOIN; - root.left = &left; + root.op = nt::FOL_OPERATION_JOIN; + root.left = &left; root.right = &right; // Execute and collect matched names nt::VM vm(f.cursors); std::vector matched; - while (nt::Tuple* t = vm.Next(&root)) - { + while (nt::Tuple* t = vm.Next(&root)) { for (const auto& attr : t->attrs()) if (attr.name == "name") matched.push_back(attr.value); @@ -177,9 +168,9 @@ TEST_CASE("JOIN filters a stored relation with eq ephemeral", "[join]") // Jude (age=25) and Peter (age=25) should match; Jogn (age=30) should not REQUIRE(matched.size() == 2); - REQUIRE(std::find(matched.begin(), matched.end(), "Jude") != matched.end()); + REQUIRE(std::find(matched.begin(), matched.end(), "Jude") != matched.end()); REQUIRE(std::find(matched.begin(), matched.end(), "Peter") != matched.end()); - REQUIRE(std::find(matched.begin(), matched.end(), "John") == matched.end()); + REQUIRE(std::find(matched.begin(), matched.end(), "John") == matched.end()); f.cursors.Close(people_cursor); f.cursors.Close(eq_cursor); @@ -187,15 +178,14 @@ TEST_CASE("JOIN filters a stored relation with eq ephemeral", "[join]") f.handler.Close(eq_handle); } -TEST_CASE("TAKE limits tuples emitted from a SCAN", "[take]") -{ +TEST_CASE("TAKE limits tuples emitted from a SCAN", "[take]") { Fixture f; - const std::vector path = { "relations", "items" }; + const std::vector path = {"relations", "items"}; f.objects.Register(path, std::make_unique(), make_relation_type()); - store_tuple(f.backend, f.objects, path, { { "id", "1" } }); - store_tuple(f.backend, f.objects, path, { { "id", "2" } }); - store_tuple(f.backend, f.objects, path, { { "id", "3" } }); + store_tuple(f.backend, f.objects, path, {{"id", "1"}}); + store_tuple(f.backend, f.objects, path, {{"id", "2"}}); + store_tuple(f.backend, f.objects, path, {{"id", "3"}}); auto* handle = f.handler.Open(path, &f.conn); REQUIRE(handle != nullptr); @@ -204,17 +194,18 @@ TEST_CASE("TAKE limits tuples emitted from a SCAN", "[take]") REQUIRE(cursor != nullptr); nt::PlanNode scan; - scan.op = nt::PlanNode::Op::SCAN; + scan.op = nt::FOL_OPERATION_SCAN; scan.scan_cursor = cursor; nt::PlanNode take; - take.op = nt::PlanNode::Op::TAKE; - take.left = &scan; + take.op = nt::FOL_OPERATION_TAKE; + take.left = &scan; take.take_limit = 2; nt::VM vm(f.cursors); int count = 0; - while (vm.Next(&take)) ++count; + while (vm.Next(&take)) + ++count; REQUIRE(count == 2); @@ -222,13 +213,12 @@ TEST_CASE("TAKE limits tuples emitted from a SCAN", "[take]") f.handler.Close(handle); } -TEST_CASE("PROJECT filters tuple attributes by name", "[project]") -{ +TEST_CASE("PROJECT filters tuple attributes by name", "[project]") { Fixture f; - const std::vector path = { "relations", "people" }; + const std::vector path = {"relations", "people"}; f.objects.Register(path, std::make_unique(), make_relation_type()); - store_tuple(f.backend, f.objects, path, { { "name", "John" }, { "age", "30" }, { "city", "Lisbon" } }); + store_tuple(f.backend, f.objects, path, {{"name", "John"}, {"age", "30"}, {"city", "Lisbon"}}); auto* handle = f.handler.Open(path, &f.conn); REQUIRE(handle != nullptr); @@ -237,20 +227,21 @@ TEST_CASE("PROJECT filters tuple attributes by name", "[project]") REQUIRE(cursor != nullptr); nt::PlanNode scan; - scan.op = nt::PlanNode::Op::SCAN; + scan.op = nt::FOL_OPERATION_SCAN; scan.scan_cursor = cursor; nt::PlanNode project; - project.op = nt::PlanNode::Op::PROJECT; - project.left = &scan; - project.project_attrs = { "name", "city" }; + project.op = nt::FOL_OPERATION_PROJECT; + project.left = &scan; + project.project_attrs = {"name", "city"}; nt::VM vm(f.cursors); nt::Tuple* t = vm.Next(&project); REQUIRE(t != nullptr); std::vector names; - for (const auto& attr : t->attrs()) names.push_back(attr.name); + for (const auto& attr : t->attrs()) + names.push_back(attr.name); REQUIRE(names.size() == 2); REQUIRE(std::find(names.begin(), names.end(), "name") != names.end()); -- cgit v1.2.3