| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- /**
- * SafePathTest - Unit tests for SafePath
- *
- * Comprehensive tests for the SafePath factory class which creates
- * URL-encoded EntityPath instances.
- */
- using Implexus.Core;
- public static int main(string[] args) {
- int passed = 0;
- int failed = 0;
- // ========================================
- // 1. Basic Path Construction Tests
- // ========================================
-
- // Test: Single segment path
- if (test_basic_single_segment()) {
- passed++;
- stdout.puts("PASS: test_basic_single_segment\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_basic_single_segment\n");
- }
- // Test: Multi-segment path
- if (test_basic_multi_segment()) {
- passed++;
- stdout.puts("PASS: test_basic_multi_segment\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_basic_multi_segment\n");
- }
- // Test: Empty segments handling
- if (test_basic_empty_segments()) {
- passed++;
- stdout.puts("PASS: test_basic_empty_segments\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_basic_empty_segments\n");
- }
- // ========================================
- // 2. URL Encoding Tests
- // ========================================
- // Test: Spaces in segments
- if (test_encoding_spaces()) {
- passed++;
- stdout.puts("PASS: test_encoding_spaces\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_encoding_spaces\n");
- }
- // Test: Special characters (/, ?, #, =, &)
- if (test_encoding_special_chars()) {
- passed++;
- stdout.puts("PASS: test_encoding_special_chars\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_encoding_special_chars\n");
- }
- // Test: Unicode characters (Japanese, emoji)
- if (test_encoding_unicode()) {
- passed++;
- stdout.puts("PASS: test_encoding_unicode\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_encoding_unicode\n");
- }
- // Test: Reserved characters that should be encoded
- if (test_encoding_reserved_chars()) {
- passed++;
- stdout.puts("PASS: test_encoding_reserved_chars\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_encoding_reserved_chars\n");
- }
- // ========================================
- // 3. Variadic API Tests
- // ========================================
- // Test: Null as first argument (should return root path)
- if (test_variadic_null_first()) {
- passed++;
- stdout.puts("PASS: test_variadic_null_first\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_variadic_null_first\n");
- }
- // Test: Single segment + null
- if (test_variadic_single_segment()) {
- passed++;
- stdout.puts("PASS: test_variadic_single_segment\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_variadic_single_segment\n");
- }
- // Test: Multiple segments + null
- if (test_variadic_multiple_segments()) {
- passed++;
- stdout.puts("PASS: test_variadic_multiple_segments\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_variadic_multiple_segments\n");
- }
- // ========================================
- // 4. Array API Tests
- // ========================================
- // Test: Normal array of segments
- if (test_array_normal()) {
- passed++;
- stdout.puts("PASS: test_array_normal\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_array_normal\n");
- }
- // Test: Empty array (should return root path)
- if (test_array_empty()) {
- passed++;
- stdout.puts("PASS: test_array_empty\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_array_empty\n");
- }
- // Test: Array with special characters
- if (test_array_special_chars()) {
- passed++;
- stdout.puts("PASS: test_array_special_chars\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_array_special_chars\n");
- }
- // ========================================
- // 5. Decode Tests
- // ========================================
- // Test: Decoding %20 to space
- if (test_decode_space()) {
- passed++;
- stdout.puts("PASS: test_decode_space\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_decode_space\n");
- }
- // Test: Decoding %2F to /
- if (test_decode_slash()) {
- passed++;
- stdout.puts("PASS: test_decode_slash\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_decode_slash\n");
- }
- // Test: Decoding unicode percent-encoded strings
- if (test_decode_unicode()) {
- passed++;
- stdout.puts("PASS: test_decode_unicode\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_decode_unicode\n");
- }
- // Test: Invalid encoding error handling
- if (test_decode_invalid_encoding()) {
- passed++;
- stdout.puts("PASS: test_decode_invalid_encoding\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_decode_invalid_encoding\n");
- }
- // ========================================
- // 6. Integration Tests
- // ========================================
- // Test: Verify returned EntityPath works correctly
- if (test_integration_entity_path()) {
- passed++;
- stdout.puts("PASS: test_integration_entity_path\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_integration_entity_path\n");
- }
- // Test: to_string() on resulting paths
- if (test_integration_to_string()) {
- passed++;
- stdout.puts("PASS: test_integration_to_string\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_integration_to_string\n");
- }
- // Test: Path operations (parent, append_child)
- if (test_integration_path_operations()) {
- passed++;
- stdout.puts("PASS: test_integration_path_operations\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_integration_path_operations\n");
- }
- // Test: Round-trip encode/decode
- if (test_round_trip()) {
- passed++;
- stdout.puts("PASS: test_round_trip\n");
- } else {
- failed++;
- stdout.puts("FAIL: test_round_trip\n");
- }
- stdout.printf("\nResults: %d passed, %d failed\n", passed, failed);
- return failed > 0 ? 1 : 0;
- }
- // ========================================
- // 1. Basic Path Construction Tests
- // ========================================
- // Test: Single segment path
- bool test_basic_single_segment() {
- var path = SafePath.path("catalogue", null);
-
- if (path.is_root) return false;
- if (path.depth != 1) return false;
- if (path.name != "catalogue") return false;
- if (path.to_string() != "/catalogue") return false;
-
- return true;
- }
- // Test: Multi-segment path
- bool test_basic_multi_segment() {
- var path = SafePath.path("catalogue", "category", "document", null);
-
- if (path.is_root) return false;
- if (path.depth != 3) return false;
- if (path.name != "document") return false;
- if (path.to_string() != "/catalogue/category/document") return false;
-
- return true;
- }
- // Test: Empty segments handling
- bool test_basic_empty_segments() {
- // Empty string segment should be preserved as empty encoded segment
- var path = SafePath.path("a", "", "c", null);
-
- // Empty segments should still be counted
- if (path.depth != 3) return false;
-
- return true;
- }
- // ========================================
- // 2. URL Encoding Tests
- // ========================================
- // Test: Spaces in segments (should be encoded as %20)
- bool test_encoding_spaces() {
- var path = SafePath.path("users", "john doe", null);
- string path_str = path.to_string();
-
- // Space should be encoded as %20
- if (!path_str.contains("%20")) return false;
- if (path_str.contains(" ")) return false; // No literal space
- if (path_str != "/users/john%20doe") return false;
-
- // Test multiple spaces
- var path2 = SafePath.path("hello world test", null);
- if (path2.to_string() != "/hello%20world%20test") return false;
-
- return true;
- }
- // Test: Special characters (/, ?, #, =, &)
- bool test_encoding_special_chars() {
- // Forward slash should be encoded
- var path1 = SafePath.path("a/b", null);
- if (!path1.to_string().contains("%2F")) return false;
-
- // Question mark should be encoded
- var path2 = SafePath.path("query?param", null);
- if (!path2.to_string().contains("%3F")) return false;
-
- // Hash should be encoded
- var path3 = SafePath.path("anchor#link", null);
- if (!path3.to_string().contains("%23")) return false;
-
- // Equals should be encoded
- var path4 = SafePath.path("key=value", null);
- if (!path4.to_string().contains("%3D")) return false;
-
- // Ampersand should be encoded
- var path5 = SafePath.path("a&b", null);
- if (!path5.to_string().contains("%26")) return false;
-
- return true;
- }
- // Test: Unicode characters (Japanese, emoji)
- // Note: GLib.Uri.escape_string preserves unicode characters as-is (IRIs)
- // This is correct behavior for modern URIs
- bool test_encoding_unicode() {
- // Japanese characters - preserved as-is in the path
- var path1 = SafePath.path("ユーザー", null);
- string str1 = path1.to_string();
- // Should contain the unicode characters
- if (!str1.has_prefix("/")) return false;
- if (!str1.contains("ユーザー")) return false; // Unicode preserved
-
- // Emoji - also preserved
- var path2 = SafePath.path("hello🎉world", null);
- string str2 = path2.to_string();
- if (!str2.contains("🎉")) return false;
-
- // Chinese characters - also preserved
- var path3 = SafePath.path("用户", null);
- string str3 = path3.to_string();
- if (!str3.contains("用户")) return false;
-
- // But special URI characters within unicode strings should still be encoded
- var path4 = SafePath.path("ユーザー/名前", null);
- string str4 = path4.to_string();
- if (!str4.contains("%2F")) return false; // Slash should be encoded
-
- return true;
- }
- // Test: Reserved characters that should be encoded
- bool test_encoding_reserved_chars() {
- // Test various reserved characters
- string[] reserved_chars = { ":", "/", "?", "#", "[", "]", "@", "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "=" };
-
- foreach (var ch in reserved_chars) {
- var path = SafePath.path("test" + ch + "value", null);
- string result = path.to_string();
- // Reserved chars should be encoded (contain %)
- // The character itself should not appear literally (except for special cases)
- if (ch != "/" && result.contains(ch) && !result.contains("%")) {
- return false;
- }
- }
-
- return true;
- }
- // ========================================
- // 3. Variadic API Tests
- // ========================================
- // Test: Null as first argument (should return root path)
- bool test_variadic_null_first() {
- var path = SafePath.path(null);
-
- if (!path.is_root) return false;
- if (path.depth != 0) return false;
- if (path.to_string() != "/") return false;
-
- return true;
- }
- // Test: Single segment + null
- bool test_variadic_single_segment() {
- var path = SafePath.path("catalogue", null);
-
- if (path.is_root) return false;
- if (path.depth != 1) return false;
- if (path.name != "catalogue") return false;
-
- return true;
- }
- // Test: Multiple segments + null
- bool test_variadic_multiple_segments() {
- var path = SafePath.path("a", "b", "c", "d", "e", null);
-
- if (path.depth != 5) return false;
- if (path.to_string() != "/a/b/c/d/e") return false;
-
- // Verify each segment
- if (path.name != "e") return false;
- if (path.parent.name != "d") return false;
-
- return true;
- }
- // ========================================
- // 4. Array API Tests
- // ========================================
- // Test: Normal array of segments
- bool test_array_normal() {
- string[] segments = { "catalogue", "category", "document" };
- var path = SafePath.from_array(segments);
-
- if (path.depth != 3) return false;
- if (path.to_string() != "/catalogue/category/document") return false;
- if (path.name != "document") return false;
-
- return true;
- }
- // Test: Empty array (should return root path)
- bool test_array_empty() {
- string[] segments = { };
- var path = SafePath.from_array(segments);
-
- if (!path.is_root) return false;
- if (path.depth != 0) return false;
- if (path.to_string() != "/") return false;
-
- return true;
- }
- // Test: Array with special characters
- bool test_array_special_chars() {
- string[] segments = { "user name", "doc/with/slashes", "query?test" };
- var path = SafePath.from_array(segments);
-
- if (path.depth != 3) return false;
-
- string path_str = path.to_string();
-
- // Verify encoding
- if (!path_str.contains("%20")) return false; // Space encoded
- if (!path_str.contains("%2F")) return false; // Slash encoded
- if (!path_str.contains("%3F")) return false; // Question mark encoded
-
- return true;
- }
- // ========================================
- // 5. Decode Tests
- // ========================================
- // Test: Decoding %20 to space
- bool test_decode_space() {
- try {
- string decoded = SafePath.decode_segment("john%20doe");
- if (decoded != "john doe") return false;
-
- // Multiple spaces
- string decoded2 = SafePath.decode_segment("hello%20world%20test");
- if (decoded2 != "hello world test") return false;
-
- return true;
- } catch (EntityError e) {
- stdout.printf("Unexpected error: %s\n", e.message);
- return false;
- }
- }
- // Test: Decoding %2F to /
- bool test_decode_slash() {
- try {
- string decoded = SafePath.decode_segment("path%2Fwith%2Fslashes");
- if (decoded != "path/with/slashes") return false;
-
- return true;
- } catch (EntityError e) {
- stdout.printf("Unexpected error: %s\n", e.message);
- return false;
- }
- }
- // Test: Decoding unicode percent-encoded strings
- bool test_decode_unicode() {
- try {
- // Japanese characters encoded
- string decoded = SafePath.decode_segment("%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC");
- if (decoded != "ユーザー") return false;
-
- // Emoji encoded
- string decoded2 = SafePath.decode_segment("hello%F0%9F%8E%89world");
- if (decoded2 != "hello🎉world") return false;
-
- return true;
- } catch (EntityError e) {
- stdout.printf("Unexpected error: %s\n", e.message);
- return false;
- }
- }
- // Test: Invalid encoding error handling
- bool test_decode_invalid_encoding() {
- // Invalid percent encoding - incomplete sequence
- try {
- SafePath.decode_segment("invalid%");
- return false; // Should have thrown
- } catch (EntityError e) {
- // Expected - continue to test more cases
- }
-
- // Invalid hex digits
- try {
- SafePath.decode_segment("invalid%GG");
- return false; // Should have thrown
- } catch (EntityError e) {
- // Expected
- }
-
- // Incomplete percent sequence at end
- try {
- SafePath.decode_segment("test%2");
- return false; // Should have thrown
- } catch (EntityError e) {
- // Expected
- }
-
- return true;
- }
- // ========================================
- // 6. Integration Tests
- // ========================================
- // Test: Verify returned EntityPath works correctly
- bool test_integration_entity_path() {
- var path = SafePath.path("catalogue", "category", null);
-
- // Test is_root
- if (path.is_root) return false;
-
- // Test depth
- if (path.depth != 2) return false;
-
- // Test name
- if (path.name != "category") return false;
-
- // Test parent
- var parent = path.parent;
- if (parent.depth != 1) return false;
- if (parent.name != "catalogue") return false;
-
- // Test is_ancestor_of / is_descendant_of
- if (!parent.is_ancestor_of(path)) return false;
- if (!path.is_descendant_of(parent)) return false;
-
- return true;
- }
- // Test: to_string() on resulting paths
- bool test_integration_to_string() {
- // Simple path
- var path1 = SafePath.path("a", null);
- if (path1.to_string() != "/a") return false;
-
- // Multi-segment path
- var path2 = SafePath.path("a", "b", "c", null);
- if (path2.to_string() != "/a/b/c") return false;
-
- // Root path
- var path3 = SafePath.path(null);
- if (path3.to_string() != "/") return false;
-
- // Path with encoded characters
- var path4 = SafePath.path("hello world", null);
- if (path4.to_string() != "/hello%20world") return false;
-
- // Array API
- string[] segments = { "x", "y", "z" };
- var path5 = SafePath.from_array(segments);
- if (path5.to_string() != "/x/y/z") return false;
-
- return true;
- }
- // Test: Path operations (parent, append_child)
- bool test_integration_path_operations() {
- var path = SafePath.path("catalogue", "category", null);
-
- // Test parent
- var parent = path.parent;
- if (parent.to_string() != "/catalogue") return false;
-
- // Test append_child - note: EntityPath.append_child does NOT encode
- // It expects pre-encoded segment names
- var child = path.append_child("document");
- if (child.to_string() != "/catalogue/category/document") return false;
- if (child.name != "document") return false;
-
- // Test parent chain
- if (!child.parent.equals(path)) return false;
-
- // To add a child with special chars, use SafePath to encode first
- // or manually encode the segment
- var child_with_space = path.append_child("my%20document");
- if (!child_with_space.to_string().contains("%20")) return false;
-
- return true;
- }
- // Test: Round-trip encode/decode
- bool test_round_trip() {
- try {
- // Test with spaces
- string original1 = "john doe";
- var path1 = SafePath.path(original1, null);
- string encoded_name1 = path1.name;
- string decoded1 = SafePath.decode_segment(encoded_name1);
- if (decoded1 != original1) return false;
-
- // Test with special characters
- string original2 = "a/b?c#d=e&f";
- var path2 = SafePath.path(original2, null);
- string encoded_name2 = path2.name;
- string decoded2 = SafePath.decode_segment(encoded_name2);
- if (decoded2 != original2) return false;
-
- // Test with unicode
- string original3 = "ユーザー🎉";
- var path3 = SafePath.path(original3, null);
- string encoded_name3 = path3.name;
- string decoded3 = SafePath.decode_segment(encoded_name3);
- if (decoded3 != original3) return false;
-
- return true;
- } catch (EntityError e) {
- stdout.printf("Unexpected error in round-trip: %s\n", e.message);
- return false;
- }
- }
|