/** * EntityPathTest - Unit tests for EntityPath */ using Implexus.Core; public static int main(string[] args) { int passed = 0; int failed = 0; // Test 1: Root path parsing if (test_root_path()) { passed++; stdout.puts("PASS: test_root_path\n"); } else { failed++; stdout.puts("FAIL: test_root_path\n"); } // Test 2: Simple path parsing if (test_simple_path()) { passed++; stdout.puts("PASS: test_simple_path\n"); } else { failed++; stdout.puts("FAIL: test_simple_path\n"); } // Test 3: Nested path parsing if (test_nested_path()) { passed++; stdout.puts("PASS: test_nested_path\n"); } else { failed++; stdout.puts("FAIL: test_nested_path\n"); } // Test 4: Path construction if (test_path_construction()) { passed++; stdout.puts("PASS: test_path_construction\n"); } else { failed++; stdout.puts("FAIL: test_path_construction\n"); } // Test 5: Parent relationship if (test_parent_relationship()) { passed++; stdout.puts("PASS: test_parent_relationship\n"); } else { failed++; stdout.puts("FAIL: test_parent_relationship\n"); } // Test 6: Child relationship if (test_child_relationship()) { passed++; stdout.puts("PASS: test_child_relationship\n"); } else { failed++; stdout.puts("FAIL: test_child_relationship\n"); } // Test 7: Ancestor/descendant if (test_ancestor_descendant()) { passed++; stdout.puts("PASS: test_ancestor_descendant\n"); } else { failed++; stdout.puts("FAIL: test_ancestor_descendant\n"); } // Test 8: Path equality if (test_path_equality()) { passed++; stdout.puts("PASS: test_path_equality\n"); } else { failed++; stdout.puts("FAIL: test_path_equality\n"); } // Test 9: Path to string if (test_path_to_string()) { passed++; stdout.puts("PASS: test_path_to_string\n"); } else { failed++; stdout.puts("FAIL: test_path_to_string\n"); } // Test 10: Path key serialization if (test_path_key_serialization()) { passed++; stdout.puts("PASS: test_path_key_serialization\n"); } else { failed++; stdout.puts("FAIL: test_path_key_serialization\n"); } // Test 11: Resolve relative path if (test_resolve_relative()) { passed++; stdout.puts("PASS: test_resolve_relative\n"); } else { failed++; stdout.puts("FAIL: test_resolve_relative\n"); } // Test 12: Edge cases if (test_edge_cases()) { passed++; stdout.puts("PASS: test_edge_cases\n"); } else { failed++; stdout.puts("FAIL: test_edge_cases\n"); } // Test 13: Path depth if (test_path_depth()) { passed++; stdout.puts("PASS: test_path_depth\n"); } else { failed++; stdout.puts("FAIL: test_path_depth\n"); } // Test 14: Path name if (test_path_name()) { passed++; stdout.puts("PASS: test_path_name\n"); } else { failed++; stdout.puts("FAIL: test_path_name\n"); } // Test 15: Relative path if (test_relative_to()) { passed++; stdout.puts("PASS: test_relative_to\n"); } else { failed++; stdout.puts("FAIL: test_relative_to\n"); } // Test 16: Slash rejection in entity names if (test_slash_rejection()) { passed++; stdout.puts("PASS: test_slash_rejection\n"); } else { failed++; stdout.puts("FAIL: test_slash_rejection\n"); } // Test 17: Key separator is slash if (test_key_separator_is_slash()) { passed++; stdout.puts("PASS: test_key_separator_is_slash\n"); } else { failed++; stdout.puts("FAIL: test_key_separator_is_slash\n"); } stdout.printf("\nResults: %d passed, %d failed\n", passed, failed); return failed > 0 ? 1 : 0; } // Test 1: Root path parsing bool test_root_path() { var root1 = new EntityPath.root(); var root2 = new EntityPath("/"); var root3 = new EntityPath(""); if (!root1.is_root) return false; if (!root2.is_root) return false; if (!root3.is_root) return false; if (root1.to_string() != "/") return false; if (root1.depth != 0) return false; if (root1.name != "") return false; return true; } // Test 2: Simple path parsing bool test_simple_path() { var path = new EntityPath("/users"); if (path.is_root) return false; if (path.depth != 1) return false; if (path.name != "users") return false; if (path.to_string() != "/users") return false; return true; } // Test 3: Nested path parsing bool test_nested_path() { var path = new EntityPath("/users/john/profile"); if (path.is_root) return false; if (path.depth != 3) return false; if (path.name != "profile") return false; if (path.to_string() != "/users/john/profile") return false; return true; } // Test 4: Path construction bool test_path_construction() { var root = new EntityPath.root(); var users = root.append_child("users"); var john = users.append_child("john"); if (!root.is_root) return false; if (users.to_string() != "/users") return false; if (john.to_string() != "/users/john") return false; return true; } // Test 5: Parent relationship bool test_parent_relationship() { var path = new EntityPath("/users/john"); var parent = path.parent; if (parent.is_root) return false; // Parent of "/users/john" is "/users", not root if (parent.to_string() != "/users") return false; var root = new EntityPath.root(); if (root.parent != root) return false; // Root's parent is itself return true; } // Test 6: Child relationship bool test_child_relationship() { var parent = new EntityPath("/users"); var child = parent.append_child("john"); if (child.to_string() != "/users/john") return false; if (child.parent.equals(parent) == false) return false; return true; } // Test 7: Ancestor/descendant bool test_ancestor_descendant() { var root = new EntityPath.root(); var users = new EntityPath("/users"); var john = new EntityPath("/users/john"); var profile = new EntityPath("/users/john/profile"); if (!root.is_ancestor_of(users)) return false; if (!root.is_ancestor_of(john)) return false; if (!users.is_ancestor_of(john)) return false; if (!john.is_ancestor_of(profile)) return false; if (root.is_ancestor_of(root)) return false; // Not ancestor of itself if (john.is_ancestor_of(users)) return false; // Wrong direction if (!profile.is_descendant_of(root)) return false; if (!profile.is_descendant_of(users)) return false; if (!john.is_descendant_of(root)) return false; return true; } // Test 8: Path equality bool test_path_equality() { var path1 = new EntityPath("/users/john"); var path2 = new EntityPath("/users/john"); var path3 = new EntityPath("/users/jane"); var root1 = new EntityPath.root(); var root2 = new EntityPath("/"); if (!path1.equals(path2)) return false; if (path1.equals(path3)) return false; if (!root1.equals(root2)) return false; // Hash codes should match for equal paths if (path1.hash_code() != path2.hash_code()) return false; if (root1.hash_code() != root2.hash_code()) return false; return true; } // Test 9: Path to string bool test_path_to_string() { var paths = new string[] { "/", "/users", "/users/john", "/a/b/c/d" }; foreach (var path_str in paths) { var path = new EntityPath(path_str); if (path.to_string() != path_str) return false; } return true; } // Test 10: Path key serialization bool test_path_key_serialization() { var paths = new EntityPath[] { new EntityPath.root(), new EntityPath("/users"), new EntityPath("/users/john/profile") }; foreach (var path in paths) { var key = path.to_key(); var restored = EntityPath.from_key(key); if (!path.equals(restored)) return false; } return true; } // Test 11: Resolve relative path bool test_resolve_relative() { var base_path = new EntityPath("/users/john"); // Test simple child var result1 = base_path.resolve(new EntityPath("profile")); if (result1.to_string() != "/users/john/profile") return false; // Test parent navigation var result2 = base_path.resolve(new EntityPath("..")); if (result2.to_string() != "/users") return false; // Test current directory var result3 = base_path.resolve(new EntityPath(".")); if (result3.to_string() != "/users/john") return false; // Test combined var result4 = base_path.resolve(new EntityPath("../jane")); if (result4.to_string() != "/users/jane") return false; return true; } // Test 12: Edge cases bool test_edge_cases() { // Trailing slash var path1 = new EntityPath("/users/"); if (path1.to_string() != "/users") return false; // Multiple slashes (empty segments are skipped) var path2 = new EntityPath("/users//john"); // This should normalize to /users/john if (path2.depth != 2) return false; // Root variations var root1 = new EntityPath.root(); var root2 = new EntityPath("/"); var root3 = new EntityPath(""); if (!root1.equals(root2)) return false; if (!root1.equals(root3)) return false; return true; } // Test 13: Path depth bool test_path_depth() { if (new EntityPath.root().depth != 0) return false; if (new EntityPath("/a").depth != 1) return false; if (new EntityPath("/a/b").depth != 2) return false; if (new EntityPath("/a/b/c").depth != 3) return false; return true; } // Test 14: Path name bool test_path_name() { if (new EntityPath.root().name != "") return false; if (new EntityPath("/users").name != "users") return false; if (new EntityPath("/users/john").name != "john") return false; return true; } // Test 15: Relative path bool test_relative_to() { var root = new EntityPath.root(); var users = new EntityPath("/users"); var john = new EntityPath("/users/john"); var profile = new EntityPath("/users/john/profile"); try { var rel1 = profile.relative_to(john); if (rel1.to_string() != "/profile") return false; var rel2 = profile.relative_to(root); if (rel2.to_string() != "/users/john/profile") return false; var rel3 = john.relative_to(users); if (rel3.to_string() != "/john") return false; } catch (EngineError e) { return false; } // Should throw for non-ancestor try { john.relative_to(profile); return false; // Should have thrown } catch (EngineError e) { // Expected } return true; } // Test 16: Slash rejection in entity names bool test_slash_rejection() { // The validate_name method rejects "/" in entity names // This is tested via append_child which catches the error internally // For now, we verify that paths with "/" in parsing are split correctly // (i.e., "/a/b" becomes two segments "a" and "b", not one segment "a/b") var path = new EntityPath("/users/john"); if (path.depth != 2) return false; if (path.name != "john") return false; // Verify KEY_SEPARATOR constant is "/" if (EntityPath.KEY_SEPARATOR != "/") return false; return true; } // Test 17: Key separator is slash bool test_key_separator_is_slash() { // Test that to_key() uses "/" as separator var path = new EntityPath("/users/john/profile"); var key = path.to_key(); // Key should be "users/john/profile" (no leading slash, "/" between segments) if (key != "users/john/profile") return false; // Test round-trip var restored = EntityPath.from_key(key); if (!path.equals(restored)) return false; // Test root path var root = new EntityPath.root(); if (root.to_key() != "") return false; var restored_root = EntityPath.from_key(""); if (!restored_root.is_root) return false; // Test single segment var single = new EntityPath("/users"); if (single.to_key() != "users") return false; return true; }