Compare commits

..

No commits in common. "22f01d3ab22ea32800cb234032551abe33fb8b7f" and "0d8af97e2c59ffbfe45121e52581be5411714ec5" have entirely different histories.

5 changed files with 102 additions and 461 deletions

2
go.mod
View File

@ -4,7 +4,6 @@ go 1.19
require (
git.tcp.direct/kayos/common v0.9.7
github.com/davecgh/go-spew v1.1.1
github.com/fasthttp/router v1.5.1
github.com/knadh/koanf/parsers/toml v0.1.0
github.com/knadh/koanf/providers/basicflag v1.0.0
@ -12,7 +11,6 @@ require (
github.com/knadh/koanf/v2 v2.1.1
github.com/rs/zerolog v1.33.0
github.com/valyala/fasthttp v1.55.0
golang.org/x/text v0.16.0
)
require (

3
go.sum
View File

@ -4,7 +4,6 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fasthttp/router v1.5.1 h1:uViy8UYYhm5npJSKEZ4b/ozM//NGzVCfJbh6VJ0VKr8=
github.com/fasthttp/router v1.5.1/go.mod h1:WrmsLo3mrerZP2VEXRV1E8nL8ymJFYCDTr4HmnB8+Zs=
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c=
@ -50,8 +49,6 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
nullprogram.com/x/rng v1.1.0 h1:SMU7DHaQSWtKJNTpNFIFt8Wd/KSmOuSDPXrMFp/UMro=
nullprogram.com/x/rng v1.1.0/go.mod h1:glGw6V87vyfawxCzqOABL3WfL95G65az9Z2JZCylCkg=

View File

@ -1,336 +0,0 @@
package toml
import (
"bytes"
"errors"
"fmt"
"io"
"reflect"
"strconv"
"strings"
"git.tcp.direct/kayos/common/pool"
"github.com/davecgh/go-spew/spew"
"golang.org/x/text/encoding/unicode"
)
var (
ErrInvalidTOML = errors.New("invalid TOML")
ErrBadTarget = errors.New("bad target")
ErrMismatchingSchema = errors.New("mismatching schema types")
)
type decoder struct {
buf *pool.Buffer
utf8 io.Reader
target interface{}
inArray bool
tables map[string]interface{}
}
func newDecoder(input []byte, v interface{}) *decoder {
d := &decoder{
target: v,
utf8: unicode.UTF8.NewDecoder().Reader(bytes.NewReader(input)),
tables: make(map[string]interface{}),
}
return d
}
func (d *decoder) nextTableName() (tableName []byte, err error) {
if _, err = d.buf.ReadBytes('['); err != nil {
return nil, fmt.Errorf("%w (%w): %w", ErrInvalidTOML, io.ErrUnexpectedEOF, err)
}
if tableName, err = d.buf.ReadBytes(']'); err != nil {
if errors.Is(err, io.EOF) {
err = fmt.Errorf("%w: missing ']'", io.ErrUnexpectedEOF)
}
return nil, fmt.Errorf("%w: %w", ErrInvalidTOML, err)
}
tableName = tableName[:len(tableName)-1]
return tableName, nil
}
func handleBool(v any) (bool, error) {
vBool, boolOK := v.(bool)
vInt, intOK := v.(int64)
vStr, strOK := v.(string)
switch {
case intOK:
if vInt == 0 || vInt == 1 {
vBool = vInt == 1
boolOK = true
}
case strOK:
parsedBool, parseErr := strconv.ParseBool(vStr)
if parseErr != nil {
return false, fmt.Errorf("%w: expected bool-ish: %w", ErrMismatchingSchema, parseErr)
}
vBool = parsedBool
boolOK = true
case boolOK:
default:
}
if !boolOK {
return false, fmt.Errorf("%w: expected bool, got %T", ErrMismatchingSchema, v)
}
return vBool, nil
}
func handleBottom(targetElem reflect.Value, v any, j int) error {
if !targetElem.CanSet() {
return fmt.Errorf("%w: cannot set field", ErrBadTarget)
}
println(targetElem.Type().Kind().String())
switch targetElem.Kind() {
case reflect.String:
vStr, strOK := v.(string)
if !strOK {
return fmt.Errorf("%w: expected string, got %T", ErrMismatchingSchema, v)
}
targetElem.SetString(vStr)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
vInt, intOK := v.(int64)
if !intOK {
return fmt.Errorf("%w: expected int, got %T", ErrMismatchingSchema, v)
}
targetElem.SetInt(vInt)
case reflect.Slice:
switch field := targetElem; field.Type().Elem().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
vInt, intOK := v.([]int64)
if !intOK {
return fmt.Errorf("%w: expected int slice, got %T", ErrMismatchingSchema, v)
}
slice := reflect.MakeSlice(field.Type().Elem(), len(vInt), len(vInt))
for i := 0; i < len(vInt); i++ {
slice.Index(i).SetInt(vInt[i])
}
targetElem.Field(j).Set(slice)
case reflect.String:
vStr, strOK := v.([]string)
if !strOK {
return fmt.Errorf("%w: expected string slice, got %T", ErrMismatchingSchema, v)
}
slice := reflect.MakeSlice(field.Type().Elem(), len(vStr), len(vStr))
for i := 0; i < len(vStr); i++ {
slice.Index(i).SetString(vStr[i])
}
targetElem.Field(j).Set(slice)
}
case reflect.Bool:
vBool, boolErr := handleBool(v)
if boolErr != nil {
return fmt.Errorf("%w: %w", ErrMismatchingSchema, boolErr)
}
targetElem.Field(j).SetBool(vBool)
}
return nil
}
func (d *decoder) handleLine(lines []string, i int, myTable map[string]interface{}) error {
var key string
var value interface{}
split := strings.SplitN(lines[i], "=", 2)
if len(split) != 2 {
return nil
}
key = strings.TrimSpace(split[0])
valueString := strings.TrimSpace(split[1])
if valueString == "[" {
d.inArray = true
var continued []byte
var err error
continued, err = d.buf.ReadBytes(']')
if err != nil {
return fmt.Errorf("%w: %w in mthe middle of array %w", ErrInvalidTOML, io.ErrUnexpectedEOF, err)
}
valueString += string(continued)
valueString = strings.ReplaceAll(valueString, "\n", "")
}
switch {
case d.inArray:
valueString = strings.Trim(valueString, "[]")
asplit := strings.Split(valueString, ",")
intVals := make([]int64, 0, len(asplit))
for aindex := range asplit {
asplit[aindex] = strings.Trim(strings.TrimSpace(asplit[aindex]), "\"'")
avalInt, intErr := strconv.ParseInt(valueString, 10, 64)
if intErr == nil {
intVals = append(intVals, avalInt)
}
println("array value: ", asplit[aindex])
}
if len(intVals) == len(asplit) && len(intVals) > 0 {
value = intVals
} else {
value = asplit
}
d.inArray = false
default:
valueString = strings.Trim(valueString, "\"'")
valBool, boolErr := strconv.ParseBool(valueString)
valInt, intErr := strconv.ParseInt(valueString, 10, 64)
switch {
case boolErr == nil:
value = valBool
case intErr == nil:
value = valInt
default:
value = valueString
}
}
if value == nil || key == "" || len(valueString) == 0 {
return io.EOF
}
fmt.Printf("key: %s, value(%T): %v\n", key, value, value)
myTable[key] = value
return nil
}
func findStructTag(struc reflect.Value, sought string) (int, error) {
for i := 0; i < struc.NumField(); i++ {
if struc.Type().Field(i).Tag.Get("toml") == sought {
return i, nil
}
}
return -1, fmt.Errorf("%w: %s", ErrMismatchingSchema, sought)
}
func (d *decoder) handleTables() error {
spew.Dump(d.tables)
for k, v := range d.tables {
if !strings.Contains(k, ".") {
vTable, tableOK := v.(map[string]interface{})
if !tableOK {
return fmt.Errorf("%w: expected table, got %T", ErrMismatchingSchema, v)
}
println("table:", vTable)
targetElem := reflect.ValueOf(d.target).Elem()
fieldIndex, fieldErr := findStructTag(targetElem, k)
if fieldErr != nil {
continue
}
println("field index: ", fieldIndex)
if targetElem.Field(fieldIndex).Type().Kind() != reflect.Struct {
return fmt.Errorf("%w: expected struct, got %T", ErrMismatchingSchema, targetElem.Field(fieldIndex).Type())
}
}
}
return nil
}
func (d *decoder) start() error {
d.buf = bufs.Get()
defer bufs.MustPut(d.buf)
n, err := d.buf.ReadFrom(d.utf8)
if err == nil && n == 0 {
err = io.ErrUnexpectedEOF
}
if err != nil {
return fmt.Errorf("%w: %w", ErrInvalidTOML, err)
}
for d.buf.Len() > 0 {
var tableName []byte
var tableNameErr error
if tableName, tableNameErr = d.nextTableName(); tableNameErr != nil && !errors.Is(tableNameErr, io.EOF) {
return tableNameErr
}
println("table: ", string(tableName))
myTable, mapAssertOK := d.tables[string(tableName)].(map[string]interface{})
if !mapAssertOK {
d.tables[string(tableName)] = make(map[string]interface{})
myTable = d.tables[string(tableName)].(map[string]interface{}) //nolint:forcetypeassert
}
var tableData []byte
if tableData, err = d.buf.ReadBytes('['); err != nil && !errors.Is(err, io.EOF) {
return fmt.Errorf("%w: %w", ErrInvalidTOML, err)
}
tableDataStr := string(tableData)
lines := strings.Split(tableDataStr, "\n")
if strings.Contains(lines[len(lines)-1], "[") && !strings.Contains(lines[len(lines)-1], "=") {
_ = d.buf.UnreadByte()
}
for i := 0; i < len(lines); i++ {
if err = d.handleLine(lines, i, myTable); err != nil {
if errors.Is(err, io.EOF) {
break
}
return err
}
}
if len(d.tables) == 0 {
return fmt.Errorf("%w: empty TOML, %w", ErrInvalidTOML, io.ErrUnexpectedEOF)
}
}
return d.handleTables()
}
func trimTest(data []byte) (trimmed []byte) {
for _, c := range []byte{' ', '\n', '\t', '\r', '[', ']', '='} {
trimmed = bytes.ReplaceAll(data, []byte{c}, []byte(""))
}
return
}
func UnmarshalTOML(data []byte, v interface{}) error {
var err error
if data, err = unicode.UTF8.NewDecoder().Bytes(data); err != nil {
return err
}
if !bytes.Contains(data, []byte("[")) {
return fmt.Errorf("%w: missing '['", ErrInvalidTOML)
}
if !bytes.Contains(data, []byte("]")) {
return fmt.Errorf("%w: missing ']'", ErrInvalidTOML)
}
if !bytes.Contains(data, []byte("=")) {
return fmt.Errorf("%w: missing '='", ErrInvalidTOML)
}
if len(trimTest(data)) < 2 {
return fmt.Errorf("%w: empty TOML", ErrInvalidTOML)
}
ref := reflect.ValueOf(v)
if ref.Kind() != reflect.Ptr {
return fmt.Errorf("%w: non-pointer", ErrBadTarget)
}
if ref.IsNil() {
return fmt.Errorf("%w: nil pointer", ErrBadTarget)
}
if ref.Elem().Kind() != reflect.Struct {
return fmt.Errorf("%w: non-struct", ErrBadTarget)
}
data = bytes.ReplaceAll(data, []byte("\r"), []byte(""))
return newDecoder(data, v).start()
}

View File

@ -23,7 +23,7 @@ type subStruct struct {
parent *subStruct
}
func (sub *subStruct) writeTableHeader(buf *pool.Buffer) {
func (sub *subStruct) writeKey(buf *pool.Buffer) {
parent := sub.parent
var parents = make([]string, 0)
for parent != nil {
@ -33,22 +33,28 @@ func (sub *subStruct) writeTableHeader(buf *pool.Buffer) {
slices.Reverse(parents)
parents = append(parents, sub.name)
if len(parents) > 1 {
writeTableHeaders(buf, parents[0], parents[1:]...)
writeKey(buf, parents[0], parents[1:]...)
}
if len(parents) == 1 {
writeTableHeaders(buf, parents[0], parents[1:]...)
writeKey(buf, parents[0], parents[1:]...)
}
}
func mustValidateTableName(tableName string) {
for _, b := range tableName {
func mustValidateKey(key string) {
for _, b := range key {
if !unicode.IsLetter(b) && b != '.' && b != '_' {
panic("table name must contain only letters, bad character: " + string(b))
panic("key must contain only letters, bad character: " + string(b))
}
}
}
func shouldSkip(field reflect.StructField) (skip bool) {
defer func() {
if skip {
print("should skip: " + field.Name + " (tag: " + field.Tag.Get("toml") + ")? ")
println(strconv.FormatBool(skip))
}
}()
if !field.IsExported() || field.Tag.Get("toml") == "-" {
skip = true
return
@ -56,13 +62,13 @@ func shouldSkip(field reflect.StructField) (skip bool) {
return
}
func writeTableHeaders(buf *pool.Buffer, tableName string, subTableNames ...string) {
mustValidateTableName(tableName)
func writeKey(buf *pool.Buffer, key string, subkeys ...string) {
mustValidateKey(key)
_, _ = buf.WriteString("[")
_, _ = buf.WriteString(tableName)
if len(subTableNames) > 0 {
for _, sub := range subTableNames {
mustValidateTableName(sub)
_, _ = buf.WriteString(key)
if len(subkeys) > 0 {
for _, sub := range subkeys {
mustValidateKey(sub)
_, _ = buf.WriteString(".")
_, _ = buf.WriteString(sub)
}
@ -80,7 +86,7 @@ func handlePanic(err error) error {
panic(r)
}
ve := &reflect.ValueError{}
if !errors.As(r.(error), &ve) { //golint:forcetypeassert
if !errors.As(r.(error), &ve) {
panic(r)
}
if err == nil {
@ -117,7 +123,6 @@ func handleBottomLevelField(field reflect.StructField, ref reflect.Value, buf *p
}
_, _ = buf.WriteString(field.Tag.Get("toml"))
_, _ = buf.WriteString(" = ")
//goland:noinspection GoSwitchMissingCasesForIotaConsts
switch ref.Kind() {
case reflect.String:
if err := handleString(ref.String(), buf); err != nil {
@ -130,8 +135,7 @@ func handleBottomLevelField(field reflect.StructField, ref reflect.Value, buf *p
case reflect.Bool:
_, _ = buf.WriteString(strconv.FormatBool(ref.Bool()))
case reflect.Slice:
//goland:noinspection GoSwitchMissingCasesForIotaConsts
switch ref.Type().Elem().Kind() { //nolint:exhaustive
switch ref.Type().Elem().Kind() {
case reflect.String:
if ref.Len() == 0 {
return nil
@ -146,18 +150,6 @@ func handleBottomLevelField(field reflect.StructField, ref reflect.Value, buf *p
}
}
_, _ = buf.WriteString("]")
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if ref.Len() == 0 {
return nil
}
_, _ = buf.WriteString("[")
for i := 0; i < ref.Len(); i++ {
_, _ = buf.WriteString(strconv.FormatInt(ref.Index(i).Int(), 10))
if i < ref.Len()-1 {
_, _ = buf.WriteString(", ")
}
}
_, _ = buf.WriteString("]")
}
}
@ -167,6 +159,14 @@ func handleBottomLevelField(field reflect.StructField, ref reflect.Value, buf *p
}
func allChildrenEmpty(sub reflect.Value) (empty bool, err error) {
/* var additionalMsg string
defer func() {
debugMsg := "allChildrenEmpty in '" + sub.Type().Name() + "'? " + strconv.FormatBool(empty)
if additionalMsg != "" {
debugMsg += ": " + additionalMsg
}
println(debugMsg)
}()*/
if sub.Kind() != reflect.Struct {
return false, errors.New("input to allChildrenEmpty must be a struct")
}
@ -194,22 +194,24 @@ func (sub *subStruct) handleSubStructField(field reflect.StructField, ref reflec
return nil
}
if field.Type.Kind() == reflect.Ptr {
println("pointer: " + field.Name)
ref = ref.Elem()
if !ref.IsValid() {
println("invalid pointer: " + field.Name)
return nil
}
}
ft := ref.Type()
switch ft.Kind() { //nolint:exhaustive
switch ft.Kind() {
case reflect.Struct:
child := &subStruct{name: field.Tag.Get("toml"), ref: ref, parent: sub}
if empty, err := allChildrenEmpty(ref); empty || err != nil {
return err
}
_, _ = buf.WriteString("\n")
child.writeTableHeader(buf)
child.writeKey(buf)
for i := 0; i < ft.NumField(); i++ {
if err := child.handleSubStructField(ft.Field(i), ref.Field(i), buf); err != nil {
return err
@ -246,7 +248,7 @@ func handleFieldTopLevel(field reflect.StructField, ref reflect.Value, buf *pool
}
child := &subStruct{name: field.Tag.Get("toml"), parent: nil, ref: ref}
child.writeTableHeader(buf)
child.writeKey(buf)
for i := 0; i < ref.NumField(); i++ {
if err := child.handleSubStructField(ref.Type().Field(i), ref.Field(i), buf); err != nil {
@ -283,3 +285,7 @@ func MarshalTOML(v interface{}) (data []byte, err error) {
return bytes.TrimSpace(buf.Bytes()), nil
}
func UnmarshalTOML(data []byte, v interface{}) error {
return nil
}

View File

@ -2,11 +2,8 @@ package toml
import (
"errors"
"reflect"
"strings"
"testing"
"github.com/davecgh/go-spew/spew"
)
var (
@ -20,55 +17,57 @@ var (
testResErrFmt = "\n" + wantedErr + "\n%s\n" + actualErr + "\n%s\n" + divErr + "\n"
)
type test struct {
Name string
Unmarshaled any
Marshaled []byte
wantError error
type Test struct {
Name string
UnmarshalInput []byte
UnmarshalOutput any
MarshalInput any
MarshalOutput []byte
wantError error
}
type TestGeets struct {
Geeters string `toml:"geeters"`
YeetIndex []int `toml:"yeet_index"`
type Geets struct {
Geeters string `toml:"geeters"`
}
type TestMcGeeParameters struct {
Username string `toml:"username"`
SkipTag string `toml:"-"`
SubGeet *TestGeets `toml:"sub_geet"`
type McGeeParameters struct {
Username string `toml:"username"`
SkipTag string `toml:"-"`
SubGeet *Geets `toml:"sub_geet"`
}
type TestYeetersonParameters struct {
ServerName string `toml:"server_name"`
DenyList []string `toml:"deny_list"`
PortNumber int `toml:"port_number"`
YeetMode bool `toml:"yeet_mode"`
McGee TestMcGeeParameters `toml:"mcgeet"`
unexported string `toml:"unexported"` //golint:unused
type YeetersonParameters struct {
ServerName string `toml:"server_name"`
DenyList []string `toml:"deny_list"`
PortNumber int `toml:"port_number"`
YeetMode bool `toml:"yeet_mode"`
McGee McGeeParameters `toml:"mcgeet"`
unexported string `toml:"unexported"` //golint:unused
}
type parameters struct {
Yeeterson TestYeetersonParameters `toml:"yeet"`
McGee TestMcGeeParameters `toml:"mcgee"`
SkipMe string `toml:"-"`
type Parameters struct {
Yeeterson YeetersonParameters `toml:"yeet"`
McGee McGeeParameters `toml:"mcgee"`
SkipMe string `toml:"-"`
skipMe string `toml:"skip_me"` //golint:unused
}
var simpleYeeterson = TestYeetersonParameters{
var simpleYeeterson = YeetersonParameters{
ServerName: "yeeterson",
DenyList: []string{"yeet", "yeeterson", "yeeterson.com"},
PortNumber: 8080,
YeetMode: true,
}
var (
test1 = test{
//nolint:funlen
func TestMarshalTOML(t *testing.T) {
test1 := Test{
Name: "simple",
Unmarshaled: parameters{
MarshalInput: Parameters{
Yeeterson: simpleYeeterson,
McGee: TestMcGeeParameters{
McGee: McGeeParameters{
Username: "mcgee",
},
},
Marshaled: []byte(`[yeet]
MarshalOutput: []byte(`[yeet]
server_name = "yeeterson"
deny_list = ["yeet", "yeeterson", "yeeterson.com"]
port_number = 8080
@ -78,22 +77,22 @@ yeet_mode = true
username = "mcgee"`),
}
test2 = test{
Name: "with empty string, negative number, spaced strings, punctuation",
Unmarshaled: parameters{
Yeeterson: TestYeetersonParameters{
test2 := Test{
Name: "with empty string, negative number, spaced strings, and punctuation",
MarshalInput: Parameters{
Yeeterson: YeetersonParameters{
ServerName: "",
DenyList: []string{"yeet it."},
PortNumber: -5,
YeetMode: false,
},
McGee: TestMcGeeParameters{
McGee: McGeeParameters{
Username: "the yeet guy",
SkipTag: "skip me",
},
SkipMe: "skip me",
},
Marshaled: []byte(`[yeet]
MarshalOutput: []byte(`[yeet]
server_name = ""
deny_list = ["yeet it."]
port_number = -5
@ -103,25 +102,25 @@ yeet_mode = false
username = "the yeet guy"`),
}
yeetersonWithChild = TestYeetersonParameters{
yeetersonWithChild := YeetersonParameters{
ServerName: simpleYeeterson.ServerName,
DenyList: simpleYeeterson.DenyList,
PortNumber: simpleYeeterson.PortNumber,
YeetMode: simpleYeeterson.YeetMode,
McGee: TestMcGeeParameters{
McGee: McGeeParameters{
Username: "Yeeterson McGeeterson",
},
}
test3 = test{
test3 := Test{
Name: "with sub-structs",
Unmarshaled: parameters{
MarshalInput: Parameters{
Yeeterson: yeetersonWithChild,
McGee: TestMcGeeParameters{
McGee: McGeeParameters{
Username: "mcgee",
},
},
Marshaled: []byte(`[yeet]
MarshalOutput: []byte(`[yeet]
server_name = "yeeterson"
deny_list = ["yeet", "yeeterson", "yeeterson.com"]
port_number = 8080
@ -134,72 +133,49 @@ username = "Yeeterson McGeeterson"
username = "mcgee"`),
}
test4 = test{
test4 := Test{
Name: "with empty structs",
Unmarshaled: parameters{
Yeeterson: TestYeetersonParameters{},
McGee: TestMcGeeParameters{
MarshalInput: Parameters{
Yeeterson: YeetersonParameters{},
McGee: McGeeParameters{
Username: "mcgeets",
SubGeet: &TestGeets{},
SubGeet: &Geets{},
},
},
Marshaled: []byte(`[mcgee]
MarshalOutput: []byte(`[mcgee]
username = "mcgeets"`),
}
test5 = test{
test5 := Test{
Name: "with pointer struct",
Unmarshaled: parameters{
Yeeterson: TestYeetersonParameters{},
McGee: TestMcGeeParameters{
MarshalInput: Parameters{
Yeeterson: YeetersonParameters{},
McGee: McGeeParameters{
Username: "geetsies",
SubGeet: &TestGeets{Geeters: "geets", YeetIndex: []int{1, 2, 3}},
SubGeet: &Geets{Geeters: "geets"},
},
},
Marshaled: []byte(`[mcgee]
MarshalOutput: []byte(`[mcgee]
username = "geetsies"
[mcgee.sub_geet]
geeters = "geets"
yeet_index = [1, 2, 3]`),
geeters = "geets"`),
}
tests = []test{test1, test2, test3, test4, test5}
)
tests := []Test{test1, test2, test3, test4, test5}
//nolint:funlen
func TestMarshalTOML(t *testing.T) {
for _, tt := range tests {
t.Run(tt.Name, func(t *testing.T) {
output, err := MarshalTOML(tt.Unmarshaled)
if !errors.Is(err, tt.wantError) {
for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
output, err := MarshalTOML(test.MarshalInput)
if !errors.Is(err, test.wantError) {
errWantString := "nil"
if tt.wantError != nil {
errWantString = tt.wantError.Error()
if test.wantError != nil {
errWantString = test.wantError.Error()
}
t.Errorf(testResErrFmt, errWantString, err)
}
if string(output) != string(tt.Marshaled) {
t.Errorf(testResFmt, tt.Marshaled, output)
}
})
}
}
func TestUnmarshalTOML(t *testing.T) {
for _, tt := range tests {
t.Run(tt.Name, func(t *testing.T) {
output := new(parameters)
err := UnmarshalTOML(tt.Marshaled, output)
if !errors.Is(err, tt.wantError) {
errWantString := "nil"
if tt.wantError != nil {
errWantString = tt.wantError.Error()
}
t.Errorf(testResErrFmt, errWantString, err)
}
if !reflect.DeepEqual(*output, tt.Unmarshaled) {
t.Errorf(testResFmt, tt.Unmarshaled, spew.Sdump(*output))
if string(output) != string(test.MarshalOutput) {
t.Errorf(testResFmt, test.MarshalOutput, output)
}
})
}