1
0
mirror of https://github.com/DATA-DOG/go-sqlmock.git synced 2025-07-17 01:22:23 +02:00

Add Column Metadata #152

This commit is contained in:
Ales Pour
2020-06-22 22:26:35 +02:00
parent 3b99664e4f
commit 3b533ba431
10 changed files with 422 additions and 3 deletions

View File

@ -6,7 +6,9 @@ import (
"database/sql"
"encoding/json"
"fmt"
"reflect"
"testing"
"time"
)
func TestQueryMultiRows(t *testing.T) {
@ -203,3 +205,183 @@ func TestQueryRowBytesNotInvalidatedByClose_jsonRawMessageIntoCustomBytes(t *tes
}
queryRowBytesNotInvalidatedByClose(t, rows, scan, []byte(`{"thing": "one", "thing2": "two"}`))
}
func TestNewColumnWithDefinition(t *testing.T) {
now, _ := time.Parse(time.RFC3339, "2020-06-20T22:08:41Z")
t.Run("with one ResultSet", func(t *testing.T) {
db, mock, _ := New()
column1 := mock.NewColumn("test").OfType("VARCHAR", "").Nullable(true).WithLength(100)
column2 := mock.NewColumn("number").OfType("DECIMAL", float64(0.0)).Nullable(false).WithPrecisionAndScale(10, 4)
column3 := mock.NewColumn("when").OfType("TIMESTAMP", now)
rows := mock.NewRowsWithColumnDefinition(column1, column2, column3)
rows.AddRow("foo.bar", float64(10.123), now)
mQuery := mock.ExpectQuery("SELECT test, number, when from dummy")
isQuery := mQuery.WillReturnRows(rows)
isQueryClosed := mQuery.RowsWillBeClosed()
isDbClosed := mock.ExpectClose()
query, _ := db.Query("SELECT test, number, when from dummy")
if false == isQuery.fulfilled() {
t.Error("Query is not executed")
}
if query.Next() {
var test string
var number float64
var when time.Time
if queryError := query.Scan(&test, &number, &when); queryError != nil {
t.Error(queryError)
} else if test != "foo.bar" {
t.Error("field test is not 'foo.bar'")
} else if number != float64(10.123) {
t.Error("field number is not '10.123'")
} else if when != now {
t.Errorf("field when is not %v", now)
}
if columnTypes, colTypErr := query.ColumnTypes(); colTypErr != nil {
t.Error(colTypErr)
} else if len(columnTypes) != 3 {
t.Error("number of columnTypes")
} else if name := columnTypes[0].Name(); name != "test" {
t.Errorf("field 'test' has a wrong name '%s'", name)
} else if dbType := columnTypes[0].DatabaseTypeName(); dbType != "VARCHAR" {
t.Errorf("field 'test' has a wrong db type '%s'", dbType)
} else if columnTypes[0].ScanType().Kind() != reflect.String {
t.Error("field 'test' has a wrong scanType")
} else if _, _, ok := columnTypes[0].DecimalSize(); ok {
t.Error("field 'test' should have not precision, scale")
} else if length, ok := columnTypes[0].Length(); length != 100 || !ok {
t.Errorf("field 'test' has a wrong length '%d'", length)
} else if name := columnTypes[1].Name(); name != "number" {
t.Errorf("field 'number' has a wrong name '%s'", name)
} else if dbType := columnTypes[1].DatabaseTypeName(); dbType != "DECIMAL" {
t.Errorf("field 'number' has a wrong db type '%s'", dbType)
} else if columnTypes[1].ScanType().Kind() != reflect.Float64 {
t.Error("field 'number' has a wrong scanType")
} else if precision, scale, ok := columnTypes[1].DecimalSize(); precision != int64(10) || scale != int64(4) || !ok {
t.Error("field 'number' has a wrong precision, scale")
} else if _, ok := columnTypes[1].Length(); ok {
t.Error("field 'number' is not variable length type")
} else if _, ok := columnTypes[2].Nullable(); ok {
t.Error("field 'when' should have nullability unknown")
}
} else {
t.Error("no result set")
}
query.Close()
if false == isQueryClosed.fulfilled() {
t.Error("Query is not executed")
}
db.Close()
if false == isDbClosed.fulfilled() {
t.Error("Db is not closed")
}
})
t.Run("with more then one ResultSet", func(t *testing.T) {
db, mock, _ := New()
column1 := mock.NewColumn("test").OfType("VARCHAR", "").Nullable(true).WithLength(100)
column2 := mock.NewColumn("number").OfType("DECIMAL", float64(0.0)).Nullable(false).WithPrecisionAndScale(10, 4)
column3 := mock.NewColumn("when").OfType("TIMESTAMP", now)
rows1 := mock.NewRowsWithColumnDefinition(column1, column2, column3)
rows1.AddRow("foo.bar", float64(10.123), now)
rows2 := mock.NewRowsWithColumnDefinition(column1, column2, column3)
rows2.AddRow("bar.foo", float64(123.10), now.Add(time.Second*10))
rows3 := mock.NewRowsWithColumnDefinition(column1, column2, column3)
rows3.AddRow("lollipop", float64(10.321), now.Add(time.Second*20))
mQuery := mock.ExpectQuery("SELECT test, number, when from dummy")
isQuery := mQuery.WillReturnRows(rows1, rows2, rows3)
isQueryClosed := mQuery.RowsWillBeClosed()
isDbClosed := mock.ExpectClose()
query, _ := db.Query("SELECT test, number, when from dummy")
if false == isQuery.fulfilled() {
t.Error("Query is not executed")
}
rowsSi := 0
for query.Next() {
var test string
var number float64
var when time.Time
if queryError := query.Scan(&test, &number, &when); queryError != nil {
t.Error(queryError)
} else if rowsSi == 0 && test != "foo.bar" {
t.Error("field test is not 'foo.bar'")
} else if rowsSi == 0 && number != float64(10.123) {
t.Error("field number is not '10.123'")
} else if rowsSi == 0 && when != now {
t.Errorf("field when is not %v", now)
} else if rowsSi == 1 && test != "bar.foo" {
t.Error("field test is not 'bar.bar'")
} else if rowsSi == 1 && number != float64(123.10) {
t.Error("field number is not '123.10'")
} else if rowsSi == 1 && when != now.Add(time.Second*10) {
t.Errorf("field when is not %v", now)
} else if rowsSi == 2 && test != "lollipop" {
t.Error("field test is not 'lollipop'")
} else if rowsSi == 2 && number != float64(10.321) {
t.Error("field number is not '10.321'")
} else if rowsSi == 2 && when != now.Add(time.Second*20) {
t.Errorf("field when is not %v", now)
}
rowsSi++
if columnTypes, colTypErr := query.ColumnTypes(); colTypErr != nil {
t.Error(colTypErr)
} else if len(columnTypes) != 3 {
t.Error("number of columnTypes")
} else if name := columnTypes[0].Name(); name != "test" {
t.Errorf("field 'test' has a wrong name '%s'", name)
} else if dbType := columnTypes[0].DatabaseTypeName(); dbType != "VARCHAR" {
t.Errorf("field 'test' has a wrong db type '%s'", dbType)
} else if columnTypes[0].ScanType().Kind() != reflect.String {
t.Error("field 'test' has a wrong scanType")
} else if _, _, ok := columnTypes[0].DecimalSize(); ok {
t.Error("field 'test' should not have precision, scale")
} else if length, ok := columnTypes[0].Length(); length != 100 || !ok {
t.Errorf("field 'test' has a wrong length '%d'", length)
} else if name := columnTypes[1].Name(); name != "number" {
t.Errorf("field 'number' has a wrong name '%s'", name)
} else if dbType := columnTypes[1].DatabaseTypeName(); dbType != "DECIMAL" {
t.Errorf("field 'number' has a wrong db type '%s'", dbType)
} else if columnTypes[1].ScanType().Kind() != reflect.Float64 {
t.Error("field 'number' has a wrong scanType")
} else if precision, scale, ok := columnTypes[1].DecimalSize(); precision != int64(10) || scale != int64(4) || !ok {
t.Error("field 'number' has a wrong precision, scale")
} else if _, ok := columnTypes[1].Length(); ok {
t.Error("field 'number' is not variable length type")
} else if _, ok := columnTypes[2].Nullable(); ok {
t.Error("field 'when' should have nullability unknown")
}
}
if rowsSi == 0 {
t.Error("no result set")
}
query.Close()
if false == isQueryClosed.fulfilled() {
t.Error("Query is not executed")
}
db.Close()
if false == isDbClosed.fulfilled() {
t.Error("Db is not closed")
}
})
}