Слияние кода завершено, страница обновится автоматически
// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"reflect"
"testing"
"time"
"github.com/hanchuanchuan/goInception/mysql"
"github.com/hanchuanchuan/goInception/sessionctx/stmtctx"
"github.com/hanchuanchuan/goInception/types/json"
. "github.com/pingcap/check"
)
var _ = Suite(&testDatumSuite{})
type testDatumSuite struct {
}
func (ts *testDatumSuite) TestDatum(c *C) {
values := []interface{}{
int64(1),
uint64(1),
1.1,
"abc",
[]byte("abc"),
[]int{1},
}
for _, val := range values {
var d Datum
d.SetValue(val)
x := d.GetValue()
c.Assert(x, DeepEquals, val)
}
}
func testDatumToBool(c *C, in interface{}, res int) {
datum := NewDatum(in)
res64 := int64(res)
sc := new(stmtctx.StatementContext)
sc.IgnoreTruncate = true
b, err := datum.ToBool(sc)
c.Assert(err, IsNil)
c.Assert(b, Equals, res64)
}
func (ts *testDatumSuite) TestToBool(c *C) {
testDatumToBool(c, int(0), 0)
testDatumToBool(c, int64(0), 0)
testDatumToBool(c, uint64(0), 0)
testDatumToBool(c, float32(0.1), 0)
testDatumToBool(c, float64(0.1), 0)
testDatumToBool(c, "", 0)
testDatumToBool(c, "0.1", 0)
testDatumToBool(c, []byte{}, 0)
testDatumToBool(c, []byte("0.1"), 0)
testDatumToBool(c, NewBinaryLiteralFromUint(0, -1), 0)
testDatumToBool(c, Enum{Name: "a", Value: 1}, 1)
testDatumToBool(c, Set{Name: "a", Value: 1}, 1)
t, err := ParseTime(&stmtctx.StatementContext{TimeZone: time.UTC}, "2011-11-10 11:11:11.999999", mysql.TypeTimestamp, 6)
c.Assert(err, IsNil)
testDatumToBool(c, t, 1)
td, err := ParseDuration(nil, "11:11:11.999999", 6)
c.Assert(err, IsNil)
testDatumToBool(c, td, 1)
ft := NewFieldType(mysql.TypeNewDecimal)
ft.Decimal = 5
v, err := Convert(0.1415926, ft)
c.Assert(err, IsNil)
testDatumToBool(c, v, 0)
d := NewDatum(&invalidMockType{})
sc := new(stmtctx.StatementContext)
sc.IgnoreTruncate = true
_, err = d.ToBool(sc)
c.Assert(err, NotNil)
}
func (ts *testDatumSuite) TestEqualDatums(c *C) {
tests := []struct {
a []interface{}
b []interface{}
same bool
}{
// Positive cases
{[]interface{}{1}, []interface{}{1}, true},
{[]interface{}{1, "aa"}, []interface{}{1, "aa"}, true},
{[]interface{}{1, "aa", 1}, []interface{}{1, "aa", 1}, true},
// negative cases
{[]interface{}{1}, []interface{}{2}, false},
{[]interface{}{1, "a"}, []interface{}{1, "aaaaaa"}, false},
{[]interface{}{1, "aa", 3}, []interface{}{1, "aa", 2}, false},
// Corner cases
{[]interface{}{}, []interface{}{}, true},
{[]interface{}{nil}, []interface{}{nil}, true},
{[]interface{}{}, []interface{}{1}, false},
{[]interface{}{1}, []interface{}{1, 1}, false},
{[]interface{}{nil}, []interface{}{1}, false},
}
for _, tt := range tests {
testEqualDatums(c, tt.a, tt.b, tt.same)
}
}
func testEqualDatums(c *C, a []interface{}, b []interface{}, same bool) {
sc := new(stmtctx.StatementContext)
sc.IgnoreTruncate = true
res, err := EqualDatums(sc, MakeDatums(a...), MakeDatums(b...))
c.Assert(err, IsNil)
c.Assert(res, Equals, same, Commentf("a: %v, b: %v", a, b))
}
func testDatumToInt64(c *C, val interface{}, expect int64) {
d := NewDatum(val)
sc := new(stmtctx.StatementContext)
sc.IgnoreTruncate = true
b, err := d.ToInt64(sc)
c.Assert(err, IsNil)
c.Assert(b, Equals, expect)
}
func (ts *testTypeConvertSuite) TestToInt64(c *C) {
testDatumToInt64(c, "0", int64(0))
testDatumToInt64(c, int(0), int64(0))
testDatumToInt64(c, int64(0), int64(0))
testDatumToInt64(c, uint64(0), int64(0))
testDatumToInt64(c, float32(3.1), int64(3))
testDatumToInt64(c, float64(3.1), int64(3))
testDatumToInt64(c, NewBinaryLiteralFromUint(100, -1), int64(100))
testDatumToInt64(c, Enum{Name: "a", Value: 1}, int64(1))
testDatumToInt64(c, Set{Name: "a", Value: 1}, int64(1))
testDatumToInt64(c, json.CreateBinary(int64(3)), int64(3))
t, err := ParseTime(&stmtctx.StatementContext{
TimeZone: time.UTC,
}, "2011-11-10 11:11:11.999999", mysql.TypeTimestamp, 0)
c.Assert(err, IsNil)
testDatumToInt64(c, t, int64(20111110111112))
td, err := ParseDuration(nil, "11:11:11.999999", 6)
c.Assert(err, IsNil)
testDatumToInt64(c, td, int64(111112))
ft := NewFieldType(mysql.TypeNewDecimal)
ft.Decimal = 5
v, err := Convert(3.1415926, ft)
c.Assert(err, IsNil)
testDatumToInt64(c, v, int64(3))
binLit, err := ParseHexStr("0x9999999999999999999999999999999999999999999")
c.Assert(err, IsNil)
testDatumToInt64(c, binLit, -1)
}
func (ts *testTypeConvertSuite) TestToFloat32(c *C) {
ft := NewFieldType(mysql.TypeFloat)
var datum = NewFloat64Datum(281.37)
sc := new(stmtctx.StatementContext)
sc.IgnoreTruncate = true
converted, err := datum.ConvertTo(sc, ft)
c.Assert(err, IsNil)
c.Assert(converted.Kind(), Equals, KindFloat32)
c.Assert(converted.GetFloat32(), Equals, float32(281.37))
datum.SetString("281.37")
converted, err = datum.ConvertTo(sc, ft)
c.Assert(err, IsNil)
c.Assert(converted.Kind(), Equals, KindFloat32)
c.Assert(converted.GetFloat32(), Equals, float32(281.37))
ft = NewFieldType(mysql.TypeDouble)
datum = NewFloat32Datum(281.37)
converted, err = datum.ConvertTo(sc, ft)
c.Assert(err, IsNil)
c.Assert(converted.Kind(), Equals, KindFloat64)
// Convert to float32 and convert back to float64, we will get a different value.
c.Assert(converted.GetFloat64(), Not(Equals), 281.37)
c.Assert(converted.GetFloat64(), Equals, datum.GetFloat64())
}
// mustParseTimeIntoDatum is similar to ParseTime but panic if any error occurs.
func mustParseTimeIntoDatum(s string, tp byte, fsp int) (d Datum) {
t, err := ParseTime(&stmtctx.StatementContext{TimeZone: time.UTC}, s, tp, fsp)
if err != nil {
panic("ParseTime fail")
}
d.SetMysqlTime(t)
return
}
func (ts *testDatumSuite) TestToJSON(c *C) {
ft := NewFieldType(mysql.TypeJSON)
sc := new(stmtctx.StatementContext)
tests := []struct {
datum Datum
expected string
success bool
}{
{NewIntDatum(1), `1.0`, true},
{NewFloat64Datum(2), `2`, true},
{NewStringDatum("\"hello, 世界\""), `"hello, 世界"`, true},
{NewStringDatum("[1, 2, 3]"), `[1, 2, 3]`, true},
{NewStringDatum("{}"), `{}`, true},
{mustParseTimeIntoDatum("2011-11-10 11:11:11.111111", mysql.TypeTimestamp, 6), `"2011-11-10 11:11:11.111111"`, true},
// can not parse JSON from this string, so error occurs.
{NewStringDatum("hello, 世界"), "", false},
}
for _, tt := range tests {
obtain, err := tt.datum.ConvertTo(sc, ft)
if tt.success {
c.Assert(err, IsNil)
sd := NewStringDatum(tt.expected)
var expected Datum
expected, err = sd.ConvertTo(sc, ft)
c.Assert(err, IsNil)
var cmp int
cmp, err = obtain.CompareDatum(sc, &expected)
c.Assert(err, IsNil)
c.Assert(cmp, Equals, 0)
} else {
c.Assert(err, NotNil)
}
}
}
func (ts *testDatumSuite) TestIsNull(c *C) {
tests := []struct {
data interface{}
isnull bool
}{
{nil, true},
{0, false},
{1, false},
{1.1, false},
{"string", false},
{"", false},
}
for _, tt := range tests {
testIsNull(c, tt.data, tt.isnull)
}
}
func testIsNull(c *C, data interface{}, isnull bool) {
d := NewDatum(data)
c.Assert(d.IsNull(), Equals, isnull, Commentf("data: %v, isnull: %v", data, isnull))
}
func (ts *testDatumSuite) TestCoerceDatum(c *C) {
tests := []struct {
a Datum
b Datum
kind byte
}{
{NewIntDatum(1), NewIntDatum(1), KindInt64},
{NewUintDatum(1), NewDecimalDatum(NewDecFromInt(1)), KindMysqlDecimal},
{NewFloat64Datum(1), NewDecimalDatum(NewDecFromInt(1)), KindFloat64},
{NewFloat64Datum(1), NewFloat64Datum(1), KindFloat64},
}
sc := new(stmtctx.StatementContext)
sc.IgnoreTruncate = true
for _, tt := range tests {
x, y, err := CoerceDatum(sc, tt.a, tt.b)
c.Check(err, IsNil)
c.Check(x.Kind(), Equals, y.Kind())
c.Check(x.Kind(), Equals, tt.kind)
}
}
func (ts *testDatumSuite) TestToBytes(c *C) {
tests := []struct {
a Datum
out []byte
}{
{NewIntDatum(1), []byte("1")},
{NewDecimalDatum(NewDecFromInt(1)), []byte("1")},
{NewFloat64Datum(1.23), []byte("1.23")},
{NewStringDatum("abc"), []byte("abc")},
}
sc := new(stmtctx.StatementContext)
sc.IgnoreTruncate = true
for _, tt := range tests {
bin, err := tt.a.ToBytes()
c.Assert(err, IsNil)
c.Assert(bin, BytesEquals, tt.out)
}
}
func mustParseDurationDatum(str string, fsp int) Datum {
dur, err := ParseDuration(nil, str, fsp)
if err != nil {
panic(err)
}
return NewDurationDatum(dur)
}
func (ts *testDatumSuite) TestComputePlusAndMinus(c *C) {
sc := &stmtctx.StatementContext{TimeZone: time.UTC}
tests := []struct {
a Datum
b Datum
plus Datum
minus Datum
hasErr bool
}{
{NewIntDatum(72), NewIntDatum(28), NewIntDatum(100), NewIntDatum(44), false},
{NewIntDatum(72), NewUintDatum(28), NewIntDatum(100), NewIntDatum(44), false},
{NewUintDatum(72), NewUintDatum(28), NewUintDatum(100), NewUintDatum(44), false},
{NewUintDatum(72), NewIntDatum(28), NewUintDatum(100), NewUintDatum(44), false},
{NewFloat64Datum(72.0), NewFloat64Datum(28.0), NewFloat64Datum(100.0), NewFloat64Datum(44.0), false},
{NewDecimalDatum(NewDecFromStringForTest("72.5")), NewDecimalDatum(NewDecFromInt(3)), NewDecimalDatum(NewDecFromStringForTest("75.5")), NewDecimalDatum(NewDecFromStringForTest("69.5")), false},
{NewIntDatum(72), NewFloat64Datum(42), Datum{}, Datum{}, true},
{NewStringDatum("abcd"), NewIntDatum(42), Datum{}, Datum{}, true},
}
for ith, tt := range tests {
got, err := ComputePlus(tt.a, tt.b)
c.Assert(err != nil, Equals, tt.hasErr)
v, err := got.CompareDatum(sc, &tt.plus)
c.Assert(err, IsNil)
c.Assert(v, Equals, 0, Commentf("%dth got:%#v, expect:%#v", ith, got, tt.plus))
}
}
func (ts *testDatumSuite) TestCopyDatum(c *C) {
var raw Datum
raw.b = []byte("raw")
raw.k = KindRaw
tests := []Datum{
NewIntDatum(72),
NewUintDatum(72),
NewStringDatum("abcd"),
NewBytesDatum([]byte("abcd")),
raw,
}
sc := new(stmtctx.StatementContext)
sc.IgnoreTruncate = true
for _, tt := range tests {
tt1 := CopyDatum(tt)
res, err := tt.CompareDatum(sc, &tt1)
c.Assert(err, IsNil)
c.Assert(res, Equals, 0)
if tt.b != nil {
c.Assert(&tt.b[0], Not(Equals), &tt1.b[0])
}
}
}
func prepareCompareDatums() ([]Datum, []Datum) {
vals := make([]Datum, 0, 5)
vals = append(vals, NewIntDatum(1))
vals = append(vals, NewFloat64Datum(1.23))
vals = append(vals, NewStringDatum("abcde"))
vals = append(vals, NewDecimalDatum(NewDecFromStringForTest("1.2345")))
vals = append(vals, NewTimeDatum(Time{Time: FromGoTime(time.Date(2018, 3, 8, 16, 1, 0, 315313000, time.UTC)), Fsp: 6, Type: mysql.TypeTimestamp}))
vals1 := make([]Datum, 0, 5)
vals1 = append(vals1, NewIntDatum(1))
vals1 = append(vals1, NewFloat64Datum(1.23))
vals1 = append(vals1, NewStringDatum("abcde"))
vals1 = append(vals1, NewDecimalDatum(NewDecFromStringForTest("1.2345")))
vals1 = append(vals1, NewTimeDatum(Time{Time: FromGoTime(time.Date(2018, 3, 8, 16, 1, 0, 315313000, time.UTC)), Fsp: 6, Type: mysql.TypeTimestamp}))
return vals, vals1
}
func BenchmarkCompareDatum(b *testing.B) {
vals, vals1 := prepareCompareDatums()
sc := new(stmtctx.StatementContext)
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j, v := range vals {
v.CompareDatum(sc, &vals1[j])
}
}
}
func BenchmarkCompareDatumByReflect(b *testing.B) {
vals, vals1 := prepareCompareDatums()
b.ResetTimer()
for i := 0; i < b.N; i++ {
reflect.DeepEqual(vals, vals1)
}
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарий ( 0 )