1 /* 2 * Copyright 2025 Matheus C. França 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 module ada.url; 17 18 version (D_BetterC) // no DRT 19 { 20 /// if betterC and LDC, disable moduleinfo and typeinfo 21 version (LDC) 22 { 23 pragma(LDC_no_moduleinfo); 24 pragma(LDC_no_typeinfo); 25 } 26 } 27 28 public import ada.c.wrapper; 29 30 @("Simple URL parser user-friendly API") 31 @nogc nothrow unittest 32 { 33 import core.stdc.string : strlen; // @system 34 import ada.c.ada; 35 36 // Test ada_parse 37 const(char)* input = "http://user:pass@example.com:8080/path/to/file.html?query=value#fragment"; 38 auto url = ada_parse(input, strlen(input)); 39 scope (exit) 40 ada_free(url); 41 assert(ada_is_valid(url)); 42 } 43 44 @("Search params parser key-value pair") 45 nothrow @nogc unittest 46 { 47 import core.stdc.string : strlen; // @system 48 import ada.c.ada; 49 50 const(char)* input = "a=b&c=d&c=e&f=g"; 51 auto url = ada_parse_search_params(input, strlen(input)); 52 53 assert(ada_search_params_size(url) == 4); 54 55 const(char)* key = "key1"; 56 const(char)* value = "value1"; 57 const(char)* value2 = "value2"; 58 ada_search_params_append(url, key, strlen(key), value, strlen(value)); 59 assert(ada_search_params_size(url) == 5); 60 61 ada_search_params_set(url, key, strlen(key), value2, strlen(value2)); 62 assert(ada_search_params_size(url) == 5); 63 64 assert(ada_search_params_has(url, key, strlen(key))); 65 assert(!ada_search_params_has_value(url, key, strlen(key), value, strlen(value))); 66 assert(ada_search_params_has_value(url, key, strlen(key), value2, strlen(value2))); 67 68 auto result = ada_search_params_get_all(url, key, strlen(key)); 69 assert(ada_strings_size(result) == 1); 70 ada_free_strings(result); 71 72 auto keys = ada_search_params_get_keys(url); 73 auto values = ada_search_params_get_values(url); 74 auto entries = ada_search_params_get_entries(url); 75 76 assert(ada_search_params_keys_iter_has_next(keys)); 77 assert(ada_search_params_values_iter_has_next(values)); 78 assert(ada_search_params_entries_iter_has_next(entries)); 79 80 assert(str_convert(ada_search_params_keys_iter_next(keys)) == "a"); 81 assert(str_convert(ada_search_params_keys_iter_next(keys)) == "c"); 82 assert(str_convert(ada_search_params_keys_iter_next(keys)) == "c"); 83 assert(str_convert(ada_search_params_keys_iter_next(keys)) == "f"); 84 assert(str_convert(ada_search_params_keys_iter_next(keys)) == "key1"); 85 assert(!ada_search_params_keys_iter_has_next(keys)); 86 87 assert(str_convert(ada_search_params_values_iter_next(values)) == "b"); 88 assert(str_convert(ada_search_params_values_iter_next(values)) == "d"); 89 assert(str_convert(ada_search_params_values_iter_next(values)) == "e"); 90 assert(str_convert(ada_search_params_values_iter_next(values)) == "g"); 91 assert(str_convert(ada_search_params_values_iter_next(values)) == "value2"); 92 assert(!ada_search_params_values_iter_has_next(values)); 93 94 auto pair = ada_search_params_entries_iter_next(entries); 95 assert(str_convert(pair.value) == "b"); 96 assert(str_convert(pair.key) == "a"); 97 98 pair = ada_search_params_entries_iter_next(entries); 99 assert(str_convert(pair.value) == "d"); 100 assert(str_convert(pair.key) == "c"); 101 102 while (ada_search_params_entries_iter_has_next(entries)) 103 { 104 ada_search_params_entries_iter_next(entries); 105 } 106 107 ada_search_params_remove(url, key, strlen(key)); 108 ada_search_params_remove_value(url, key, strlen(key), value, strlen(value)); 109 110 auto str = ada_search_params_to_string(url); 111 assert(str_convert(str) == "a=b&c=d&c=e&f=g"); 112 113 ada_free_search_params_keys_iter(keys); 114 ada_free_search_params_values_iter(values); 115 ada_free_search_params_entries_iter(entries); 116 ada_free_owned_string(str); 117 ada_free_search_params(url); 118 } 119 120 @("Wrapped API") 121 @safe nothrow @nogc unittest 122 { 123 // Test parsing a URL 124 auto url = AdaUrl(ParseOptions("https://example.com/path?query=value#hash")); 125 assert(url.isValid()); 126 127 assert(url.getProtocol() == "https:"); 128 assert(url.getHost() == "example.com"); 129 assert(url.getPathname() == "/path"); 130 assert(url.getSearch().toString().str_convert() == "query=value"); 131 assert(url.getHash() == "#hash"); 132 133 // Test setting URL components 134 url.setProtocol("http"); 135 assert(url.getProtocol() == "http:"); 136 url.setHost("example.org"); 137 assert(url.getHost() == "example.org"); 138 url.setPathname("/new-path"); 139 assert(url.getPathname() == "/new-path"); 140 url.setSearch("?new=value"); 141 assert(url.getSearch().toString().str_convert() == "new=value"); 142 url.setHash("#new-hash"); 143 assert(url.getHash() == "#new-hash"); 144 145 // Test clearing URL components 146 url.clearPort(); 147 assert(!url.hasPort()); 148 url.clearHash(); 149 assert(!url.hasHash()); 150 url.clearSearch(); 151 assert(!url.hasSearch()); 152 153 // Test parsing with base URL 154 auto baseUrl = AdaUrl(ParseOptions("https://example.com/base")); 155 auto relativeUrl = AdaUrl(ParseOptions("/relative/path?query=value#hash", baseUrl.getHref())); 156 assert(relativeUrl.getProtocol() == "https:"); 157 assert(relativeUrl.getHost() == "example.com"); 158 assert(relativeUrl.getPathname() == "/relative/path"); 159 assert(relativeUrl.getSearch().toString().str_convert() == "query=value"); 160 assert(relativeUrl.getHash() == "#hash"); 161 }