package native import ( "bufio" "bytes" "github.com/ziutek/mymysql/mysql" "math" "reflect" "strconv" "testing" "time" ) var ( Bytes = []byte("Ala ma Kota!") String = "ssss" //"A kot ma AlÄ™!" blob = mysql.Blob{1, 2, 3} dateT = time.Date(2010, 12, 30, 17, 21, 01, 0, time.Local) tstamp = mysql.Timestamp{dateT.Add(1e9)} date = mysql.Date{Year: 2011, Month: 2, Day: 3} tim = -time.Duration((5*24*3600+4*3600+3*60+2)*1e9 + 1) bol = true pBytes *[]byte pString *string pBlob *mysql.Blob pDateT *time.Time pTstamp *mysql.Timestamp pDate *mysql.Date pTim *time.Duration pBol *bool raw = mysql.Raw{MYSQL_TYPE_INT24, &[]byte{3, 2, 1, 0}} Int8 = int8(1) Uint8 = uint8(2) Int16 = int16(3) Uint16 = uint16(4) Int32 = int32(5) Uint32 = uint32(6) Int64 = int64(0x7000100020003001) Uint64 = uint64(0xffff0000ffff0000) Int = int(7) Uint = uint(8) Float32 = float32(1e10) Float64 = 256e256 pInt8 *int8 pUint8 *uint8 pInt16 *int16 pUint16 *uint16 pInt32 *int32 pUint32 *uint32 pInt64 *int64 pUint64 *uint64 pInt *int pUint *uint pFloat32 *float32 pFloat64 *float64 ) type BindTest struct { val interface{} typ uint16 length int } func intSize() int { switch strconv.IntSize { case 32: return 4 case 64: return 8 } panic("bad int size") } func intType() uint16 { switch strconv.IntSize { case 32: return MYSQL_TYPE_LONG case 64: return MYSQL_TYPE_LONGLONG } panic("bad int size") } var bindTests = []BindTest{ BindTest{nil, MYSQL_TYPE_NULL, 0}, BindTest{Bytes, MYSQL_TYPE_VAR_STRING, -1}, BindTest{String, MYSQL_TYPE_STRING, -1}, BindTest{blob, MYSQL_TYPE_BLOB, -1}, BindTest{dateT, MYSQL_TYPE_DATETIME, -1}, BindTest{tstamp, MYSQL_TYPE_TIMESTAMP, -1}, BindTest{date, MYSQL_TYPE_DATE, -1}, BindTest{tim, MYSQL_TYPE_TIME, -1}, BindTest{bol, MYSQL_TYPE_TINY, -1}, BindTest{&Bytes, MYSQL_TYPE_VAR_STRING, -1}, BindTest{&String, MYSQL_TYPE_STRING, -1}, BindTest{&blob, MYSQL_TYPE_BLOB, -1}, BindTest{&dateT, MYSQL_TYPE_DATETIME, -1}, BindTest{&tstamp, MYSQL_TYPE_TIMESTAMP, -1}, BindTest{&date, MYSQL_TYPE_DATE, -1}, BindTest{&tim, MYSQL_TYPE_TIME, -1}, BindTest{pBytes, MYSQL_TYPE_VAR_STRING, -1}, BindTest{pString, MYSQL_TYPE_STRING, -1}, BindTest{pBlob, MYSQL_TYPE_BLOB, -1}, BindTest{pDateT, MYSQL_TYPE_DATETIME, -1}, BindTest{pTstamp, MYSQL_TYPE_TIMESTAMP, -1}, BindTest{pDate, MYSQL_TYPE_DATE, -1}, BindTest{pTim, MYSQL_TYPE_TIME, -1}, BindTest{pBol, MYSQL_TYPE_TINY, -1}, BindTest{raw, MYSQL_TYPE_INT24, -1}, BindTest{Int8, MYSQL_TYPE_TINY, 1}, BindTest{Int16, MYSQL_TYPE_SHORT, 2}, BindTest{Int32, MYSQL_TYPE_LONG, 4}, BindTest{Int64, MYSQL_TYPE_LONGLONG, 8}, BindTest{Int, intType(), intSize()}, BindTest{&Int8, MYSQL_TYPE_TINY, 1}, BindTest{&Int16, MYSQL_TYPE_SHORT, 2}, BindTest{&Int32, MYSQL_TYPE_LONG, 4}, BindTest{&Int64, MYSQL_TYPE_LONGLONG, 8}, BindTest{&Int, intType(), intSize()}, BindTest{pInt8, MYSQL_TYPE_TINY, 1}, BindTest{pInt16, MYSQL_TYPE_SHORT, 2}, BindTest{pInt32, MYSQL_TYPE_LONG, 4}, BindTest{pInt64, MYSQL_TYPE_LONGLONG, 8}, BindTest{pInt, intType(), intSize()}, BindTest{Uint8, MYSQL_TYPE_TINY | MYSQL_UNSIGNED_MASK, 1}, BindTest{Uint16, MYSQL_TYPE_SHORT | MYSQL_UNSIGNED_MASK, 2}, BindTest{Uint32, MYSQL_TYPE_LONG | MYSQL_UNSIGNED_MASK, 4}, BindTest{Uint64, MYSQL_TYPE_LONGLONG | MYSQL_UNSIGNED_MASK, 8}, BindTest{Uint, intType() | MYSQL_UNSIGNED_MASK, intSize()}, BindTest{&Uint8, MYSQL_TYPE_TINY | MYSQL_UNSIGNED_MASK, 1}, BindTest{&Uint16, MYSQL_TYPE_SHORT | MYSQL_UNSIGNED_MASK, 2}, BindTest{&Uint32, MYSQL_TYPE_LONG | MYSQL_UNSIGNED_MASK, 4}, BindTest{&Uint64, MYSQL_TYPE_LONGLONG | MYSQL_UNSIGNED_MASK, 8}, BindTest{&Uint, intType() | MYSQL_UNSIGNED_MASK, intSize()}, BindTest{pUint8, MYSQL_TYPE_TINY | MYSQL_UNSIGNED_MASK, 1}, BindTest{pUint16, MYSQL_TYPE_SHORT | MYSQL_UNSIGNED_MASK, 2}, BindTest{pUint32, MYSQL_TYPE_LONG | MYSQL_UNSIGNED_MASK, 4}, BindTest{pUint64, MYSQL_TYPE_LONGLONG | MYSQL_UNSIGNED_MASK, 8}, BindTest{pUint, intType() | MYSQL_UNSIGNED_MASK, intSize()}, BindTest{Float32, MYSQL_TYPE_FLOAT, 4}, BindTest{Float64, MYSQL_TYPE_DOUBLE, 8}, BindTest{&Float32, MYSQL_TYPE_FLOAT, 4}, BindTest{&Float64, MYSQL_TYPE_DOUBLE, 8}, } func makeAddressable(v reflect.Value) reflect.Value { if v.IsValid() { // Make an addresable value av := reflect.New(v.Type()).Elem() av.Set(v) v = av } return v } func TestBind(t *testing.T) { for _, test := range bindTests { v := makeAddressable(reflect.ValueOf(test.val)) val := bindValue(v) if val.typ != test.typ || val.length != test.length { t.Errorf( "Type: %s exp=0x%x res=0x%x Len: exp=%d res=%d", reflect.TypeOf(test.val), test.typ, val.typ, test.length, val.length, ) } } } type WriteTest struct { val interface{} exp []byte } var writeTest []WriteTest func encodeU16(v uint16) []byte { buf := make([]byte, 2) EncodeU16(buf, v) return buf } func encodeU24(v uint32) []byte { buf := make([]byte, 3) EncodeU24(buf, v) return buf } func encodeU32(v uint32) []byte { buf := make([]byte, 4) EncodeU32(buf, v) return buf } func encodeU64(v uint64) []byte { buf := make([]byte, 8) EncodeU64(buf, v) return buf } func encodeDuration(d time.Duration) []byte { buf := make([]byte, 13) n := EncodeDuration(buf, d) return buf[:n] } func encodeTime(t time.Time) []byte { buf := make([]byte, 12) n := EncodeTime(buf, t) return buf[:n] } func encodeDate(d mysql.Date) []byte { buf := make([]byte, 5) n := EncodeDate(buf, d) return buf[:n] } func encodeUint(u uint) []byte { switch strconv.IntSize { case 32: return encodeU32(uint32(u)) case 64: return encodeU64(uint64(u)) } panic("bad int size") } func init() { b := make([]byte, 64*1024) for ii := range b { b[ii] = byte(ii) } blob = mysql.Blob(b) writeTest = []WriteTest{ WriteTest{Bytes, append([]byte{byte(len(Bytes))}, Bytes...)}, WriteTest{String, append([]byte{byte(len(String))}, []byte(String)...)}, WriteTest{pBytes, nil}, WriteTest{pString, nil}, WriteTest{ blob, append( append([]byte{253}, byte(len(blob)), byte(len(blob)>>8), byte(len(blob)>>16)), []byte(blob)...), }, WriteTest{ dateT, []byte{ 7, byte(dateT.Year()), byte(dateT.Year() >> 8), byte(dateT.Month()), byte(dateT.Day()), byte(dateT.Hour()), byte(dateT.Minute()), byte(dateT.Second()), }, }, WriteTest{ &dateT, []byte{ 7, byte(dateT.Year()), byte(dateT.Year() >> 8), byte(dateT.Month()), byte(dateT.Day()), byte(dateT.Hour()), byte(dateT.Minute()), byte(dateT.Second()), }, }, WriteTest{ date, []byte{ 4, byte(date.Year), byte(date.Year >> 8), byte(date.Month), byte(date.Day), }, }, WriteTest{ &date, []byte{ 4, byte(date.Year), byte(date.Year >> 8), byte(date.Month), byte(date.Day), }, }, WriteTest{ tim, []byte{12, 1, 5, 0, 0, 0, 4, 3, 2, 1, 0, 0, 0}, }, WriteTest{ &tim, []byte{12, 1, 5, 0, 0, 0, 4, 3, 2, 1, 0, 0, 0}, }, WriteTest{bol, []byte{1}}, WriteTest{&bol, []byte{1}}, WriteTest{pBol, nil}, WriteTest{dateT, encodeTime(dateT)}, WriteTest{&dateT, encodeTime(dateT)}, WriteTest{pDateT, nil}, WriteTest{tstamp, encodeTime(tstamp.Time)}, WriteTest{&tstamp, encodeTime(tstamp.Time)}, WriteTest{pTstamp, nil}, WriteTest{date, encodeDate(date)}, WriteTest{&date, encodeDate(date)}, WriteTest{pDate, nil}, WriteTest{tim, encodeDuration(tim)}, WriteTest{&tim, encodeDuration(tim)}, WriteTest{pTim, nil}, WriteTest{Int, encodeUint(uint(Int))}, WriteTest{Int16, encodeU16(uint16(Int16))}, WriteTest{Int32, encodeU32(uint32(Int32))}, WriteTest{Int64, encodeU64(uint64(Int64))}, WriteTest{Uint, encodeUint(Uint)}, WriteTest{Uint16, encodeU16(Uint16)}, WriteTest{Uint32, encodeU32(Uint32)}, WriteTest{Uint64, encodeU64(Uint64)}, WriteTest{&Int, encodeUint(uint(Int))}, WriteTest{&Int16, encodeU16(uint16(Int16))}, WriteTest{&Int32, encodeU32(uint32(Int32))}, WriteTest{&Int64, encodeU64(uint64(Int64))}, WriteTest{&Uint, encodeUint(Uint)}, WriteTest{&Uint16, encodeU16(Uint16)}, WriteTest{&Uint32, encodeU32(Uint32)}, WriteTest{&Uint64, encodeU64(Uint64)}, WriteTest{pInt, nil}, WriteTest{pInt16, nil}, WriteTest{pInt32, nil}, WriteTest{pInt64, nil}, WriteTest{Float32, encodeU32(math.Float32bits(Float32))}, WriteTest{Float64, encodeU64(math.Float64bits(Float64))}, WriteTest{&Float32, encodeU32(math.Float32bits(Float32))}, WriteTest{&Float64, encodeU64(math.Float64bits(Float64))}, WriteTest{pFloat32, nil}, WriteTest{pFloat64, nil}, } } func TestWrite(t *testing.T) { buf := new(bytes.Buffer) for _, test := range writeTest { buf.Reset() var seq byte pw := &pktWriter{ wr: bufio.NewWriter(buf), seq: &seq, to_write: len(test.exp), } v := makeAddressable(reflect.ValueOf(test.val)) val := bindValue(v) pw.writeValue(&val) if !reflect.Indirect(v).IsValid() && len(buf.Bytes()) == 0 { // writeValue writes nothing for nil continue } if len(buf.Bytes()) != len(test.exp)+4 || !bytes.Equal(buf.Bytes()[4:], test.exp) || val.Len() != len(test.exp) { t.Fatalf("%s - exp_len=%d res_len=%d exp: %v res: %v", reflect.TypeOf(test.val), len(test.exp), val.Len(), test.exp, buf.Bytes(), ) } } }