Line data Source code
1 : /* TLD library -- test the TLD interface
2 : * Copyright (c) 2011-2018 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 : #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 48760 : void cat_ext(int offset, char *uri)
68 : {
69 : int k, l;
70 :
71 48760 : strcat(uri, tld_descriptions[offset].f_tld);
72 48760 : l = offset;
73 435723940 : for(k = offset + 1; k < tld_end_offset; ++k)
74 : {
75 435675180 : if(l >= tld_descriptions[k].f_start_offset
76 33592090 : && l < tld_descriptions[k].f_end_offset)
77 : {
78 : /* found a parent */
79 56290 : strcat(uri, ".");
80 56290 : strcat(uri, tld_descriptions[k].f_tld);
81 56290 : l = k;
82 56290 : k = tld_descriptions[k].f_end_offset;
83 : }
84 : }
85 48760 : }
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 9732 : for(i = 0; i < tld_end_offset; ++i)
119 : {
120 58386 : for(j = 0; j < max_subdomains; ++j)
121 : {
122 48655 : strcpy(uri, sub_domains[j]);
123 48655 : strcat(uri, "domain-name.");
124 48655 : cat_ext(i, uri);
125 : /* reset the structure so we can verify it gets initialized */
126 48655 : memset(&info, 0xFE, sizeof(info));
127 48655 : r = tld(uri, &info);
128 : /*
129 : for(size_t 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/%d], country[%s],"
134 : " tld[%s], offset[%d]\n",
135 : uri,
136 : (int)info.f_category,
137 : (int)info.f_status, (int)tld_descriptions[i].f_status,
138 : info.f_country,
139 : info.f_tld, (int)info.f_offset);
140 : */
141 48655 : p = i;
142 48655 : if(tld_descriptions[i].f_status == TLD_STATUS_EXCEPTION)
143 : {
144 105 : if(tld_descriptions[i].f_exception_apply_to == USHRT_MAX)
145 : {
146 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",
147 : uri, i, r);
148 0 : ++err_count;
149 : }
150 : else
151 : {
152 105 : p = tld_descriptions[i].f_exception_apply_to;
153 : }
154 : }
155 48655 : if(tld_descriptions[i].f_status == TLD_STATUS_VALID)
156 : {
157 46830 : if(r != TLD_RESULT_SUCCESS)
158 : {
159 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted successfully (returned: %d)\n",
160 : uri, i, r);
161 0 : ++err_count;
162 : }
163 : else
164 : {
165 : /* in this case we have to test the top domain name only */
166 46830 : if(strncmp(uri + info.f_offset - 11, "domain-name", 11) != 0)
167 : {
168 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted successfully (returned: %d)\n",
169 : uri, i, r);
170 0 : ++err_count;
171 : }
172 : /*
173 : else
174 : fprintf(stderr, "valid: \"%s\" -> \"%s\"\n", uri, info.f_tld);
175 : */
176 : }
177 : }
178 1825 : else if(tld_descriptions[i].f_status == TLD_STATUS_EXCEPTION)
179 : {
180 105 : if(r != TLD_RESULT_SUCCESS)
181 : {
182 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted successfully (returned: %d)\n",
183 : uri, i, r);
184 0 : ++err_count;
185 : }
186 : else
187 : {
188 105 : strcpy(extension_uri, ".");
189 105 : cat_ext(p, extension_uri);
190 105 : if(strcmp(info.f_tld, extension_uri) != 0)
191 : //if(strncmp(uri + info.f_offset - 11, "domain-name", 11) != 0)
192 : {
193 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted successfully (returned: %d)\n",
194 : uri, i, r);
195 0 : ++err_count;
196 : }
197 : /*
198 : else
199 : fprintf(stderr, "valid: \"%s\" -> \"%s\"\n", uri, info.f_tld);
200 : */
201 : }
202 : }
203 : else
204 : {
205 1720 : if(tld_descriptions[i].f_status == TLD_STATUS_UNUSED
206 985 : && tld_descriptions[i].f_start_offset != USHRT_MAX
207 680 : && strcmp(tld_descriptions[tld_descriptions[i].f_start_offset].f_tld, "*") == 0)
208 : {
209 : /* this is somewhat of a special case, at this point
210 : * we have entries such as:
211 : *
212 : * *.blah.com
213 : *
214 : * and that means the result is going to be SUCCESS
215 : * instead of INVALID...
216 : */
217 310 : if(r != TLD_RESULT_INVALID
218 155 : || info.f_status != TLD_STATUS_UNUSED)
219 : {
220 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted as expected (returned: %d) [1]\n",
221 : uri, i, r);
222 0 : ++err_count;
223 : }
224 : }
225 1565 : else if(r != TLD_RESULT_INVALID)
226 : {
227 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted as expected (returned: %d) [2]\n",
228 : uri, i, r);
229 0 : ++err_count;
230 : }
231 1565 : else if(p != i)
232 : {
233 0 : strcpy(extension_uri, ".");
234 0 : cat_ext(p, extension_uri);
235 0 : if(strcmp(info.f_tld, extension_uri) != 0)
236 : {
237 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted successfully (returned: %d/%s) [1]\n",
238 : uri, i, r, info.f_tld);
239 0 : ++err_count;
240 : }
241 : /*
242 : else
243 : fprintf(stderr, "?? invalid: \"%s\" -> \"%s\"\n", uri, info.f_tld);
244 : */
245 : }
246 : else
247 : {
248 1565 : if(strncmp(uri + info.f_offset - 11, "domain-name", 11) != 0)
249 : {
250 0 : fprintf(stderr, "error: domain name for \"%s\" (%d) could not be extracted successfully (returned: %d/%s) [2]\n",
251 : uri, i, r, info.f_tld);
252 0 : ++err_count;
253 : }
254 : /*
255 : else
256 : fprintf(stderr, "?? invalid: \"%s\" -> \"%s\"\n", uri, info.f_tld);
257 : */
258 : }
259 : }
260 : }
261 : }
262 1 : }
263 :
264 :
265 : /*
266 : * This test checks out URIs that end with an invalid TLD. This is
267 : * expected to return an error every single time.
268 : */
269 1 : void test_unknown()
270 : {
271 : struct bad_data
272 : {
273 : const char * f_uri;
274 : };
275 1 : struct bad_data d[] =
276 : {
277 : { "this.is.wrong" },
278 : { "missing.tld" },
279 : { ".net.absolutely.com.no.info.on.this" }
280 : };
281 : struct tld_info info;
282 : int i, max;
283 : enum tld_result r;
284 :
285 1 : max = sizeof(d) / sizeof(d[0]);
286 4 : for(i = 0; i < max; ++i)
287 : {
288 3 : memset(&info, 0xFE, sizeof(info));
289 3 : r = tld(d[i].f_uri, &info);
290 3 : if(r != TLD_RESULT_NOT_FOUND)
291 : {
292 0 : fprintf(stderr, "error: the invalid URI \"%s\" was found by tld()!\n", d[i].f_uri);
293 0 : ++err_count;
294 : }
295 : }
296 1 : }
297 :
298 :
299 :
300 :
301 1 : void test_invalid()
302 : {
303 : struct tld_info undefined_info;
304 : struct tld_info clear_info;
305 : struct tld_info info;
306 : enum tld_result r;
307 :
308 : /*
309 : * We reset the undefined_info the same way we reset the info
310 : * structure because the alignment on 64bits may add another
311 : * 4 bytes at the end of the structure that are not otherwise
312 : * accessible.
313 : */
314 1 : memset(&undefined_info, 0xFE, sizeof(undefined_info));
315 1 : undefined_info.f_category = TLD_CATEGORY_UNDEFINED;
316 1 : undefined_info.f_status = TLD_STATUS_UNDEFINED;
317 1 : undefined_info.f_country = (const char *) 0;
318 1 : undefined_info.f_tld = (const char *) 0;
319 1 : undefined_info.f_offset = -1;
320 :
321 1 : memset(&clear_info, 0xFE, sizeof(clear_info));
322 :
323 : /* test: NULL */
324 1 : info = clear_info;
325 1 : r = tld(NULL, &info);
326 1 : if(r != TLD_RESULT_NULL)
327 : {
328 0 : fprintf(stderr, "error: the NULL URI did not return the TLD_RESULT_NULL result.\n");
329 0 : ++err_count;
330 : }
331 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
332 : {
333 0 : fprintf(stderr, "error: the NULL URI did not return a reset info structure.\n");
334 0 : ++err_count;
335 : }
336 :
337 : /* test: "" */
338 1 : info = clear_info;
339 1 : r = tld("", &info);
340 1 : if(r != TLD_RESULT_NULL)
341 : {
342 0 : fprintf(stderr, "error: the \"\" URI did not return the TLD_RESULT_NULL result.\n");
343 0 : ++err_count;
344 : }
345 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
346 : {
347 0 : fprintf(stderr, "error: the \"\" URI did not return a reset info structure.\n");
348 0 : ++err_count;
349 : }
350 :
351 : /* test: ".." (two periods one after another) */
352 1 : info = clear_info;
353 1 : r = tld("test..com", &info);
354 1 : if(r != TLD_RESULT_BAD_URI)
355 : {
356 0 : fprintf(stderr, "error: the \"test..com\" URI did not return the TLD_RESULT_BAD_URI result.\n");
357 0 : ++err_count;
358 : }
359 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
360 : {
361 0 : fprintf(stderr, "error: the \"test..com\" URI did not return a reset info structure.\n");
362 0 : ++err_count;
363 : }
364 :
365 : /* test: ".." (two periods one after another) */
366 1 : info = clear_info;
367 1 : r = tld("more..test.com", &info);
368 1 : if(r != TLD_RESULT_BAD_URI)
369 : {
370 0 : fprintf(stderr, "error: the \"more..test.com\" URI did not return the TLD_RESULT_BAD_URI result.\n");
371 0 : ++err_count;
372 : }
373 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
374 : {
375 0 : fprintf(stderr, "error: the \"more..test.com\" URI did not return a reset info structure.\n");
376 0 : ++err_count;
377 : }
378 :
379 : /* test: "noperiodanywhere" (no periods anywhere) */
380 1 : info = clear_info;
381 1 : r = tld("noperiodanywhere", &info);
382 1 : if(r != TLD_RESULT_NO_TLD)
383 : {
384 0 : fprintf(stderr, "error: the \"noperiodanywhere\" URI did not return the TLD_RESULT_NO_TLD result.\n");
385 0 : ++err_count;
386 : }
387 1 : if(memcmp(&info, &undefined_info, sizeof(info)) != 0)
388 : {
389 0 : fprintf(stderr, "error: the \"noperiodanywhere\" URI did not return a reset info structure.\n");
390 0 : ++err_count;
391 : }
392 1 : }
393 :
394 :
395 :
396 :
397 1 : int main(int argc, char *argv[])
398 : {
399 1 : fprintf(stderr, "testing tld version %s\n", tld_version());
400 :
401 1 : if(argc > 1)
402 : {
403 0 : if(strcmp(argv[1], "-v") == 0)
404 : {
405 0 : verbose = 1;
406 : }
407 : }
408 :
409 : /* call all the tests, one by one
410 : * failures are "recorded" in the err_count global variable
411 : * and the process stops with an error message and exit(1)
412 : * if err_count is not zero.
413 : */
414 1 : test_all();
415 1 : test_unknown();
416 1 : test_invalid();
417 :
418 1 : if(err_count)
419 : {
420 0 : fprintf(stderr, "%d error%s occured.\n",
421 0 : err_count, err_count != 1 ? "s" : "");
422 : }
423 1 : exit(err_count ? 1 : 0);
424 : }
425 :
426 : /* vim: ts=4 sw=4
427 : */
|