EntityPathTest.vala 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. /**
  2. * EntityPathTest - Unit tests for EntityPath
  3. */
  4. using Implexus.Core;
  5. public static int main(string[] args) {
  6. int passed = 0;
  7. int failed = 0;
  8. // Test 1: Root path parsing
  9. if (test_root_path()) {
  10. passed++;
  11. stdout.puts("PASS: test_root_path\n");
  12. } else {
  13. failed++;
  14. stdout.puts("FAIL: test_root_path\n");
  15. }
  16. // Test 2: Simple path parsing
  17. if (test_simple_path()) {
  18. passed++;
  19. stdout.puts("PASS: test_simple_path\n");
  20. } else {
  21. failed++;
  22. stdout.puts("FAIL: test_simple_path\n");
  23. }
  24. // Test 3: Nested path parsing
  25. if (test_nested_path()) {
  26. passed++;
  27. stdout.puts("PASS: test_nested_path\n");
  28. } else {
  29. failed++;
  30. stdout.puts("FAIL: test_nested_path\n");
  31. }
  32. // Test 4: Path construction
  33. if (test_path_construction()) {
  34. passed++;
  35. stdout.puts("PASS: test_path_construction\n");
  36. } else {
  37. failed++;
  38. stdout.puts("FAIL: test_path_construction\n");
  39. }
  40. // Test 5: Parent relationship
  41. if (test_parent_relationship()) {
  42. passed++;
  43. stdout.puts("PASS: test_parent_relationship\n");
  44. } else {
  45. failed++;
  46. stdout.puts("FAIL: test_parent_relationship\n");
  47. }
  48. // Test 6: Child relationship
  49. if (test_child_relationship()) {
  50. passed++;
  51. stdout.puts("PASS: test_child_relationship\n");
  52. } else {
  53. failed++;
  54. stdout.puts("FAIL: test_child_relationship\n");
  55. }
  56. // Test 7: Ancestor/descendant
  57. if (test_ancestor_descendant()) {
  58. passed++;
  59. stdout.puts("PASS: test_ancestor_descendant\n");
  60. } else {
  61. failed++;
  62. stdout.puts("FAIL: test_ancestor_descendant\n");
  63. }
  64. // Test 8: Path equality
  65. if (test_path_equality()) {
  66. passed++;
  67. stdout.puts("PASS: test_path_equality\n");
  68. } else {
  69. failed++;
  70. stdout.puts("FAIL: test_path_equality\n");
  71. }
  72. // Test 9: Path to string
  73. if (test_path_to_string()) {
  74. passed++;
  75. stdout.puts("PASS: test_path_to_string\n");
  76. } else {
  77. failed++;
  78. stdout.puts("FAIL: test_path_to_string\n");
  79. }
  80. // Test 10: Path key serialization
  81. if (test_path_key_serialization()) {
  82. passed++;
  83. stdout.puts("PASS: test_path_key_serialization\n");
  84. } else {
  85. failed++;
  86. stdout.puts("FAIL: test_path_key_serialization\n");
  87. }
  88. // Test 11: Resolve relative path
  89. if (test_resolve_relative()) {
  90. passed++;
  91. stdout.puts("PASS: test_resolve_relative\n");
  92. } else {
  93. failed++;
  94. stdout.puts("FAIL: test_resolve_relative\n");
  95. }
  96. // Test 12: Edge cases
  97. if (test_edge_cases()) {
  98. passed++;
  99. stdout.puts("PASS: test_edge_cases\n");
  100. } else {
  101. failed++;
  102. stdout.puts("FAIL: test_edge_cases\n");
  103. }
  104. // Test 13: Path depth
  105. if (test_path_depth()) {
  106. passed++;
  107. stdout.puts("PASS: test_path_depth\n");
  108. } else {
  109. failed++;
  110. stdout.puts("FAIL: test_path_depth\n");
  111. }
  112. // Test 14: Path name
  113. if (test_path_name()) {
  114. passed++;
  115. stdout.puts("PASS: test_path_name\n");
  116. } else {
  117. failed++;
  118. stdout.puts("FAIL: test_path_name\n");
  119. }
  120. // Test 15: Relative path
  121. if (test_relative_to()) {
  122. passed++;
  123. stdout.puts("PASS: test_relative_to\n");
  124. } else {
  125. failed++;
  126. stdout.puts("FAIL: test_relative_to\n");
  127. }
  128. // Test 16: Slash rejection in entity names
  129. if (test_slash_rejection()) {
  130. passed++;
  131. stdout.puts("PASS: test_slash_rejection\n");
  132. } else {
  133. failed++;
  134. stdout.puts("FAIL: test_slash_rejection\n");
  135. }
  136. // Test 17: Key separator is slash
  137. if (test_key_separator_is_slash()) {
  138. passed++;
  139. stdout.puts("PASS: test_key_separator_is_slash\n");
  140. } else {
  141. failed++;
  142. stdout.puts("FAIL: test_key_separator_is_slash\n");
  143. }
  144. stdout.printf("\nResults: %d passed, %d failed\n", passed, failed);
  145. return failed > 0 ? 1 : 0;
  146. }
  147. // Test 1: Root path parsing
  148. bool test_root_path() {
  149. var root1 = new EntityPath.root();
  150. var root2 = new EntityPath("/");
  151. var root3 = new EntityPath("");
  152. if (!root1.is_root) return false;
  153. if (!root2.is_root) return false;
  154. if (!root3.is_root) return false;
  155. if (root1.to_string() != "/") return false;
  156. if (root1.depth != 0) return false;
  157. if (root1.name != "") return false;
  158. return true;
  159. }
  160. // Test 2: Simple path parsing
  161. bool test_simple_path() {
  162. var path = new EntityPath("/users");
  163. if (path.is_root) return false;
  164. if (path.depth != 1) return false;
  165. if (path.name != "users") return false;
  166. if (path.to_string() != "/users") return false;
  167. return true;
  168. }
  169. // Test 3: Nested path parsing
  170. bool test_nested_path() {
  171. var path = new EntityPath("/users/john/profile");
  172. if (path.is_root) return false;
  173. if (path.depth != 3) return false;
  174. if (path.name != "profile") return false;
  175. if (path.to_string() != "/users/john/profile") return false;
  176. return true;
  177. }
  178. // Test 4: Path construction
  179. bool test_path_construction() {
  180. var root = new EntityPath.root();
  181. var users = root.append_child("users");
  182. var john = users.append_child("john");
  183. if (!root.is_root) return false;
  184. if (users.to_string() != "/users") return false;
  185. if (john.to_string() != "/users/john") return false;
  186. return true;
  187. }
  188. // Test 5: Parent relationship
  189. bool test_parent_relationship() {
  190. var path = new EntityPath("/users/john");
  191. var parent = path.parent;
  192. if (parent.is_root) return false; // Parent of "/users/john" is "/users", not root
  193. if (parent.to_string() != "/users") return false;
  194. var root = new EntityPath.root();
  195. if (root.parent != root) return false; // Root's parent is itself
  196. return true;
  197. }
  198. // Test 6: Child relationship
  199. bool test_child_relationship() {
  200. var parent = new EntityPath("/users");
  201. var child = parent.append_child("john");
  202. if (child.to_string() != "/users/john") return false;
  203. if (child.parent.equals(parent) == false) return false;
  204. return true;
  205. }
  206. // Test 7: Ancestor/descendant
  207. bool test_ancestor_descendant() {
  208. var root = new EntityPath.root();
  209. var users = new EntityPath("/users");
  210. var john = new EntityPath("/users/john");
  211. var profile = new EntityPath("/users/john/profile");
  212. if (!root.is_ancestor_of(users)) return false;
  213. if (!root.is_ancestor_of(john)) return false;
  214. if (!users.is_ancestor_of(john)) return false;
  215. if (!john.is_ancestor_of(profile)) return false;
  216. if (root.is_ancestor_of(root)) return false; // Not ancestor of itself
  217. if (john.is_ancestor_of(users)) return false; // Wrong direction
  218. if (!profile.is_descendant_of(root)) return false;
  219. if (!profile.is_descendant_of(users)) return false;
  220. if (!john.is_descendant_of(root)) return false;
  221. return true;
  222. }
  223. // Test 8: Path equality
  224. bool test_path_equality() {
  225. var path1 = new EntityPath("/users/john");
  226. var path2 = new EntityPath("/users/john");
  227. var path3 = new EntityPath("/users/jane");
  228. var root1 = new EntityPath.root();
  229. var root2 = new EntityPath("/");
  230. if (!path1.equals(path2)) return false;
  231. if (path1.equals(path3)) return false;
  232. if (!root1.equals(root2)) return false;
  233. // Hash codes should match for equal paths
  234. if (path1.hash_code() != path2.hash_code()) return false;
  235. if (root1.hash_code() != root2.hash_code()) return false;
  236. return true;
  237. }
  238. // Test 9: Path to string
  239. bool test_path_to_string() {
  240. var paths = new string[] { "/", "/users", "/users/john", "/a/b/c/d" };
  241. foreach (var path_str in paths) {
  242. var path = new EntityPath(path_str);
  243. if (path.to_string() != path_str) return false;
  244. }
  245. return true;
  246. }
  247. // Test 10: Path key serialization
  248. bool test_path_key_serialization() {
  249. var paths = new EntityPath[] {
  250. new EntityPath.root(),
  251. new EntityPath("/users"),
  252. new EntityPath("/users/john/profile")
  253. };
  254. foreach (var path in paths) {
  255. var key = path.to_key();
  256. var restored = EntityPath.from_key(key);
  257. if (!path.equals(restored)) return false;
  258. }
  259. return true;
  260. }
  261. // Test 11: Resolve relative path
  262. bool test_resolve_relative() {
  263. var base_path = new EntityPath("/users/john");
  264. // Test simple child
  265. var result1 = base_path.resolve(new EntityPath("profile"));
  266. if (result1.to_string() != "/users/john/profile") return false;
  267. // Test parent navigation
  268. var result2 = base_path.resolve(new EntityPath(".."));
  269. if (result2.to_string() != "/users") return false;
  270. // Test current directory
  271. var result3 = base_path.resolve(new EntityPath("."));
  272. if (result3.to_string() != "/users/john") return false;
  273. // Test combined
  274. var result4 = base_path.resolve(new EntityPath("../jane"));
  275. if (result4.to_string() != "/users/jane") return false;
  276. return true;
  277. }
  278. // Test 12: Edge cases
  279. bool test_edge_cases() {
  280. // Trailing slash
  281. var path1 = new EntityPath("/users/");
  282. if (path1.to_string() != "/users") return false;
  283. // Multiple slashes (empty segments are skipped)
  284. var path2 = new EntityPath("/users//john");
  285. // This should normalize to /users/john
  286. if (path2.depth != 2) return false;
  287. // Root variations
  288. var root1 = new EntityPath.root();
  289. var root2 = new EntityPath("/");
  290. var root3 = new EntityPath("");
  291. if (!root1.equals(root2)) return false;
  292. if (!root1.equals(root3)) return false;
  293. return true;
  294. }
  295. // Test 13: Path depth
  296. bool test_path_depth() {
  297. if (new EntityPath.root().depth != 0) return false;
  298. if (new EntityPath("/a").depth != 1) return false;
  299. if (new EntityPath("/a/b").depth != 2) return false;
  300. if (new EntityPath("/a/b/c").depth != 3) return false;
  301. return true;
  302. }
  303. // Test 14: Path name
  304. bool test_path_name() {
  305. if (new EntityPath.root().name != "") return false;
  306. if (new EntityPath("/users").name != "users") return false;
  307. if (new EntityPath("/users/john").name != "john") return false;
  308. return true;
  309. }
  310. // Test 15: Relative path
  311. bool test_relative_to() {
  312. var root = new EntityPath.root();
  313. var users = new EntityPath("/users");
  314. var john = new EntityPath("/users/john");
  315. var profile = new EntityPath("/users/john/profile");
  316. try {
  317. var rel1 = profile.relative_to(john);
  318. if (rel1.to_string() != "/profile") return false;
  319. var rel2 = profile.relative_to(root);
  320. if (rel2.to_string() != "/users/john/profile") return false;
  321. var rel3 = john.relative_to(users);
  322. if (rel3.to_string() != "/john") return false;
  323. } catch (EngineError e) {
  324. return false;
  325. }
  326. // Should throw for non-ancestor
  327. try {
  328. john.relative_to(profile);
  329. return false; // Should have thrown
  330. } catch (EngineError e) {
  331. // Expected
  332. }
  333. return true;
  334. }
  335. // Test 16: Slash rejection in entity names
  336. bool test_slash_rejection() {
  337. // The validate_name method rejects "/" in entity names
  338. // This is tested via append_child which catches the error internally
  339. // For now, we verify that paths with "/" in parsing are split correctly
  340. // (i.e., "/a/b" becomes two segments "a" and "b", not one segment "a/b")
  341. var path = new EntityPath("/users/john");
  342. if (path.depth != 2) return false;
  343. if (path.name != "john") return false;
  344. // Verify KEY_SEPARATOR constant is "/"
  345. if (EntityPath.KEY_SEPARATOR != "/") return false;
  346. return true;
  347. }
  348. // Test 17: Key separator is slash
  349. bool test_key_separator_is_slash() {
  350. // Test that to_key() uses "/" as separator
  351. var path = new EntityPath("/users/john/profile");
  352. var key = path.to_key();
  353. // Key should be "users/john/profile" (no leading slash, "/" between segments)
  354. if (key != "users/john/profile") return false;
  355. // Test round-trip
  356. var restored = EntityPath.from_key(key);
  357. if (!path.equals(restored)) return false;
  358. // Test root path
  359. var root = new EntityPath.root();
  360. if (root.to_key() != "") return false;
  361. var restored_root = EntityPath.from_key("");
  362. if (!restored_root.is_root) return false;
  363. // Test single segment
  364. var single = new EntityPath("/users");
  365. if (single.to_key() != "users") return false;
  366. return true;
  367. }