Line data Source code
1 : /* TLD library -- test the TLD interface
2 : * Copyright (C) 2011-2015 Made to Order Software Corp.
3 : *
4 : * Permission is hereby granted, free of charge, to any person obtaining a
5 : * copy of this software and associated documentation files (the
6 : * "Software"), to deal in the Software without restriction, including
7 : * without limitation the rights to use, copy, modify, merge, publish,
8 : * distribute, sublicense, and/or sell copies of the Software, and to
9 : * permit persons to whom the Software is furnished to do so, subject to
10 : * the following conditions:
11 : *
12 : * The above copyright notice and this permission notice shall be included
13 : * in all copies or substantial portions of the Software.
14 : *
15 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 : * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 : * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 : * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 : * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 : */
23 :
24 : /** \file
25 : * \brief Test the tld() function like an end user.
26 : *
27 : * This file implements various tests verifying the tld() function.
28 : * The tests defined here are not for coverage but rather edge
29 : * cases which could be hard to expect in a full coverage test.
30 : */
31 :
32 : #include "libtld/tld.h"
33 : #include <string.h>
34 : #include <stdlib.h>
35 : #include <stdio.h>
36 : #include <limits.h>
37 :
38 : /* we get access to the table with all the TLDs so we can go through them all
39 : * the library does not give direct access by default... (although maybe we
40 : * could give users access to the data)
41 : */
42 : #include "tld_data.h"
43 : extern const struct tld_description tld_descriptions[];
44 : extern unsigned short tld_start_offset;
45 : extern unsigned short tld_end_offset;
46 :
47 : int err_count = 0;
48 : int verbose = 0;
49 :
50 : /*
51 : * This test calls the tld() function with all the TLDs and then
52 : * with wrong TLDs to make sure that the tld() functions works as
53 : * expected.
54 : *
55 : * extern enum tld_result tld(const char *uri, struct tld_info *info);
56 : */
57 :
58 :
59 : /** \brief Build an extension from any offset.
60 : *
61 : * Create a domain name extensions from any entry in the TLD
62 : * descriptions.
63 : *
64 : * \param[in] offset The offset in the tld_descriptions table
65 : * \param[in] uri The URI buffer
66 : */
67 42790 : void cat_ext(int offset, char *uri)
68 : {
69 : int k, l;
70 :
71 42790 : strcat(uri, tld_descriptions[offset].f_tld);
72 42790 : l = offset;
73 336291720 : for(k = offset + 1; k < tld_end_offset; ++k)
74 : {
75 336248930 : if(l >= tld_descriptions[k].f_start_offset
76 24529920 : && l < tld_descriptions[k].f_end_offset)
77 : {
78 : /* found a parent */
79 49970 : strcat(uri, ".");
80 49970 : strcat(uri, tld_descriptions[k].f_tld);
81 49970 : l = k;
82 49970 : k = tld_descriptions[k].f_end_offset;
83 : }
84 : }
85 42790 : }
86 :
87 : /*
88 : * This test goes through all the domain names and extracts the domain,
89 : * sub-domains and TLDs. (Or at least verifies that we get the correct
90 : * information in order to do so.)
91 : *
92 : * It builds a URI with zero to many sub-domain names, adds a specific
93 : * domain name, then append a complete TLD. The result is then checked
94 : * with the tld() function from the library. The tld() is expected to
95 : * either return VALID or INVALID but nothing else (since all those
96 : * TLDs exist in our table.) Then we verify that the returned offset is
97 : * a perfect match.
98 : */
99 1 : void test_all()
100 : {
101 1 : const char *sub_domains[] = {
102 : "",
103 : "www.",
104 : "tld.",
105 : "george.snap.",
106 : "very.long.sub.domain.ext.en.sion.here."
107 : "host.%20.space."
108 : "host.%fa.u-acute."
109 : "host.%FA.U-acute."
110 : };
111 : struct tld_info info;
112 : char uri[256], extension_uri[256];
113 : int i, j, p, max_subdomains;
114 : enum tld_result r;
115 :
116 1 : max_subdomains = sizeof(sub_domains) / sizeof(sub_domains[0]);
117 :
118 8537 : for(i = 0; i < tld_end_offset; ++i)
119 : {
120 51216 : for(j = 0; j < max_subdomains; ++j)
121 : {
122 42680 : strcpy(uri, sub_domains[j]);
123 42680 : strcat(uri, "domain-name.");
124 42680 : cat_ext(i, uri);
125 : /* reset the structure so we can verify it gets initialized */
126 42680 : memset(&info, 0xFE, sizeof(info));
127 42680 : r = tld(uri, &info);
128 : /*
129 : for(int l = 0; l < sizeof(info); ++l)
130 : {
131 : fprintf(stderr, "0x%02X ", ((unsigned char*)&info)[l]);
132 : }
133 : fprintf(stderr, "\nresult for [%s]: category[%d], status[%d], country[%s],"
134 : " tld[%s], offset[%d]\n",
135 : uri,
136 : (int)info.f_category, (int)info.f_status, info.f_country,
137 : info.f_tld, (int)info.f_offset);
138 : */
139 42680 : p = i;
140 42680 : if(tld_descriptions[i].f_status == TLD_STATUS_EXCEPTION)
141 : {
142 110 : if(tld_descriptions[i].f_exception_apply_to == USHRT_MAX)
143 : {
144 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) is said to be an exception but it has no apply-to parameter. (result: %d)\n",
145 : uri, i, r);
146 0 : ++err_count;
147 : }
148 : else
149 : {
150 110 : p = tld_descriptions[i].f_exception_apply_to;
151 : }
152 : }
153 42680 : if(tld_descriptions[i].f_status == TLD_STATUS_VALID)
154 : {
155 41765 : if(r != TLD_RESULT_SUCCESS)
156 : {
157 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted successfully (returned: %d)\n",
158 : uri, i, r);
159 0 : ++err_count;
160 : }
161 : else
162 : {
163 : /* in this case we have to test the top domain name only */
164 41765 : if(strncmp(uri + info.f_offset - 11, "domain-name", 11) != 0)
165 : {
166 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted successfully (returned: %d)\n",
167 : uri, i, r);
168 0 : ++err_count;
169 : }
170 : /*
171 : else
172 : fprintf(stderr, "valid: \"%s\" -> \"%s\"\n", uri, info.f_tld);
173 : */
174 : }
175 : }
176 915 : else if(tld_descriptions[i].f_status == TLD_STATUS_EXCEPTION)
177 : {
178 110 : if(r != TLD_RESULT_SUCCESS)
179 : {
180 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted successfully (returned: %d)\n",
181 : uri, i, r);
182 0 : ++err_count;
183 : }
184 : else
185 : {
186 110 : strcpy(extension_uri, ".");
187 110 : cat_ext(p, extension_uri);
188 110 : if(strcmp(info.f_tld, extension_uri) != 0)
189 : //if(strncmp(uri + info.f_offset - 11, "domain-name", 11) != 0)
190 : {
191 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted successfully (returned: %d)\n",
192 : uri, i, r);
193 0 : ++err_count;
194 : }
195 : /*
196 : else
197 : fprintf(stderr, "valid: \"%s\" -> \"%s\"\n", uri, info.f_tld);
198 : */
199 : }
200 : }
201 : else
202 : {
203 805 : if(r != TLD_RESULT_INVALID)
204 : {
205 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted as expected (returned: %d)\n",
206 : uri, i, r);
207 0 : ++err_count;
208 : }
209 805 : else if(p != i)
210 : {
211 0 : strcpy(extension_uri, ".");
212 0 : cat_ext(p, extension_uri);
213 0 : if(strcmp(info.f_tld, extension_uri) != 0)
214 : {
215 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted successfully (returned: %d/%s)\n",
216 : uri, i, r, info.f_tld);
217 0 : ++err_count;
218 : }
219 : /*
220 : else
221 : fprintf(stderr, "?? invalid: \"%s\" -> \"%s\"\n", uri, info.f_tld);
222 : */
223 : }
224 : else
225 : {
226 805 : if(strncmp(uri + info.f_offset - 11, "domain-name", 11) != 0)
227 : {
228 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted successfully (returned: %d/%s)\n",
229 : uri, i, r, info.f_tld);
230 0 : ++err_count;
231 : }
232 : /*
233 : else
234 : fprintf(stderr, "?? invalid: \"%s\" -> \"%s\"\n", uri, info.f_tld);
235 : */
236 : }
237 : }
238 : }
239 : }
240 1 : }
241 :
242 :
243 : /*
244 : * This test checks out URIs that end with an invalid TLD. This is
245 : * expected to return an error every single time.
246 : */
247 1 : void test_unknown()
248 : {
249 : struct bad_data
250 : {
251 : const char * f_uri;
252 : };
253 1 : struct bad_data d[] =
254 : {
255 : { "this.is.wrong" },
256 : { "missing.tld" },
257 : { ".net.absolutely.com.no.info.on.this" }
258 : };
259 : struct tld_info info;
260 : int i, max;
261 : enum tld_result r;
262 :
263 1 : max = sizeof(d) / sizeof(d[0]);
264 4 : for(i = 0; i < max; ++i)
265 : {
266 3 : memset(&info, 0xFE, sizeof(info));
267 3 : r = tld(d[i].f_uri, &info);
268 3 : if(r != TLD_RESULT_NOT_FOUND)
269 : {
270 0 : fprintf(stderr, "error: the invalid URI \"%s\" was found by tld()!\n", d[i].f_uri);
271 0 : ++err_count;
272 : }
273 : }
274 1 : }
275 :
276 :
277 :
278 :
279 1 : void test_invalid()
280 : {
281 : struct tld_info undefined_info;
282 : struct tld_info clear_info;
283 : struct tld_info info;
284 : enum tld_result r;
285 :
286 : /*
287 : * We reset the undefined_info the same way we reset the info
288 : * structure because the alignment on 64bits may add another
289 : * 4 bytes at the end of the structure that are not otherwise
290 : * accessible.
291 : */
292 1 : memset(&undefined_info, 0xFE, sizeof(undefined_info));
293 1 : undefined_info.f_category = TLD_CATEGORY_UNDEFINED;
294 1 : undefined_info.f_status = TLD_STATUS_UNDEFINED;
295 1 : undefined_info.f_country = (const char *) 0;
296 1 : undefined_info.f_tld = (const char *) 0;
297 1 : undefined_info.f_offset = -1;
298 :
299 1 : memset(&clear_info, 0xFE, sizeof(clear_info));
300 :
301 : /* test: NULL */
302 1 : info = clear_info;
303 1 : r = tld(NULL, &info);
304 1 : if(r != TLD_RESULT_NULL)
305 : {
306 0 : fprintf(stderr, "error: the NULL URI did not return the TLD_RESULT_NULL result.\n");
307 0 : ++err_count;
308 : }
309 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
310 : {
311 0 : fprintf(stderr, "error: the NULL URI did not return a reset info structure.\n");
312 0 : ++err_count;
313 : }
314 :
315 : /* test: "" */
316 1 : info = clear_info;
317 1 : r = tld("", &info);
318 1 : if(r != TLD_RESULT_NULL)
319 : {
320 0 : fprintf(stderr, "error: the \"\" URI did not return the TLD_RESULT_NULL result.\n");
321 0 : ++err_count;
322 : }
323 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
324 : {
325 0 : fprintf(stderr, "error: the \"\" URI did not return a reset info structure.\n");
326 0 : ++err_count;
327 : }
328 :
329 : /* test: ".." (two periods one after another) */
330 1 : info = clear_info;
331 1 : r = tld("test..com", &info);
332 1 : if(r != TLD_RESULT_BAD_URI)
333 : {
334 0 : fprintf(stderr, "error: the \"test..com\" URI did not return the TLD_RESULT_BAD_URI result.\n");
335 0 : ++err_count;
336 : }
337 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
338 : {
339 0 : fprintf(stderr, "error: the \"test..com\" URI did not return a reset info structure.\n");
340 0 : ++err_count;
341 : }
342 :
343 : /* test: ".." (two periods one after another) */
344 1 : info = clear_info;
345 1 : r = tld("more..test.com", &info);
346 1 : if(r != TLD_RESULT_BAD_URI)
347 : {
348 0 : fprintf(stderr, "error: the \"more..test.com\" URI did not return the TLD_RESULT_BAD_URI result.\n");
349 0 : ++err_count;
350 : }
351 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
352 : {
353 0 : fprintf(stderr, "error: the \"more..test.com\" URI did not return a reset info structure.\n");
354 0 : ++err_count;
355 : }
356 :
357 : /* test: "noperiodanywhere" (no periods anywhere) */
358 1 : info = clear_info;
359 1 : r = tld("noperiodanywhere", &info);
360 1 : if(r != TLD_RESULT_NO_TLD)
361 : {
362 0 : fprintf(stderr, "error: the \"noperiodanywhere\" URI did not return the TLD_RESULT_NO_TLD result.\n");
363 0 : ++err_count;
364 : }
365 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
366 : {
367 0 : fprintf(stderr, "error: the \"noperiodanywhere\" URI did not return a reset info structure.\n");
368 0 : ++err_count;
369 : }
370 1 : }
371 :
372 :
373 :
374 :
375 1 : int main(int argc, char *argv[])
376 : {
377 1 : fprintf(stderr, "testing tld version %s\n", tld_version());
378 :
379 1 : if(argc > 1)
380 : {
381 0 : if(strcmp(argv[1], "-v") == 0)
382 : {
383 0 : verbose = 1;
384 : }
385 : }
386 :
387 : /* call all the tests, one by one
388 : * failures are "recorded" in the err_count global variable
389 : * and the process stops with an error message and exit(1)
390 : * if err_count is not zero.
391 : */
392 1 : test_all();
393 1 : test_unknown();
394 1 : test_invalid();
395 :
396 1 : if(err_count)
397 : {
398 0 : fprintf(stderr, "%d error%s occured.\n",
399 0 : err_count, err_count != 1 ? "s" : "");
400 : }
401 1 : exit(err_count ? 1 : 0);
402 : }
403 :
404 : /* vim: ts=4 sw=4
405 : */
|