blob: 1fc62848a95dda6bc0accdbad31bb17673ce0283 [file] [log] [blame]
/*
Copyright 2016 The Transicator Authors
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,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package common
import (
"bytes"
"strconv"
"testing/quick"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
/*
Tests for value conversion. What fun.
*/
var _ = Describe("Value conversion tests", func() {
It("bool", func() {
Expect(quick.Check(testBool, nil)).Should(Succeed())
})
It("int64", func() {
Expect(quick.Check(func(iv int64) bool {
c := &Change{
NewRow: Row{
"val": &ColumnVal{
Value: iv,
},
},
}
col := marshUnmarsh(c)
return testInt(col, iv, 64)
}, nil)).Should(Succeed())
})
It("int32", func() {
Expect(quick.Check(func(iv int32) bool {
c := &Change{
NewRow: Row{
"val": &ColumnVal{
Value: iv,
},
},
}
col := marshUnmarsh(c)
return testInt(col, int64(iv), 32)
}, nil)).Should(Succeed())
})
It("int16", func() {
Expect(quick.Check(func(iv int16) bool {
c := &Change{
NewRow: Row{
"val": &ColumnVal{
Value: iv,
},
},
}
col := marshUnmarsh(c)
return testInt(col, int64(iv), 16)
}, nil)).Should(Succeed())
})
It("uint64", func() {
Expect(quick.Check(func(iv uint64) bool {
c := &Change{
NewRow: Row{
"val": &ColumnVal{
Value: iv,
},
},
}
col := marshUnmarsh(c)
return testUint(col, iv, 64)
}, nil)).Should(Succeed())
})
It("uint32", func() {
Expect(quick.Check(func(iv uint32) bool {
c := &Change{
NewRow: Row{
"val": &ColumnVal{
Value: iv,
},
},
}
col := marshUnmarsh(c)
return testUint(col, uint64(iv), 32)
}, nil)).Should(Succeed())
})
It("uint16", func() {
Expect(quick.Check(func(iv uint16) bool {
c := &Change{
NewRow: Row{
"val": &ColumnVal{
Value: iv,
},
},
}
col := marshUnmarsh(c)
return testUint(col, uint64(iv), 16)
}, nil)).Should(Succeed())
})
It("float32", func() {
Expect(quick.Check(func(iv float32) bool {
c := &Change{
NewRow: Row{
"val": &ColumnVal{
Value: iv,
},
},
}
col := marshUnmarsh(c)
return testFloat(col, float64(iv), 32)
}, nil)).Should(Succeed())
})
It("float64", func() {
Expect(quick.Check(func(iv float64) bool {
c := &Change{
NewRow: Row{
"val": &ColumnVal{
Value: iv,
},
},
}
col := marshUnmarsh(c)
return testFloat(col, iv, 64)
}, nil)).Should(Succeed())
})
It("string", func() {
Expect(quick.Check(testString, nil)).Should(Succeed())
})
It("bytes", func() {
Expect(quick.Check(testBytes, nil)).Should(Succeed())
})
It("timestamp", func() {
now := time.Now()
c := &Change{
NewRow: Row{
"val": &ColumnVal{
Value: now,
},
},
}
nv := marshUnmarsh(c)
var rts time.Time
err := nv.Get(&rts)
Expect(err).Should(Succeed())
// Go timestamp has microseconds but not PG timestamp
Expect(rts.UnixNano()).Should(BeNumerically("~", now.UnixNano(), 1000))
var tss string
err = nv.Get(&tss)
Expect(err).Should(Succeed())
pts, err := time.Parse("2006-01-02 15:04:05.99999999 -0700 MST", tss)
Expect(err).Should(Succeed())
Expect(pts.UnixNano()).Should(BeNumerically("~", now.UnixNano(), 1000))
})
It("Get", func() {
c := &Change{
NewRow: Row{
"val": &ColumnVal{
Value: int64(123),
},
},
}
var sv string
err := c.NewRow.Get("val", &sv)
Expect(err).Should(Succeed())
Expect(sv).Should(Equal("123"))
var iv int64
err = c.NewRow.Get("val", &iv)
Expect(err).Should(Succeed())
Expect(iv).Should(Equal(int64(123)))
})
It("Get Null", func() {
c := &Change{
NewRow: Row{},
}
var iv6 int16 = 123
err := c.NewRow.Get("val", &iv6)
Expect(err).Should(Succeed())
Expect(iv6).Should(BeZero())
var uv6 uint16 = 123
err = c.NewRow.Get("val", &uv6)
Expect(err).Should(Succeed())
Expect(iv6).Should(BeZero())
var fv float64 = 3.14
err = c.NewRow.Get("val", &fv)
Expect(err).Should(Succeed())
Expect(fv).Should(BeZero())
bv := []byte("something")
err = c.NewRow.Get("val", &bv)
Expect(err).Should(Succeed())
Expect(bv).Should(BeNil())
sv := "something"
err = c.NewRow.Get("val", &sv)
Expect(err).Should(Succeed())
Expect(sv).Should(Equal(""))
})
It("Timestamp sanity checks", func() {
unixEpoch, err :=
time.Parse("1/2/2006 15:04:05 -0700", "1/1/1970 00:00:00 -0000")
Expect(err).Should(Succeed())
Expect(unixEpoch.Unix()).Should(BeZero())
pgEpoch, err :=
time.Parse("1/2/2006 15:04:05 -0700", "1/1/2000 00:00:00 -0000")
Expect(err).Should(Succeed())
Expect(pgEpoch.UnixNano()).Should(BeEquivalentTo(postgresEpochNanos))
})
It("Timestamp conversion", func() {
now := time.Now()
nowRounded := time.Unix(0, now.UnixNano()-now.UnixNano()%1000)
r := PgTimestampToTime(TimeToPgTimestamp(nowRounded))
Expect(r.UnixNano()).Should(Equal(nowRounded.UnixNano()))
Expect(r).Should(Equal(nowRounded))
})
})
func marshUnmarsh(c *Change) *ColumnVal {
buf := c.MarshalProto()
after, err := UnmarshalChangeProto(buf)
Expect(err).Should(Succeed())
col := after.NewRow["val"]
Expect(col).ShouldNot(BeNil())
return col
}
func testString(val string) bool {
before := Change{
NewRow: Row{
"val": &ColumnVal{
Value: val,
},
},
}
col := marshUnmarsh(&before)
var ss string
err := col.Get(&ss)
Expect(err).Should(Succeed())
Expect(ss).Should(Equal(val))
var bs []byte
err = col.Get(&bs)
Expect(err).Should(Succeed())
Expect(bytes.Equal(bs, []byte(val))).Should(BeTrue())
return true
}
func testBytes(val []byte) bool {
before := Change{
NewRow: Row{
"val": &ColumnVal{
Value: val,
},
},
}
col := marshUnmarsh(&before)
var ss string
err := col.Get(&ss)
Expect(err).Should(Succeed())
Expect(bytes.Equal([]byte(ss), val)).Should(BeTrue())
var bs []byte
err = col.Get(&bs)
Expect(err).Should(Succeed())
Expect(bytes.Equal(bs, val)).Should(BeTrue())
return true
}
func testBool(val bool) bool {
before := Change{
NewRow: Row{
"val": &ColumnVal{
Value: val,
},
},
}
col := marshUnmarsh(&before)
var bv bool
err := col.Get(&bv)
Expect(err).Should(Succeed())
Expect(bv).Should(Equal(val))
var iv int
var sv string
if val {
iv = 1
sv = "true"
} else {
iv = 0
sv = "false"
}
var iv6 int16
err = col.Get(&iv6)
Expect(err).Should(Succeed())
Expect(iv6).Should(BeEquivalentTo(iv))
var iv3 int32
err = col.Get(&iv3)
Expect(err).Should(Succeed())
Expect(iv3).Should(BeEquivalentTo(iv))
var iv4 int64
err = col.Get(&iv4)
Expect(err).Should(Succeed())
Expect(iv4).Should(BeEquivalentTo(iv))
var uv6 uint16
err = col.Get(&uv6)
Expect(err).Should(Succeed())
Expect(uv6).Should(BeEquivalentTo(iv))
var uv3 uint32
err = col.Get(&uv3)
Expect(err).Should(Succeed())
Expect(uv3).Should(BeEquivalentTo(iv))
var uv4 uint64
err = col.Get(&uv4)
Expect(err).Should(Succeed())
Expect(uv4).Should(BeEquivalentTo(iv))
var fv3 float32
err = col.Get(&fv3)
Expect(err).Should(Succeed())
Expect(fv3).Should(BeEquivalentTo(iv))
var fv4 float64
err = col.Get(&fv4)
Expect(err).Should(Succeed())
Expect(fv4).Should(BeEquivalentTo(iv))
var svv string
err = col.Get(&svv)
Expect(err).Should(Succeed())
Expect(svv).Should(Equal(sv))
var yv []byte
err = col.Get(&yv)
Expect(err).ShouldNot(Succeed())
return true
}
func testInt(col *ColumnVal, iv int64, bits int) bool {
var bv bool
err := col.Get(&bv)
Expect(err).Should(Succeed())
if iv == 0 {
Expect(bv).Should(BeFalse())
} else {
Expect(bv).Should(BeTrue())
}
sv := strconv.FormatInt(iv, 10)
var svv string
err = col.Get(&svv)
Expect(err).Should(Succeed())
Expect(svv).Should(Equal(sv))
if bits < 32 {
var iv6 int16
err = col.Get(&iv6)
Expect(err).Should(Succeed())
Expect(iv6).Should(BeEquivalentTo(iv))
}
if bits < 64 {
var iv3 int32
err = col.Get(&iv3)
Expect(err).Should(Succeed())
Expect(iv3).Should(BeEquivalentTo(iv))
var ii3 int
err = col.Get(&ii3)
Expect(err).Should(Succeed())
Expect(ii3).Should(BeEquivalentTo(iv))
var fv3 float32
err = col.Get(&fv3)
Expect(err).Should(Succeed())
Expect(fv3).Should(BeEquivalentTo(float32(iv)))
}
var iv4 int64
err = col.Get(&iv4)
Expect(err).Should(Succeed())
Expect(iv4).Should(BeEquivalentTo(iv))
var fv4 float64
err = col.Get(&fv4)
Expect(err).Should(Succeed())
Expect(fv4).Should(BeEquivalentTo(float64(iv)))
var yv []byte
err = col.Get(&yv)
Expect(err).ShouldNot(Succeed())
return true
}
func testUint(col *ColumnVal, iv uint64, bits int) bool {
var bv bool
err := col.Get(&bv)
Expect(err).Should(Succeed())
if iv == 0 {
Expect(bv).Should(BeFalse())
} else {
Expect(bv).Should(BeTrue())
}
sv := strconv.FormatUint(iv, 10)
var svv string
err = col.Get(&svv)
Expect(err).Should(Succeed())
Expect(svv).Should(Equal(sv))
if bits < 32 {
var iv6 uint16
err = col.Get(&iv6)
Expect(err).Should(Succeed())
Expect(iv6).Should(BeEquivalentTo(iv))
}
if bits < 64 {
var iv3 uint32
err = col.Get(&iv3)
Expect(err).Should(Succeed())
Expect(iv3).Should(BeEquivalentTo(iv))
var fv3 float32
err = col.Get(&fv3)
Expect(err).Should(Succeed())
Expect(fv3).Should(BeEquivalentTo(float32(iv)))
}
var iv4 uint64
err = col.Get(&iv4)
Expect(err).Should(Succeed())
Expect(iv4).Should(BeEquivalentTo(iv))
var fv4 float64
err = col.Get(&fv4)
Expect(err).Should(Succeed())
Expect(fv4).Should(BeEquivalentTo(float64(iv)))
var yv []byte
err = col.Get(&yv)
Expect(err).ShouldNot(Succeed())
return true
}
func testFloat(col *ColumnVal, iv float64, bits int) bool {
var bv bool
err := col.Get(&bv)
Expect(err).Should(Succeed())
if iv == 0.0 {
Expect(bv).Should(BeFalse())
} else {
Expect(bv).Should(BeTrue())
}
if bits < 64 {
var iv3 int32
err = col.Get(&iv3)
Expect(err).Should(Succeed())
Expect(iv3).Should(BeEquivalentTo(int32(iv)))
var fv3 float32
err = col.Get(&fv3)
Expect(err).Should(Succeed())
Expect(fv3).Should(BeEquivalentTo(float32(iv)))
} else {
sv := strconv.FormatFloat(iv, 'G', -1, bits)
var svv string
err = col.Get(&svv)
Expect(err).Should(Succeed())
Expect(svv).Should(Equal(sv))
}
var iv4 int64
err = col.Get(&iv4)
Expect(err).Should(Succeed())
Expect(iv4).Should(BeEquivalentTo(int64(iv)))
var fv4 float64
err = col.Get(&fv4)
Expect(err).Should(Succeed())
Expect(fv4).Should(BeEquivalentTo(iv))
var yv []byte
err = col.Get(&yv)
Expect(err).ShouldNot(Succeed())
return true
}