Line data Source code
1 : /* TLD library -- test the TLD interface
2 : * Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved
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 : // libtld
33 : //
34 : #include <libtld/tld.h>
35 : #include <libtld/tld_data.h>
36 : #include <libtld/tld_file.h>
37 :
38 :
39 : // C
40 : //
41 : #include <string.h>
42 : #include <stdlib.h>
43 : #include <stdio.h>
44 : #include <limits.h>
45 :
46 :
47 :
48 :
49 :
50 :
51 : int err_count = 0;
52 : int verbose = 0;
53 :
54 : /*
55 : * This test calls the tld() function with all the TLDs and then
56 : * with wrong TLDs to make sure that the tld() functions works as
57 : * expected.
58 : *
59 : * extern enum tld_result tld(const char *uri, struct tld_info *info);
60 : */
61 :
62 :
63 : char * g_filename1 = "../../BUILD/Debug/contrib/libtld/libtld/tlds.tld";
64 : char * g_filename2 = "../libtld/tlds.tld";
65 : struct tld_file * g_tld_file = NULL;
66 :
67 :
68 : /* we get access to the table with all the TLDs so we can go through them all
69 : * the library does not give direct access by default... (although maybe we
70 : * could give users access to the data)
71 : */
72 1 : void load_tlds()
73 : {
74 : enum tld_file_error err;
75 :
76 1 : err = tld_file_load(g_filename1, &g_tld_file);
77 1 : if(err == TLD_FILE_ERROR_NONE)
78 : {
79 1 : return;
80 : }
81 :
82 0 : err = tld_file_load(g_filename2, &g_tld_file);
83 0 : if(err == TLD_FILE_ERROR_NONE)
84 : {
85 0 : return;
86 : }
87 :
88 0 : fprintf(stderr, "fatal error: could not read TLD files \"%s\" or \"%s\".\n",
89 : g_filename1, g_filename2);
90 0 : exit(1);
91 : }
92 :
93 :
94 1 : void free_tlds()
95 : {
96 1 : tld_file_free(&g_tld_file);
97 1 : }
98 :
99 :
100 : /** \brief Build an extension from any offset.
101 : *
102 : * Create a domain name extensions from any entry in the TLD
103 : * descriptions.
104 : *
105 : * \param[in] offset The offset in the tld_descriptions table
106 : * \param[in] uri The URI buffer
107 : *
108 : * \return true if the first TLD is a star ("*").
109 : */
110 59920 : int cat_ext(int offset, char * uri)
111 : {
112 : int o, has_star;
113 59920 : uint32_t k, l;
114 : struct tld_description const * tld;
115 : char const * name;
116 59920 : char * d = uri;
117 :
118 1998250 : while(*d != '\0')
119 : {
120 1938330 : ++d;
121 : }
122 :
123 59920 : tld = tld_file_description(g_tld_file, offset);
124 59920 : name = tld_file_string(g_tld_file, tld->f_tld, &l);
125 :
126 : // verify that the names do match between the library TLDs file and
127 : // our copy of the file
128 : {
129 59920 : struct tld_file const * lib_tld = tld_get_tlds();
130 59920 : tld = tld_file_description(lib_tld, offset);
131 59920 : uint32_t length = 2000;
132 59920 : char const * name2 = tld_file_string(lib_tld, tld->f_tld, &length);
133 59920 : if(l != length || memcmp(name, name2, l) != 0)
134 : {
135 0 : fprintf(stderr, "error: the names in our and the library files do not match: [%.*s] vs [%.*s]\n",
136 : l, name, length, name2);
137 0 : abort();
138 : }
139 : }
140 :
141 59920 : has_star = l == 1 && name[0] == '*';
142 :
143 59920 : if(!has_star)
144 : {
145 59110 : *d++ = '.';
146 460270 : for(; *name != '\0' && l > 0; --l)
147 : {
148 401160 : *d++ = *name++;
149 : }
150 : //strcat(uri, ".");
151 : //strncat(uri, name, l);
152 : }
153 59920 : o = offset;
154 662052290 : for(k = offset + 1; k < g_tld_file->f_descriptions_count; ++k)
155 : {
156 661992370 : tld = tld_file_description(g_tld_file, k);
157 661992370 : if(o >= tld->f_start_offset
158 60325135 : && o < tld->f_end_offset)
159 : {
160 : /* found a parent */
161 76140 : name = tld_file_string(g_tld_file, tld->f_tld, &l);
162 76140 : if(l != 1 || name[0] != '*')
163 : {
164 76140 : *d++ = '.';
165 392505 : for(; *name != '\0' && l > 0; --l)
166 : {
167 316365 : *d++ = *name++;
168 : }
169 : }
170 : else
171 : {
172 0 : fprintf(stderr, "fatal error: found \"*\" at the wrong place; it's only supported as the very first segment.\n");
173 0 : exit(1);
174 : }
175 76140 : o = k;
176 76140 : k = tld->f_end_offset;
177 : }
178 : }
179 :
180 59920 : *d = '\0';
181 :
182 59920 : return has_star;
183 : }
184 :
185 :
186 :
187 :
188 : struct test_uris
189 : {
190 : const char * f_uri;
191 : enum tld_result f_result;
192 : int f_offset;
193 : };
194 :
195 :
196 : const struct test_uris g_uris[] =
197 : {
198 : {
199 : "advisor-z2-ngprod-1997768525.us-west-2.elb.amazonaws.com",
200 : TLD_RESULT_SUCCESS,
201 : 28,
202 : },
203 : {
204 : "us-west-2.elb.amazonaws.com",
205 : TLD_RESULT_SUCCESS,
206 : 0,
207 : },
208 : {
209 : "m2osw.com",
210 : TLD_RESULT_SUCCESS,
211 : 5,
212 : },
213 : {
214 : ".com",
215 : TLD_RESULT_SUCCESS,
216 : 0,
217 : },
218 : {
219 : "com",
220 : TLD_RESULT_NO_TLD,
221 : -1,
222 : },
223 : {
224 : ".ar",
225 : TLD_RESULT_SUCCESS,
226 : 0,
227 : },
228 : {
229 : "int.ar",
230 : TLD_RESULT_SUCCESS,
231 : 0,
232 : },
233 : {
234 : "blah.int.ar",
235 : TLD_RESULT_SUCCESS,
236 : 4,
237 : },
238 : {
239 : "orange.blah.int.ar",
240 : TLD_RESULT_SUCCESS,
241 : 11,
242 : },
243 : {
244 : "congresodelalengua3.ar", /* congresodelalengua3 is an exceptional 2nd level */
245 : TLD_RESULT_SUCCESS,
246 : 19,
247 : },
248 : {
249 : "special.congresodelalengua3.ar", /* congresodelalengua3 is an exceptional 2nd level */
250 : TLD_RESULT_SUCCESS,
251 : 27,
252 : },
253 : {
254 : "night-club.kawasaki.jp",
255 : TLD_RESULT_SUCCESS,
256 : 0,
257 : },
258 : {
259 : "orange.night-club.kawasaki.jp",
260 : TLD_RESULT_SUCCESS,
261 : 6,
262 : },
263 : {
264 : "a-really-long-name-is-not-considered-valid-when-more-than-63-chars.com",
265 : TLD_RESULT_BAD_URI,
266 : -1,
267 : },
268 : {
269 : "very.many.sub-domain.names.can.make.the.uri.more.than.the.allowed.253.characterss.because.the.dns.limit.is.255.bytes.total.but.that.includes.an.extra.size.and.the.null.terminator.so.we.cannot.have.that.many.names.after.all.although.frankly.this.is.huge.com",
270 : TLD_RESULT_BAD_URI,
271 : -1,
272 : },
273 : };
274 :
275 :
276 : /*
277 : * This tests various ad hoc domains with expected results.
278 : *
279 : * This way we can verify specific things we want to check.
280 : */
281 1 : void test_specific()
282 : {
283 16 : for(size_t idx = 0; idx < sizeof(g_uris) / sizeof(g_uris[0]); ++idx)
284 : {
285 15 : struct tld_info info;
286 15 : enum tld_result r = tld(g_uris[idx].f_uri, &info);
287 15 : if(verbose)
288 : {
289 0 : fprintf(
290 : stderr
291 : , "info: URI \"%s\" returned %d and TLD is \"%s\"\n"
292 0 : , g_uris[idx].f_uri
293 : , r
294 0 : , g_uris[idx].f_uri + info.f_offset);
295 : }
296 :
297 15 : if(r != g_uris[idx].f_result)
298 : {
299 0 : fprintf(stderr, "error: testing URI \"%s\" got result %d, expected %d and TLD of \"%s\"\n",
300 0 : g_uris[idx].f_uri, r, g_uris[idx].f_result,
301 0 : g_uris[idx].f_uri + g_uris[idx].f_offset);
302 0 : ++err_count;
303 : }
304 15 : else if(info.f_offset != g_uris[idx].f_offset)
305 : {
306 0 : fprintf(stderr, "error: testing URI \"%s\" got offset %d, expected %d and TLD of \"%s\"\n",
307 0 : g_uris[idx].f_uri, info.f_offset, g_uris[idx].f_offset,
308 0 : g_uris[idx].f_uri + info.f_offset);
309 0 : ++err_count;
310 : }
311 : }
312 1 : }
313 :
314 :
315 : /*
316 : * This test goes through all the domain names and extracts the domain,
317 : * sub-domains and TLDs. (Or at least verifies that we get the correct
318 : * information in order to do so.)
319 : *
320 : * It builds a URI with zero to many sub-domain names, adds a specific
321 : * domain name, then append a complete TLD. The result is then checked
322 : * with the tld() function from the library. The tld() is expected to
323 : * either return VALID or INVALID but nothing else (since all those
324 : * TLDs exist in our table.) Then we verify that the returned offset is
325 : * a perfect match.
326 : */
327 1 : void test_all()
328 : {
329 1 : char const * sub_domains[] = {
330 : "",
331 : "www.",
332 : "tld.",
333 : "george.snap.",
334 : "very.long.sub.domain.ext.en.sion.here."
335 : "host.%20.space."
336 : "host.%fa.u-acute."
337 : "host.%FA.U-acute."
338 : };
339 1 : struct tld_info info;
340 1 : char uri[256], extension_uri[256];
341 : char const * name;
342 1 : uint32_t i, j, l, p, max_subdomains;
343 : int has_star, sub_has_star;
344 : enum tld_result r;
345 : struct tld_description const * tld_desc;
346 : struct tld_description const * sub_tld;
347 :
348 1 : max_subdomains = sizeof(sub_domains) / sizeof(sub_domains[0]);
349 :
350 11966 : for(i = 0; i < g_tld_file->f_descriptions_count; ++i)
351 : {
352 71790 : for(j = 0; j < max_subdomains; ++j)
353 : {
354 59825 : strcpy(uri, sub_domains[j]);
355 59825 : strcat(uri, "domain-name");
356 59825 : has_star = cat_ext(i, uri);
357 :
358 : /* just in case make sure that we did not overflow the buffer */
359 59825 : if(strlen(uri) >= sizeof(uri))
360 : {
361 0 : fprintf(stderr, "fatal error: the URI \"%s\" is longer than the uri[] array.\n", uri);
362 0 : exit(1);
363 : }
364 :
365 : /* reset the structure so we can verify it gets initialized */
366 59825 : memset(&info, 0xFE, sizeof(info));
367 :
368 59825 : r = tld(uri, &info);
369 : #if 0
370 : if(i == 5108)
371 : {
372 : for(size_t l = 0; l < sizeof(info); ++l)
373 : {
374 : if((l % 16) == 0 && l > 0)
375 : {
376 : fprintf(stderr, "\n");
377 : }
378 : fprintf(stderr, "0x%02X ", ((unsigned char*)&info)[l]);
379 : }
380 : fprintf(stderr, "\nresult for [%s]: category[%d], status[%d/%%d n.a.], country[%s],"
381 : " tld[%s], offset[%d]\n",
382 : uri,
383 : (int)info.f_category,
384 : (int)info.f_status, //(int)tld_descriptions[i].f_status,
385 : info.f_country,
386 : info.f_tld, (int)info.f_offset);
387 : }
388 : #endif
389 59825 : p = i;
390 59825 : tld_desc = tld_file_description(g_tld_file, i);
391 59825 : if(tld_desc->f_status == TLD_STATUS_EXCEPTION)
392 : {
393 95 : if(tld_desc->f_exception_apply_to == USHRT_MAX)
394 : {
395 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",
396 : uri, i, r);
397 0 : ++err_count;
398 : }
399 : else
400 : {
401 95 : p = tld_desc->f_exception_apply_to;
402 : }
403 : }
404 59825 : if(tld_desc->f_status == TLD_STATUS_VALID)
405 : {
406 48975 : if(r != TLD_RESULT_SUCCESS)
407 : {
408 0 : fprintf(stderr, "error: valid domain name for \"%s\" (%d) could not be extracted successfully (returned: %d)\n",
409 : uri, i, r);
410 0 : ++err_count;
411 : }
412 48975 : else if(has_star)
413 : {
414 : /* the "domain-name" is absorbed as part of the TLD */
415 810 : int expected = strlen(sub_domains[j]);
416 810 : if(expected != 0)
417 : {
418 648 : --expected; /* ignore the "." */
419 : }
420 810 : if(info.f_offset != expected)
421 : {
422 0 : fprintf(stderr, "error: valid domain name for \"%s\" (%d) could not be extracted successfully (offset: %d, expected: %d)\n",
423 : uri, i,
424 : info.f_offset, expected);
425 0 : ++err_count;
426 : }
427 : }
428 : else
429 : {
430 : /* verify the top domain name */
431 48165 : if(info.f_offset < 11)
432 : {
433 0 : fprintf(stderr, "error: somehow the top domain name in \"%s\" (%d) cannot properly be extracted\n",
434 : uri, i);
435 0 : ++err_count;
436 : }
437 48165 : else if(strncmp(uri + info.f_offset - 11, "domain-name", 11) != 0)
438 : {
439 0 : fprintf(stderr, "error: valid domain name for \"%s\" (%d) could not be extracted successfully (offset: %d)\n",
440 : uri, i, info.f_offset);
441 0 : ++err_count;
442 : }
443 : /*
444 : else
445 : fprintf(stderr, "valid: \"%s\" -> \"%s\"\n", uri, info.f_tld);
446 : */
447 : }
448 : }
449 10850 : else if(tld_desc->f_status == TLD_STATUS_EXCEPTION)
450 : {
451 95 : if(r != TLD_RESULT_SUCCESS)
452 : {
453 0 : fprintf(stderr, "error: exceptional domain name for \"%s\" (%d) could not be extracted successfully (returned: %d)\n",
454 : uri, i, r);
455 0 : ++err_count;
456 : }
457 : else
458 : {
459 95 : extension_uri[0] = '\0';
460 95 : cat_ext(p, extension_uri);
461 95 : if(strcmp(info.f_tld, extension_uri) != 0)
462 : //if(strncmp(uri + info.f_offset - 11, "domain-name", 11) != 0)
463 : {
464 0 : fprintf(stderr, "error: exceptional domain name for \"%s\" (%d/%d) could not be extracted successfully as \"%s\" (offset: %d)\n",
465 : uri, i, p, extension_uri, info.f_offset);
466 0 : ++err_count;
467 : }
468 : /*
469 : else
470 : fprintf(stderr, "valid: \"%s\" -> \"%s\"\n", uri, info.f_tld);
471 : */
472 : }
473 : }
474 : else
475 : {
476 10755 : sub_has_star = 0;
477 10755 : if(tld_desc->f_status == TLD_STATUS_UNUSED
478 3125 : && tld_desc->f_start_offset != USHRT_MAX)
479 : {
480 2780 : sub_tld = tld_file_description(g_tld_file, tld_desc->f_start_offset);
481 2780 : name = tld_file_string(g_tld_file, sub_tld->f_tld, &l);
482 2780 : sub_has_star = l == 1 && name[0] == '*';
483 : }
484 10755 : if(sub_has_star)
485 : {
486 : /* this is a special case, an entry such as:
487 : *
488 : * *.blah.com
489 : *
490 : * and that means the result is going to be SUCCESS
491 : * and VALID...
492 : */
493 810 : if(r != TLD_RESULT_SUCCESS
494 810 : || info.f_status != TLD_STATUS_VALID)
495 : {
496 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted as expected (returned: %d) [1]\n",
497 : uri, i, r);
498 0 : ++err_count;
499 : }
500 : }
501 9945 : else if(r != TLD_RESULT_INVALID)
502 : {
503 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted as expected (returned: %d) [2]\n",
504 : uri, i, r);
505 0 : ++err_count;
506 : }
507 9945 : else if(p != i)
508 : {
509 0 : extension_uri[0] = '\0';
510 0 : cat_ext(p, extension_uri);
511 0 : if(strcmp(info.f_tld, extension_uri) != 0)
512 : {
513 0 : fprintf(stderr, "error: other domain name for \"%s\" (%d) could not be extracted successfully (returned: %d/%s != %s) [1]\n",
514 : uri, i, r, info.f_tld, extension_uri);
515 0 : ++err_count;
516 : }
517 : /*
518 : else
519 : fprintf(stderr, "?? invalid: \"%s\" -> \"%s\"\n", uri, info.f_tld);
520 : */
521 : }
522 : else
523 : {
524 9945 : if(strncmp(uri + info.f_offset - 11, "domain-name", 11) != 0)
525 : {
526 0 : fprintf(stderr, "error: other domain name for \"%s\" (%d) could not be extracted successfully (returned: %d/%s) [2]\n",
527 : uri, i, r, info.f_tld);
528 0 : ++err_count;
529 : }
530 : /*
531 : else
532 : fprintf(stderr, "?? invalid: \"%s\" -> \"%s\"\n", uri, info.f_tld);
533 : */
534 : }
535 : }
536 : }
537 : }
538 1 : }
539 :
540 :
541 : /*
542 : * This test checks out URIs that end with an invalid TLD. This is
543 : * expected to return an error every single time.
544 : */
545 1 : void test_unknown()
546 : {
547 : struct bad_data
548 : {
549 : const char * f_uri;
550 : };
551 1 : struct bad_data d[] =
552 : {
553 : { "this.is.wrong" },
554 : { "missing.tld" },
555 : { ".net.absolutely.com.no.info.on.this" }
556 : };
557 1 : struct tld_info info;
558 : int i, max;
559 : enum tld_result r;
560 :
561 1 : max = sizeof(d) / sizeof(d[0]);
562 4 : for(i = 0; i < max; ++i)
563 : {
564 3 : memset(&info, 0xFE, sizeof(info));
565 3 : r = tld(d[i].f_uri, &info);
566 3 : if(r != TLD_RESULT_NOT_FOUND)
567 : {
568 0 : fprintf(stderr, "error: the invalid URI \"%s\" was found by tld()!\n", d[i].f_uri);
569 0 : ++err_count;
570 : }
571 : }
572 1 : }
573 :
574 :
575 :
576 :
577 1 : void test_invalid()
578 : {
579 1 : struct tld_info undefined_info;
580 1 : struct tld_info clear_info;
581 1 : struct tld_info info;
582 : enum tld_result r;
583 :
584 : /*
585 : * We reset the undefined_info the same way we reset the info
586 : * structure because the alignment on 64bits may add another
587 : * 4 bytes at the end of the structure that are not otherwise
588 : * accessible.
589 : */
590 1 : memset(&undefined_info, 0xFE, sizeof(undefined_info));
591 1 : undefined_info.f_category = TLD_CATEGORY_UNDEFINED;
592 1 : undefined_info.f_status = TLD_STATUS_UNDEFINED;
593 1 : memset(undefined_info.f_country, 0, sizeof(undefined_info.f_country));
594 1 : undefined_info.f_tld = (const char *) 0;
595 1 : undefined_info.f_offset = -1;
596 1 : undefined_info.f_tld_index = -1;
597 :
598 1 : memset(&clear_info, 0xFE, sizeof(clear_info));
599 :
600 : /* test: NULL */
601 1 : info = clear_info;
602 1 : r = tld(NULL, &info);
603 1 : if(r != TLD_RESULT_NULL)
604 : {
605 0 : fprintf(stderr, "error: the NULL URI did not return the TLD_RESULT_NULL result.\n");
606 0 : ++err_count;
607 : }
608 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
609 : {
610 0 : fprintf(stderr, "error: the NULL URI did not return a reset info structure.\n");
611 0 : ++err_count;
612 : }
613 :
614 : /* test: "" */
615 1 : info = clear_info;
616 1 : r = tld("", &info);
617 1 : if(r != TLD_RESULT_NULL)
618 : {
619 0 : fprintf(stderr, "error: the \"\" URI did not return the TLD_RESULT_NULL result.\n");
620 0 : ++err_count;
621 : }
622 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
623 : {
624 0 : fprintf(stderr, "error: the \"\" URI did not return a reset info structure.\n");
625 0 : ++err_count;
626 : }
627 :
628 : /* test: ".." (two periods one after another) */
629 1 : info = clear_info;
630 1 : r = tld("test..com", &info);
631 1 : if(r != TLD_RESULT_BAD_URI)
632 : {
633 0 : fprintf(stderr, "error: the \"test..com\" URI did not return the TLD_RESULT_BAD_URI result.\n");
634 0 : ++err_count;
635 : }
636 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
637 : {
638 0 : fprintf(stderr, "error: the \"test..com\" URI did not return a reset info structure.\n");
639 0 : ++err_count;
640 : }
641 :
642 : /* test: ".." (two periods one after another) */
643 1 : info = clear_info;
644 1 : r = tld("more..test.com", &info);
645 1 : if(r != TLD_RESULT_BAD_URI)
646 : {
647 0 : fprintf(stderr, "error: the \"more..test.com\" URI did not return the TLD_RESULT_BAD_URI result.\n");
648 0 : ++err_count;
649 : }
650 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
651 : {
652 0 : fprintf(stderr, "error: the \"more..test.com\" URI did not return a reset info structure.\n");
653 0 : ++err_count;
654 : }
655 :
656 : /* test: "noperiodanywhere" (no periods anywhere) */
657 1 : info = clear_info;
658 1 : r = tld("noperiodanywhere", &info);
659 1 : if(r != TLD_RESULT_NO_TLD)
660 : {
661 0 : fprintf(stderr, "error: the \"noperiodanywhere\" URI did not return the TLD_RESULT_NO_TLD result.\n");
662 0 : ++err_count;
663 : }
664 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
665 : {
666 0 : fprintf(stderr, "error: the \"noperiodanywhere\" URI did not return a reset info structure.\n");
667 0 : ++err_count;
668 : }
669 1 : }
670 :
671 :
672 1 : void test_tags()
673 : {
674 1 : struct tld_info info;
675 : enum tld_result result;
676 1 : const char * tld_name = "info.%e6%be%b3%e9%96%80";
677 : int tag_count;
678 1 : struct tld_tag_definition tag_info;
679 :
680 1 : result = tld(tld_name, &info);
681 1 : if(result != TLD_RESULT_SUCCESS)
682 : {
683 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI did not return a valid info structure (error: %d).\n",
684 : result);
685 0 : ++err_count;
686 0 : return;
687 : }
688 :
689 1 : if(info.f_status != TLD_STATUS_VALID)
690 : {
691 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI did not return a VALID status as expected.\n");
692 0 : ++err_count;
693 0 : return;
694 : }
695 :
696 1 : if(info.f_category != TLD_CATEGORY_COUNTRY)
697 : {
698 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI did not return a country category as expected, got %d instead.\n",
699 0 : info.f_category);
700 0 : ++err_count;
701 0 : return;
702 : }
703 :
704 1 : if(strcmp(info.f_country, "Macao") != 0)
705 : {
706 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI did not return \"Macao\" as the country name.\n");
707 0 : ++err_count;
708 0 : return;
709 : }
710 :
711 1 : if(info.f_tld != tld_name + 4)
712 : {
713 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI did not return the expected f_tld pointer.\n");
714 0 : ++err_count;
715 0 : return;
716 : }
717 :
718 1 : if(info.f_offset != 4)
719 : {
720 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI did not return the expected f_offset.\n");
721 0 : ++err_count;
722 0 : return;
723 : }
724 :
725 : // info.f_tld_index -- we assume this will change, there is no real point
726 : // in testing this specifically
727 :
728 1 : tag_count = tld_tag_count(&info);
729 1 : if(tag_count < 0)
730 : {
731 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI returned a negative tag_count.\n");
732 0 : ++err_count;
733 0 : return;
734 : }
735 1 : if(tag_count != 6)
736 : {
737 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI was expected to have 6 tags. Edit test if new tags were added.\n");
738 0 : ++err_count;
739 : }
740 :
741 7 : for(int idx = 0; idx < tag_count; ++idx)
742 : {
743 6 : result = tld_get_tag(&info, idx, &tag_info);
744 6 : if(result != TLD_RESULT_SUCCESS)
745 : {
746 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI returned an error retrieving tag %d.\n", idx);
747 0 : ++err_count;
748 0 : return;
749 : }
750 :
751 : // the order in which tags are saved in not guaranteed, so we must
752 : // test the name and decide what to do next
753 : //
754 6 : if(tag_info.f_name_length == 7
755 1 : && memcmp(tag_info.f_name, "country", 7) == 0)
756 : {
757 1 : if(tag_info.f_value_length != 5
758 1 : || memcmp(tag_info.f_value, "Macao", 5) != 0)
759 : {
760 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI \"country\" name was expected to be \"Macao\".\n");
761 0 : ++err_count;
762 0 : return;
763 : }
764 : }
765 5 : else if(tag_info.f_name_length == 17
766 1 : && memcmp(tag_info.f_name, "country_full_name", 17) == 0)
767 : {
768 1 : if(tag_info.f_value_length != 76
769 1 : || memcmp(tag_info.f_value, "Macao Special Administrative Region of the People's Republic of China (MSAR)", 76) != 0)
770 : {
771 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI \"country_full_name\" was expected to be \"Macao Special Administrative Region of the People's Republic of China (MSAR)\".\n");
772 0 : ++err_count;
773 0 : return;
774 : }
775 : }
776 4 : else if(tag_info.f_name_length == 11
777 1 : && memcmp(tag_info.f_name, "description", 11) == 0)
778 : {
779 1 : if(tag_info.f_value_length != 12
780 1 : || memcmp(tag_info.f_value, "Macao Island", 12) != 0)
781 : {
782 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI \"description\" was expected to be \"Macao Island\".\n");
783 0 : ++err_count;
784 0 : return;
785 : }
786 : }
787 3 : else if(tag_info.f_name_length == 4
788 1 : && memcmp(tag_info.f_name, "note", 4) == 0)
789 : {
790 1 : if(tag_info.f_value_length != 5
791 1 : || memcmp(tag_info.f_value, "Macao", 5) != 0)
792 : {
793 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI \"note\" was expected to be \"Macao\".\n");
794 0 : ++err_count;
795 0 : return;
796 : }
797 : }
798 2 : else if(tag_info.f_name_length == 8
799 2 : && memcmp(tag_info.f_name, "language", 8) == 0)
800 : {
801 1 : if(tag_info.f_value_length != 20
802 1 : || memcmp(tag_info.f_value, "Chinese, Traditional", 20) != 0)
803 : {
804 0 : fprintf(stderr, "error: the \"info.\xE6\xBE\xB3\xE9\x96\x80\" URI \"language\" was expected to be \"Chinese, Traditional\".\n");
805 0 : ++err_count;
806 0 : return;
807 : }
808 : }
809 : }
810 : }
811 :
812 :
813 :
814 :
815 1 : int main(int argc, char *argv[])
816 : {
817 1 : fprintf(stderr, "testing tld version %s\n", tld_version());
818 :
819 1 : if(argc > 1)
820 : {
821 0 : if(strcmp(argv[1], "-v") == 0)
822 : {
823 0 : verbose = 1;
824 : }
825 : else
826 : {
827 0 : fprintf(stderr, "error: unknown command line option \"%s\"\n", argv[1]);
828 0 : exit(1);
829 : }
830 : }
831 :
832 : /* call all the tests, one by one
833 : * failures are "recorded" in the err_count global variable
834 : * and the process stops with an error message and exit(1)
835 : * if err_count is not zero.
836 : */
837 1 : load_tlds();
838 1 : test_specific();
839 1 : test_all();
840 1 : test_unknown();
841 1 : test_invalid();
842 1 : test_tags();
843 1 : free_tlds();
844 :
845 1 : if(err_count)
846 : {
847 0 : fprintf(stderr, "%d error%s occured.\n",
848 0 : err_count, err_count != 1 ? "s" : "");
849 : }
850 1 : exit(err_count ? 1 : 0);
851 : }
852 :
853 : /* vim: ts=4 sw=4 et
854 : */
|