/* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ // First include (the generated) my_config.h, to get correct platform defines. #include "my_config.h" #include #include "test_utils.h" #include "fake_table.h" #include "field.h" #include "sql_time.h" #include namespace field_unittests { using my_testing::Server_initializer; using my_testing::Mock_error_handler; class FieldTest : public ::testing::Test { protected: virtual void SetUp() { initializer.SetUp(); } virtual void TearDown() { initializer.TearDown(); } THD *thd() { return initializer.thd(); } Server_initializer initializer; Field_set *create_field_set(TYPELIB *tl); }; static void compareMysqlTime(const MYSQL_TIME& first, const MYSQL_TIME& second) { EXPECT_EQ(first.year, second.year); EXPECT_EQ(first.month, second.month); EXPECT_EQ(first.day, second.day); EXPECT_EQ(first.hour, second.hour); EXPECT_EQ(first.minute, second.minute); EXPECT_EQ(first.second, second.second); EXPECT_EQ(first.second_part, second.second_part); EXPECT_EQ(first.neg, second.neg); EXPECT_EQ(first.time_type, second.time_type); } class Mock_table : public TABLE { public: Mock_table(THD *thd) { null_row= false; read_set= 0; in_use= thd; } }; // A mock Protocol class to be able to test Field::send_binary // It just verifies that store_time has been passed what is expected class Mock_protocol : public Protocol { private: MYSQL_TIME t; uint p; public: Mock_protocol(THD *thd) {} virtual bool store_time(MYSQL_TIME *time, uint precision) { t= *time; p= precision; return false; } void verify_time(MYSQL_TIME *time, uint precision) { compareMysqlTime(*time, t); EXPECT_EQ(precision, p); } // Lots of functions that require implementation int read_packet() { return 0; } ulong get_client_capabilities() { return 0; } bool has_client_capability(unsigned long client_capability) {return false;} void end_partial_result_set() {} int shutdown(bool server_shutdown= false) { return 0; } void *get_ssl() { return 0; } void start_row() {} bool end_row() { return false; } bool connection_alive() { return false; } void abort_row() {} uint get_rw_status() { return 0; } bool get_compression() { return false; } bool start_result_metadata(uint num_cols, uint flags, const CHARSET_INFO *resultcs) { return false; } void send_num_fields(uint) {} void send_num_rows(uint) {} bool send_field_metadata(Send_field *field, const CHARSET_INFO *charset) { return false; } virtual bool send_ok(uint server_status, uint statement_warn_count, ulonglong affected_rows, ulonglong last_insert_id, const char *message) { return false; } virtual bool send_eof(uint server_status, uint statement_warn_count) { return false; } virtual bool send_error(uint sql_errno, const char *err_msg, const char *sql_state) { return false; } bool end_result_metadata() { return false; } virtual bool store_null() { return false; } virtual bool store_tiny(longlong from) { return false; } virtual bool store_short(longlong from) { return false; } virtual bool store_long(longlong from) { return false; } virtual bool store_longlong(longlong from, bool unsigned_flag) { return false; } virtual bool store_decimal(const my_decimal *, uint, uint) { return false; } virtual bool store(const char *from, size_t length, const CHARSET_INFO *fromcs) { return false; } virtual bool store(float from, uint32 decimals, String *buffer) { return false; } virtual bool store(double from, uint32 decimals, String *buffer) { return false; } virtual bool store(MYSQL_TIME *time, uint precision) { return false; } virtual bool store_date(MYSQL_TIME *time) { return false; } virtual bool store(Proto_field *field) { return false; } virtual enum enum_protocol_type type() { return PROTOCOL_LOCAL; }; virtual enum enum_vio_type connection_type() { return NO_VIO_TYPE; } virtual int get_command(COM_DATA *com_data, enum_server_command *cmd) { return -1; } }; TEST_F(FieldTest, FieldTimef) { uchar fieldBuf[6]; uchar nullPtr[1]= {0}; MYSQL_TIME time= {0, 0, 0, 12, 23, 12, 123400, false, MYSQL_TIMESTAMP_TIME}; Field_timef* field= new Field_timef(fieldBuf, nullPtr, false, Field::NONE, "f1", 4); // Test public member functions EXPECT_EQ(4UL, field->decimals()); //TS-TODO EXPECT_EQ(MYSQL_TYPE_TIME, field->type()); EXPECT_EQ(MYSQL_TYPE_TIME2, field->binlog_type()); longlong packed= TIME_to_longlong_packed(&time); EXPECT_EQ(0, field->store_packed(packed)); EXPECT_DOUBLE_EQ(122312.1234, field->val_real()); EXPECT_EQ(122312, field->val_int()); EXPECT_EQ(packed, field->val_time_temporal()); my_decimal decval; my_decimal* dec= field->val_decimal(&decval); double res; my_decimal2double(0, dec, &res); EXPECT_DOUBLE_EQ(122312.1234, res); EXPECT_EQ(5UL, field->pack_length()); EXPECT_EQ(5UL, field->pack_length_from_metadata(4)); EXPECT_EQ(5UL, field->row_pack_length()); String str(7); field->sql_type(str); EXPECT_STREQ("time(4)", str.c_ptr_safe()); EXPECT_EQ(1, field->zero_pack()); EXPECT_EQ(&my_charset_bin, field->sort_charset()); // Test clone Field* copy= field->clone(); EXPECT_EQ(field->decimals(), copy->decimals()); EXPECT_EQ(field->type(), copy->type()); EXPECT_DOUBLE_EQ(field->val_real(), copy->val_real()); EXPECT_EQ(field->val_int(), copy->val_int()); EXPECT_EQ(field->val_time_temporal(), copy->val_time_temporal()); EXPECT_EQ(0, field->cmp(field->ptr, copy->ptr)); // Test reset EXPECT_EQ(0, field->reset()); EXPECT_DOUBLE_EQ(0.0, field->val_real()); EXPECT_EQ(0, field->val_int()); // Test inherited member functions // Functions inherited from Field_time_common field->store_time(&time, 4); EXPECT_EQ(4UL, field->decimals()); EXPECT_EQ(MYSQL_TYPE_TIME, field->type()); EXPECT_DOUBLE_EQ(122312.1234, field->val_real()); EXPECT_EQ(122312, field->val_int()); EXPECT_EQ(packed, field->val_time_temporal()); String timeStr(15); EXPECT_STREQ("12:23:12.1234", field->val_str(&timeStr, &timeStr)->c_ptr()); field->store_time(&time, 0); EXPECT_DOUBLE_EQ(122312.1234, field->val_real()); // Correct? MYSQL_TIME dateTime; MYSQL_TIME bigTime= {0, 0, 0, 123, 45, 45, 555500, false, MYSQL_TIMESTAMP_TIME}; EXPECT_EQ(0, field->store_time(&bigTime, 4)); EXPECT_FALSE(field->get_date(&dateTime, 0)); make_datetime((Date_time_format *)0, &dateTime, &timeStr, 6); // Skip 'yyyy-mm-dd ' since that will depend on current time zone. EXPECT_STREQ("03:45:45.555500", timeStr.c_ptr() + 11); MYSQL_TIME t; EXPECT_FALSE(field->get_time(&t)); compareMysqlTime(bigTime, t); Mock_protocol protocol(thd()); EXPECT_EQ(protocol.connection_type(), NO_VIO_TYPE); EXPECT_FALSE(field->send_binary(&protocol)); // The verification below fails because send_binary move hours to days // protocol.verify_time(&bigTime, 0); // Why 0? // Function inherited from Field_temporal EXPECT_TRUE(field->is_temporal()); EXPECT_EQ(STRING_RESULT, field->result_type()); EXPECT_EQ(15UL, field->max_display_length()); EXPECT_TRUE(field->str_needs_quotes()); // Not testing is_equal() yet, will require a mock TABLE object // Create_field cf(field, field); // EXPECT_TRUE(field->is_equal(&cf)); EXPECT_EQ(DECIMAL_RESULT, field->numeric_context_result_type()); EXPECT_EQ(INT_RESULT, field->cmp_type()); EXPECT_EQ(INT_RESULT, field->cmp_type()); EXPECT_EQ(DERIVATION_NUMERIC, field->derivation()); EXPECT_EQ(&my_charset_numeric, field->charset()); EXPECT_TRUE(field->can_be_compared_as_longlong()); EXPECT_TRUE(field->binary()); // Below is not tested, because of ASSERT // EXPECT_EQ(TIMESTAMP_NO_AUTO_SET, field->get_auto_set_type()); // Not testing make_field, it also needs a mock TABLE object EXPECT_EQ(TYPE_OK, field->store("12:23:12.123456", 15, &my_charset_numeric)); EXPECT_DOUBLE_EQ(122312.1235, field->val_real()); EXPECT_EQ(TYPE_OK, field->store_decimal(dec)); EXPECT_DOUBLE_EQ(122312.1234, field->val_real()); EXPECT_EQ(TYPE_OK, field->store(-234545, false)); EXPECT_DOUBLE_EQ(-234545.0, field->val_real()); { // Test that store() with a to big number gives right error Mock_error_handler error_handler(thd(), ER_TRUNCATED_WRONG_VALUE); EXPECT_EQ(TYPE_WARN_OUT_OF_RANGE, field->store(0x80000000, true)); // Test that error handler was actually called EXPECT_EQ(1, error_handler.handle_called()); // Test that field contains expecte max time value EXPECT_DOUBLE_EQ(8385959, field->val_real()); // Max time value } EXPECT_EQ(TYPE_OK, field->store(1234545.555555)); EXPECT_DOUBLE_EQ(1234545.5556, field->val_real()); // Some of the functions inherited from Field Field *f= field; EXPECT_EQ(TYPE_OK, f->store_time(&time, MYSQL_TIMESTAMP_TIME)); EXPECT_DOUBLE_EQ(122312.1234, f->val_real()); // Why decimals here? EXPECT_STREQ("12:23:12.1234", f->val_str(&timeStr)->c_ptr()); EXPECT_STREQ("122312", f->val_int_as_str(&timeStr, false)->c_ptr()); EXPECT_TRUE(f->eq(copy)); EXPECT_TRUE(f->eq_def(copy)); // Not testing store(const char, uint, const CHARSET_INFO *, enum_check_fields) // it requires a mock table Mock_table m_table(thd()); f->table= &m_table; struct timeval tv; int warnings= 0; EXPECT_FALSE(f->get_timestamp(&tv, &warnings)); EXPECT_EQ(123400, tv.tv_usec); delete field; } TEST_F(FieldTest, FieldTimefCompare) { const int nFields= 7; uchar fieldBufs[nFields][6]; uchar nullPtrs[nFields]; MYSQL_TIME times[nFields]= { {0, 0, 0, 12, 23, 12, 100000, true, MYSQL_TIMESTAMP_TIME}, {0, 0, 0, 0, 0, 0, 10000, true, MYSQL_TIMESTAMP_TIME}, {0, 0, 0, 0, 0, 0, 0, false, MYSQL_TIMESTAMP_TIME}, {0, 0, 0, 0, 0, 0, 999900, false, MYSQL_TIMESTAMP_TIME}, {0, 0, 0, 0, 0, 0, 999990, false, MYSQL_TIMESTAMP_TIME}, {0, 0, 0, 11, 59, 59, 999999, false, MYSQL_TIMESTAMP_TIME}, {0, 0, 0, 12, 00, 00, 100000, false, MYSQL_TIMESTAMP_TIME}}; Field* fields[nFields]; uchar sortStrings[nFields][6]; for (int i=0; i < nFields; ++i) { char fieldName[3]; sprintf(fieldName, "f%c", i); fields[i]= new Field_timef(fieldBufs[i], nullPtrs+i, false, Field::NONE, fieldName, 6); longlong packed= TIME_to_longlong_packed(×[i]); EXPECT_EQ(0, fields[i]->store_packed(packed)); fields[i]->make_sort_key(sortStrings[i], fields[i]->pack_length()); } for (int i=0; i < nFields; ++i) for (int j=0; j < nFields; ++j) { String tmp; if (i < j) { EXPECT_GT(0, memcmp(sortStrings[i], sortStrings[j], fields[i]->pack_length())) << fields[i]->val_str(&tmp)->c_ptr() << " < " << fields[j]->val_str(&tmp)->c_ptr(); EXPECT_GT(0, fields[i]->cmp(fields[i]->ptr, fields[j]->ptr)) << fields[i]->val_str(&tmp)->c_ptr() << " < " << fields[j]->val_str(&tmp)->c_ptr(); } else if (i > j) { EXPECT_LT(0, memcmp(sortStrings[i], sortStrings[j], fields[i]->pack_length())) << fields[i]->val_str(&tmp)->c_ptr() << " > " << fields[j]->val_str(&tmp)->c_ptr(); EXPECT_LT(0, fields[i]->cmp(fields[i]->ptr, fields[j]->ptr)) << fields[i]->val_str(&tmp)->c_ptr() << " > " << fields[j]->val_str(&tmp)->c_ptr(); } else { EXPECT_EQ(0, memcmp(sortStrings[i], sortStrings[j], fields[i]->pack_length())) << fields[i]->val_str(&tmp)->c_ptr() << " = " << fields[j]->val_str(&tmp)->c_ptr(); EXPECT_EQ(0, fields[i]->cmp(fields[i]->ptr, fields[j]->ptr)) << fields[i]->val_str(&tmp)->c_ptr() << " = " << fields[j]->val_str(&tmp)->c_ptr(); } } } TEST_F(FieldTest, FieldTime) { uchar fieldBuf[6]; uchar nullPtr[1]= {0}; MYSQL_TIME bigTime= {0, 0, 0, 123, 45, 45, 555500, false, MYSQL_TIMESTAMP_TIME}; Field_time* field= new Field_time(fieldBuf, nullPtr, false, Field::NONE, "f1"); EXPECT_EQ(0, field->store_time(&bigTime, 4)); MYSQL_TIME t; EXPECT_FALSE(field->get_time(&t)); compareMysqlTime(bigTime, t); } const char *type_names3[]= { "one", "two", "three", NULL }; unsigned int type_lengths3[]= { 3U, 3U, 5U, 0U }; TYPELIB tl3= { 3, "tl3", type_names3, type_lengths3 }; const char *type_names4[]= { "one", "two", "three", "four", NULL }; unsigned int type_lengths4[]= { 3U, 3U, 5U, 4U, 0U }; TYPELIB tl4= { 4, "tl4", type_names4, type_lengths4 }; Field_set *FieldTest::create_field_set(TYPELIB *tl) { Field_set *f= new (thd()->mem_root) Field_set(NULL, // ptr_arg 42, // len_arg NULL, // null_ptr_arg '\0', // null_bit_arg Field::NONE, // unireg_check_arg "f1", // field_name_arg 1, // packlength_arg tl, // typelib_arg &my_charset_latin1); // charset_arg f->table= new Fake_TABLE(f); return f; } // Bug#13871079 RQG_MYISAM_DML_ALTER_VALGRIND FAILS ON VALGRIND PN PB2 TEST_F(FieldTest, CopyFieldSet) { int err; char fields[]= "one,two"; my_ulonglong typeset= find_typeset(fields, &tl3, &err); EXPECT_EQ(0, err); // Using two different TYPELIBs will set cf->do_copy to do_field_string(). Field_set *f_to= create_field_set(&tl3); bitmap_set_all(f_to->table->write_set); uchar to_fieldval= 0; f_to->ptr= &to_fieldval; Field_set *f_from= create_field_set(&tl4); bitmap_set_all(f_from->table->write_set); bitmap_set_all(f_from->table->read_set); uchar from_fieldval= static_cast(typeset); f_from->ptr= &from_fieldval; Copy_field *cf= new (thd()->mem_root) Copy_field; cf->set(f_to, f_from, false); cf->invoke_do_copy(cf); // Copy_field DTOR is not invoked in all contexts, so we may leak memory. EXPECT_FALSE(cf->tmp.is_alloced()); delete f_to->table; delete f_from->table; } /* Tests that make_sort_key() is well behaved and does not cause buffer overruns nor writes a too short key. We stop at the first error seen. - field - The field whose make_sort_key() method we test. - from - A buffer of size field->pack_length() that we will trick the field into using as its record buffer. - expected - A buffer of size field->pack_length() + 1, the first n bytes of which make_sort_key() is expected to fill out. The n + 1:th byte is expected to be untouched. We try all possible values of n. - min_key_length - Some Field classes assert on a certain minimum key length. To avoid that, pass the minimum length here. */ void test_make_sort_key(Field *field, uchar *from, const uchar *expected, int min_key_length) { const uint pack_length= field->pack_length(); Fake_TABLE table(field); table.s->db_low_byte_first= false; field->ptr= from; for (uint key_length= min_key_length; key_length <= pack_length; ++key_length) { uchar buff[MAX_FIELD_WIDTH + 1]; memset(buff, 'a', pack_length + 1); field->make_sort_key(buff, key_length); // Check for a too short key. for (uint i= 0; i < key_length; ++i) ASSERT_FALSE(buff[i] == 'a') << "Too few bytes written at " << i << " with buffer size " << key_length << "."; // Check for wrong result for (uint i= 0; i < key_length; ++i) ASSERT_EQ(expected[i], buff[i]) << "Wrong output at " << i << " with buffer size " << key_length << " and pack length " << pack_length << "."; EXPECT_EQ('a', buff[key_length]) << "Buffer overrun" << " with buffer size " << key_length << "."; } // Try key_length == pack_length uchar buff[MAX_FIELD_WIDTH]; memset(buff, 'a', pack_length + 1); field->make_sort_key(buff, pack_length); EXPECT_EQ('a', buff[pack_length]) << "Buffer overrun"; } // Convenience function for large values. void test_make_sort_key(Field *field) { const int pack_length= field->pack_length(); uchar from[MAX_FIELD_WIDTH]; memset(from, 'b', pack_length); uchar to[MAX_FIELD_WIDTH + 1]; memset(to, 'b', pack_length + 1); test_make_sort_key(field, from, to, 1); } extern "C" { static size_t mock_strnxfrm(const CHARSET_INFO *, uchar *, size_t, uint, const uchar *, size_t, uint); } class Mock_collation : public MY_COLLATION_HANDLER { public: Mock_collation() { strnxfrm= mock_strnxfrm; } }; class Mock_charset : public CHARSET_INFO { Mock_collation mock_collation; public: mutable bool strnxfrm_called; Mock_charset() { strnxfrm_called= false; coll= &mock_collation; mbmaxlen= 1; } ~Mock_charset() { EXPECT_TRUE(strnxfrm_called); } }; size_t mock_strnxfrm(const CHARSET_INFO *charset, uchar *, size_t dstlen, uint, const uchar *, size_t, uint) { // CHARSET_INFO is not polymorphic, hence the abomination. static_cast(charset)->strnxfrm_called= true; return dstlen; }; void test_integer_field(Field *field) { uchar from[MAX_FIELD_WIDTH], expected[MAX_FIELD_WIDTH]; const int pack_length= field->pack_length(); for (int i= 0; i < pack_length; ++i) { from[i]= '0' + i; #ifdef WORDS_BIGENDIAN expected[i]= '0' + i; #else expected[pack_length - 1 - i]= '0' + i; #endif } test_make_sort_key(field, from, expected, pack_length); } // Tests all make_sort_key() implementations. // We keep the same order of classes here as in field.h in order to make it // easy to manually verify that all field types have been tested. TEST_F(FieldTest, MakeSortKey) { { SCOPED_TRACE("Field_decimal"); Field_decimal fd(NULL, 64, NULL, '\0', Field::NONE, "", 0, false, false); test_make_sort_key(&fd); } { SCOPED_TRACE("Field_new_decimal"); Field_new_decimal fnd(64, true, "", 0, false); test_make_sort_key(&fnd); } { SCOPED_TRACE("Field_tiny"); Field_tiny ft(NULL, 0, NULL, '\0', Field::NONE, "", false, true); test_make_sort_key(&ft); } { SCOPED_TRACE("Field_short"); Field_short fs(0,false, "", true); test_integer_field(&fs); } { SCOPED_TRACE("Field_long"); Field_long fl(0,false, "", true); test_integer_field(&fl); } { SCOPED_TRACE("Field_longlong"); Field_longlong fll(NULL, 64, NULL, '\0', Field::NONE, "", 0, true); test_integer_field(&fll); } { SCOPED_TRACE("Field_float"); Field_float ff(NULL, 0, NULL, '\0', Field::NONE, "", 0, false, false); float from= 0.0; uchar to []= { 128, 0, 0, 0 }; test_make_sort_key(&ff, reinterpret_cast(&from), to, 4); } { SCOPED_TRACE("Field_double"); Field_double fd(NULL, 0, NULL, '\0', Field::NONE, "", 0, false, false); double from= 0.0; uchar expected []= { 128, 0, 0, 0, 0, 0, 0, 0 }; test_make_sort_key(&fd, reinterpret_cast(&from), expected, 1); } { SCOPED_TRACE("Field_null"); CHARSET_INFO cs; cs.state= MY_CHARSET_UNDEFINED; // Avoid valgrind warning. Field_null fn(NULL, 0, Field::NONE, "", &cs); test_make_sort_key(&fn); } { SCOPED_TRACE("Field_timestamp"); Field_timestamp fts(false, ""); test_integer_field(&fts); } { SCOPED_TRACE("Field_timestampf"); Field_timestampf ftsf(NULL, NULL, 0, Field::NONE, "", DATETIME_MAX_DECIMALS); test_make_sort_key(&ftsf); } { SCOPED_TRACE("field_newdate"); Field_newdate fnd(false, ""); uchar from []= { '3', '2', '1' }; uchar expected []= { '1', '2', '3' }; test_make_sort_key(&fnd, from, expected, 3); } { SCOPED_TRACE("Field_time"); Field_time ft(false, ""); uchar from []= { 3, 2, 1 }; uchar expected []= { 129, 2, 3 }; test_make_sort_key(&ft, from, expected, 3); } { SCOPED_TRACE("Field_timef"); Field_timef ftf(false, "", 0); test_make_sort_key(&ftf); } { SCOPED_TRACE("Field_datetime"); Field_datetime fdt(NULL, NULL, '\0', Field::NONE, NULL); test_integer_field(&fdt); } { SCOPED_TRACE("Field_string"); Mock_charset mock_charset; Field_string fs(NULL, 0, NULL, '\0', Field::NONE, "", &mock_charset); uchar to; fs.make_sort_key(&to, 666); } { SCOPED_TRACE("Field_varstring"); Mock_charset mock_charset; Fake_TABLE_SHARE fake_share(0); uchar ptr[8]= {0, 0, 0, 0, 0, 0, 0, 0}; Field_varstring fvs(ptr, 0, 0, NULL, '\0', Field::NONE, "", &fake_share, &mock_charset); uchar to; fvs.make_sort_key(&to, 666); } { SCOPED_TRACE("Field_blob"); CHARSET_INFO cs; cs.state= MY_CHARSET_UNDEFINED; // Avoid valgrind warning. Field_blob fb(0, false, "", &cs, false); } { SCOPED_TRACE("Field_enum"); for (int pack_length= 1; pack_length <= 8; ++pack_length) for (int key_length= 1; key_length <= 8; ++key_length) { Field_enum fe(NULL, 0, NULL, '\0', Field::NONE, "", pack_length, NULL, &my_charset_bin); uchar from []= { '1', '2', '3', '4', '5', '6', '7', '8' }; uchar expected []= #ifdef WORDS_BIGENDIAN { '1', '2', '3', '4', '5', '6', '7', '8' }; test_make_sort_key(&fe, from, expected, key_length); #else { '8', '7', '6', '5', '4', '3', '2', '1' }; test_make_sort_key(&fe, from, expected + 8 - pack_length, key_length); #endif } } { SCOPED_TRACE("Field_bit"); Field_bit fb(NULL, 0, NULL, '\0', NULL, '\0', Field::NONE, ""); } } void testCopyInteger(bool is_big_endian, bool is_unsigned) { const uchar from_template[]= { '1', '2', '3', '4', '5', '6', '7', '8' }, expected_for_big_endian[]= { '1', '2', '3', '4', '5', '6', '7', '8' }, expected_for_little_endian[]= { '8', '7', '6', '5', '4', '3', '2', '1' }; const size_t max_length= sizeof(from_template); for (uint from_length= 1; from_length < max_length; ++from_length) for (uint to_length= 1; to_length <= from_length; ++to_length) { uchar to[]= { '0', '0', '0', '0', '0', '0', '0', '0', '0' }; uchar from[max_length]; memcpy(from, from_template, max_length); if (is_big_endian) copy_integer(to, to_length, from, from_length, is_unsigned); else copy_integer(to, to_length, from, from_length, is_unsigned); EXPECT_EQ('0', to[to_length]) << "Buffer overrun @ position " << to_length << "."; ASSERT_EQ(is_unsigned ? 0 : 128, to[0] & 128) << "Sign bit should" << (is_unsigned ? " not" : "") << " be flipped"; const uchar *expected= is_big_endian ? expected_for_big_endian : expected_for_little_endian + max_length - from_length; for (uint i= 1; i < to_length; ++i) { ASSERT_FALSE(to[i] == '\0') << "Too few bytes written @ position " << i << " when copying a size " << from_length << " integer into a size " << to_length << " integer."; ASSERT_EQ(expected[i], to[i]) << "Result differs at position " << i << " when copying a size " << from_length << " integer into a size " << to_length << " integer."; } } } // Test of the copy_integer<>() function. TEST_F(FieldTest, copyInteger) { { SCOPED_TRACE("Big endian unsigned"); testCopyInteger(true, true); } { SCOPED_TRACE("Big endian signed"); testCopyInteger(true, false); } { SCOPED_TRACE("Little endian unsigned"); testCopyInteger(false, true); } { SCOPED_TRACE("Little endian signed"); testCopyInteger(false, false); } } } #include "field_date-t.cc" #include "field_datetime-t.cc" #include "field_long-t.cc" #include "field_newdecimal-t.cc" #include "field_timestamp-t.cc"