mirror of
https://github.com/ent/ent.git
synced 2026-04-28 05:30:56 +03:00
368 lines
9.8 KiB
Go
368 lines
9.8 KiB
Go
// Copyright 2019-present Facebook Inc. All rights reserved.
|
|
// This source code is licensed under the Apache 2.0 license found
|
|
// in the LICENSE file in the root directory of this source tree.
|
|
|
|
package sql
|
|
|
|
import (
|
|
"database/sql"
|
|
"database/sql/driver"
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/DATA-DOG/go-sqlmock"
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestScanSlice(t *testing.T) {
|
|
mock := sqlmock.NewRows([]string{"name"}).
|
|
AddRow("foo").
|
|
AddRow("bar")
|
|
var v0 []string
|
|
require.NoError(t, ScanSlice(toRows(mock), &v0))
|
|
require.Equal(t, []string{"foo", "bar"}, v0)
|
|
|
|
mock = sqlmock.NewRows([]string{"age"}).
|
|
AddRow(1).
|
|
AddRow(2)
|
|
var v1 []int
|
|
require.NoError(t, ScanSlice(toRows(mock), &v1))
|
|
require.Equal(t, []int{1, 2}, v1)
|
|
|
|
mock = sqlmock.NewRows([]string{"name", "COUNT(*)"}).
|
|
AddRow("foo", 1).
|
|
AddRow("bar", 2)
|
|
var v2 []struct {
|
|
Name string
|
|
Count int
|
|
}
|
|
require.NoError(t, ScanSlice(toRows(mock), &v2))
|
|
require.Equal(t, "foo", v2[0].Name)
|
|
require.Equal(t, "bar", v2[1].Name)
|
|
require.Equal(t, 1, v2[0].Count)
|
|
require.Equal(t, 2, v2[1].Count)
|
|
|
|
mock = sqlmock.NewRows([]string{"nick_name", "COUNT(*)"}).
|
|
AddRow("foo", 1).
|
|
AddRow("bar", 2)
|
|
var v3 []struct {
|
|
Count int
|
|
Name string `json:"nick_name"`
|
|
}
|
|
require.NoError(t, ScanSlice(toRows(mock), &v3))
|
|
require.Equal(t, "foo", v3[0].Name)
|
|
require.Equal(t, "bar", v3[1].Name)
|
|
require.Equal(t, 1, v3[0].Count)
|
|
require.Equal(t, 2, v3[1].Count)
|
|
|
|
mock = sqlmock.NewRows([]string{"nick_name", "COUNT(*)"}).
|
|
AddRow("foo", 1).
|
|
AddRow("bar", 2)
|
|
var v4 []*struct {
|
|
Count int
|
|
Name string `json:"nick_name"`
|
|
Ignored string `json:"string"`
|
|
}
|
|
require.NoError(t, ScanSlice(toRows(mock), &v4))
|
|
require.Equal(t, "foo", v4[0].Name)
|
|
require.Equal(t, "bar", v4[1].Name)
|
|
require.Equal(t, 1, v4[0].Count)
|
|
require.Equal(t, 2, v4[1].Count)
|
|
|
|
mock = sqlmock.NewRows([]string{"nick_name", "COUNT(*)"}).
|
|
AddRow("foo", 1).
|
|
AddRow("bar", 2)
|
|
var v5 []*struct {
|
|
Count int
|
|
Name string `json:"name" sql:"nick_name"`
|
|
}
|
|
require.NoError(t, ScanSlice(toRows(mock), &v5))
|
|
require.Equal(t, "foo", v5[0].Name)
|
|
require.Equal(t, "bar", v5[1].Name)
|
|
require.Equal(t, 1, v5[0].Count)
|
|
require.Equal(t, 2, v5[1].Count)
|
|
|
|
mock = sqlmock.NewRows([]string{"age", "name"}).
|
|
AddRow(1, nil).
|
|
AddRow(nil, "a8m")
|
|
var v6 []struct {
|
|
Age NullInt64
|
|
Name NullString
|
|
}
|
|
require.NoError(t, ScanSlice(toRows(mock), &v6))
|
|
require.EqualValues(t, 1, v6[0].Age.Int64)
|
|
require.False(t, v6[0].Name.Valid)
|
|
require.False(t, v6[1].Age.Valid)
|
|
require.Equal(t, "a8m", v6[1].Name.String)
|
|
|
|
u1, u2 := uuid.New().String(), uuid.New().String()
|
|
mock = sqlmock.NewRows([]string{"ids"}).
|
|
AddRow([]byte(u1)).
|
|
AddRow([]byte(u2))
|
|
var ids []uuid.UUID
|
|
require.NoError(t, ScanSlice(toRows(mock), &ids))
|
|
require.Equal(t, u1, ids[0].String())
|
|
require.Equal(t, u2, ids[1].String())
|
|
|
|
mock = sqlmock.NewRows([]string{"pids"}).
|
|
AddRow([]byte(u1)).
|
|
AddRow([]byte(u2))
|
|
var pids []*uuid.UUID
|
|
require.NoError(t, ScanSlice(toRows(mock), &pids))
|
|
require.Equal(t, u1, pids[0].String())
|
|
require.Equal(t, u2, pids[1].String())
|
|
|
|
mock = sqlmock.NewRows([]string{"id", "first", "last"}).
|
|
AddRow(10, "Ariel", "Mashraki")
|
|
err := ScanSlice(toRows(mock), nil)
|
|
require.EqualError(t, err, "sql/scan: ScanSlice(nil)")
|
|
type P struct {
|
|
_ int
|
|
ID int
|
|
First string
|
|
Last string
|
|
}
|
|
var p []P
|
|
err = ScanSlice(toRows(mock), p)
|
|
require.EqualError(t, err, "sql/scan: ScanSlice(non-pointer []sql.P)")
|
|
|
|
require.NoError(t, ScanSlice(toRows(mock), &p))
|
|
require.Equal(t, 10, p[0].ID)
|
|
require.Equal(t, "Ariel", p[0].First)
|
|
require.Equal(t, "Mashraki", p[0].Last)
|
|
|
|
var pp []struct{ _, id int }
|
|
mock = sqlmock.NewRows([]string{"id"}).
|
|
AddRow(10)
|
|
err = ScanSlice(toRows(mock), &pp)
|
|
require.EqualError(t, err, "sql/scan: missing struct field for column: id (id)")
|
|
require.Empty(t, pp)
|
|
}
|
|
|
|
func TestScanSlice_CamelTags(t *testing.T) {
|
|
mock := sqlmock.NewRows([]string{"nickName"}).
|
|
AddRow("foo").
|
|
AddRow("bar")
|
|
var v []*struct {
|
|
NickName string `json:"nickName"`
|
|
}
|
|
require.NoError(t, ScanSlice(toRows(mock), &v))
|
|
require.Equal(t, "foo", v[0].NickName)
|
|
}
|
|
|
|
func TestScanJSON(t *testing.T) {
|
|
mock := sqlmock.NewRows([]string{"v", "p"}).
|
|
AddRow([]byte(`{"i": 1, "s":"a8m"}`), []byte(`{"i": 1, "s":"a8m"}`)).
|
|
AddRow([]byte(`{"i": 2, "s":"tmr"}`), []byte(`{"i": 2, "s":"tmr"}`)).
|
|
AddRow([]byte(nil), []byte(`null`)).
|
|
AddRow(nil, nil)
|
|
var v1 []*struct {
|
|
V struct {
|
|
I int `json:"i"`
|
|
S string `json:"s"`
|
|
} `json:"v"`
|
|
P *struct {
|
|
I int `json:"i"`
|
|
S string `json:"s"`
|
|
} `json:"p"`
|
|
}
|
|
require.NoError(t, ScanSlice(toRows(mock), &v1))
|
|
require.Equal(t, 1, v1[0].V.I)
|
|
require.Equal(t, "a8m", v1[0].V.S)
|
|
require.Equal(t, v1[0].V, *v1[0].P)
|
|
require.Equal(t, 2, v1[1].V.I)
|
|
require.Equal(t, "tmr", v1[1].V.S)
|
|
require.Equal(t, v1[1].V, *v1[1].P)
|
|
require.Equal(t, 0, v1[2].V.I)
|
|
require.Equal(t, "", v1[2].V.S)
|
|
require.Nil(t, v1[2].P)
|
|
require.Equal(t, 0, v1[3].V.I)
|
|
require.Equal(t, "", v1[3].V.S)
|
|
require.Nil(t, v1[3].P)
|
|
|
|
mock = sqlmock.NewRows([]string{"v", "p"}).
|
|
AddRow([]byte(`[1]`), []byte(`[1]`)).
|
|
AddRow([]byte(`[2]`), []byte(`[2]`))
|
|
var v2 []*struct {
|
|
V []int `json:"v"`
|
|
P *[]int `json:"p"`
|
|
}
|
|
require.NoError(t, ScanSlice(toRows(mock), &v2))
|
|
require.Equal(t, []int{1}, v2[0].V)
|
|
require.Equal(t, v2[0].V, *v2[0].P)
|
|
require.Equal(t, []int{2}, v2[1].V)
|
|
require.Equal(t, v2[1].V, *v2[1].P)
|
|
|
|
mock = sqlmock.NewRows([]string{"v", "p"}).
|
|
AddRow([]byte(`null`), []byte(`{}`)).
|
|
AddRow(nil, nil)
|
|
var v3 []*struct {
|
|
V json.RawMessage `json:"v"`
|
|
P *json.RawMessage `json:"p"`
|
|
}
|
|
require.NoError(t, ScanSlice(toRows(mock), &v3))
|
|
require.Equal(t, json.RawMessage("null"), v3[0].V)
|
|
require.Equal(t, json.RawMessage("{}"), *v3[0].P)
|
|
require.Equal(t, json.RawMessage(nil), v3[1].V)
|
|
require.Nil(t, v3[1].P)
|
|
|
|
// Unmarshal errors.
|
|
mock = sqlmock.NewRows([]string{"v", "p"}).
|
|
AddRow([]byte(`{invalid}`), []byte(`{}`))
|
|
require.EqualError(t, ScanSlice(toRows(mock), &v1), `unmarshal field "V": invalid character 'i' looking for beginning of object key string`)
|
|
mock = sqlmock.NewRows([]string{"v", "p"}).
|
|
AddRow([]byte(``), []byte(``))
|
|
require.EqualError(t, ScanSlice(toRows(mock), &v1), `unmarshal field "V": unexpected end of JSON input`)
|
|
}
|
|
|
|
func TestScanNestedStruct(t *testing.T) {
|
|
mock := sqlmock.NewRows([]string{"name", "age"}).
|
|
AddRow("foo", 1).
|
|
AddRow("bar", 2).
|
|
AddRow("baz", nil)
|
|
type T struct{ Name string }
|
|
var v []struct {
|
|
T
|
|
Age int
|
|
}
|
|
require.NoError(t, ScanSlice(toRows(mock), &v))
|
|
require.Equal(t, "foo", v[0].Name)
|
|
require.Equal(t, 1, v[0].Age)
|
|
require.Equal(t, "bar", v[1].Name)
|
|
require.Equal(t, 2, v[1].Age)
|
|
require.Equal(t, "baz", v[2].Name)
|
|
require.Equal(t, 0, v[2].Age)
|
|
|
|
mock = sqlmock.NewRows([]string{"name", "age"}).
|
|
AddRow("foo", 1).
|
|
AddRow("bar", nil)
|
|
type T1 struct{ Name **string }
|
|
var v1 []struct {
|
|
T1
|
|
Age *int
|
|
}
|
|
require.NoError(t, ScanSlice(toRows(mock), &v1))
|
|
require.Equal(t, "foo", **v1[0].Name)
|
|
require.Equal(t, "bar", **v1[1].Name)
|
|
require.Equal(t, 1, *v1[0].Age)
|
|
require.Nil(t, v1[1].Age)
|
|
}
|
|
|
|
func TestScanSlicePtr(t *testing.T) {
|
|
mock := sqlmock.NewRows([]string{"name"}).
|
|
AddRow("foo").
|
|
AddRow("bar")
|
|
var v0 []*string
|
|
require.NoError(t, ScanSlice(toRows(mock), &v0))
|
|
require.Equal(t, "foo", *v0[0])
|
|
require.Equal(t, "bar", *v0[1])
|
|
|
|
mock = sqlmock.NewRows([]string{"age"}).
|
|
AddRow(1).
|
|
AddRow(2)
|
|
var v1 []**int
|
|
require.NoError(t, ScanSlice(toRows(mock), &v1))
|
|
require.Equal(t, 1, **v1[0])
|
|
require.Equal(t, 2, **v1[1])
|
|
|
|
mock = sqlmock.NewRows([]string{"age", "name"}).
|
|
AddRow(1, "a8m").
|
|
AddRow(2, "nati")
|
|
var v2 []*struct {
|
|
Age *int
|
|
Name **string
|
|
}
|
|
require.NoError(t, ScanSlice(toRows(mock), &v2))
|
|
require.Equal(t, 1, *v2[0].Age)
|
|
require.Equal(t, "a8m", **v2[0].Name)
|
|
require.Equal(t, 2, *v2[1].Age)
|
|
require.Equal(t, "nati", **v2[1].Name)
|
|
}
|
|
|
|
func TestScanInt64(t *testing.T) {
|
|
mock := sqlmock.NewRows([]string{"age"}).
|
|
AddRow("10").
|
|
AddRow("20")
|
|
n, err := ScanInt64(toRows(mock))
|
|
require.Error(t, err)
|
|
require.Zero(t, n)
|
|
|
|
mock = sqlmock.NewRows([]string{"age", "count"}).
|
|
AddRow("10", "1")
|
|
n, err = ScanInt64(toRows(mock))
|
|
require.Error(t, err)
|
|
require.Zero(t, n)
|
|
|
|
mock = sqlmock.NewRows([]string{"count"}).
|
|
AddRow(10)
|
|
n, err = ScanInt64(toRows(mock))
|
|
require.NoError(t, err)
|
|
require.EqualValues(t, 10, n)
|
|
|
|
mock = sqlmock.NewRows([]string{"count"}).
|
|
AddRow("10")
|
|
n, err = ScanInt64(toRows(mock))
|
|
require.NoError(t, err)
|
|
require.EqualValues(t, 10, n)
|
|
}
|
|
|
|
func TestScanValue(t *testing.T) {
|
|
mock := sqlmock.NewRows([]string{"count"}).
|
|
AddRow(10)
|
|
n, err := ScanValue(toRows(mock))
|
|
require.NoError(t, err)
|
|
require.EqualValues(t, 10, n)
|
|
}
|
|
|
|
func TestScanOne(t *testing.T) {
|
|
mock := sqlmock.NewRows([]string{"name"}).
|
|
AddRow("10").
|
|
AddRow("20")
|
|
err := ScanOne(toRows(mock), new(string))
|
|
require.Error(t, err, "multiple lines")
|
|
|
|
mock = sqlmock.NewRows([]string{"name"}).
|
|
AddRow("10")
|
|
err = ScanOne(toRows(mock), "")
|
|
require.Error(t, err, "not a pointer")
|
|
|
|
mock = sqlmock.NewRows([]string{"name"}).
|
|
AddRow("10")
|
|
var s string
|
|
err = ScanOne(toRows(mock), &s)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "10", s)
|
|
}
|
|
|
|
func TestInterface(t *testing.T) {
|
|
mock := sqlmock.NewRows([]string{"age"}).
|
|
AddRow("10").
|
|
AddRow("20")
|
|
var values []driver.Value
|
|
err := ScanSlice(toRows(mock), &values)
|
|
require.NoError(t, err)
|
|
require.Equal(t, []driver.Value{"10", "20"}, values)
|
|
|
|
mock = sqlmock.NewRows([]string{"age"}).
|
|
AddRow(10).
|
|
AddRow(20)
|
|
values = values[:0:0]
|
|
err = ScanSlice(toRows(mock), &values)
|
|
require.NoError(t, err)
|
|
require.Equal(t, []driver.Value{int64(10), int64(20)}, values)
|
|
}
|
|
|
|
func TestScanTypeOf(t *testing.T) {
|
|
mock := &Rows{ColumnScanner: toRows(sqlmock.NewRows([]string{"age"}).AddRow(10))}
|
|
tv := ScanTypeOf(mock, 0)
|
|
require.IsType(t, (*any)(nil), tv)
|
|
}
|
|
|
|
func toRows(mrows *sqlmock.Rows) *sql.Rows {
|
|
db, mock, _ := sqlmock.New()
|
|
mock.ExpectQuery("").WillReturnRows(mrows)
|
|
rows, _ := db.Query("")
|
|
return rows
|
|
}
|