1 /* Copyright (c) 2015-2017 the Civetweb developers
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 #ifndef _CRT_SECURE_NO_WARNINGS
24 #define _CRT_SECURE_NO_WARNINGS
31 #include "public_func.h"
34 /* This unit test file uses the excellent Check unit testing library.
35 * The API documentation is available here:
36 * http://check.sourceforge.net/doc/check_html/index.html
39 START_TEST(test_mg_version
)
41 const char *ver
= mg_version();
42 unsigned major
= 0, minor
= 0;
43 unsigned feature_files
, feature_https
, feature_cgi
, feature_ipv6
,
44 feature_websocket
, feature_lua
, feature_duktape
, feature_caching
;
45 unsigned expect_files
= 0, expect_https
= 0, expect_cgi
= 0,
46 expect_ipv6
= 0, expect_websocket
= 0, expect_lua
= 0,
47 expect_duktape
= 0, expect_caching
= 0;
51 ck_assert(ver
!= NULL
);
52 ck_assert_str_eq(ver
, CIVETWEB_VERSION
);
54 /* check structure of version string */
55 ret
= sscanf(ver
, "%u.%u", &major
, &minor
);
56 ck_assert_int_eq(ret
, 2);
57 ck_assert_uint_ge(major
, 1);
59 ck_assert_uint_ge(minor
, 8); /* current version is 1.8 */
63 feature_files
= mg_check_feature(1);
64 feature_https
= mg_check_feature(2);
65 feature_cgi
= mg_check_feature(4);
66 feature_ipv6
= mg_check_feature(8);
67 feature_websocket
= mg_check_feature(16);
68 feature_lua
= mg_check_feature(32);
69 feature_duktape
= mg_check_feature(64);
70 feature_caching
= mg_check_feature(128);
72 #if !defined(NO_FILES)
84 #if defined(USE_WEBSOCKET)
90 #if defined(USE_DUKTAPE)
93 #if !defined(NO_CACHING)
97 ck_assert_uint_eq(expect_files
, !!feature_files
);
98 ck_assert_uint_eq(expect_https
, !!feature_https
);
99 ck_assert_uint_eq(expect_cgi
, !!feature_cgi
);
100 ck_assert_uint_eq(expect_ipv6
, !!feature_ipv6
);
101 ck_assert_uint_eq(expect_websocket
, !!feature_websocket
);
102 ck_assert_uint_eq(expect_lua
, !!feature_lua
);
103 ck_assert_uint_eq(expect_duktape
, !!feature_duktape
);
104 ck_assert_uint_eq(expect_caching
, !!feature_caching
);
106 /* get system information */
107 len
= mg_get_system_info(NULL
, 0);
108 ck_assert_int_gt(len
, 0);
109 buf
= (char *)malloc((unsigned)len
+ 1);
110 ck_assert_ptr_ne(buf
, NULL
);
111 ret
= mg_get_system_info(buf
, len
+ 1);
112 ck_assert_int_eq(len
, ret
);
113 ret
= (int)strlen(buf
);
114 ck_assert_int_eq(len
, ret
);
120 START_TEST(test_mg_get_valid_options
)
123 const struct mg_option
*default_options
= mg_get_valid_options();
125 ck_assert(default_options
!= NULL
);
127 for (i
= 0; default_options
[i
].name
!= NULL
; i
++) {
128 ck_assert(default_options
[i
].name
!= NULL
);
129 ck_assert(strlen(default_options
[i
].name
) > 0);
130 ck_assert(((int)default_options
[i
].type
) > 0);
138 START_TEST(test_mg_get_builtin_mime_type
)
140 ck_assert_str_eq(mg_get_builtin_mime_type("x.txt"), "text/plain");
141 ck_assert_str_eq(mg_get_builtin_mime_type("x.html"), "text/html");
142 ck_assert_str_eq(mg_get_builtin_mime_type("x.HTML"), "text/html");
143 ck_assert_str_eq(mg_get_builtin_mime_type("x.hTmL"), "text/html");
144 ck_assert_str_eq(mg_get_builtin_mime_type("/abc/def/ghi.htm"), "text/html");
145 ck_assert_str_eq(mg_get_builtin_mime_type("x.unknown_extention_xyz"),
151 START_TEST(test_mg_strncasecmp
)
153 ck_assert(mg_strncasecmp("abc", "abc", 3) == 0);
154 ck_assert(mg_strncasecmp("abc", "abcd", 3) == 0);
155 ck_assert(mg_strncasecmp("abc", "abcd", 4) != 0);
156 ck_assert(mg_strncasecmp("a", "A", 1) == 0);
158 ck_assert(mg_strncasecmp("A", "B", 1) < 0);
159 ck_assert(mg_strncasecmp("A", "b", 1) < 0);
160 ck_assert(mg_strncasecmp("a", "B", 1) < 0);
161 ck_assert(mg_strncasecmp("a", "b", 1) < 0);
162 ck_assert(mg_strncasecmp("b", "A", 1) > 0);
163 ck_assert(mg_strncasecmp("B", "A", 1) > 0);
164 ck_assert(mg_strncasecmp("b", "a", 1) > 0);
165 ck_assert(mg_strncasecmp("B", "a", 1) > 0);
167 ck_assert(mg_strncasecmp("xAx", "xBx", 3) < 0);
168 ck_assert(mg_strncasecmp("xAx", "xbx", 3) < 0);
169 ck_assert(mg_strncasecmp("xax", "xBx", 3) < 0);
170 ck_assert(mg_strncasecmp("xax", "xbx", 3) < 0);
171 ck_assert(mg_strncasecmp("xbx", "xAx", 3) > 0);
172 ck_assert(mg_strncasecmp("xBx", "xAx", 3) > 0);
173 ck_assert(mg_strncasecmp("xbx", "xax", 3) > 0);
174 ck_assert(mg_strncasecmp("xBx", "xax", 3) > 0);
179 START_TEST(test_mg_get_cookie
)
183 const char *longcookie
= "key1=1; key2=2; key3; key4=4; key5=; key6; "
184 "key7=this+is+it; key8=8; key9";
186 /* invalid result buffer */
187 ret
= mg_get_cookie("", "notfound", NULL
, 999);
188 ck_assert_int_eq(ret
, -2);
190 /* zero size result buffer */
191 ret
= mg_get_cookie("", "notfound", buf
, 0);
192 ck_assert_int_eq(ret
, -2);
194 /* too small result buffer */
195 ret
= mg_get_cookie("key=toooooooooolong", "key", buf
, 4);
196 ck_assert_int_eq(ret
, -3);
198 /* key not found in string */
199 ret
= mg_get_cookie("", "notfound", buf
, sizeof(buf
));
200 ck_assert_int_eq(ret
, -1);
202 ret
= mg_get_cookie(longcookie
, "notfound", buf
, sizeof(buf
));
203 ck_assert_int_eq(ret
, -1);
205 /* key not found in string */
206 ret
= mg_get_cookie("key1=1; key2=2; key3=3", "notfound", buf
, sizeof(buf
));
207 ck_assert_int_eq(ret
, -1);
209 /* keys are found as first, middle and last key */
210 memset(buf
, 77, sizeof(buf
));
211 ret
= mg_get_cookie("key1=1; key2=2; key3=3", "key1", buf
, sizeof(buf
));
212 ck_assert_int_eq(ret
, 1);
213 ck_assert_str_eq("1", buf
);
215 memset(buf
, 77, sizeof(buf
));
216 ret
= mg_get_cookie("key1=1; key2=2; key3=3", "key2", buf
, sizeof(buf
));
217 ck_assert_int_eq(ret
, 1);
218 ck_assert_str_eq("2", buf
);
220 memset(buf
, 77, sizeof(buf
));
221 ret
= mg_get_cookie("key1=1; key2=2; key3=3", "key3", buf
, sizeof(buf
));
222 ck_assert_int_eq(ret
, 1);
223 ck_assert_str_eq("3", buf
);
225 /* longer value in the middle of a longer string */
226 memset(buf
, 77, sizeof(buf
));
227 ret
= mg_get_cookie(longcookie
, "key7", buf
, sizeof(buf
));
228 ck_assert_int_eq(ret
, 10);
229 ck_assert_str_eq("this+is+it", buf
);
231 /* key with = but without value in the middle of a longer string */
232 memset(buf
, 77, sizeof(buf
));
233 ret
= mg_get_cookie(longcookie
, "key5", buf
, sizeof(buf
));
234 ck_assert_int_eq(ret
, 0);
235 ck_assert_str_eq("", buf
);
237 /* key without = and without value in the middle of a longer string */
238 memset(buf
, 77, sizeof(buf
));
239 ret
= mg_get_cookie(longcookie
, "key6", buf
, sizeof(buf
));
240 ck_assert_int_eq(ret
, -1);
241 /* TODO: mg_get_cookie and mg_get_var(2) should have the same behavior */
246 START_TEST(test_mg_get_var
)
250 const char *shortquery
= "key1=1&key2=2&key3=3";
251 const char *longquery
= "key1=1&key2=2&key3&key4=4&key5=&key6&"
252 "key7=this+is+it&key8=8&key9&&key10=&&"
253 "key7=that+is+it&key12=12";
255 /* invalid result buffer */
256 ret
= mg_get_var2("", 0, "notfound", NULL
, 999, 0);
257 ck_assert_int_eq(ret
, -2);
259 /* zero size result buffer */
260 ret
= mg_get_var2("", 0, "notfound", buf
, 0, 0);
261 ck_assert_int_eq(ret
, -2);
263 /* too small result buffer */
264 ret
= mg_get_var2("key=toooooooooolong", 19, "key", buf
, 4, 0);
265 /* ck_assert_int_eq(ret, -3);
266 --> TODO: mg_get_cookie returns -3, mg_get_var -2. This should be
270 /* key not found in string */
271 ret
= mg_get_var2("", 0, "notfound", buf
, sizeof(buf
), 0);
272 ck_assert_int_eq(ret
, -1);
275 longquery
, strlen(longquery
), "notfound", buf
, sizeof(buf
), 0);
276 ck_assert_int_eq(ret
, -1);
278 /* key not found in string */
280 shortquery
, strlen(shortquery
), "notfound", buf
, sizeof(buf
), 0);
281 ck_assert_int_eq(ret
, -1);
283 /* key not found in string */
284 ret
= mg_get_var2("key1=1&key2=2&key3=3¬found=here",
290 ck_assert_int_eq(ret
, -1);
292 /* key not found in string */
294 shortquery
, strlen(shortquery
), "key1", buf
, sizeof(buf
), 1);
295 ck_assert_int_eq(ret
, -1);
297 /* keys are found as first, middle and last key */
298 memset(buf
, 77, sizeof(buf
));
300 shortquery
, strlen(shortquery
), "key1", buf
, sizeof(buf
), 0);
301 ck_assert_int_eq(ret
, 1);
302 ck_assert_str_eq("1", buf
);
304 memset(buf
, 77, sizeof(buf
));
306 shortquery
, strlen(shortquery
), "key2", buf
, sizeof(buf
), 0);
307 ck_assert_int_eq(ret
, 1);
308 ck_assert_str_eq("2", buf
);
310 memset(buf
, 77, sizeof(buf
));
312 shortquery
, strlen(shortquery
), "key3", buf
, sizeof(buf
), 0);
313 ck_assert_int_eq(ret
, 1);
314 ck_assert_str_eq("3", buf
);
316 /* mg_get_var call mg_get_var2 with last argument 0 */
317 memset(buf
, 77, sizeof(buf
));
318 ret
= mg_get_var(shortquery
, strlen(shortquery
), "key1", buf
, sizeof(buf
));
319 ck_assert_int_eq(ret
, 1);
320 ck_assert_str_eq("1", buf
);
322 /* longer value in the middle of a longer string */
323 memset(buf
, 77, sizeof(buf
));
325 mg_get_var2(longquery
, strlen(longquery
), "key7", buf
, sizeof(buf
), 0);
326 ck_assert_int_eq(ret
, 10);
327 ck_assert_str_eq("this is it", buf
);
329 /* longer value in the middle of a longer string - seccond occurance of key
331 memset(buf
, 77, sizeof(buf
));
333 mg_get_var2(longquery
, strlen(longquery
), "key7", buf
, sizeof(buf
), 1);
334 ck_assert_int_eq(ret
, 10);
335 ck_assert_str_eq("that is it", buf
);
337 /* key with = but without value in the middle of a longer string */
338 memset(buf
, 77, sizeof(buf
));
340 mg_get_var2(longquery
, strlen(longquery
), "key5", buf
, sizeof(buf
), 0);
341 ck_assert_int_eq(ret
, 0);
342 ck_assert_str_eq(buf
, "");
344 /* key without = and without value in the middle of a longer string */
345 memset(buf
, 77, sizeof(buf
));
347 mg_get_var2(longquery
, strlen(longquery
), "key6", buf
, sizeof(buf
), 0);
348 ck_assert_int_eq(ret
, -1);
349 ck_assert_str_eq(buf
, "");
350 /* TODO: this is the same situation as with mg_get_value */
355 START_TEST(test_mg_md5
)
359 const char *long_str
=
360 "_123456789A123456789B123456789C123456789D123456789E123456789F123456789"
361 "G123456789H123456789I123456789J123456789K123456789L123456789M123456789"
362 "N123456789O123456789P123456789Q123456789R123456789S123456789T123456789"
363 "U123456789V123456789W123456789X123456789Y123456789Z";
365 memset(buf
, 77, sizeof(buf
));
366 ret
= mg_md5(buf
, NULL
);
367 ck_assert_str_eq(buf
, "d41d8cd98f00b204e9800998ecf8427e");
368 ck_assert_str_eq(ret
, "d41d8cd98f00b204e9800998ecf8427e");
369 ck_assert_ptr_eq(ret
, buf
);
371 memset(buf
, 77, sizeof(buf
));
372 ret
= mg_md5(buf
, "The quick brown fox jumps over the lazy dog.", NULL
);
373 ck_assert_str_eq(buf
, "e4d909c290d0fb1ca068ffaddf22cbd0");
374 ck_assert_str_eq(ret
, "e4d909c290d0fb1ca068ffaddf22cbd0");
375 ck_assert_ptr_eq(ret
, buf
);
377 memset(buf
, 77, sizeof(buf
));
391 ck_assert_str_eq(buf
, "e4d909c290d0fb1ca068ffaddf22cbd0");
392 ck_assert_str_eq(ret
, "e4d909c290d0fb1ca068ffaddf22cbd0");
393 ck_assert_ptr_eq(ret
, buf
);
395 memset(buf
, 77, sizeof(buf
));
396 ret
= mg_md5(buf
, long_str
, NULL
);
397 ck_assert_str_eq(buf
, "1cb13cf9f16427807f081b2138241f08");
398 ck_assert_str_eq(ret
, "1cb13cf9f16427807f081b2138241f08");
399 ck_assert_ptr_eq(ret
, buf
);
401 memset(buf
, 77, sizeof(buf
));
402 ret
= mg_md5(buf
, long_str
+ 1, NULL
);
403 ck_assert_str_eq(buf
, "cf62d3264334154f5779d3694cc5093f");
404 ck_assert_str_eq(ret
, "cf62d3264334154f5779d3694cc5093f");
405 ck_assert_ptr_eq(ret
, buf
);
410 START_TEST(test_mg_url_encode
)
415 memset(buf
, 77, sizeof(buf
));
416 ret
= mg_url_encode("abc", buf
, sizeof(buf
));
417 ck_assert_int_eq(3, ret
);
418 ck_assert_str_eq("abc", buf
);
420 memset(buf
, 77, sizeof(buf
));
421 ret
= mg_url_encode("a%b/c&d.e", buf
, sizeof(buf
));
422 ck_assert_int_eq(15, ret
);
423 ck_assert_str_eq("a%25b%2fc%26d.e", buf
);
425 memset(buf
, 77, sizeof(buf
));
426 ret
= mg_url_encode("%%%", buf
, 4);
427 ck_assert_int_eq(-1, ret
);
428 ck_assert_str_eq("%25", buf
);
433 START_TEST(test_mg_url_decode
)
438 ret
= mg_url_decode("abc", 3, buf
, sizeof(buf
), 0);
439 ck_assert_int_eq(ret
, 3);
440 ck_assert_str_eq(buf
, "abc");
442 ret
= mg_url_decode("abcdef", 3, buf
, sizeof(buf
), 0);
443 ck_assert_int_eq(ret
, 3);
444 ck_assert_str_eq(buf
, "abc");
446 ret
= mg_url_decode("x+y", 3, buf
, sizeof(buf
), 0);
447 ck_assert_int_eq(ret
, 3);
448 ck_assert_str_eq(buf
, "x+y");
450 ret
= mg_url_decode("x+y", 3, buf
, sizeof(buf
), 1);
451 ck_assert_int_eq(ret
, 3);
452 ck_assert_str_eq(buf
, "x y");
454 ret
= mg_url_decode("%25", 3, buf
, sizeof(buf
), 1);
455 ck_assert_int_eq(ret
, 1);
456 ck_assert_str_eq(buf
, "%");
461 START_TEST(test_mg_get_response_code_text
)
467 for (i
= 100; i
< 600; i
++) {
468 resp
= mg_get_response_code_text(NULL
, i
);
469 ck_assert_ptr_ne(resp
, NULL
);
471 ck_assert_uint_gt(len
, 1);
472 ck_assert_uint_lt(len
, 32);
473 for (j
= 0; j
< len
; j
++) {
474 if (resp
[j
] == ' ') {
476 } else if (resp
[j
] == '-') {
477 /* hyphen is valid */
478 } else if (resp
[j
] >= 'A' && resp
[j
] <= 'Z') {
480 } else if (resp
[j
] >= 'a' && resp
[j
] <= 'z') {
483 ck_abort_msg("Found letter %c (%02xh) in %s",
494 #if !defined(REPLACE_CHECK_FOR_LOCAL_DEBUGGING)
496 make_public_func_suite(void)
498 Suite
*const suite
= suite_create("PublicFunc");
500 TCase
*const tcase_version
= tcase_create("Version");
501 TCase
*const tcase_get_valid_options
= tcase_create("Options");
502 TCase
*const tcase_get_builtin_mime_type
= tcase_create("MIME types");
503 TCase
*const tcase_strncasecmp
= tcase_create("strcasecmp");
504 TCase
*const tcase_urlencodingdecoding
=
505 tcase_create("URL encoding decoding");
506 TCase
*const tcase_cookies
= tcase_create("Cookies and variables");
507 TCase
*const tcase_md5
= tcase_create("MD5");
508 TCase
*const tcase_aux
= tcase_create("Aux functions");
510 tcase_add_test(tcase_version
, test_mg_version
);
511 tcase_set_timeout(tcase_version
, civetweb_min_test_timeout
);
512 suite_add_tcase(suite
, tcase_version
);
514 tcase_add_test(tcase_get_valid_options
, test_mg_get_valid_options
);
515 tcase_set_timeout(tcase_get_valid_options
, civetweb_min_test_timeout
);
516 suite_add_tcase(suite
, tcase_get_valid_options
);
518 tcase_add_test(tcase_get_builtin_mime_type
, test_mg_get_builtin_mime_type
);
519 tcase_set_timeout(tcase_get_builtin_mime_type
, civetweb_min_test_timeout
);
520 suite_add_tcase(suite
, tcase_get_builtin_mime_type
);
522 tcase_add_test(tcase_strncasecmp
, test_mg_strncasecmp
);
523 tcase_set_timeout(tcase_strncasecmp
, civetweb_min_test_timeout
);
524 suite_add_tcase(suite
, tcase_strncasecmp
);
526 tcase_add_test(tcase_urlencodingdecoding
, test_mg_url_encode
);
527 tcase_add_test(tcase_urlencodingdecoding
, test_mg_url_decode
);
528 tcase_set_timeout(tcase_urlencodingdecoding
, civetweb_min_test_timeout
);
529 suite_add_tcase(suite
, tcase_urlencodingdecoding
);
531 tcase_add_test(tcase_cookies
, test_mg_get_cookie
);
532 tcase_add_test(tcase_cookies
, test_mg_get_var
);
533 tcase_set_timeout(tcase_cookies
, civetweb_min_test_timeout
);
534 suite_add_tcase(suite
, tcase_cookies
);
536 tcase_add_test(tcase_md5
, test_mg_md5
);
537 tcase_set_timeout(tcase_md5
, civetweb_min_test_timeout
);
538 suite_add_tcase(suite
, tcase_md5
);
540 tcase_add_test(tcase_aux
, test_mg_get_response_code_text
);
541 tcase_set_timeout(tcase_aux
, civetweb_min_test_timeout
);
542 suite_add_tcase(suite
, tcase_aux
);