~ubuntu-branches/ubuntu/trusty/mysql-5.6/trusty

« back to all changes in this revision

Viewing changes to unittest/gunit/field_newdecimal-t.cc

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-02-12 11:54:27 UTC
  • Revision ID: package-import@ubuntu.com-20140212115427-oq6tfsqxl1wuwehi
Tags: upstream-5.6.15
ImportĀ upstreamĀ versionĀ 5.6.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
 
15
 
 
16
// First include (the generated) my_config.h, to get correct platform defines.
 
17
#include "my_config.h"
 
18
#include <gtest/gtest.h>
 
19
 
 
20
#include "test_utils.h"
 
21
#include "fake_table.h"
 
22
 
 
23
#include "field.h"
 
24
 
 
25
type_conversion_status
 
26
store_internal_with_error_check(Field_new_decimal *field,
 
27
                                int conversion_err, my_decimal *value);
 
28
namespace field_newdecimal_unittest {
 
29
 
 
30
using my_testing::chars_2_decimal;
 
31
using my_testing::Server_initializer;
 
32
using my_testing::Mock_error_handler;
 
33
 
 
34
class FieldNewDecimalTest : public ::testing::Test
 
35
{
 
36
protected:
 
37
  virtual void SetUp() { initializer.SetUp(); }
 
38
  virtual void TearDown() { initializer.TearDown(); }
 
39
 
 
40
  THD *thd() { return initializer.thd(); }
 
41
 
 
42
  Server_initializer initializer;
 
43
 
 
44
  Field_set *create_field_set(TYPELIB *tl);
 
45
};
 
46
 
 
47
 
 
48
class Mock_field_new_decimal : public Field_new_decimal
 
49
{
 
50
  uchar buffer[MAX_FIELD_WIDTH];
 
51
  uchar null_byte;
 
52
  void initialize()
 
53
  {
 
54
    ptr= buffer;
 
55
    null_ptr= &null_byte;
 
56
    memset(buffer, 0, MAX_FIELD_WIDTH);
 
57
    null_byte= '\0';
 
58
  }
 
59
 
 
60
public:
 
61
  Mock_field_new_decimal(int decimals)
 
62
    : Field_new_decimal(0,                      // ptr_arg
 
63
                        8,                      // len_arg
 
64
                        NULL,                   // null_ptr_arg
 
65
                        1,                      // null_bit_arg
 
66
                        Field::NONE,            // unireg_check_arg
 
67
                        "field_name",           // field_name_arg
 
68
                        decimals,               // dec_arg
 
69
                        false,                  // zero_arg
 
70
                        false)                  // unsigned_arg
 
71
  {
 
72
    initialize();
 
73
  }
 
74
 
 
75
  void make_writable() { bitmap_set_bit(table->write_set, field_index); }
 
76
 
 
77
  void test_store_string(const char *store_value, const int length,
 
78
                         const char *expected_string_result,
 
79
                         const longlong expected_int_result,
 
80
                         const double expected_real_result,
 
81
                         const int expected_error_no,
 
82
                         const type_conversion_status expected_status)
 
83
  {
 
84
    char buff[MAX_FIELD_WIDTH];
 
85
    String str(buff, sizeof(buff), &my_charset_bin);
 
86
    String unused;
 
87
 
 
88
    Mock_error_handler error_handler(table->in_use, expected_error_no);
 
89
    type_conversion_status err= store(store_value, length, &my_charset_latin1);
 
90
    val_str(&str, &unused);
 
91
    EXPECT_STREQ(expected_string_result, str.ptr());
 
92
    EXPECT_EQ(expected_int_result, val_int());
 
93
    EXPECT_EQ(expected_real_result, val_real());
 
94
 
 
95
    EXPECT_FALSE(is_null());
 
96
    EXPECT_EQ(expected_status, err);
 
97
    EXPECT_EQ((expected_error_no == 0 ? 0 : 1), error_handler.handle_called());
 
98
  }
 
99
 
 
100
};
 
101
 
 
102
 
 
103
TEST_F(FieldNewDecimalTest, StoreLegalStringValues)
 
104
{
 
105
  // Alows storing this range [-999.999, 999.999]
 
106
  Mock_field_new_decimal field_dec(3);
 
107
  Fake_TABLE table(&field_dec);
 
108
  table.in_use= thd();
 
109
  field_dec.make_writable();
 
110
  thd()->count_cuted_fields= CHECK_FIELD_WARN;
 
111
 
 
112
  {
 
113
    SCOPED_TRACE("");
 
114
    field_dec.test_store_string(STRING_WITH_LEN("10.01"), "10.010", 10, 10.01,
 
115
                                0, TYPE_OK);
 
116
  }
 
117
  {
 
118
    SCOPED_TRACE("");
 
119
    field_dec.test_store_string(STRING_WITH_LEN("0"), "0.000", 0, 0,
 
120
                                0, TYPE_OK);
 
121
  }
 
122
}
 
123
 
 
124
 
 
125
TEST_F(FieldNewDecimalTest, StoreIllegalStringValues)
 
126
{
 
127
  // Alows storing this range [-999.999, 999.999]
 
128
  Mock_field_new_decimal field_dec(3);
 
129
  Fake_TABLE table(&field_dec);
 
130
  table.in_use= thd();
 
131
  field_dec.make_writable();
 
132
  thd()->count_cuted_fields= CHECK_FIELD_WARN;
 
133
 
 
134
  // Truncated (precision beyond 3 decimals is lost)
 
135
  {
 
136
    SCOPED_TRACE("");
 
137
    field_dec.test_store_string(STRING_WITH_LEN("10.0101"), "10.010",
 
138
                                10, 10.01,
 
139
                                WARN_DATA_TRUNCATED, TYPE_NOTE_TRUNCATED);
 
140
  }
 
141
  {
 
142
    SCOPED_TRACE("");
 
143
    field_dec.test_store_string(STRING_WITH_LEN("10.0109"), "10.011",
 
144
                                10, 10.011,
 
145
                                WARN_DATA_TRUNCATED, TYPE_NOTE_TRUNCATED);
 
146
  }
 
147
  // Values higher and lower than valid range for the decimal
 
148
  {
 
149
    SCOPED_TRACE("");
 
150
    field_dec.test_store_string(STRING_WITH_LEN("10000"), "999.999",
 
151
                                1000, 999.999,
 
152
                                ER_WARN_DATA_OUT_OF_RANGE,
 
153
                                TYPE_WARN_OUT_OF_RANGE);
 
154
  }
 
155
 
 
156
  // Values higher and lower than valid range for the decimal
 
157
  {
 
158
    SCOPED_TRACE("");
 
159
    field_dec.test_store_string(STRING_WITH_LEN("-10000"), "-999.999",
 
160
                                -1000, -999.999,
 
161
                                ER_WARN_DATA_OUT_OF_RANGE,
 
162
                                TYPE_WARN_OUT_OF_RANGE);
 
163
  }
 
164
}
 
165
 
 
166
 
 
167
static void test_store_internal(Field_new_decimal *field,
 
168
                                my_decimal *value,
 
169
                                const char *expected_string_result,
 
170
                                const longlong expected_int_result,
 
171
                                const double expected_real_result,
 
172
                                const int conversion_error,
 
173
                                const int expected_error_no,
 
174
                                const type_conversion_status expected_status)
 
175
{
 
176
  char buff[MAX_FIELD_WIDTH];
 
177
  String str(buff, sizeof(buff), &my_charset_bin);
 
178
  String unused;
 
179
 
 
180
  Mock_error_handler error_handler(field->table->in_use, expected_error_no);
 
181
  type_conversion_status err=
 
182
    store_internal_with_error_check(field, conversion_error, value);
 
183
  field->val_str(&str, &unused);
 
184
  EXPECT_STREQ(expected_string_result, str.ptr());
 
185
  EXPECT_EQ(expected_int_result, field->val_int());
 
186
  EXPECT_EQ(expected_real_result, field->val_real());
 
187
 
 
188
  EXPECT_EQ(expected_status, err);
 
189
}
 
190
 
 
191
 
 
192
/**
 
193
  Test store_internal_with_error_check(). This is an internal store
 
194
  function for Field_new_decimal. The function does not modify the
 
195
  NULL value of the field so we don't test field.is_null()
 
196
*/
 
197
TEST_F(FieldNewDecimalTest, storeInternalWithErrorCheckLegalValues)
 
198
{
 
199
  // Alows storing this range [-99.9999, 99.9999]
 
200
  Mock_field_new_decimal field_dec(4);
 
201
  Fake_TABLE table(&field_dec);
 
202
  table.in_use= thd();
 
203
  field_dec.make_writable();
 
204
  thd()->count_cuted_fields= CHECK_FIELD_WARN;
 
205
 
 
206
  my_decimal d10_01;
 
207
  my_decimal dMin10_01;
 
208
  my_decimal d10_01001;
 
209
  my_decimal d10_01009;
 
210
  my_decimal dInsignificant;
 
211
 
 
212
  EXPECT_EQ(0, chars_2_decimal("10.01", &d10_01));
 
213
  EXPECT_EQ(0, chars_2_decimal("-10.01", &dMin10_01));
 
214
  EXPECT_EQ(0, chars_2_decimal("10.01001", &d10_01001));
 
215
  EXPECT_EQ(0, chars_2_decimal("10.01009", &d10_01009));
 
216
  EXPECT_EQ(0, chars_2_decimal("0.00000000001", &dInsignificant));
 
217
 
 
218
  // Legal values
 
219
  {
 
220
    SCOPED_TRACE("");
 
221
    test_store_internal(&field_dec, &d10_01, "10.0100", 10, 10.01,
 
222
                        E_DEC_OK, 0, TYPE_OK);
 
223
  }
 
224
  {
 
225
    SCOPED_TRACE("");
 
226
    test_store_internal(&field_dec, &dMin10_01, "-10.0100", -10, -10.01,
 
227
                        E_DEC_OK, 0, TYPE_OK);
 
228
  }
 
229
 
 
230
  // Legal values, but rounded
 
231
  {
 
232
    SCOPED_TRACE("");
 
233
    test_store_internal(&field_dec, &d10_01001, "10.0100", 10, 10.01,
 
234
                        E_DEC_OK, WARN_DATA_TRUNCATED, TYPE_NOTE_TRUNCATED);
 
235
  }
 
236
  {
 
237
    SCOPED_TRACE("");
 
238
    test_store_internal(&field_dec, &d10_01009, "10.0101", 10, 10.0101,
 
239
                        E_DEC_OK, WARN_DATA_TRUNCATED, TYPE_NOTE_TRUNCATED);
 
240
  }
 
241
  {
 
242
    SCOPED_TRACE("");
 
243
    test_store_internal(&field_dec, &dInsignificant, "0.0000", 0, 0, E_DEC_OK,
 
244
                        WARN_DATA_TRUNCATED, TYPE_NOTE_TRUNCATED);
 
245
  }
 
246
}
 
247
 
 
248
 
 
249
/**
 
250
  Test store_internal_with_error_check() - out of range valuse
 
251
*/
 
252
TEST_F(FieldNewDecimalTest, storeInternalWithErrorCheckOutOfRange)
 
253
{
 
254
  // Alows storing this range [-99.9999, 99.9999]
 
255
  Mock_field_new_decimal field_dec(4);
 
256
  Fake_TABLE table(&field_dec);
 
257
  table.in_use= thd();
 
258
  field_dec.make_writable();
 
259
  thd()->count_cuted_fields= CHECK_FIELD_WARN;
 
260
 
 
261
  my_decimal dTooHigh;
 
262
  my_decimal dTooLow;
 
263
 
 
264
  EXPECT_EQ(0, chars_2_decimal("1000", &dTooHigh));
 
265
  EXPECT_EQ(0, chars_2_decimal("-1000", &dTooLow));
 
266
 
 
267
  {
 
268
    SCOPED_TRACE("");
 
269
    test_store_internal(&field_dec, &dTooHigh, "99.9999", 100, 99.9999,
 
270
                        E_DEC_OK, ER_WARN_DATA_OUT_OF_RANGE,
 
271
                        TYPE_WARN_OUT_OF_RANGE);
 
272
  }
 
273
  {
 
274
    SCOPED_TRACE("");
 
275
    test_store_internal(&field_dec, &dTooLow, "-99.9999", -100, -99.9999,
 
276
                        E_DEC_OK, ER_WARN_DATA_OUT_OF_RANGE,
 
277
                        TYPE_WARN_OUT_OF_RANGE);
 
278
  }
 
279
 
 
280
}
 
281
 
 
282
 
 
283
/**
 
284
  Test store_internal_with_error_check() - Test first parameter: the error.
 
285
 
 
286
  When E_DEC_OVERFLOW is specified, the min/max value (depends on
 
287
  the sign of the input value) of the field is used to overwrite the
 
288
  input decimal value because E_DEC_OVERFLOW indicates that the decimal
 
289
  conversion got a number that was too high/low.
 
290
*/
 
291
TEST_F(FieldNewDecimalTest, storeInternalWithErrorCheckEDecOverflow)
 
292
{
 
293
  // Alows storing this range [-99.9999, 99.9999]
 
294
  Mock_field_new_decimal field_dec(4);
 
295
  Fake_TABLE table(&field_dec);
 
296
  table.in_use= thd();
 
297
  field_dec.make_writable();
 
298
  thd()->count_cuted_fields= CHECK_FIELD_WARN;
 
299
 
 
300
  my_decimal d10_01;
 
301
  my_decimal dMin10_01;
 
302
  my_decimal dInsignificant;
 
303
  my_decimal dTooHigh;
 
304
  my_decimal dTooLow;
 
305
 
 
306
  EXPECT_EQ(0, chars_2_decimal("10.01", &d10_01));
 
307
  EXPECT_EQ(0, chars_2_decimal("-10.01", &dMin10_01));
 
308
  EXPECT_EQ(0, chars_2_decimal("0.00000000001", &dInsignificant));
 
309
  EXPECT_EQ(0, chars_2_decimal("1000", &dTooHigh));
 
310
  EXPECT_EQ(0, chars_2_decimal("-1000", &dTooLow));
 
311
 
 
312
  // Positive number - the field's MAX value is used
 
313
  {
 
314
    SCOPED_TRACE("");
 
315
    test_store_internal(&field_dec, &d10_01, "99.9999", 100, 99.9999,
 
316
                        E_DEC_OVERFLOW, ER_WARN_DATA_OUT_OF_RANGE,
 
317
                        TYPE_WARN_OUT_OF_RANGE);
 
318
  }
 
319
  {
 
320
    SCOPED_TRACE("");
 
321
    test_store_internal(&field_dec, &dInsignificant, "99.9999", 100, 99.9999,
 
322
                        E_DEC_OVERFLOW, ER_WARN_DATA_OUT_OF_RANGE,
 
323
                        TYPE_WARN_OUT_OF_RANGE);
 
324
 
 
325
  }
 
326
  {
 
327
    SCOPED_TRACE("");
 
328
    test_store_internal(&field_dec, &dTooHigh, "99.9999", 100, 99.9999,
 
329
                        E_DEC_OVERFLOW, ER_WARN_DATA_OUT_OF_RANGE,
 
330
                        TYPE_WARN_OUT_OF_RANGE);
 
331
  }
 
332
 
 
333
  // Negative number - the field's MIN value is used
 
334
  {
 
335
    SCOPED_TRACE("");
 
336
    test_store_internal(&field_dec, &dMin10_01, "-99.9999", -100, -99.9999,
 
337
                        E_DEC_OVERFLOW, ER_WARN_DATA_OUT_OF_RANGE,
 
338
                        TYPE_WARN_OUT_OF_RANGE);
 
339
 
 
340
  }
 
341
  {
 
342
    SCOPED_TRACE("");
 
343
    test_store_internal(&field_dec, &dTooLow, "-99.9999", -100, -99.9999,
 
344
                        E_DEC_OVERFLOW, ER_WARN_DATA_OUT_OF_RANGE,
 
345
                        TYPE_WARN_OUT_OF_RANGE);
 
346
  }
 
347
}
 
348
 
 
349
 
 
350
/**
 
351
  Test store_internal_with_error_check() - Test first parameter: the error.
 
352
 
 
353
  When E_DEC_TRUNCATED is specified, a truncation warning will
 
354
  appear iff Field_new_decimal::store_value() would otherwise not
 
355
  issue a warning. The rationale is that E_DEC_TRUNCATED indicates
 
356
  that the value to store has already been truncated, something that
 
357
  will not be noticed by store_value(). However, the value is not
 
358
  automatically changed like in the E_DEC_OVERFLOW case tested
 
359
  above.
 
360
*/
 
361
TEST_F(FieldNewDecimalTest, storeInternalWithErrorCheckEDecTrunkated)
 
362
{
 
363
  // Alows storing this range [-99.9999, 99.9999]
 
364
  Mock_field_new_decimal field_dec(4);
 
365
  Fake_TABLE table(&field_dec);
 
366
  table.in_use= thd();
 
367
  field_dec.make_writable();
 
368
  thd()->count_cuted_fields= CHECK_FIELD_WARN;
 
369
 
 
370
  my_decimal d10_01;
 
371
  my_decimal dMin10_01;
 
372
  my_decimal dInsignificant;
 
373
  my_decimal dTooHigh;
 
374
  my_decimal dTooLow;
 
375
 
 
376
  EXPECT_EQ(0, chars_2_decimal("10.01", &d10_01));
 
377
  EXPECT_EQ(0, chars_2_decimal("-10.01", &dMin10_01));
 
378
  EXPECT_EQ(0, chars_2_decimal("0.00000000001", &dInsignificant));
 
379
  EXPECT_EQ(0, chars_2_decimal("1000", &dTooHigh));
 
380
  EXPECT_EQ(0, chars_2_decimal("-1000", &dTooLow));
 
381
 
 
382
 
 
383
  // Conversion went fine
 
384
  {
 
385
    SCOPED_TRACE("");
 
386
    test_store_internal(&field_dec, &d10_01, "10.0100", 10, 10.01,
 
387
                        E_DEC_TRUNCATED, WARN_DATA_TRUNCATED,
 
388
                        TYPE_NOTE_TRUNCATED);
 
389
  }
 
390
  {
 
391
    SCOPED_TRACE("");
 
392
    test_store_internal(&field_dec, &dMin10_01, "-10.0100", -10, -10.01,
 
393
                        E_DEC_TRUNCATED, WARN_DATA_TRUNCATED,
 
394
                        TYPE_NOTE_TRUNCATED);
 
395
  }
 
396
 
 
397
  {
 
398
    SCOPED_TRACE("");
 
399
    test_store_internal(&field_dec, &dInsignificant, "0.0000", 0, 0,
 
400
                        E_DEC_TRUNCATED, WARN_DATA_TRUNCATED,
 
401
                        TYPE_NOTE_TRUNCATED);
 
402
  }
 
403
 
 
404
  /*
 
405
    In what follows, the values are out of range causing warning
 
406
    ER_WARN_DATA_OUT_OF_RANGE instead of WARN_DATA_TRUNCATED.
 
407
  */
 
408
  {
 
409
    SCOPED_TRACE("");
 
410
    test_store_internal(&field_dec, &dTooHigh, "99.9999", 100, 99.9999,
 
411
                        E_DEC_TRUNCATED, ER_WARN_DATA_OUT_OF_RANGE,
 
412
                        TYPE_WARN_OUT_OF_RANGE);
 
413
  }
 
414
  {
 
415
    SCOPED_TRACE("");
 
416
    test_store_internal(&field_dec, &dTooLow, "-99.9999", -100, -99.9999,
 
417
                        E_DEC_TRUNCATED, ER_WARN_DATA_OUT_OF_RANGE,
 
418
                        TYPE_WARN_OUT_OF_RANGE);
 
419
  }
 
420
}
 
421
 
 
422
 
 
423
/**
 
424
  Test store_internal_with_error_check() - Test first parameter: the error.
 
425
 
 
426
  Any E_DEC_* value other than E_DEC_OK, E_DEC_TRUNCATED and
 
427
  E_DEC_OVERFLOW will be ignored.
 
428
*/
 
429
TEST_F(FieldNewDecimalTest, storeInternalWithErrorCheckRestOfParams)
 
430
{
 
431
  // Alows storing this range [-99.9999, 99.9999]
 
432
  Mock_field_new_decimal field_dec(4);
 
433
  Fake_TABLE table(&field_dec);
 
434
  table.in_use= thd();
 
435
  field_dec.make_writable();
 
436
  thd()->count_cuted_fields= CHECK_FIELD_WARN;
 
437
 
 
438
  my_decimal d10_01;
 
439
  EXPECT_EQ(0, chars_2_decimal("10.01", &d10_01));
 
440
 
 
441
  test_store_internal(&field_dec, &d10_01, "10.0100", 10, 10.01,
 
442
                      E_DEC_DIV_ZERO, 0, TYPE_OK);
 
443
 
 
444
  test_store_internal(&field_dec, &d10_01, "10.0100", 10, 10.01,
 
445
                      E_DEC_BAD_NUM, 0, TYPE_OK);
 
446
 
 
447
  test_store_internal(&field_dec, &d10_01, "10.0100", 10, 10.01,
 
448
                      E_DEC_OOM, 0, TYPE_OK);
 
449
}
 
450
 
 
451
}