safing-portmaster/service/netquery/orm/encoder_test.go
2024-03-27 16:17:58 +01:00

261 lines
4.5 KiB
Go

package orm
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"zombiezen.com/go/sqlite"
)
func TestEncodeAsMap(t *testing.T) { //nolint:tparallel
t.Parallel()
ctx := context.TODO()
refTime := time.Date(2022, time.February, 15, 9, 51, 0, 0, time.UTC)
cases := []struct {
Desc string
Input interface{}
Expected map[string]interface{}
}{
{
"Encode basic types",
struct {
I int
F float64
S string
B []byte
}{
I: 1,
F: 1.2,
S: "string",
B: ([]byte)("bytes"),
},
map[string]interface{}{
"I": 1,
"F": 1.2,
"S": "string",
"B": ([]byte)("bytes"),
},
},
{
"Encode using struct tags",
struct {
I int `sqlite:"col_int"`
S string `sqlite:"col_string"`
}{
I: 1,
S: "string value",
},
map[string]interface{}{
"col_int": 1,
"col_string": "string value",
},
},
{
"Ignore Private fields",
struct {
I int
s string
}{
I: 1,
s: "string value",
},
map[string]interface{}{
"I": 1,
},
},
{
"Handle Pointers",
struct {
I *int
S *string
}{
I: new(int),
},
map[string]interface{}{
"I": 0,
"S": nil,
},
},
{
"Handle time.Time types",
struct {
TinInt time.Time `sqlite:",integer,unixnano"`
TinString time.Time `sqlite:",text"`
}{
TinInt: refTime,
TinString: refTime,
},
map[string]interface{}{
"TinInt": refTime.UnixNano(),
"TinString": refTime.Format(SqliteTimeFormat),
},
},
{
"Handle time.Time pointer types",
struct {
TinInt *time.Time `sqlite:",integer,unixnano"`
TinString *time.Time `sqlite:",text"`
Tnil1 *time.Time `sqlite:",text"`
Tnil2 *time.Time `sqlite:",text"`
}{
TinInt: &refTime,
TinString: &refTime,
Tnil1: nil,
Tnil2: (*time.Time)(nil),
},
map[string]interface{}{
"TinInt": refTime.UnixNano(),
"TinString": refTime.Format(SqliteTimeFormat),
"Tnil1": nil,
"Tnil2": nil,
},
},
}
for idx := range cases { //nolint:paralleltest
c := cases[idx]
t.Run(c.Desc, func(t *testing.T) {
res, err := ToParamMap(ctx, c.Input, "", DefaultEncodeConfig, nil)
require.NoError(t, err)
assert.Equal(t, c.Expected, res)
})
}
}
func TestEncodeValue(t *testing.T) { //nolint:tparallel
t.Parallel()
ctx := context.TODO()
refTime := time.Date(2022, time.February, 15, 9, 51, 0, 0, time.UTC)
cases := []struct {
Desc string
Column ColumnDef
Input interface{}
Output interface{}
}{
{
"Special value time.Time as text",
ColumnDef{
IsTime: true,
Type: sqlite.TypeText,
},
refTime,
refTime.Format(SqliteTimeFormat),
},
{
"Special value time.Time as unix-epoch",
ColumnDef{
IsTime: true,
Type: sqlite.TypeInteger,
},
refTime,
refTime.Unix(),
},
{
"Special value time.Time as unixnano-epoch",
ColumnDef{
IsTime: true,
Type: sqlite.TypeInteger,
UnixNano: true,
},
refTime,
refTime.UnixNano(),
},
{
"Special value zero time",
ColumnDef{
IsTime: true,
Type: sqlite.TypeText,
},
time.Time{},
nil,
},
{
"Special value zero time pointer",
ColumnDef{
IsTime: true,
Type: sqlite.TypeText,
},
new(time.Time),
nil,
},
{
"Special value *time.Time as text",
ColumnDef{
IsTime: true,
Type: sqlite.TypeText,
},
&refTime,
refTime.Format(SqliteTimeFormat),
},
{
"Special value untyped nil",
ColumnDef{
Nullable: true,
IsTime: true,
Type: sqlite.TypeText,
},
nil,
nil,
},
{
"Special value typed nil",
ColumnDef{
IsTime: true,
Type: sqlite.TypeText,
},
(*time.Time)(nil),
nil,
},
{
"Time formated as string",
ColumnDef{
IsTime: true,
Type: sqlite.TypeText,
},
refTime.In(time.Local).Format(time.RFC3339),
refTime.Format(SqliteTimeFormat),
},
{
"Nullable integer",
ColumnDef{
Type: sqlite.TypeInteger,
Nullable: true,
},
nil,
nil,
},
{
"Not-Null integer",
ColumnDef{
Name: "test",
Type: sqlite.TypeInteger,
},
nil,
0,
},
{
"Not-Null string",
ColumnDef{
Type: sqlite.TypeText,
},
nil,
"",
},
}
for idx := range cases { //nolint:paralleltest
c := cases[idx]
t.Run(c.Desc, func(t *testing.T) {
res, err := EncodeValue(ctx, &c.Column, c.Input, DefaultEncodeConfig)
require.NoError(t, err)
assert.Equal(t, c.Output, res)
})
}
}