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-02-21 09:36:06 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       87900 : 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       87900 :         char *in = tds_new(char, from_len ? from_len : 1);
      62       87900 :         char *out = tds_new(char, *dest_len);
      63             :         int res;
      64             :         TDSSTATICINSTREAM r;
      65             :         TDSSTATICOUTSTREAM w;
      66             : 
      67       87900 :         assert(in && out);
      68             : 
      69       87900 :         memcpy(in, from, from_len);
      70       87900 :         tds_staticin_stream_init(&r, in, from_len);
      71       87900 :         tds_staticout_stream_init(&w, out, *dest_len);
      72       87900 :         last_errno = 0;
      73       87900 :         res = tds_convert_stream(tds, conv, direction, &r.stream, &w.stream);
      74       87900 :         last_errno = errno;
      75       87900 :         memcpy(dest, out, *dest_len - w.stream.buf_len);
      76       87900 :         *dest_len = *dest_len - w.stream.buf_len;
      77             : 
      78       87900 :         free(in);
      79       87900 :         free(out);
      80       87900 :         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       14800 : add_odd(char *buf, int *pos, enum Odd type)
      97             : {
      98       14800 :         const unsigned char x = 0xa0;
      99             : 
     100       14800 :         switch (type) {
     101             :         case ODD_NONE:
     102             :                 return 0;
     103             : 
     104        4440 :         case ODD_NORMAL:
     105        4440 :                 buf[*pos] = 0xC0 + (x >> 6);
     106        4440 :                 ++*pos;
     107        4440 :                 buf[*pos] = 0x80 + (x & 0x3f);
     108        4440 :                 ++*pos;
     109        4440 :                 return 0;
     110             : 
     111        4440 :         case ODD_INVALID:
     112        4440 :                 buf[*pos] = 0xff;
     113        4440 :                 ++*pos;
     114        4440 :                 return EILSEQ;
     115             : 
     116        1480 :         case ODD_INCOMPLETE:
     117        1480 :                 buf[*pos] = 0xC2;
     118        1480 :                 ++*pos;
     119        1480 :                 return EINVAL;
     120             : 
     121             :         default:
     122           0 :                 assert(0);
     123             :         }
     124             :         return 0;
     125             : }
     126             : 
     127             : static void
     128       14740 : add_odd2(char *buf, int *pos, enum Odd type)
     129             : {
     130       14740 :         const unsigned char x = 0xa0;
     131             : 
     132       14740 :         switch (type) {
     133             :         case ODD_NONE:
     134             :                 return;
     135        4400 :         case ODD_NORMAL:
     136        4400 :                 buf[*pos] = x;
     137        4400 :                 ++*pos;
     138        4400 :                 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       38980 : err_handler(const TDSCONTEXT * tds_ctx TDS_UNUSED, TDSSOCKET * tds TDS_UNUSED, TDSMESSAGE * msg)
     152             : {
     153       38980 :         int old_err = captured_errno;
     154       38980 :         if (msg->msgno == TDSEICONVAVAIL) {
     155         740 :                 captured_errno = EINVAL;
     156       38240 :         } else if (strstr(msg->message, "could not be converted")) {
     157        2210 :                 captured_errno = EILSEQ;
     158       36030 :         } else if (msg->msgno == TDSEICONVIU) {
     159       36030 :                 captured_errno = E2BIG;
     160             :         } else {
     161           0 :                 fprintf(stderr, "Unexpected error: %s\n", msg->message);
     162           0 :                 exit(1);
     163             :         }
     164       38980 :         assert(old_err == 0 || old_err == captured_errno);
     165       38980 :         return TDS_INT_CANCEL;
     166             : }
     167             : 
     168             : static TDSICONV * conv = NULL;
     169             : static int pos_type = 0;
     170             : 
     171             : static void
     172         240 : test(TDSSOCKET *tds, enum Odd odd_type)
     173             : {
     174             :         int i, l;
     175             : 
     176         240 :         captured_errno = 0;
     177             : 
     178             :         /* do not complete incomplete */
     179         240 :         if (odd_type == ODD_INCOMPLETE && pos_type > 0)
     180          40 :                 return;
     181             : 
     182         200 :         printf("test pos %d type %s\n", pos_type, odd_names[odd_type]);
     183             : 
     184       15000 :         for (i = 0; i < 4096+20; ++i) {
     185             :                 size_t out_len;
     186             :                 TDSRET res;
     187             :                 int err;
     188             : 
     189       14800 :                 if (i == 34)
     190         200 :                         i = 4096-20;
     191             : 
     192       14800 :                 l = i;
     193       14800 :                 memset(buf, 'a', sizeof(buf));
     194       14800 :                 switch (pos_type) {
     195        5920 :                 case 0: /* end */
     196        5920 :                         err = add_odd(buf, &l, odd_type);
     197        5920 :                         break;
     198        4440 :                 case 1: /* start */
     199        4440 :                         l = 0;
     200        4440 :                         err = add_odd(buf, &l, odd_type);
     201        4440 :                         if (l > i) continue;
     202        4380 :                         l = i;
     203        4380 :                         break;
     204        4440 :                 case 2: /* middle */
     205        4440 :                         err = add_odd(buf, &l, odd_type);
     206        4440 :                         l = 4096+30;
     207        4440 :                         break;
     208           0 :                 default:
     209           0 :                         exit(1);
     210             :                         return;
     211             :                 }
     212             : 
     213             :                 /* convert it */
     214       14740 :                 out_len = sizeof(buf_out);
     215       14740 :                 res = convert(tds, conv, to_server, buf, l, buf_out, &out_len);
     216       14740 :                 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       14740 :                 l = i;
     221       14740 :                 memset(buf, 'a', sizeof(buf));
     222       14740 :                 switch (pos_type) {
     223        5920 :                 case 0: /* end */
     224        5920 :                         add_odd2(buf, &l, odd_type);
     225        5920 :                         break;
     226        4380 :                 case 1: /* start */
     227        4380 :                         l = 0;
     228        4380 :                         add_odd2(buf, &l, odd_type);
     229        4380 :                         l = i;
     230        4380 :                         if (odd_type == ODD_NORMAL) l = i-1;
     231        4380 :                         if (odd_type == ODD_INVALID) l = 0;
     232             :                         break;
     233        4440 :                 case 2: /* middle */
     234        4440 :                         add_odd2(buf, &l, odd_type);
     235        4440 :                         l = 4096+30;
     236        4440 :                         if (odd_type == ODD_NORMAL) --l;
     237        4440 :                         if (odd_type == ODD_INVALID) l = i;
     238             :                         break;
     239             :                 }
     240             : 
     241             : 
     242       14740 :                 if (err) {
     243        5900 :                         assert(last_errno == err);
     244        5900 :                         assert(TDS_FAILED(res));
     245        5900 :                         assert(!tds || captured_errno == last_errno);
     246             :                 } else {
     247        8840 :                         assert(TDS_SUCCEED(res));
     248        8840 :                         assert(captured_errno == 0);
     249             :                 }
     250       14740 :                 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       14740 :                 assert(memcmp(buf_out, buf, l) == 0);
     256             :         }
     257             : }
     258             : 
     259             : static void
     260          20 : big_test(TDSSOCKET *tds)
     261             : {
     262             :         int i, l;
     263          20 :         const int limit = 1025;
     264             : 
     265          20 :         captured_errno = 0;
     266             : 
     267          20 :         printf("E2BIG test\n");
     268             : 
     269       73180 :         for (i = 0; i < 4096+20; ++i) {
     270             :                 size_t out_len;
     271             :                 TDSRET res;
     272             :                 int err;
     273             : 
     274       73160 :                 if (i == 32)
     275          20 :                         i = 490;
     276             : 
     277       73160 :                 l = i;
     278       73160 :                 memset(buf, 0xa0, sizeof(buf));
     279             : 
     280             :                 /* convert it */
     281       73160 :                 out_len = limit;
     282       73160 :                 res = convert(tds, conv, to_client, buf, l, buf_out, &out_len);
     283       73160 :                 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       74260 :                 err = l * 2 > limit ? E2BIG : 0;
     286             : 
     287             :                 if (err) {
     288       72060 :                         assert(last_errno == err);
     289       72060 :                         assert(TDS_FAILED(res));
     290       72060 :                         assert(!tds || captured_errno == last_errno);
     291             :                 } else {
     292        1100 :                         assert(TDS_SUCCEED(res));
     293        1100 :                         assert(captured_errno == 0);
     294             :                 }
     295       73160 :                 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          20 : }
     302             : 
     303             : 
     304             : int
     305          10 : main(void)
     306             : {
     307             :         int i;
     308          10 :         TDSCONTEXT *ctx = tds_alloc_context(NULL);
     309          10 :         TDSSOCKET *tds = tds_alloc_socket(ctx, 512);
     310             :         const tds_dir_char *tdsdump;
     311             : 
     312          10 :         setbuf(stdout, NULL);
     313          10 :         setbuf(stderr, NULL);
     314             : 
     315          10 :         ctx->err_handler = err_handler;
     316             : 
     317             :         /* allow dumps, we don't have a connection here */
     318          10 :         tdsdump = tds_dir_getenv(TDS_DIR("TDSDUMP"));
     319          10 :         if (tdsdump)
     320           0 :                 tdsdump_open(tdsdump);
     321             : 
     322          10 :         if (!ctx || !tds) {
     323           0 :                 fprintf(stderr, "Error creating socket!\n");
     324           0 :                 return 1;
     325             :         }
     326             : 
     327          10 :         tds_iconv_open(tds->conn, "ISO-8859-1", 0);
     328             : 
     329          10 :         conv = tds_iconv_get(tds->conn, "UTF-8", "ISO-8859-1");
     330          10 :         if (conv == NULL) {
     331           0 :                 fprintf(stderr, "Error creating conversion, giving up!\n");
     332           0 :                 return 1;
     333             :         }
     334             : 
     335         240 :         for (i = 0; i < ODD_NUM_VALUES*3*2; ++i) {
     336         240 :                 int n = i;
     337         240 :                 enum Odd odd_type = (enum Odd) (n % ODD_NUM_VALUES);
     338         240 :                 n /= ODD_NUM_VALUES;
     339         240 :                 pos_type = n % 3; n /= 3;
     340             : 
     341         240 :                 test(n ? tds : NULL, odd_type);
     342             :         }
     343             : 
     344             :         /* not try E2BIG error */
     345          10 :         big_test(NULL);
     346          10 :         big_test(tds);
     347             : 
     348          10 :         tds_free_socket(tds);
     349          10 :         tds_free_context(ctx);
     350          10 :         return 0;
     351             : }

Generated by: LCOV version 1.13