mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-12-25 13:54:05 -06:00
375 lines
9.5 KiB
Go
375 lines
9.5 KiB
Go
package toml
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestEncode(t *testing.T) {
|
|
type Embedded struct {
|
|
Int int `toml:"_int"`
|
|
}
|
|
type NonStruct int
|
|
|
|
date := time.Date(2014, 5, 11, 19, 30, 40, 0, time.UTC)
|
|
dateStr := "2014-05-11T19:30:40Z"
|
|
|
|
tests := map[string]struct {
|
|
input interface{}
|
|
wantOutput string
|
|
wantError error
|
|
}{
|
|
"bool field": {
|
|
input: struct {
|
|
BoolTrue bool
|
|
BoolFalse bool
|
|
}{true, false},
|
|
wantOutput: "BoolTrue = true\nBoolFalse = false\n",
|
|
},
|
|
"int fields": {
|
|
input: struct {
|
|
Int int
|
|
Int8 int8
|
|
Int16 int16
|
|
Int32 int32
|
|
Int64 int64
|
|
}{1, 2, 3, 4, 5},
|
|
wantOutput: "Int = 1\nInt8 = 2\nInt16 = 3\nInt32 = 4\nInt64 = 5\n",
|
|
},
|
|
"uint fields": {
|
|
input: struct {
|
|
Uint uint
|
|
Uint8 uint8
|
|
Uint16 uint16
|
|
Uint32 uint32
|
|
Uint64 uint64
|
|
}{1, 2, 3, 4, 5},
|
|
wantOutput: "Uint = 1\nUint8 = 2\nUint16 = 3\nUint32 = 4" +
|
|
"\nUint64 = 5\n",
|
|
},
|
|
"float fields": {
|
|
input: struct {
|
|
Float32 float32
|
|
Float64 float64
|
|
}{1.5, 2.5},
|
|
wantOutput: "Float32 = 1.5\nFloat64 = 2.5\n",
|
|
},
|
|
"string field": {
|
|
input: struct{ String string }{"foo"},
|
|
wantOutput: "String = \"foo\"\n",
|
|
},
|
|
"string field with \\n escape": {
|
|
input: struct{ String string }{"foo\n"},
|
|
wantOutput: "String = \"foo\\n\"\n",
|
|
},
|
|
"string field and unexported field": {
|
|
input: struct {
|
|
String string
|
|
unexported int
|
|
}{"foo", 0},
|
|
wantOutput: "String = \"foo\"\n",
|
|
},
|
|
"datetime field in UTC": {
|
|
input: struct{ Date time.Time }{date},
|
|
wantOutput: fmt.Sprintf("Date = %s\n", dateStr),
|
|
},
|
|
"datetime field as primitive": {
|
|
// Using a map here to fail if isStructOrMap() returns true for
|
|
// time.Time.
|
|
input: map[string]interface{}{
|
|
"Date": date,
|
|
"Int": 1,
|
|
},
|
|
wantOutput: fmt.Sprintf("Date = %s\nInt = 1\n", dateStr),
|
|
},
|
|
"array fields": {
|
|
input: struct {
|
|
IntArray0 [0]int
|
|
IntArray3 [3]int
|
|
}{[0]int{}, [3]int{1, 2, 3}},
|
|
wantOutput: "IntArray0 = []\nIntArray3 = [1, 2, 3]\n",
|
|
},
|
|
"slice fields": {
|
|
input: struct{ IntSliceNil, IntSlice0, IntSlice3 []int }{
|
|
nil, []int{}, []int{1, 2, 3},
|
|
},
|
|
wantOutput: "IntSlice0 = []\nIntSlice3 = [1, 2, 3]\n",
|
|
},
|
|
"datetime slices": {
|
|
input: struct{ DatetimeSlice []time.Time }{
|
|
[]time.Time{date, date},
|
|
},
|
|
wantOutput: fmt.Sprintf("DatetimeSlice = [%s, %s]\n",
|
|
dateStr, dateStr),
|
|
},
|
|
"nested arrays and slices": {
|
|
input: struct {
|
|
SliceOfArrays [][2]int
|
|
ArrayOfSlices [2][]int
|
|
SliceOfArraysOfSlices [][2][]int
|
|
ArrayOfSlicesOfArrays [2][][2]int
|
|
SliceOfMixedArrays [][2]interface{}
|
|
ArrayOfMixedSlices [2][]interface{}
|
|
}{
|
|
[][2]int{{1, 2}, {3, 4}},
|
|
[2][]int{{1, 2}, {3, 4}},
|
|
[][2][]int{
|
|
{
|
|
{1, 2}, {3, 4},
|
|
},
|
|
{
|
|
{5, 6}, {7, 8},
|
|
},
|
|
},
|
|
[2][][2]int{
|
|
{
|
|
{1, 2}, {3, 4},
|
|
},
|
|
{
|
|
{5, 6}, {7, 8},
|
|
},
|
|
},
|
|
[][2]interface{}{
|
|
{1, 2}, {"a", "b"},
|
|
},
|
|
[2][]interface{}{
|
|
{1, 2}, {"a", "b"},
|
|
},
|
|
},
|
|
wantOutput: `SliceOfArrays = [[1, 2], [3, 4]]
|
|
ArrayOfSlices = [[1, 2], [3, 4]]
|
|
SliceOfArraysOfSlices = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
|
|
ArrayOfSlicesOfArrays = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
|
|
SliceOfMixedArrays = [[1, 2], ["a", "b"]]
|
|
ArrayOfMixedSlices = [[1, 2], ["a", "b"]]
|
|
`,
|
|
},
|
|
"empty slice": {
|
|
input: struct{ Empty []interface{} }{[]interface{}{}},
|
|
wantOutput: "Empty = []\n",
|
|
},
|
|
"(error) slice with element type mismatch (string and integer)": {
|
|
input: struct{ Mixed []interface{} }{[]interface{}{1, "a"}},
|
|
wantOutput: "Mixed = [1, \"a\"]\n",
|
|
},
|
|
"(error) slice with element type mismatch (integer and float)": {
|
|
input: struct{ Mixed []interface{} }{[]interface{}{1, 2.5}},
|
|
wantOutput: "Mixed = [1, 2.5]\n",
|
|
},
|
|
"slice with elems of differing Go types, same TOML types": {
|
|
input: struct {
|
|
MixedInts []interface{}
|
|
MixedFloats []interface{}
|
|
}{
|
|
[]interface{}{
|
|
int(1), int8(2), int16(3), int32(4), int64(5),
|
|
uint(1), uint8(2), uint16(3), uint32(4), uint64(5),
|
|
},
|
|
[]interface{}{float32(1.5), float64(2.5)},
|
|
},
|
|
wantOutput: "MixedInts = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]\n" +
|
|
"MixedFloats = [1.5, 2.5]\n",
|
|
},
|
|
"(error) slice w/ element type mismatch (one is nested array)": {
|
|
input: struct{ Mixed []interface{} }{
|
|
[]interface{}{1, []interface{}{2}},
|
|
},
|
|
wantOutput: "Mixed = [1, [2]]\n",
|
|
},
|
|
"(error) slice with 1 nil element": {
|
|
input: struct{ NilElement1 []interface{} }{[]interface{}{nil}},
|
|
wantError: errArrayNilElement,
|
|
},
|
|
"(error) slice with 1 nil element (and other non-nil elements)": {
|
|
input: struct{ NilElement []interface{} }{
|
|
[]interface{}{1, nil},
|
|
},
|
|
wantError: errArrayNilElement,
|
|
},
|
|
"simple map": {
|
|
input: map[string]int{"a": 1, "b": 2},
|
|
wantOutput: "a = 1\nb = 2\n",
|
|
},
|
|
"map with interface{} value type": {
|
|
input: map[string]interface{}{"a": 1, "b": "c"},
|
|
wantOutput: "a = 1\nb = \"c\"\n",
|
|
},
|
|
"map with interface{} value type, some of which are structs": {
|
|
input: map[string]interface{}{
|
|
"a": struct{ Int int }{2},
|
|
"b": 1,
|
|
},
|
|
wantOutput: "b = 1\n\n[a]\n Int = 2\n",
|
|
},
|
|
"nested map": {
|
|
input: map[string]map[string]int{
|
|
"a": {"b": 1},
|
|
"c": {"d": 2},
|
|
},
|
|
wantOutput: "[a]\n b = 1\n\n[c]\n d = 2\n",
|
|
},
|
|
"nested struct": {
|
|
input: struct{ Struct struct{ Int int } }{
|
|
struct{ Int int }{1},
|
|
},
|
|
wantOutput: "[Struct]\n Int = 1\n",
|
|
},
|
|
"nested struct and non-struct field": {
|
|
input: struct {
|
|
Struct struct{ Int int }
|
|
Bool bool
|
|
}{struct{ Int int }{1}, true},
|
|
wantOutput: "Bool = true\n\n[Struct]\n Int = 1\n",
|
|
},
|
|
"2 nested structs": {
|
|
input: struct{ Struct1, Struct2 struct{ Int int } }{
|
|
struct{ Int int }{1}, struct{ Int int }{2},
|
|
},
|
|
wantOutput: "[Struct1]\n Int = 1\n\n[Struct2]\n Int = 2\n",
|
|
},
|
|
"deeply nested structs": {
|
|
input: struct {
|
|
Struct1, Struct2 struct{ Struct3 *struct{ Int int } }
|
|
}{
|
|
struct{ Struct3 *struct{ Int int } }{&struct{ Int int }{1}},
|
|
struct{ Struct3 *struct{ Int int } }{nil},
|
|
},
|
|
wantOutput: "[Struct1]\n [Struct1.Struct3]\n Int = 1" +
|
|
"\n\n[Struct2]\n",
|
|
},
|
|
"nested struct with nil struct elem": {
|
|
input: struct {
|
|
Struct struct{ Inner *struct{ Int int } }
|
|
}{
|
|
struct{ Inner *struct{ Int int } }{nil},
|
|
},
|
|
wantOutput: "[Struct]\n",
|
|
},
|
|
"nested struct with no fields": {
|
|
input: struct {
|
|
Struct struct{ Inner struct{} }
|
|
}{
|
|
struct{ Inner struct{} }{struct{}{}},
|
|
},
|
|
wantOutput: "[Struct]\n [Struct.Inner]\n",
|
|
},
|
|
"struct with tags": {
|
|
input: struct {
|
|
Struct struct {
|
|
Int int `toml:"_int"`
|
|
} `toml:"_struct"`
|
|
Bool bool `toml:"_bool"`
|
|
}{
|
|
struct {
|
|
Int int `toml:"_int"`
|
|
}{1}, true,
|
|
},
|
|
wantOutput: "_bool = true\n\n[_struct]\n _int = 1\n",
|
|
},
|
|
"embedded struct": {
|
|
input: struct{ Embedded }{Embedded{1}},
|
|
wantOutput: "_int = 1\n",
|
|
},
|
|
"embedded *struct": {
|
|
input: struct{ *Embedded }{&Embedded{1}},
|
|
wantOutput: "_int = 1\n",
|
|
},
|
|
"nested embedded struct": {
|
|
input: struct {
|
|
Struct struct{ Embedded } `toml:"_struct"`
|
|
}{struct{ Embedded }{Embedded{1}}},
|
|
wantOutput: "[_struct]\n _int = 1\n",
|
|
},
|
|
"nested embedded *struct": {
|
|
input: struct {
|
|
Struct struct{ *Embedded } `toml:"_struct"`
|
|
}{struct{ *Embedded }{&Embedded{1}}},
|
|
wantOutput: "[_struct]\n _int = 1\n",
|
|
},
|
|
"embedded non-struct": {
|
|
input: struct{ NonStruct }{5},
|
|
wantOutput: "NonStruct = 5\n",
|
|
},
|
|
"array of tables": {
|
|
input: struct {
|
|
Structs []*struct{ Int int } `toml:"struct"`
|
|
}{
|
|
[]*struct{ Int int }{{1}, {3}},
|
|
},
|
|
wantOutput: "[[struct]]\n Int = 1\n\n[[struct]]\n Int = 3\n",
|
|
},
|
|
"array of tables order": {
|
|
input: map[string]interface{}{
|
|
"map": map[string]interface{}{
|
|
"zero": 5,
|
|
"arr": []map[string]int{
|
|
{
|
|
"friend": 5,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
wantOutput: "[map]\n zero = 5\n\n [[map.arr]]\n friend = 5\n",
|
|
},
|
|
"empty key name": {
|
|
input: map[string]int{"": 1},
|
|
wantOutput: `"" = 1` + "\n",
|
|
},
|
|
"key with \\n escape": {
|
|
input: map[string]string{"\n": "\n"},
|
|
wantOutput: `"\n" = "\n"` + "\n",
|
|
},
|
|
|
|
"empty map name": {
|
|
input: map[string]interface{}{
|
|
"": map[string]int{"v": 1},
|
|
},
|
|
wantOutput: "[\"\"]\n v = 1\n",
|
|
},
|
|
"(error) top-level slice": {
|
|
input: []struct{ Int int }{{1}, {2}, {3}},
|
|
wantError: errNoKey,
|
|
},
|
|
"(error) map no string key": {
|
|
input: map[int]string{1: ""},
|
|
wantError: errNonString,
|
|
},
|
|
|
|
"tbl-in-arr-struct": {
|
|
input: struct {
|
|
Arr [][]struct{ A, B, C int }
|
|
}{[][]struct{ A, B, C int }{{{1, 2, 3}, {4, 5, 6}}}},
|
|
wantOutput: "Arr = [[{A = 1, B = 2, C = 3}, {A = 4, B = 5, C = 6}]]",
|
|
},
|
|
|
|
"tbl-in-arr-map": {
|
|
input: map[string]interface{}{
|
|
"arr": []interface{}{[]interface{}{
|
|
map[string]interface{}{
|
|
"a": []interface{}{"hello", "world"},
|
|
"b": []interface{}{1.12, 4.1},
|
|
"c": 1,
|
|
"d": map[string]interface{}{"e": "E"},
|
|
"f": struct{ A, B int }{1, 2},
|
|
"g": []struct{ A, B int }{{3, 4}, {5, 6}},
|
|
},
|
|
}},
|
|
},
|
|
wantOutput: `arr = [[{a = ["hello", "world"], b = [1.12, 4.1], c = 1, d = {e = "E"}, f = {A = 1, B = 2}, g = [{A = 3, B = 4}, {A = 5, B = 6}]}]]`,
|
|
},
|
|
|
|
"slice of slice": {
|
|
input: struct {
|
|
Slices [][]struct{ Int int }
|
|
}{
|
|
[][]struct{ Int int }{{{1}}, {{2}}, {{3}}},
|
|
},
|
|
wantOutput: "Slices = [[{Int = 1}], [{Int = 2}], [{Int = 3}]]",
|
|
},
|
|
}
|
|
for label, test := range tests {
|
|
encodeExpected(t, label, test.input, test.wantOutput, test.wantError)
|
|
}
|
|
}
|