LCOV - code coverage report
Current view: top level - src/odbc/unittests - connection_string_parse.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 73 82 89.0 %
Date: 2026-07-19 14:02:14 Functions: 11 11 100.0 %

          Line data    Source code
       1             : #include "common.h"
       2             : #include <assert.h>
       3             : #include "freetds/odbc.h"
       4             : 
       5             : 
       6             : static void
       7         120 : assert_equal_dstr(DSTR a, const char *b)
       8             : {
       9         240 :         assert(b && strcmp(tds_dstr_cstr(&a), b)==0);
      10         120 : }
      11             : 
      12             : static void
      13         150 : assert_equal_str(TDS_PARSED_PARAM param, const char *b)
      14             : {
      15             :         /* printf("param %.*s b %s\n", (int) param.len, param.p, b); */
      16         150 :         if (b && strlen(b) == param.len && strncmp(param.p, b, param.len) == 0)
      17             :                 return;
      18             : 
      19           0 :         if (!b)
      20           0 :                 b = "(null)";
      21             : 
      22           0 :         fprintf(stderr, "(%d) \"%s\"\n", (int) strlen(b), b);
      23           0 :         fprintf(stderr, "(%d) \"%.*s\"\n", (int) param.len, (int) param.len, param.p);
      24           0 :         assert(!"Strings differ.");
      25             : }
      26             : 
      27             : typedef void check_func_t(TDSLOGIN * login, TDS_PARSED_PARAM * parsed_params);
      28             : 
      29             : static void
      30          80 : test_common(const char *name, const char *connect_string, check_func_t *check_func)
      31             : {
      32             :         TDSLOGIN *login;
      33          80 :         TDS_ERRS errs = {0};
      34             :         TDSLOCALE *locale;
      35             :         TDS_PARSED_PARAM parsed_params[ODBC_PARAM_SIZE];
      36             : 
      37          80 :         const char *connect_string_end = connect_string + strlen(connect_string);
      38          80 :         login = tds_alloc_login(false);
      39          80 :         if (!tds_set_language(login, "us_english")) {
      40           0 :                 fprintf(stderr, "Error setting language in test '%s'\n", name);
      41           0 :                 exit(1);
      42             :         }
      43          80 :         locale = tds_alloc_locale();
      44          80 :         login = tds_init_login(login, locale);
      45             : 
      46          80 :         odbc_errs_reset(&errs);
      47             : 
      48          80 :         if (!odbc_parse_connect_string(&errs, connect_string, connect_string_end, login, NULL, parsed_params)) {
      49          10 :                 assert(errs.num_errors > 0);
      50          10 :                 if (check_func) {
      51           0 :                         fprintf(stderr, "Error parsing string in test '%s'\n", name);
      52           0 :                         exit(1);
      53             :                 }
      54             :         } else {
      55          70 :                 assert(errs.num_errors == 0);
      56          70 :                 assert(check_func != NULL);
      57          70 :                 check_func(login, parsed_params);
      58             :         }
      59             : 
      60          80 :         odbc_errs_reset(&errs);
      61          80 :         tds_free_login(login);
      62          80 :         tds_free_locale(locale);
      63          80 : }
      64             : 
      65             : #define CHECK(name, s) \
      66             :         static void name ## _check(TDSLOGIN *login, TDS_PARSED_PARAM *parsed_params); \
      67             :         static void name(void) { \
      68             :                 static const char connect_string[] = s; \
      69             :                 test_common(#name, connect_string, name ## _check); \
      70             :         } \
      71             :         static void name ## _check(TDSLOGIN *login TDS_UNUSED, TDS_PARSED_PARAM *parsed_params)
      72             : 
      73             : #define CHECK_ERROR(name, s) \
      74             :         static void name(void) { \
      75             :                 static const char connect_string[] = s; \
      76             :                 test_common(#name, connect_string, NULL); \
      77             :         }
      78             : 
      79          20 : CHECK(simple_string,
      80             :         "DRIVER=libtdsodbc.so;SERVER=127.0.0.1;PORT=1337;UID=test_username;PWD=test_password;DATABASE=test_db;"
      81             :         "ClientCharset=UTF-8;")
      82             : {
      83          10 :         assert_equal_str(parsed_params[ODBC_PARAM_UID], "test_username");
      84          10 :         assert_equal_dstr(login->server_name, "127.0.0.1");
      85          10 :         assert_equal_dstr(login->password, "test_password");
      86          10 :         assert_equal_str(parsed_params[ODBC_PARAM_PWD], "test_password");
      87          10 :         assert(login->port == 1337);
      88          10 : }
      89             : 
      90          20 : CHECK(simple_escaped_string,
      91             :         "DRIVER={libtdsodbc.so};SERVER={127.0.0.1};PORT={1337};UID={test_username};PWD={test_password};DATABASE={test_db};"
      92             :         "ClientCharset={UTF-8};")
      93             : {
      94          10 :         assert_equal_str(parsed_params[ODBC_PARAM_UID], "{test_username}");
      95          10 :         assert_equal_dstr(login->server_name, "127.0.0.1");
      96          10 :         assert_equal_dstr(login->password, "test_password");
      97          10 :         assert_equal_str(parsed_params[ODBC_PARAM_PWD], "{test_password}");
      98          10 :         assert(login->port == 1337);
      99          10 : }
     100             : 
     101          20 : CHECK(test_special_symbols,
     102             :         "DRIVER={libtdsodbc.so};SERVER={127.0.0.1};PORT={1337};UID={test_username};PWD={[]{}}(),;?*=!@};DATABASE={test_db};"
     103             :         "ClientCharset={UTF-8};")
     104             : {
     105          10 :         assert_equal_str(parsed_params[ODBC_PARAM_UID], "{test_username}");
     106          10 :         assert_equal_dstr(login->server_name, "127.0.0.1");
     107          10 :         assert_equal_dstr(login->password, "[]{}(),;?*=!@");
     108          10 :         assert_equal_str(parsed_params[ODBC_PARAM_PWD], "{[]{}}(),;?*=!@}");
     109          10 :         assert(login->port == 1337);
     110          10 : }
     111             : 
     112          20 : CHECK(password_contains_curly_braces,
     113             :         "DRIVER={libtdsodbc.so};SERVER={127.0.0.1};PORT={1337};UID={test_username};PWD={test{}}_password};DATABASE={test_db};"
     114             :         "ClientCharset={UTF-8};")
     115             : {
     116          10 :         assert_equal_str(parsed_params[ODBC_PARAM_UID], "{test_username}");
     117          10 :         assert_equal_dstr(login->server_name, "127.0.0.1");
     118          10 :         assert_equal_dstr(login->password, "test{}_password");
     119          10 :         assert_equal_str(parsed_params[ODBC_PARAM_PWD], "{test{}}_password}");
     120          10 :         assert(login->port == 1337);
     121          10 : }
     122             : 
     123          20 : CHECK(password_contains_curly_braces_and_separator,
     124             :         "DRIVER={libtdsodbc.so};SERVER={127.0.0.1};PORT={1337};UID={test_username};PWD={test{}};_password};DATABASE={test_db};"
     125             :         "ClientCharset={UTF-8};")
     126             : {
     127          10 :         assert_equal_str(parsed_params[ODBC_PARAM_UID], "{test_username}");
     128          10 :         assert_equal_dstr(login->server_name, "127.0.0.1");
     129          10 :         assert_equal_dstr(login->password, "test{};_password");
     130          10 :         assert_equal_str(parsed_params[ODBC_PARAM_PWD], "{test{}};_password}");
     131          10 :         assert(login->port == 1337);
     132          10 : }
     133             : 
     134          20 : CHECK(password_bug_report,
     135             :         "Driver=FreeTDS;Server=1.2.3.4;Port=1433;Database=test;uid=test_user;pwd={p@ssw0rd}")
     136             : {
     137          10 :         assert_equal_str(parsed_params[ODBC_PARAM_UID], "test_user");
     138          10 :         assert_equal_dstr(login->server_name, "1.2.3.4");
     139          10 :         assert_equal_dstr(login->password, "p@ssw0rd");
     140          10 :         assert_equal_str(parsed_params[ODBC_PARAM_PWD], "{p@ssw0rd}");
     141          10 :         assert(login->port == 1433);
     142          10 : }
     143             : 
     144             : /* unfinished "pwd", the "Port" before "pwd" is to reveal a leak */
     145          10 : CHECK_ERROR(unfinished,
     146             :         "Driver=FreeTDS;Server=1.2.3.4;Port=1433;pwd={p@ssw0rd")
     147             : 
     148          20 : CHECK(datetime_formats,
     149             :         "Driver=FreeTDS;Server=1.2.3.4;Port=1433;Database=test;uid=test_user;pwd=xxxx;TIMEFMT=%H:%M:%S;DATEFMT=%Y-%m-%d;DATETIMEFMT={==%Y%m%d;%H%M%S==}")
     150             : {
     151          10 :         assert_equal_str(parsed_params[ODBC_PARAM_DateFmt], "%Y-%m-%d");
     152          10 :         assert_equal_str(parsed_params[ODBC_PARAM_TimeFmt], "%H:%M:%S");
     153          10 :         assert_equal_str(parsed_params[ODBC_PARAM_DateTimeFmt], "{==%Y%m%d;%H%M%S==}");
     154          10 : }
     155             : 
     156          10 : TEST_MAIN()
     157             : {
     158             :         simple_string();
     159             : 
     160             :         simple_escaped_string();
     161             : 
     162             :         password_contains_curly_braces();
     163             : 
     164             :         test_special_symbols();
     165             : 
     166             :         password_contains_curly_braces_and_separator();
     167             : 
     168             :         password_bug_report();
     169             : 
     170             :         unfinished();
     171             : 
     172             :         datetime_formats();
     173             : 
     174          10 :         return 0;
     175             : }

Generated by: LCOV version 1.13