/** * EmbeddedEngineTest - Unit tests for EmbeddedEngine * * All tests use async methods with MainLoop wrappers for the test framework. */ using Implexus.Core; using Implexus.Engine; using Implexus.Storage; public static int main(string[] args) { int passed = 0; int failed = 0; // Test 1: Root creation if (test_root_creation()) { passed++; stdout.puts("PASS: test_root_creation\n"); } else { failed++; stdout.puts("FAIL: test_root_creation\n"); } // Test 2: Container creation if (test_container_creation()) { passed++; stdout.puts("PASS: test_container_creation\n"); } else { failed++; stdout.puts("FAIL: test_container_creation\n"); } // Test 3: Document creation if (test_document_creation()) { passed++; stdout.puts("PASS: test_document_creation\n"); } else { failed++; stdout.puts("FAIL: test_document_creation\n"); } // Test 4: Container deletion if (test_container_deletion()) { passed++; stdout.puts("PASS: test_container_deletion\n"); } else { failed++; stdout.puts("FAIL: test_container_deletion\n"); } // Test 5: Document deletion if (test_document_deletion()) { passed++; stdout.puts("PASS: test_document_deletion\n"); } else { failed++; stdout.puts("FAIL: test_document_deletion\n"); } // Test 6: Property access if (test_property_access()) { passed++; stdout.puts("PASS: test_property_access\n"); } else { failed++; stdout.puts("FAIL: test_property_access\n"); } // Test 7: Property removal if (test_property_removal()) { passed++; stdout.puts("PASS: test_property_removal\n"); } else { failed++; stdout.puts("FAIL: test_property_removal\n"); } // Test 8: Get children if (test_get_children()) { passed++; stdout.puts("PASS: test_get_children\n"); } else { failed++; stdout.puts("FAIL: test_get_children\n"); } // Test 9: Entity exists if (test_entity_exists()) { passed++; stdout.puts("PASS: test_entity_exists\n"); } else { failed++; stdout.puts("FAIL: test_entity_exists\n"); } // Test 10: Get entity if (test_get_entity()) { passed++; stdout.puts("PASS: test_get_entity\n"); } else { failed++; stdout.puts("FAIL: test_get_entity\n"); } // Test 11: Query by type if (test_query_by_type()) { passed++; stdout.puts("PASS: test_query_by_type\n"); } else { failed++; stdout.puts("FAIL: test_query_by_type\n"); } // Test 12: Nested containers if (test_nested_containers()) { passed++; stdout.puts("PASS: test_nested_containers\n"); } else { failed++; stdout.puts("FAIL: test_nested_containers\n"); } // Test 13: Multiple documents if (test_multiple_documents()) { passed++; stdout.puts("PASS: test_multiple_documents\n"); } else { failed++; stdout.puts("FAIL: test_multiple_documents\n"); } // Test 14: Entity path if (test_entity_path()) { passed++; stdout.puts("PASS: test_entity_path\n"); } else { failed++; stdout.puts("FAIL: test_entity_path\n"); } // Test 15: Persistence if (test_engine_persistence()) { passed++; stdout.puts("PASS: test_engine_persistence\n"); } else { failed++; stdout.puts("FAIL: test_engine_persistence\n"); } // Test 16: Category virtual child resolution if (test_category_virtual_child_resolution()) { passed++; stdout.puts("PASS: test_category_virtual_child_resolution\n"); } else { failed++; stdout.puts("FAIL: test_category_virtual_child_resolution\n"); } // Test 17: Category virtual child not found if (test_category_virtual_child_not_found()) { passed++; stdout.puts("PASS: test_category_virtual_child_not_found\n"); } else { failed++; stdout.puts("FAIL: test_category_virtual_child_not_found\n"); } // Test 18: Catalogue virtual child group resolution if (test_catalogue_virtual_child_group()) { passed++; stdout.puts("PASS: test_catalogue_virtual_child_group\n"); } else { failed++; stdout.puts("FAIL: test_catalogue_virtual_child_group\n"); } // Test 19: Catalogue virtual child document resolution if (test_catalogue_virtual_child_document()) { passed++; stdout.puts("PASS: test_catalogue_virtual_child_document\n"); } else { failed++; stdout.puts("FAIL: test_catalogue_virtual_child_document\n"); } // Test 20: Catalogue virtual child not found if (test_catalogue_virtual_child_not_found()) { passed++; stdout.puts("PASS: test_catalogue_virtual_child_not_found\n"); } else { failed++; stdout.puts("FAIL: test_catalogue_virtual_child_not_found\n"); } // Test 21: Index virtual child resolution if (test_index_virtual_child_resolution()) { passed++; stdout.puts("PASS: test_index_virtual_child_resolution\n"); } else { failed++; stdout.puts("FAIL: test_index_virtual_child_resolution\n"); } // Test 22: Index virtual child no matches if (test_index_virtual_child_no_matches()) { passed++; stdout.puts("PASS: test_index_virtual_child_no_matches\n"); } else { failed++; stdout.puts("FAIL: test_index_virtual_child_no_matches\n"); } // Test 23: Category direct vs navigation comparison if (test_category_direct_vs_navigation()) { passed++; stdout.puts("PASS: test_category_direct_vs_navigation\n"); } else { failed++; stdout.puts("FAIL: test_category_direct_vs_navigation\n"); } // Test 24: Catalogue direct vs navigation comparison if (test_catalogue_direct_vs_navigation()) { passed++; stdout.puts("PASS: test_catalogue_direct_vs_navigation\n"); } else { failed++; stdout.puts("FAIL: test_catalogue_direct_vs_navigation\n"); } // Test 25: Index direct vs navigation comparison if (test_index_direct_vs_navigation()) { passed++; stdout.puts("PASS: test_index_direct_vs_navigation\n"); } else { failed++; stdout.puts("FAIL: test_index_direct_vs_navigation\n"); } stdout.printf("\nResults: %d passed, %d failed\n", passed, failed); return failed > 0 ? 1 : 0; } // Helper to create temporary directory string create_temp_dir() { string temp_dir = DirUtils.mkdtemp("implexus_engine_test_XXXXXX"); return temp_dir; } // Test 1: Root creation bool test_root_creation() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { stderr.printf("Test error: %s\n", ((!)error).message); cleanup_dir(temp_dir); return false; } if (root == null) { cleanup_dir(temp_dir); return false; } if (((!)root).entity_type != EntityType.CONTAINER) { cleanup_dir(temp_dir); return false; } if (!((!)root).path.is_root) { cleanup_dir(temp_dir); return false; } if (((!)root).name != "") { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 2: Container creation bool test_container_creation() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? container = null; bool exists = false; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } ((!)root).create_container_async.begin("users", (obj, res) => { try { container = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || container == null) { cleanup_dir(temp_dir); return false; } if (((!)container).entity_type != EntityType.CONTAINER) { cleanup_dir(temp_dir); return false; } if (((!)container).name != "users") { cleanup_dir(temp_dir); return false; } if (((!)container).path.to_string() != "/users") { cleanup_dir(temp_dir); return false; } // Verify it exists engine.entity_exists_async.begin(((!)container).path, (obj, res) => { try { exists = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (!exists) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 3: Document creation bool test_document_creation() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? users = null; Entity? john = null; bool exists = false; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } ((!)root).create_container_async.begin("users", (obj, res) => { try { users = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || users == null) { cleanup_dir(temp_dir); return false; } ((!)users).create_document_async.begin("john", "User", (obj, res) => { try { john = ((!)users).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || john == null) { cleanup_dir(temp_dir); return false; } if (((!)john).entity_type != EntityType.DOCUMENT) { cleanup_dir(temp_dir); return false; } if (((!)john).name != "john") { cleanup_dir(temp_dir); return false; } if (((!)john).type_label != "User") { cleanup_dir(temp_dir); return false; } if (((!)john).path.to_string() != "/users/john") { cleanup_dir(temp_dir); return false; } // Verify it exists engine.entity_exists_async.begin(((!)john).path, (obj, res) => { try { exists = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (!exists) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 4: Container deletion bool test_container_deletion() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? container = null; bool exists_before = false; bool exists_after = true; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } ((!)root).create_container_async.begin("temp", (obj, res) => { try { container = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || container == null) { cleanup_dir(temp_dir); return false; } // Check exists before engine.entity_exists_async.begin(((!)container).path, (obj, res) => { try { exists_before = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (!exists_before) { cleanup_dir(temp_dir); return false; } // Delete ((!)container).delete_async.begin((obj, res) => { try { ((!)container).delete_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Check exists after engine.entity_exists_async.begin(((!)container).path, (obj, res) => { try { exists_after = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (exists_after) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 5: Document deletion bool test_document_deletion() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? docs = null; Entity? doc = null; bool exists_before = false; bool exists_after = true; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } ((!)root).create_container_async.begin("docs", (obj, res) => { try { docs = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || docs == null) { cleanup_dir(temp_dir); return false; } ((!)docs).create_document_async.begin("doc1", "Document", (obj, res) => { try { doc = ((!)docs).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc == null) { cleanup_dir(temp_dir); return false; } // Check exists before engine.entity_exists_async.begin(((!)doc).path, (obj, res) => { try { exists_before = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (!exists_before) { cleanup_dir(temp_dir); return false; } // Delete ((!)doc).delete_async.begin((obj, res) => { try { ((!)doc).delete_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Check exists after engine.entity_exists_async.begin(((!)doc).path, (obj, res) => { try { exists_after = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (exists_after) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 6: Property access bool test_property_access() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? docs = null; Entity? doc = null; Invercargill.Element? name = null; Invercargill.Element? count = null; Invercargill.Element? active = null; Invercargill.Element? missing = null; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } ((!)root).create_container_async.begin("docs", (obj, res) => { try { docs = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || docs == null) { cleanup_dir(temp_dir); return false; } ((!)docs).create_document_async.begin("doc1", "Document", (obj, res) => { try { doc = ((!)docs).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc == null) { cleanup_dir(temp_dir); return false; } // Set properties ((!)doc).set_entity_property_async.begin("name", new Invercargill.NativeElement("Test Document"), (obj, res) => { try { ((!)doc).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } ((!)doc).set_entity_property_async.begin("count", new Invercargill.NativeElement(42), (obj, res) => { try { ((!)doc).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } ((!)doc).set_entity_property_async.begin("active", new Invercargill.NativeElement(true), (obj, res) => { try { ((!)doc).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Get properties ((!)doc).get_entity_property_async.begin("name", (obj, res) => { try { name = ((!)doc).get_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || name == null || ((!)name).is_null()) { cleanup_dir(temp_dir); return false; } string name_val = ((!)name).as(); if (name_val != "Test Document") { cleanup_dir(temp_dir); return false; } ((!)doc).get_entity_property_async.begin("count", (obj, res) => { try { count = ((!)doc).get_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || count == null || ((!)count).is_null()) { cleanup_dir(temp_dir); return false; } int64? count_val = ((!)count).as(); if (count_val == null || (!)count_val != 42) { cleanup_dir(temp_dir); return false; } ((!)doc).get_entity_property_async.begin("active", (obj, res) => { try { active = ((!)doc).get_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || active == null || ((!)active).is_null()) { cleanup_dir(temp_dir); return false; } bool active_val = ((!)active).as(); if (active_val != true) { cleanup_dir(temp_dir); return false; } // Non-existent property ((!)doc).get_entity_property_async.begin("missing", (obj, res) => { try { missing = ((!)doc).get_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (missing != null) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 7: Property removal bool test_property_removal() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? docs = null; Entity? doc = null; Invercargill.Element? value = null; Invercargill.Element? value_after = null; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } ((!)root).create_container_async.begin("docs", (obj, res) => { try { docs = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || docs == null) { cleanup_dir(temp_dir); return false; } ((!)docs).create_document_async.begin("doc1", "Document", (obj, res) => { try { doc = ((!)docs).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc == null) { cleanup_dir(temp_dir); return false; } ((!)doc).set_entity_property_async.begin("temp", new Invercargill.NativeElement("temporary"), (obj, res) => { try { ((!)doc).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } ((!)doc).get_entity_property_async.begin("temp", (obj, res) => { try { value = ((!)doc).get_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || value == null) { cleanup_dir(temp_dir); return false; } ((!)doc).remove_property_async.begin("temp", (obj, res) => { try { ((!)doc).remove_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } ((!)doc).get_entity_property_async.begin("temp", (obj, res) => { try { value_after = ((!)doc).get_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (value_after != null) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 8: Get children bool test_get_children() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? users = null; Entity[] children = {}; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } ((!)root).create_container_async.begin("users", (obj, res) => { try { users = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || users == null) { cleanup_dir(temp_dir); return false; } // Create documents ((!)users).create_document_async.begin("john", "User", (obj, res) => { try { ((!)users).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } ((!)users).create_document_async.begin("jane", "User", (obj, res) => { try { ((!)users).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } ((!)users).create_document_async.begin("bob", "User", (obj, res) => { try { ((!)users).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } ((!)users).get_children_async.begin((obj, res) => { try { children = ((!)users).get_children_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || children.length != 3) { cleanup_dir(temp_dir); return false; } // Check all children are present var child_names = new Invercargill.DataStructures.HashSet(); foreach (var child in children) { child_names.add(child.name); } if (!child_names.has("john") || !child_names.has("jane") || !child_names.has("bob")) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 9: Entity exists bool test_entity_exists() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? users = null; bool exists1 = false; bool exists2 = true; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } ((!)root).create_container_async.begin("users", (obj, res) => { try { users = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || users == null) { cleanup_dir(temp_dir); return false; } engine.entity_exists_async.begin(new EntityPath("/users"), (obj, res) => { try { exists1 = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (!exists1) { cleanup_dir(temp_dir); return false; } engine.entity_exists_async.begin(new EntityPath("/nonexistent"), (obj, res) => { try { exists2 = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (exists2) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 10: Get entity bool test_get_entity() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? users = null; Entity? retrieved = null; Entity? nonexistent = null; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } ((!)root).create_container_async.begin("users", (obj, res) => { try { users = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || users == null) { cleanup_dir(temp_dir); return false; } ((!)users).create_document_async.begin("john", "User", (obj, res) => { try { ((!)users).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Get entity by path engine.get_entity_async.begin(new EntityPath("/users/john"), (obj, res) => { try { retrieved = engine.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || retrieved == null) { cleanup_dir(temp_dir); return false; } if (((!)retrieved).entity_type != EntityType.DOCUMENT) { cleanup_dir(temp_dir); return false; } if (((!)retrieved).name != "john") { cleanup_dir(temp_dir); return false; } if (((!)retrieved).type_label != "User") { cleanup_dir(temp_dir); return false; } // Get non-existent entity - should throw engine.get_entity_async.begin(new EntityPath("/nonexistent"), (obj, res) => { try { nonexistent = engine.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); // Should have thrown if (nonexistent != null) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 11: Query by type bool test_query_by_type() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? users = null; Entity[] user_results = {}; Entity[] admin_results = {}; Entity[] none_results = {}; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } ((!)root).create_container_async.begin("users", (obj, res) => { try { users = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || users == null) { cleanup_dir(temp_dir); return false; } ((!)users).create_document_async.begin("john", "User", (obj, res) => { try { ((!)users).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } ((!)users).create_document_async.begin("jane", "User", (obj, res) => { try { ((!)users).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } ((!)users).create_document_async.begin("admin", "Admin", (obj, res) => { try { ((!)users).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Query for Users engine.query_by_type_async.begin("User", (obj, res) => { try { user_results = engine.query_by_type_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || user_results.length != 2) { cleanup_dir(temp_dir); return false; } // Query for Admins engine.query_by_type_async.begin("Admin", (obj, res) => { try { admin_results = engine.query_by_type_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || admin_results.length != 1) { cleanup_dir(temp_dir); return false; } // Query for non-existent type engine.query_by_type_async.begin("NonExistent", (obj, res) => { try { none_results = engine.query_by_type_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || none_results.length != 0) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 12: Nested containers bool test_nested_containers() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? level1 = null; Entity? level2 = null; Entity? level3 = null; bool exists1 = false; bool exists2 = false; bool exists3 = false; Entity[] level1_children = {}; Entity[] level2_children = {}; Entity[] level3_children = {}; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } ((!)root).create_container_async.begin("level1", (obj, res) => { try { level1 = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || level1 == null) { cleanup_dir(temp_dir); return false; } ((!)level1).create_container_async.begin("level2", (obj, res) => { try { level2 = ((!)level1).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || level2 == null) { cleanup_dir(temp_dir); return false; } ((!)level2).create_container_async.begin("level3", (obj, res) => { try { level3 = ((!)level2).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || level3 == null) { cleanup_dir(temp_dir); return false; } engine.entity_exists_async.begin(new EntityPath("/level1"), (obj, res) => { try { exists1 = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (!exists1) { cleanup_dir(temp_dir); return false; } engine.entity_exists_async.begin(new EntityPath("/level1/level2"), (obj, res) => { try { exists2 = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (!exists2) { cleanup_dir(temp_dir); return false; } engine.entity_exists_async.begin(new EntityPath("/level1/level2/level3"), (obj, res) => { try { exists3 = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (!exists3) { cleanup_dir(temp_dir); return false; } // Verify parent-child relationships ((!)level1).get_children_async.begin((obj, res) => { try { level1_children = ((!)level1).get_children_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || level1_children.length != 1) { cleanup_dir(temp_dir); return false; } ((!)level2).get_children_async.begin((obj, res) => { try { level2_children = ((!)level2).get_children_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || level2_children.length != 1) { cleanup_dir(temp_dir); return false; } ((!)level3).get_children_async.begin((obj, res) => { try { level3_children = ((!)level3).get_children_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || level3_children.length != 0) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 13: Multiple documents bool test_multiple_documents() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? users = null; Entity[] children = {}; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } ((!)root).create_container_async.begin("users", (obj, res) => { try { users = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || users == null) { cleanup_dir(temp_dir); return false; } // Create multiple documents for (int i = 0; i < 10; i++) { int idx = i; Entity? doc = null; ((!)users).create_document_async.begin(@"user$idx", "User", (obj, res) => { try { doc = ((!)users).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc == null) { cleanup_dir(temp_dir); return false; } ((!)doc).set_entity_property_async.begin("index", new Invercargill.NativeElement(idx), (obj, res) => { try { ((!)doc).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } } // Verify all exist ((!)users).get_children_async.begin((obj, res) => { try { children = ((!)users).get_children_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || children.length != 10) { cleanup_dir(temp_dir); return false; } // Verify properties for (int i = 0; i < 10; i++) { int idx = i; Entity? doc = null; Invercargill.Element? index = null; engine.get_entity_async.begin(new EntityPath(@"/users/user$idx"), (obj, res) => { try { doc = engine.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc == null) { cleanup_dir(temp_dir); return false; } ((!)doc).get_entity_property_async.begin("index", (obj, res) => { try { index = ((!)doc).get_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || index == null || ((!)index).is_null()) { cleanup_dir(temp_dir); return false; } int64? index_val = ((!)index).as(); if (index_val == null || (!)index_val != idx) { cleanup_dir(temp_dir); return false; } } cleanup_dir(temp_dir); return true; } // Test 14: Entity path bool test_entity_path() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? a = null; Entity? b = null; Entity? c = null; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } ((!)root).create_container_async.begin("a", (obj, res) => { try { a = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || a == null) { cleanup_dir(temp_dir); return false; } ((!)a).create_container_async.begin("b", (obj, res) => { try { b = ((!)a).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || b == null) { cleanup_dir(temp_dir); return false; } ((!)b).create_document_async.begin("c", "Document", (obj, res) => { try { c = ((!)b).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || c == null) { cleanup_dir(temp_dir); return false; } if (!((!)root).path.is_root) { cleanup_dir(temp_dir); return false; } if (((!)a).path.to_string() != "/a") { cleanup_dir(temp_dir); return false; } if (((!)b).path.to_string() != "/a/b") { cleanup_dir(temp_dir); return false; } if (((!)c).path.to_string() != "/a/b/c") { cleanup_dir(temp_dir); return false; } // Check parent relationships if (!((!)c).path.parent.equals(((!)b).path)) { cleanup_dir(temp_dir); return false; } if (!((!)b).path.parent.equals(((!)a).path)) { cleanup_dir(temp_dir); return false; } if (!((!)a).path.parent.equals(((!)root).path)) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 15: Persistence bool test_engine_persistence() { string temp_dir = create_temp_dir(); // Create and write var engine1 = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root1 = null; Entity? users1 = null; Entity? john1 = null; bool exists1 = false; bool exists2 = false; Entity? root2 = null; Entity? john2 = null; Invercargill.Element? email = null; Error? error = null; engine1.get_root_async.begin((obj, res) => { try { root1 = engine1.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root1 == null) { cleanup_dir(temp_dir); return false; } ((!)root1).create_container_async.begin("users", (obj, res) => { try { users1 = ((!)root1).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || users1 == null) { cleanup_dir(temp_dir); return false; } ((!)users1).create_document_async.begin("john", "User", (obj, res) => { try { john1 = ((!)users1).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || john1 == null) { cleanup_dir(temp_dir); return false; } ((!)john1).set_entity_property_async.begin("email", new Invercargill.NativeElement("john@example.com"), (obj, res) => { try { ((!)john1).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Create new engine instance var engine2 = new EmbeddedEngine.with_path(temp_dir); // Verify data persists engine2.get_root_async.begin((obj, res) => { try { root2 = engine2.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root2 == null) { cleanup_dir(temp_dir); return false; } engine2.entity_exists_async.begin(new EntityPath("/users"), (obj, res) => { try { exists1 = engine2.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (!exists1) { cleanup_dir(temp_dir); return false; } engine2.entity_exists_async.begin(new EntityPath("/users/john"), (obj, res) => { try { exists2 = engine2.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (!exists2) { cleanup_dir(temp_dir); return false; } engine2.get_entity_async.begin(new EntityPath("/users/john"), (obj, res) => { try { john2 = engine2.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || john2 == null) { cleanup_dir(temp_dir); return false; } ((!)john2).get_entity_property_async.begin("email", (obj, res) => { try { email = ((!)john2).get_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || email == null || ((!)email).is_null()) { cleanup_dir(temp_dir); return false; } string email_val = ((!)email).as(); if (email_val != "john@example.com") { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Cleanup helper void cleanup_dir(string path) { try { Dir dir = Dir.open(path, 0); string? name; while ((name = dir.read_name()) != null) { FileUtils.unlink(Path.build_filename(path, name)); } } catch (FileError e) { // Ignore errors } DirUtils.remove(path); } // ============================================================================ // Virtual Entity Resolution Tests // ============================================================================ // Test 16: Category virtual child resolution - get_entity_async for member bool test_category_virtual_child_resolution() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? container = null; Entity? doc1 = null; Entity? doc2 = null; Entity? category = null; Entity? resolved_doc = null; bool exists = false; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } // Create container ((!)root).create_container_async.begin("posts", (obj, res) => { try { container = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || container == null) { cleanup_dir(temp_dir); return false; } // IMPORTANT: Create category FIRST so hooks are registered ((!)container).create_category_async.begin("published", "Post", "!draft", (obj, res) => { try { category = ((!)container).create_category_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || category == null) { cleanup_dir(temp_dir); return false; } // Now create documents - hooks will update the category index ((!)container).create_document_async.begin("post1", "Post", (obj, res) => { try { doc1 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc1 == null) { cleanup_dir(temp_dir); return false; } // Set draft = false on post1 (matches !draft predicate) ((!)doc1).set_entity_property_async.begin("draft", new Invercargill.NativeElement(false), (obj, res) => { try { ((!)doc1).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } ((!)container).create_document_async.begin("post2", "Post", (obj, res) => { try { doc2 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc2 == null) { cleanup_dir(temp_dir); return false; } // Set draft = true on post2 (does NOT match !draft predicate) ((!)doc2).set_entity_property_async.begin("draft", new Invercargill.NativeElement(true), (obj, res) => { try { ((!)doc2).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Test: Resolve category member via direct path engine.get_entity_async.begin(new EntityPath("/posts/published/post1"), (obj, res) => { try { resolved_doc = engine.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); // post1 should be found (draft = false, matches !draft) if (error != null || resolved_doc == null) { stderr.printf("Failed to resolve post1: %s\n", error != null ? ((!)error).message : "null"); cleanup_dir(temp_dir); return false; } if (((!)resolved_doc).entity_type != EntityType.DOCUMENT) { cleanup_dir(temp_dir); return false; } if (((!)resolved_doc).name != "post1") { cleanup_dir(temp_dir); return false; } // Test: entity_exists_async for category member engine.entity_exists_async.begin(new EntityPath("/posts/published/post1"), (obj, res) => { try { exists = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || !exists) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 17: Category virtual child resolution - non-existent child returns ENTITY_NOT_FOUND bool test_category_virtual_child_not_found() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? container = null; Entity? doc1 = null; Entity? category = null; Entity? resolved_doc = null; bool exists = true; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } // Create container ((!)root).create_container_async.begin("posts", (obj, res) => { try { container = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || container == null) { cleanup_dir(temp_dir); return false; } // IMPORTANT: Create category FIRST so hooks are registered ((!)container).create_category_async.begin("published", "Post", "!draft", (obj, res) => { try { category = ((!)container).create_category_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || category == null) { cleanup_dir(temp_dir); return false; } // Now create document with draft = true (does NOT match !draft predicate) ((!)container).create_document_async.begin("post1", "Post", (obj, res) => { try { doc1 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc1 == null) { cleanup_dir(temp_dir); return false; } ((!)doc1).set_entity_property_async.begin("draft", new Invercargill.NativeElement(true), (obj, res) => { try { ((!)doc1).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Test: Try to resolve non-member (post1 has draft=true, doesn't match !draft) engine.get_entity_async.begin(new EntityPath("/posts/published/post1"), (obj, res) => { try { resolved_doc = engine.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); // post1 should NOT be found (draft = true, doesn't match !draft) if (resolved_doc != null) { cleanup_dir(temp_dir); return false; } // Should have thrown ENTITY_NOT_FOUND if (error == null) { cleanup_dir(temp_dir); return false; } // Test: entity_exists_async for non-member engine.entity_exists_async.begin(new EntityPath("/posts/published/post1"), (obj, res) => { try { exists = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (exists) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 18: Catalogue virtual child resolution - group key returns CatalogueGroup bool test_catalogue_virtual_child_group() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? container = null; Entity? doc1 = null; Entity? doc2 = null; Entity? catalogue = null; Entity? resolved_group = null; bool exists = false; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } // Create container ((!)root).create_container_async.begin("posts", (obj, res) => { try { container = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || container == null) { cleanup_dir(temp_dir); return false; } // IMPORTANT: Create catalogue FIRST so hooks are registered ((!)container).create_catalogue_async.begin("by-author", "Post", "author", (obj, res) => { try { catalogue = ((!)container).create_catalogue_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || catalogue == null) { cleanup_dir(temp_dir); return false; } // Now create documents - hooks will update the catalogue index ((!)container).create_document_async.begin("post1", "Post", (obj, res) => { try { doc1 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc1 == null) { cleanup_dir(temp_dir); return false; } ((!)doc1).set_entity_property_async.begin("author", new Invercargill.NativeElement("john"), (obj, res) => { try { ((!)doc1).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } ((!)container).create_document_async.begin("post2", "Post", (obj, res) => { try { doc2 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc2 == null) { cleanup_dir(temp_dir); return false; } ((!)doc2).set_entity_property_async.begin("author", new Invercargill.NativeElement("jane"), (obj, res) => { try { ((!)doc2).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Test: Resolve group via direct path engine.get_entity_async.begin(new EntityPath("/posts/by-author/john"), (obj, res) => { try { resolved_group = engine.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || resolved_group == null) { stderr.printf("Failed to resolve group: %s\n", error != null ? ((!)error).message : "null"); cleanup_dir(temp_dir); return false; } // Should be a CatalogueGroup (appears as CATALOGUE type) if (((!)resolved_group).entity_type != EntityType.CATALOGUE) { cleanup_dir(temp_dir); return false; } if (((!)resolved_group).name != "john") { cleanup_dir(temp_dir); return false; } // Test: entity_exists_async for group engine.entity_exists_async.begin(new EntityPath("/posts/by-author/john"), (obj, res) => { try { exists = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || !exists) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 19: Catalogue virtual child resolution - document within group bool test_catalogue_virtual_child_document() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? container = null; Entity? doc1 = null; Entity? doc2 = null; Entity? catalogue = null; Entity? resolved_doc = null; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } // Create container ((!)root).create_container_async.begin("posts", (obj, res) => { try { container = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || container == null) { cleanup_dir(temp_dir); return false; } // IMPORTANT: Create catalogue FIRST so hooks are registered ((!)container).create_catalogue_async.begin("by-author", "Post", "author", (obj, res) => { try { catalogue = ((!)container).create_catalogue_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || catalogue == null) { cleanup_dir(temp_dir); return false; } // Now create documents - hooks will update the catalogue index ((!)container).create_document_async.begin("post1", "Post", (obj, res) => { try { doc1 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc1 == null) { cleanup_dir(temp_dir); return false; } ((!)doc1).set_entity_property_async.begin("author", new Invercargill.NativeElement("john"), (obj, res) => { try { ((!)doc1).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } ((!)container).create_document_async.begin("post2", "Post", (obj, res) => { try { doc2 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc2 == null) { cleanup_dir(temp_dir); return false; } ((!)doc2).set_entity_property_async.begin("author", new Invercargill.NativeElement("jane"), (obj, res) => { try { ((!)doc2).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Test: Resolve document via direct path (document name within any group) engine.get_entity_async.begin(new EntityPath("/posts/by-author/post1"), (obj, res) => { try { resolved_doc = engine.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || resolved_doc == null) { stderr.printf("Failed to resolve document: %s\n", error != null ? ((!)error).message : "null"); cleanup_dir(temp_dir); return false; } // Should be a Document if (((!)resolved_doc).entity_type != EntityType.DOCUMENT) { cleanup_dir(temp_dir); return false; } if (((!)resolved_doc).name != "post1") { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 20: Catalogue virtual child resolution - non-existent returns ENTITY_NOT_FOUND bool test_catalogue_virtual_child_not_found() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? container = null; Entity? doc1 = null; Entity? catalogue = null; Entity? resolved = null; bool exists = true; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } // Create container ((!)root).create_container_async.begin("posts", (obj, res) => { try { container = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || container == null) { cleanup_dir(temp_dir); return false; } // Create document ((!)container).create_document_async.begin("post1", "Post", (obj, res) => { try { doc1 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc1 == null) { cleanup_dir(temp_dir); return false; } ((!)doc1).set_entity_property_async.begin("author", new Invercargill.NativeElement("john"), (obj, res) => { try { ((!)doc1).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Create catalogue grouped by author ((!)container).create_catalogue_async.begin("by-author", "Post", "author", (obj, res) => { try { catalogue = ((!)container).create_catalogue_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || catalogue == null) { cleanup_dir(temp_dir); return false; } // Populate the catalogue index var catalogue_impl = catalogue as Implexus.Entities.Catalogue; if (catalogue_impl != null) { try { ((!)catalogue_impl).populate_index(); } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test: Try to resolve non-existent group engine.get_entity_async.begin(new EntityPath("/posts/by-author/nonexistent"), (obj, res) => { try { resolved = engine.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); // Should NOT be found if (resolved != null) { cleanup_dir(temp_dir); return false; } // Should have thrown ENTITY_NOT_FOUND if (error == null) { cleanup_dir(temp_dir); return false; } // Test: entity_exists_async for non-existent engine.entity_exists_async.begin(new EntityPath("/posts/by-author/nonexistent"), (obj, res) => { try { exists = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (exists) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 21: Index virtual child resolution - search pattern returns IndexResult bool test_index_virtual_child_resolution() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? container = null; Entity? doc1 = null; Entity? doc2 = null; Entity? index = null; Entity? resolved_result = null; bool exists = false; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } // Create container ((!)root).create_container_async.begin("articles", (obj, res) => { try { container = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || container == null) { cleanup_dir(temp_dir); return false; } // Create documents FIRST with searchable content ((!)container).create_document_async.begin("article1", "Article", (obj, res) => { try { doc1 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc1 == null) { cleanup_dir(temp_dir); return false; } ((!)doc1).set_entity_property_async.begin("title", new Invercargill.NativeElement("Introduction to Vala"), (obj, res) => { try { ((!)doc1).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } ((!)container).create_document_async.begin("article2", "Article", (obj, res) => { try { doc2 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc2 == null) { cleanup_dir(temp_dir); return false; } ((!)doc2).set_entity_property_async.begin("title", new Invercargill.NativeElement("Advanced Vala Techniques"), (obj, res) => { try { ((!)doc2).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Create index AFTER documents - populate_index() will be called internally ((!)container).create_index_async.begin("search", "Article", "title", (obj, res) => { try { index = ((!)container).create_index_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || index == null) { cleanup_dir(temp_dir); return false; } // Explicitly populate the index (needed for tests) var index_impl = index as Implexus.Entities.Index; if (index_impl != null) { try { ((!)index_impl).populate_index(); } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test: Resolve search pattern via direct path engine.get_entity_async.begin(new EntityPath("/articles/search/*Vala*"), (obj, res) => { try { resolved_result = engine.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || resolved_result == null) { stderr.printf("Failed to resolve search: %s\n", error != null ? ((!)error).message : "null"); cleanup_dir(temp_dir); return false; } // Should be a Container (IndexResult appears as CONTAINER) if (((!)resolved_result).entity_type != EntityType.CONTAINER) { cleanup_dir(temp_dir); return false; } // Test: entity_exists_async for search with matches engine.entity_exists_async.begin(new EntityPath("/articles/search/*Vala*"), (obj, res) => { try { exists = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || !exists) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 22: Index virtual child resolution - no matches returns ENTITY_NOT_FOUND bool test_index_virtual_child_no_matches() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? container = null; Entity? doc1 = null; Entity? index = null; Entity? resolved = null; bool exists = true; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } // Create container ((!)root).create_container_async.begin("articles", (obj, res) => { try { container = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || container == null) { cleanup_dir(temp_dir); return false; } // Create document ((!)container).create_document_async.begin("article1", "Article", (obj, res) => { try { doc1 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc1 == null) { cleanup_dir(temp_dir); return false; } ((!)doc1).set_entity_property_async.begin("title", new Invercargill.NativeElement("Introduction to Vala"), (obj, res) => { try { ((!)doc1).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Create index over title property ((!)container).create_index_async.begin("search", "Article", "title", (obj, res) => { try { index = ((!)container).create_index_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || index == null) { cleanup_dir(temp_dir); return false; } // Populate the index var index_impl = index as Implexus.Entities.Index; if (index_impl != null) { try { ((!)index_impl).populate_index(); } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test: Search with no matches engine.get_entity_async.begin(new EntityPath("/articles/search/*NonExistent*"), (obj, res) => { try { resolved = engine.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); // Should NOT be found if (resolved != null) { cleanup_dir(temp_dir); return false; } // Should have thrown ENTITY_NOT_FOUND if (error == null) { cleanup_dir(temp_dir); return false; } // Test: entity_exists_async for search with no matches engine.entity_exists_async.begin(new EntityPath("/articles/search/*NonExistent*"), (obj, res) => { try { exists = engine.entity_exists_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (exists) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 23: Comparison - direct path equals navigation for Category bool test_category_direct_vs_navigation() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? container = null; Entity? doc1 = null; Entity? category = null; Entity? direct_doc = null; Entity? nav_doc = null; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } // Create container ((!)root).create_container_async.begin("posts", (obj, res) => { try { container = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || container == null) { cleanup_dir(temp_dir); return false; } // IMPORTANT: Create category FIRST so hooks are registered ((!)container).create_category_async.begin("published", "Post", "!draft", (obj, res) => { try { category = ((!)container).create_category_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || category == null) { cleanup_dir(temp_dir); return false; } // Now create document - hooks will update the category index ((!)container).create_document_async.begin("post1", "Post", (obj, res) => { try { doc1 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc1 == null) { cleanup_dir(temp_dir); return false; } ((!)doc1).set_entity_property_async.begin("draft", new Invercargill.NativeElement(false), (obj, res) => { try { ((!)doc1).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Method 1: Direct path lookup engine.get_entity_async.begin(new EntityPath("/posts/published/post1"), (obj, res) => { try { direct_doc = engine.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || direct_doc == null) { cleanup_dir(temp_dir); return false; } // Method 2: Navigation via get_child_async ((!)category).get_child_async.begin("post1", (obj, res) => { try { nav_doc = ((!)category).get_child_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || nav_doc == null) { cleanup_dir(temp_dir); return false; } // Both methods should return the same document (by path) if (((!)direct_doc).path.to_string() != ((!)nav_doc).path.to_string()) { cleanup_dir(temp_dir); return false; } if (((!)direct_doc).name != ((!)nav_doc).name) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 24: Comparison - direct path equals navigation for Catalogue group bool test_catalogue_direct_vs_navigation() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? container = null; Entity? doc1 = null; Entity? catalogue = null; Entity? direct_group = null; Entity? nav_group = null; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } // Create container ((!)root).create_container_async.begin("posts", (obj, res) => { try { container = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || container == null) { cleanup_dir(temp_dir); return false; } // IMPORTANT: Create catalogue FIRST so hooks are registered ((!)container).create_catalogue_async.begin("by-author", "Post", "author", (obj, res) => { try { catalogue = ((!)container).create_catalogue_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || catalogue == null) { cleanup_dir(temp_dir); return false; } // Now create document - hooks will update the catalogue index ((!)container).create_document_async.begin("post1", "Post", (obj, res) => { try { doc1 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc1 == null) { cleanup_dir(temp_dir); return false; } ((!)doc1).set_entity_property_async.begin("author", new Invercargill.NativeElement("john"), (obj, res) => { try { ((!)doc1).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Method 1: Direct path lookup engine.get_entity_async.begin(new EntityPath("/posts/by-author/john"), (obj, res) => { try { direct_group = engine.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || direct_group == null) { cleanup_dir(temp_dir); return false; } // Method 2: Navigation via get_child_async ((!)catalogue).get_child_async.begin("john", (obj, res) => { try { nav_group = ((!)catalogue).get_child_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || nav_group == null) { cleanup_dir(temp_dir); return false; } // Both methods should return the same group (by path) if (((!)direct_group).path.to_string() != ((!)nav_group).path.to_string()) { cleanup_dir(temp_dir); return false; } if (((!)direct_group).name != ((!)nav_group).name) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; } // Test 25: Comparison - direct path equals navigation for Index search bool test_index_direct_vs_navigation() { string temp_dir = create_temp_dir(); var engine = new EmbeddedEngine.with_path(temp_dir); var loop = new MainLoop(); Entity? root = null; Entity? container = null; Entity? doc1 = null; Entity? index = null; Entity? direct_result = null; Entity? nav_result = null; Error? error = null; engine.get_root_async.begin((obj, res) => { try { root = engine.get_root_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || root == null) { cleanup_dir(temp_dir); return false; } // Create container ((!)root).create_container_async.begin("articles", (obj, res) => { try { container = ((!)root).create_container_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || container == null) { cleanup_dir(temp_dir); return false; } // Create document FIRST with searchable content ((!)container).create_document_async.begin("article1", "Article", (obj, res) => { try { doc1 = ((!)container).create_document_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || doc1 == null) { cleanup_dir(temp_dir); return false; } ((!)doc1).set_entity_property_async.begin("title", new Invercargill.NativeElement("Introduction to Vala"), (obj, res) => { try { ((!)doc1).set_entity_property_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null) { cleanup_dir(temp_dir); return false; } // Create index AFTER documents - populate_index() will be called internally ((!)container).create_index_async.begin("search", "Article", "title", (obj, res) => { try { index = ((!)container).create_index_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || index == null) { cleanup_dir(temp_dir); return false; } // Explicitly populate the index (needed for tests) var index_impl = index as Implexus.Entities.Index; if (index_impl != null) { try { ((!)index_impl).populate_index(); } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Method 1: Direct path lookup engine.get_entity_async.begin(new EntityPath("/articles/search/*Vala*"), (obj, res) => { try { direct_result = engine.get_entity_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || direct_result == null) { cleanup_dir(temp_dir); return false; } // Method 2: Navigation via get_child_async ((!)index).get_child_async.begin("*Vala*", (obj, res) => { try { nav_result = ((!)index).get_child_async.end(res); } catch (Error e) { error = e; } loop.quit(); }); loop.run(); if (error != null || nav_result == null) { cleanup_dir(temp_dir); return false; } // Both methods should return an IndexResult with the same path if (((!)direct_result).path.to_string() != ((!)nav_result).path.to_string()) { cleanup_dir(temp_dir); return false; } cleanup_dir(temp_dir); return true; }