|
1 | 1 | package toml
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "bytes" |
4 | 5 | "encoding/json"
|
| 6 | + "errors" |
5 | 7 | "fmt"
|
6 | 8 | "io/ioutil"
|
7 | 9 | "math"
|
8 | 10 | "os"
|
9 | 11 | "reflect"
|
| 12 | + "strconv" |
10 | 13 | "strings"
|
11 | 14 | "testing"
|
12 | 15 | "time"
|
@@ -1014,6 +1017,129 @@ func TestMetaDotConflict(t *testing.T) {
|
1014 | 1017 | }
|
1015 | 1018 | }
|
1016 | 1019 |
|
| 1020 | +type ( |
| 1021 | + Outer struct { |
| 1022 | + Int *InnerInt |
| 1023 | + Enum *Enum |
| 1024 | + Slice *InnerArrayString |
| 1025 | + } |
| 1026 | + Enum int |
| 1027 | + InnerString struct{ value string } |
| 1028 | + InnerInt struct{ value int } |
| 1029 | + InnerBool struct{ value bool } |
| 1030 | + InnerArrayString struct{ value []string } |
| 1031 | +) |
| 1032 | + |
| 1033 | +const ( |
| 1034 | + NoValue Enum = iota |
| 1035 | + OtherValue |
| 1036 | +) |
| 1037 | + |
| 1038 | +func (e *Enum) Value() string { |
| 1039 | + switch *e { |
| 1040 | + case OtherValue: |
| 1041 | + return "OTHER_VALUE" |
| 1042 | + } |
| 1043 | + return "" |
| 1044 | +} |
| 1045 | + |
| 1046 | +func (e *Enum) MarshalTOML() ([]byte, error) { |
| 1047 | + return []byte(`"` + e.Value() + `"`), nil |
| 1048 | +} |
| 1049 | + |
| 1050 | +func (e *Enum) UnmarshalTOML(value interface{}) error { |
| 1051 | + sValue, ok := value.(string) |
| 1052 | + if !ok { |
| 1053 | + return fmt.Errorf("value %v is not a string type", value) |
| 1054 | + } |
| 1055 | + for _, enum := range []Enum{NoValue, OtherValue} { |
| 1056 | + if enum.Value() == sValue { |
| 1057 | + *e = enum |
| 1058 | + return nil |
| 1059 | + } |
| 1060 | + } |
| 1061 | + return errors.New("invalid enum value") |
| 1062 | +} |
| 1063 | + |
| 1064 | +func (i *InnerInt) MarshalTOML() ([]byte, error) { |
| 1065 | + return []byte(strconv.Itoa(i.value)), nil |
| 1066 | +} |
| 1067 | +func (i *InnerInt) UnmarshalTOML(value interface{}) error { |
| 1068 | + iValue, ok := value.(int64) |
| 1069 | + if !ok { |
| 1070 | + return fmt.Errorf("value %v is not a int type", value) |
| 1071 | + } |
| 1072 | + i.value = int(iValue) |
| 1073 | + return nil |
| 1074 | +} |
| 1075 | + |
| 1076 | +func (as *InnerArrayString) MarshalTOML() ([]byte, error) { |
| 1077 | + return []byte("[\"" + strings.Join(as.value, "\", \"") + "\"]"), nil |
| 1078 | +} |
| 1079 | + |
| 1080 | +func (as *InnerArrayString) UnmarshalTOML(value interface{}) error { |
| 1081 | + if value != nil { |
| 1082 | + asValue, ok := value.([]interface{}) |
| 1083 | + if !ok { |
| 1084 | + return fmt.Errorf("value %v is not a [] type", value) |
| 1085 | + } |
| 1086 | + as.value = []string{} |
| 1087 | + for _, value := range asValue { |
| 1088 | + as.value = append(as.value, value.(string)) |
| 1089 | + } |
| 1090 | + } |
| 1091 | + return nil |
| 1092 | +} |
| 1093 | + |
| 1094 | +// Test for #341 |
| 1095 | +func TestCustomEncode(t *testing.T) { |
| 1096 | + enum := OtherValue |
| 1097 | + outer := Outer{ |
| 1098 | + Int: &InnerInt{value: 10}, |
| 1099 | + Enum: &enum, |
| 1100 | + Slice: &InnerArrayString{value: []string{"text1", "text2"}}, |
| 1101 | + } |
| 1102 | + |
| 1103 | + var buf bytes.Buffer |
| 1104 | + err := NewEncoder(&buf).Encode(outer) |
| 1105 | + if err != nil { |
| 1106 | + t.Errorf("Encode failed: %s", err) |
| 1107 | + } |
| 1108 | + |
| 1109 | + have := strings.TrimSpace(buf.String()) |
| 1110 | + want := strings.ReplaceAll(strings.TrimSpace(` |
| 1111 | + Int = 10 |
| 1112 | + Enum = "OTHER_VALUE" |
| 1113 | + Slice = ["text1", "text2"] |
| 1114 | + `), "\t", "") |
| 1115 | + if want != have { |
| 1116 | + t.Errorf("\nhave: %s\nwant: %s\n", have, want) |
| 1117 | + } |
| 1118 | +} |
| 1119 | + |
| 1120 | +// Test for #341 |
| 1121 | +func TestCustomDecode(t *testing.T) { |
| 1122 | + var outer Outer |
| 1123 | + _, err := Decode(` |
| 1124 | + Int = 10 |
| 1125 | + Enum = "OTHER_VALUE" |
| 1126 | + Slice = ["text1", "text2"] |
| 1127 | + `, &outer) |
| 1128 | + if err != nil { |
| 1129 | + t.Fatal(fmt.Sprintf("Decode failed: %s", err)) |
| 1130 | + } |
| 1131 | + |
| 1132 | + if outer.Int.value != 10 { |
| 1133 | + t.Errorf("\nhave:\n%v\nwant:\n%v\n", outer.Int.value, 10) |
| 1134 | + } |
| 1135 | + if *outer.Enum != OtherValue { |
| 1136 | + t.Errorf("\nhave:\n%v\nwant:\n%v\n", outer.Enum, OtherValue) |
| 1137 | + } |
| 1138 | + if fmt.Sprint(outer.Slice.value) != fmt.Sprint([]string{"text1", "text2"}) { |
| 1139 | + t.Errorf("\nhave:\n%v\nwant:\n%v\n", outer.Slice.value, []string{"text1", "text2"}) |
| 1140 | + } |
| 1141 | +} |
| 1142 | + |
1017 | 1143 | // errorContains checks if the error message in have contains the text in
|
1018 | 1144 | // want.
|
1019 | 1145 | //
|
|
0 commit comments