MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mysql_utils_test.cpp
1 /*
2  Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 /*
18  * mysql_utils_test.cpp
19  */
20 
21 #include <string.h> // not using namespaces yet
22 #include <stdio.h> // not using namespaces yet
23 #include <stdlib.h> // not using namespaces yet
24 #include <assert.h> // not using namespaces yet
25 
26 #include "decimal_utils.hpp"
27 #include "CharsetMap.hpp"
28 
29 #include "my_global.h"
30 #include "my_sys.h"
31 #include "mysql.h"
32 
33 void test_decimal(const char *s, int prec, int scale, int expected_rv)
34 {
35  char bin_buff[128], str_buff[128];
36  int r1, r2 = 0;
37 
38  str_buff[0] = 0;
39 
40  r1 = decimal_str2bin(s, strlen(s), prec, scale, bin_buff, 128);
41  if(r1 <= E_DEC_OVERFLOW)
42  r2 = decimal_bin2str(bin_buff, 128, prec, scale, str_buff, 128);
43 
44  printf("[%-2d,%-2d] %-29s => res=%d,%d %s\n",
45  prec, scale, s, r1, r2, str_buff);
46 
47  if(r1 != expected_rv) {
48  printf("decimal_str2bin returned %d when %d was expected.\n",
49  r1, expected_rv);
50  exit(1);
51  }
52 }
53 
54 
55 int main()
56 {
57  printf("==== init MySQL lib ====\n");
58  my_init();
60 
61  printf("==== decimal_str2bin() / decimal_bin2str() ====\n");
62 
63  test_decimal("100", 3, -1, E_DEC_BAD_SCALE);
64  test_decimal("3.3", 2, 1, E_DEC_OK);
65  test_decimal("124.000", 20, 4, E_DEC_OK);
66  test_decimal("-11", 14, 1, E_DEC_OK);
67  test_decimal("1.123456000000000", 20, 16, E_DEC_OK);
68  test_decimal("-20.333", 4, 2, E_DEC_TRUNCATED);
69  test_decimal("0", 20, 10, E_DEC_OK);
70  test_decimal("1 ", 20, 10, E_DEC_OK);
71  test_decimal("1,35", 20, 10, E_DEC_OK);
72  test_decimal("text", 20, 10, E_DEC_BAD_NUM);
73 
74  /* CharsetMap */
75  printf("\n==== CharsetMap ==== \n");
76 
77  CharsetMap csmap;
78  int utf8_num = csmap.getUTF8CharsetNumber();
79  int utf16_num = csmap.getUTF16CharsetNumber();
80 
81  /* If this mysql build does not include UTF-8 and either UCS-2 or UTF-16
82  then the test suite must fail.
83  */
84  printf("UTF-8 charset num: %d UTF-16 or UCS-2 charset num: %d\n",
85  utf8_num, utf16_num);
86  if((utf8_num == 0) || (utf16_num == 0)) exit(1);
87 
88  /* test csmap.getName()
89  */
90  const char *utf8 = csmap.getName(utf8_num);
91  if(strcmp(utf8,"UTF-8")) exit(1);
92 
93  /* MySQL 5.1 and earlier will have UCS-2 but later versions may have true
94  UTF-16. For information, print whether UTF-16 or UCS-2 is being used.
95  */
96  const char *utf16 = csmap.getMysqlName(csmap.getUTF16CharsetNumber());
97  printf("Using mysql's %s for UTF-16.\n", utf16);
98 
99 
100  /* Now we're going to recode.
101  We test with the string "ülker", which begins with the character
102  LATIN SMALL LETTER U WITH DIARESIS - unicode code point U+00FC.
103  In the latin1 encoding this is a literal 0xFC,
104  but in the UTF-8 representation it is 0xC3 0xBC.
105  */
106 
107  const char my_word_latin1[6] = { 0xFC, 'l', 'k', 'e', 'r', 0};
108  const char my_word_utf8[7] = { 0xC3, 0xBC, 'l', 'k', 'e', 'r', 0};
109  const char my_word_truncated[5] = { 0xC3, 0xBC, 'l', 'k', 0};
110  const unsigned char my_bad_utf8[5] = { 'l' , 0xBC, 'a', 'd', 0};
111  char result_buff_1[32];
112  char result_buff_2[32];
113  char result_buff_too_small[4];
114  int lengths[2];
115 
116  /* latin1 must be available to run the recode test */
117  int latin1_num = csmap.getCharsetNumber("latin1");
118  printf("latin1 charset number: %d standard name: \"%s\" \n",
119  latin1_num, csmap.getName(latin1_num));
120  assert(latin1_num != 0);
121  assert(! strcmp(csmap.getName(latin1_num) , "windows-1252"));
122 
123  printf("Latin1: \"%s\" UTF8: \"%s\" \n",
124  my_word_latin1, my_word_utf8);
125 
126  /* RECODE TEST 1: recode from UTF-8 to Latin 1 */
127  lengths[0] = 7;
128  lengths[1] = 32;
129  CharsetMap::RecodeStatus rr1 = csmap.recode(lengths, utf8_num, latin1_num,
130  my_word_utf8, result_buff_1);
131  printf("Recode Test 1 - UTF-8 to Latin-1: %d %ld %ld \"%s\" => \"%s\" \n",
132  rr1, lengths[0], lengths[1], my_word_utf8, result_buff_1);
133  assert(rr1 == CharsetMap::RECODE_OK);
134  assert(lengths[0] == 7);
135  assert(lengths[1] == 6);
136  assert(!strcmp(result_buff_1, my_word_latin1));
137 
138  /* RECODE TEST 2: recode from Latin1 to to UTF-8 */
139  lengths[0] = 6;
140  lengths[1] = 32;
141  CharsetMap::RecodeStatus rr2 = csmap.recode(lengths, latin1_num, utf8_num,
142  my_word_latin1, result_buff_2);
143  printf("Recode Test 2 - Latin-1 to UTF-8: %d %ld %ld \"%s\" => \"%s\" \n",
144  rr2, lengths[0], lengths[1], my_word_latin1, result_buff_2);
145  assert(rr2 == CharsetMap::RECODE_OK);
146  assert(lengths[0] == 6);
147  assert(lengths[1] == 7);
148  assert(!(strcmp(result_buff_2, my_word_utf8)));
149 
150  /* RECODE TEST 3: recode with a too-small result buffer */
151  lengths[0] = 6;
152  lengths[1] = 4;
153  CharsetMap::RecodeStatus rr3 = csmap.recode(lengths, latin1_num, utf8_num,
154  my_word_latin1, result_buff_too_small);
155  printf("Recode Test 3 - too-small buffer: %d %ld %ld \"%s\" => \"%s\" \n",
156  rr3, lengths[0], lengths[1], my_word_latin1, result_buff_too_small);
157  assert(rr3 == CharsetMap::RECODE_BUFF_TOO_SMALL);
158  assert(lengths[0] == 3);
159  assert(lengths[1] == 4);
160  /* Confirm that the first four characters were indeed recoded: */
161  assert(!(strncmp(result_buff_too_small, my_word_truncated, 4)));
162 
163  /* RECODE TEST 4: recode with an invalid character set */
164  CharsetMap::RecodeStatus rr4 = csmap.recode(lengths, 0, 999, my_word_latin1, result_buff_2);
165  printf("Recode Test 4 - invalid charset: %d \n", rr4);
166  assert(rr4 == CharsetMap::RECODE_BAD_CHARSET);
167 
168  /* RECODE TEST 5: source string is ill-formed UTF-8 */
169  lengths[0] = 5;
170  lengths[1] = 32;
171  int rr5 = csmap.recode(lengths, utf8_num, latin1_num,
172  my_bad_utf8, result_buff_2);
173  printf("Recode Test 5 - ill-formed source string: %d \n", rr5);
174  assert(rr5 == CharsetMap::RECODE_BAD_SRC);
175 
176 
177  printf("isMultibyte TEST: ");
178  const bool * result1, * result2, * result3;
179  result1 = csmap.isMultibyte(latin1_num);
180  result2 = csmap.isMultibyte(utf16_num);
181  result3 = csmap.isMultibyte(utf8_num);
182  printf("latin 1: %s UTF16: %s UTF8: %s\n",
183  *result1 ? "Yes" : "No" ,
184  *result2 ? "Yes" : "No" ,
185  *result3 ? "Yes" : "No");
186  assert(! *result1);
187  assert(*result2);
188  assert(*result3);
189 
190  int nNull = 0, nSingle = 0, nMulti = 0;
191  for(int i = 0 ; i < 256 ; i++) {
192  const bool *r = csmap.isMultibyte(i);
193  if(r) {
194  if(*r) nMulti++;
195  else nSingle++;
196  }
197  else nNull++;
198  }
199  printf("Charset stats: %d unused, %d single-byte, %d multi-byte\n",
200  nNull, nSingle, nMulti);
201  // If there is not at least one of each, then something is probably wrong
202  assert(nNull && nSingle && nMulti);
203 
204 
205 
207 }