LCOV - code coverage report
Current view: top level - src/tds/unittests - charconv.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 144 159 90.6 %
Date: 2025-01-18 12:13:41 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 2014   Frediano Ziglio
       3             :  *
       4             :  * This library is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU Library General Public
       6             :  * License as published by the Free Software Foundation; either
       7             :  * version 2 of the License, or (at your option) any later version.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * Library General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU Library General Public
      15             :  * License along with this library; if not, write to the
      16             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      17             :  * Boston, MA 02111-1307, USA.
      18             :  */
      19             : 
      20             : /*
      21             :  * This test test tds_convert_stream which is supposed to be the main
      22             :  * character conversion routine
      23             :  *
      24             :  * Check that error are reported to error handler if found and tds
      25             :  * is not NULL.
      26             :  *
      27             :  * Check that conversions works with NULL tds.
      28             :  *
      29             :  * Check all types of errors (EILSEQ, EINVAL, E2BIG).
      30             :  *
      31             :  * Check that error are capture in middle and on end of stream.
      32             :  */
      33             : 
      34             : #include "common.h"
      35             : #include <freetds/iconv.h>
      36             : #include <freetds/stream.h>
      37             : 
      38             : #if HAVE_UNISTD_H
      39             : #undef getpid
      40             : #include <unistd.h>
      41             : #endif /* HAVE_UNISTD_H */
      42             : 
      43             : #if HAVE_STDLIB_H
      44             : #include <stdlib.h>
      45             : #endif /* HAVE_STDLIB_H */
      46             : 
      47             : #include <assert.h>
      48             : 
      49             : /* test tds_bcp_fread */
      50             : 
      51             : static char buf[4096+80];
      52             : static char buf_out[4096+80];
      53             : 
      54             : static int last_errno = 0;
      55             : 
      56             : static TDSRET
      57       70320 : convert(TDSSOCKET *tds, TDSICONV *conv, TDS_ICONV_DIRECTION direction,
      58             :         const char *from, size_t from_len, char *dest, size_t *dest_len)
      59             : {
      60             :         /* copy to make valgrind test fail on memory problems */
      61       70320 :         char *in = tds_new(char, from_len);
      62       70320 :         char *out = tds_new(char, *dest_len);
      63             :         int res;
      64             :         TDSSTATICINSTREAM r;
      65             :         TDSSTATICOUTSTREAM w;
      66             : 
      67       70320 :         assert(in && out);
      68             : 
      69       70320 :         memcpy(in, from, from_len);
      70       70320 :         tds_staticin_stream_init(&r, in, from_len);
      71       70320 :         tds_staticout_stream_init(&w, out, *dest_len);
      72       70320 :         last_errno = 0;
      73       70320 :         res = tds_convert_stream(tds, conv, direction, &r.stream, &w.stream);
      74       70320 :         last_errno = errno;
      75       70320 :         memcpy(dest, out, *dest_len - w.stream.buf_len);
      76       70320 :         *dest_len = *dest_len - w.stream.buf_len;
      77             : 
      78       70320 :         free(in);
      79       70320 :         free(out);
      80       70320 :         return res;
      81             : }
      82             : 
      83             : enum Odd {
      84             :         ODD_NONE = 0,
      85             :         ODD_NORMAL,
      86             :         ODD_INVALID,
      87             :         ODD_INCOMPLETE,
      88             :         ODD_NUM_VALUES
      89             : };
      90             : 
      91             : static const char *odd_names[] = {
      92             :         "None", "Normal", "Invalid", "Incomplete"
      93             : };
      94             : 
      95             : static int
      96       11840 : add_odd(char *buf, int *pos, enum Odd type)
      97             : {
      98       11840 :         const unsigned char x = 0xa0;
      99             : 
     100       11840 :         switch (type) {
     101             :         case ODD_NONE:
     102             :                 return 0;
     103             : 
     104        3552 :         case ODD_NORMAL:
     105        3552 :                 buf[*pos] = 0xC0 + (x >> 6);
     106        3552 :                 ++*pos;
     107        3552 :                 buf[*pos] = 0x80 + (x & 0x3f);
     108        3552 :                 ++*pos;
     109        3552 :                 return 0;
     110             : 
     111        3552 :         case ODD_INVALID:
     112        3552 :                 buf[*pos] = 0xff;
     113        3552 :                 ++*pos;
     114        3552 :                 return EILSEQ;
     115             : 
     116        1184 :         case ODD_INCOMPLETE:
     117        1184 :                 buf[*pos] = 0xC2;
     118        1184 :                 ++*pos;
     119        1184 :                 return EINVAL;
     120             : 
     121             :         default:
     122           0 :                 assert(0);
     123             :         }
     124             :         return 0;
     125             : }
     126             : 
     127             : static void
     128       11792 : add_odd2(char *buf, int *pos, enum Odd type)
     129             : {
     130       11792 :         const unsigned char x = 0xa0;
     131             : 
     132       11792 :         switch (type) {
     133             :         case ODD_NONE:
     134             :                 return;
     135        3520 :         case ODD_NORMAL:
     136        3520 :                 buf[*pos] = x;
     137        3520 :                 ++*pos;
     138        3520 :                 break;
     139             :         case ODD_INVALID:
     140             :                 break;
     141             :         case ODD_INCOMPLETE:
     142             :                 break;
     143             :         default:
     144           0 :                 assert(0);
     145             :         }       
     146             : }
     147             : 
     148             : static int captured_errno = 0;
     149             : 
     150             : static int
     151       31184 : err_handler(const TDSCONTEXT * tds_ctx, TDSSOCKET * tds, TDSMESSAGE * msg)
     152             : {
     153       31184 :         int old_err = captured_errno;
     154       31184 :         if (msg->msgno == TDSEICONVAVAIL) {
     155         592 :                 captured_errno = EINVAL;
     156       30592 :         } else if (strstr(msg->message, "could not be converted")) {
     157        1768 :                 captured_errno = EILSEQ;
     158       28824 :         } else if (msg->msgno == TDSEICONVIU) {
     159       28824 :                 captured_errno = E2BIG;
     160             :         } else {
     161           0 :                 fprintf(stderr, "Unexpected error: %s\n", msg->message);
     162           0 :                 exit(1);
     163             :         }
     164       31184 :         assert(old_err == 0 || old_err == captured_errno);
     165       31184 :         return TDS_INT_CANCEL;
     166             : }
     167             : 
     168             : static TDSICONV * conv = NULL;
     169             : static int pos_type = 0;
     170             : 
     171             : static void
     172         192 : test(TDSSOCKET *tds, enum Odd odd_type)
     173             : {
     174             :         int i, l;
     175             : 
     176         192 :         captured_errno = 0;
     177             : 
     178             :         /* do not complete incomplete */
     179         192 :         if (odd_type == ODD_INCOMPLETE && pos_type > 0)
     180          32 :                 return;
     181             : 
     182         160 :         printf("test pos %d type %s\n", pos_type, odd_names[odd_type]);
     183             : 
     184       12000 :         for (i = 0; i < 4096+20; ++i) {
     185             :                 size_t out_len;
     186             :                 TDSRET res;
     187             :                 int err;
     188             : 
     189       11840 :                 if (i == 34)
     190         160 :                         i = 4096-20;
     191             : 
     192       11840 :                 l = i;
     193       11840 :                 memset(buf, 'a', sizeof(buf));
     194       11840 :                 switch (pos_type) {
     195        4736 :                 case 0: /* end */
     196        4736 :                         err = add_odd(buf, &l, odd_type);
     197        4736 :                         break;
     198        3552 :                 case 1: /* start */
     199        3552 :                         l = 0;
     200        3552 :                         err = add_odd(buf, &l, odd_type);
     201        3552 :                         if (l > i) continue;
     202        3504 :                         l = i;
     203        3504 :                         break;
     204        3552 :                 case 2: /* middle */
     205        3552 :                         err = add_odd(buf, &l, odd_type);
     206        3552 :                         l = 4096+30;
     207        3552 :                         break;
     208           0 :                 default:
     209           0 :                         exit(1);
     210             :                         return;
     211             :                 }
     212             : 
     213             :                 /* convert it */
     214       11792 :                 out_len = sizeof(buf_out);
     215       11792 :                 res = convert(tds, conv, to_server, buf, l, buf_out, &out_len);
     216       11792 :                 printf("i %d res %d out_len %u errno %d captured_errno %d\n",
     217             :                        i, (int) res, (unsigned int) out_len, last_errno, captured_errno);
     218             : 
     219             :                 /* test */
     220       11792 :                 l = i;
     221       11792 :                 memset(buf, 'a', sizeof(buf));
     222       11792 :                 switch (pos_type) {
     223        4736 :                 case 0: /* end */
     224        4736 :                         add_odd2(buf, &l, odd_type);
     225        4736 :                         break;
     226        3504 :                 case 1: /* start */
     227        3504 :                         l = 0;
     228        3504 :                         add_odd2(buf, &l, odd_type);
     229        3504 :                         l = i;
     230        3504 :                         if (odd_type == ODD_NORMAL) l = i-1;
     231        3504 :                         if (odd_type == ODD_INVALID) l = 0;
     232             :                         break;
     233        3552 :                 case 2: /* middle */
     234        3552 :                         add_odd2(buf, &l, odd_type);
     235        3552 :                         l = 4096+30;
     236        3552 :                         if (odd_type == ODD_NORMAL) --l;
     237        3552 :                         if (odd_type == ODD_INVALID) l = i;
     238             :                         break;
     239             :                 }
     240             : 
     241             : 
     242       11792 :                 if (err) {
     243        4720 :                         assert(last_errno == err);
     244        4720 :                         assert(TDS_FAILED(res));
     245        4720 :                         assert(!tds || captured_errno == last_errno);
     246             :                 } else {
     247        7072 :                         assert(TDS_SUCCEED(res));
     248        7072 :                         assert(captured_errno == 0);
     249             :                 }
     250       11792 :                 if (out_len != l) {
     251           0 :                         fprintf(stderr, "out %u bytes expected %d\n",
     252             :                                 (unsigned int) out_len, l);
     253           0 :                         exit(1);
     254             :                 }
     255       11792 :                 assert(memcmp(buf_out, buf, l) == 0);
     256             :         }
     257             : }
     258             : 
     259             : static void
     260          16 : big_test(TDSSOCKET *tds)
     261             : {
     262             :         int i, l;
     263          16 :         const int limit = 1025;
     264             : 
     265          16 :         captured_errno = 0;
     266             : 
     267          16 :         printf("E2BIG test\n");
     268             : 
     269       58544 :         for (i = 0; i < 4096+20; ++i) {
     270             :                 size_t out_len;
     271             :                 TDSRET res;
     272             :                 int err;
     273             : 
     274       58528 :                 if (i == 32)
     275          16 :                         i = 490;
     276             : 
     277       58528 :                 l = i;
     278       58528 :                 memset(buf, 0xa0, sizeof(buf));
     279             : 
     280             :                 /* convert it */
     281       58528 :                 out_len = limit;
     282       58528 :                 res = convert(tds, conv, to_client, buf, l, buf_out, &out_len);
     283       58528 :                 printf("i %d res %d out_len %u errno %d captured_errno %d\n",
     284             :                        i, (int) res, (unsigned int) out_len, last_errno, captured_errno);
     285       59408 :                 err = l * 2 > limit ? E2BIG : 0;
     286             : 
     287             :                 if (err) {
     288       57648 :                         assert(last_errno == err);
     289       57648 :                         assert(TDS_FAILED(res));
     290       57648 :                         assert(!tds || captured_errno == last_errno);
     291             :                 } else {
     292         880 :                         assert(TDS_SUCCEED(res));
     293         880 :                         assert(captured_errno == 0);
     294             :                 }
     295       58528 :                 if (out_len != i*2 && i*2 <= limit) {
     296           0 :                         fprintf(stderr, "out %u bytes expected %d\n",
     297             :                                 (unsigned int) out_len, i*2);
     298           0 :                         exit(1);
     299             :                 }
     300             :         }
     301          16 : }
     302             : 
     303             : 
     304             : int
     305           8 : main(int argc, char **argv)
     306             : {
     307             :         int i;
     308           8 :         TDSCONTEXT *ctx = tds_alloc_context(NULL);
     309           8 :         TDSSOCKET *tds = tds_alloc_socket(ctx, 512);
     310             :         const char *tdsdump;
     311             : 
     312           8 :         setbuf(stdout, NULL);
     313           8 :         setbuf(stderr, NULL);
     314             : 
     315           8 :         ctx->err_handler = err_handler;
     316             : 
     317             :         /* allow dumps, we don't have a connection here */
     318           8 :         tdsdump = getenv("TDSDUMP");
     319           8 :         if (tdsdump)
     320           0 :                 tdsdump_open(tdsdump);
     321             : 
     322           8 :         if (!ctx || !tds) {
     323           0 :                 fprintf(stderr, "Error creating socket!\n");
     324           0 :                 return 1;
     325             :         }
     326             : 
     327           8 :         tds_iconv_open(tds->conn, "ISO-8859-1", 0);
     328             : 
     329           8 :         conv = tds_iconv_get(tds->conn, "UTF-8", "ISO-8859-1");
     330           8 :         if (conv == NULL) {
     331           0 :                 fprintf(stderr, "Error creating conversion, giving up!\n");
     332           0 :                 return 1;
     333             :         }
     334             : 
     335         192 :         for (i = 0; i < ODD_NUM_VALUES*3*2; ++i) {
     336         192 :                 int n = i;
     337         192 :                 enum Odd odd_type = (enum Odd) (n % ODD_NUM_VALUES);
     338         192 :                 n /= ODD_NUM_VALUES;
     339         192 :                 pos_type = n % 3; n /= 3;
     340             : 
     341         192 :                 test(n ? tds : NULL, odd_type);
     342             :         }
     343             : 
     344             :         /* not try E2BIG error */
     345           8 :         big_test(NULL);
     346           8 :         big_test(tds);
     347             : 
     348           8 :         tds_free_socket(tds);
     349           8 :         tds_free_context(ctx);
     350           8 :         return 0;
     351             : }

Generated by: LCOV version 1.13