Skip to content

Commit 609628c

Browse files
joeybloggsjoeybloggs
authored andcommitted
Encoder now accepts almost any type, but returns InvalidEncodeError for invalid ones
- for issue-#6 and issue-#7
1 parent 5b3ed79 commit 609628c

File tree

3 files changed

+159
-6
lines changed

3 files changed

+159
-6
lines changed

encoder_test.go

Lines changed: 136 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,120 @@ func TestEncoderStruct(t *testing.T) {
10181018
Equal(t, val[0], tm.Format(time.RFC3339))
10191019
}
10201020

1021+
func TestDecodeAllNonStructTypes(t *testing.T) {
1022+
1023+
encoder := NewEncoder()
1024+
1025+
// test integers
1026+
1027+
i := int(3)
1028+
i8 := int8(2)
1029+
i16 := int16(1)
1030+
i32 := int32(0)
1031+
i64 := int64(3)
1032+
1033+
values, err := encoder.Encode(i)
1034+
Equal(t, err, nil)
1035+
Equal(t, values[""][0], "3")
1036+
1037+
values, err = encoder.Encode(i8)
1038+
Equal(t, err, nil)
1039+
Equal(t, values[""][0], "2")
1040+
1041+
values, err = encoder.Encode(i16)
1042+
Equal(t, err, nil)
1043+
Equal(t, values[""][0], "1")
1044+
1045+
values, err = encoder.Encode(i32)
1046+
Equal(t, err, nil)
1047+
Equal(t, values[""][0], "0")
1048+
1049+
values, err = encoder.Encode(i64)
1050+
Equal(t, err, nil)
1051+
Equal(t, values[""][0], "3")
1052+
1053+
// test unsigned integers
1054+
1055+
ui := uint(3)
1056+
ui8 := uint8(2)
1057+
ui16 := uint16(1)
1058+
ui32 := uint32(0)
1059+
ui64 := uint64(3)
1060+
1061+
values, err = encoder.Encode(ui)
1062+
Equal(t, err, nil)
1063+
Equal(t, values[""][0], "3")
1064+
1065+
values, err = encoder.Encode(ui8)
1066+
Equal(t, err, nil)
1067+
Equal(t, values[""][0], "2")
1068+
1069+
values, err = encoder.Encode(ui16)
1070+
Equal(t, err, nil)
1071+
Equal(t, values[""][0], "1")
1072+
1073+
values, err = encoder.Encode(ui32)
1074+
Equal(t, err, nil)
1075+
Equal(t, values[""][0], "0")
1076+
1077+
values, err = encoder.Encode(ui64)
1078+
Equal(t, err, nil)
1079+
Equal(t, values[""][0], "3")
1080+
1081+
// test bool
1082+
1083+
ok := true
1084+
values, err = encoder.Encode(ok)
1085+
Equal(t, err, nil)
1086+
Equal(t, values[""][0], "true")
1087+
1088+
ok = false
1089+
values, err = encoder.Encode(ok)
1090+
Equal(t, err, nil)
1091+
Equal(t, values[""][0], "false")
1092+
1093+
// test time
1094+
1095+
tm, err := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
1096+
Equal(t, err, nil)
1097+
1098+
values, err = encoder.Encode(tm)
1099+
Equal(t, err, nil)
1100+
Equal(t, values[""][0], "2006-01-02T15:04:05Z")
1101+
1102+
// test basic array
1103+
1104+
arr := []string{"arr1", "arr2"}
1105+
1106+
values, err = encoder.Encode(arr)
1107+
Equal(t, err, nil)
1108+
Equal(t, len(values), 1)
1109+
Equal(t, values[""][0], "arr1")
1110+
Equal(t, values[""][1], "arr2")
1111+
1112+
// test ptr array
1113+
1114+
s1 := "arr1"
1115+
s2 := "arr2"
1116+
arrPtr := []*string{&s1, &s2}
1117+
1118+
values, err = encoder.Encode(arrPtr)
1119+
Equal(t, err, nil)
1120+
Equal(t, len(values), 2)
1121+
Equal(t, values["[0]"][0], "arr1")
1122+
Equal(t, values["[1]"][0], "arr2")
1123+
1124+
// test map
1125+
1126+
m := map[string]string{"key1": "val1", "key2": "val2"}
1127+
1128+
values, err = encoder.Encode(m)
1129+
Equal(t, err, nil)
1130+
Equal(t, len(values), 2)
1131+
Equal(t, values["[key1]"][0], "val1")
1132+
Equal(t, values["[key2]"][0], "val2")
1133+
}
1134+
10211135
func TestEncoderNativeTime(t *testing.T) {
10221136

10231137
type TestError struct {
@@ -1094,9 +1208,29 @@ func TestEncoderErrors(t *testing.T) {
10941208
Equal(t, k.Error(), "Unsupported Map Key '<struct {} Value>' Namespace 'Struct'")
10951209
}
10961210

1097-
func TestEncoderPanic(t *testing.T) {
1211+
func TestEncoderPanicsAndBadValues(t *testing.T) {
10981212

10991213
encoder := NewEncoder()
11001214

1101-
PanicMatches(t, func() { encoder.Encode(nil) }, "interface must be a struct, pointer to a struct or interface containing one of the aforementioned")
1215+
values, err := encoder.Encode(nil)
1216+
NotEqual(t, err, nil)
1217+
Equal(t, values, nil)
1218+
1219+
_, ok := err.(*InvalidEncodeError)
1220+
Equal(t, ok, true)
1221+
Equal(t, err.Error(), "form: Encode(nil)")
1222+
1223+
type TestStruct struct {
1224+
Value string
1225+
}
1226+
1227+
var tst *TestStruct
1228+
1229+
values, err = encoder.Encode(tst)
1230+
NotEqual(t, err, nil)
1231+
Equal(t, values, nil)
1232+
1233+
_, ok = err.(*InvalidEncodeError)
1234+
Equal(t, ok, true)
1235+
Equal(t, err.Error(), "form: Encode(nil *form.TestStruct)")
11021236
}

form_decoder.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,15 @@ type InvalidDecoderError struct {
3535
}
3636

3737
func (e *InvalidDecoderError) Error() string {
38+
3839
if e.Type == nil {
3940
return "form: Decode(nil)"
4041
}
4142

4243
if e.Type.Kind() != reflect.Ptr {
4344
return "form: Decode(non-pointer " + e.Type.String() + ")"
4445
}
46+
4547
return "form: Decode(nil " + e.Type.String() + ")"
4648
}
4749

@@ -123,7 +125,6 @@ func (d *Decoder) Decode(v interface{}, values url.Values) (err error) {
123125

124126
if val.Kind() != reflect.Ptr || val.IsNil() {
125127
return &InvalidDecoderError{reflect.TypeOf(v)}
126-
// panic("interface must be a pointer")
127128
}
128129

129130
val = val.Elem()

form_encoder.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,20 @@ func (e EncodeErrors) Error() string {
2727
return strings.TrimSpace(buff.String())
2828
}
2929

30+
// An InvalidEncodeError describes an invalid argument passed to Encode.
31+
type InvalidEncodeError struct {
32+
Type reflect.Type
33+
}
34+
35+
func (e *InvalidEncodeError) Error() string {
36+
37+
if e.Type == nil {
38+
return "form: Encode(nil)"
39+
}
40+
41+
return "form: Encode(nil " + e.Type.String() + ")"
42+
}
43+
3044
// Encoder is the main encode instance
3145
type Encoder struct {
3246
tagName string
@@ -72,11 +86,15 @@ func (e *Encoder) Encode(v interface{}) (url.Values, error) {
7286

7387
val, kind := ExtractType(reflect.ValueOf(v))
7488

75-
if kind != reflect.Struct {
76-
panic("interface must be a struct, pointer to a struct or interface containing one of the aforementioned")
89+
if kind == reflect.Ptr || kind == reflect.Interface || kind == reflect.Invalid {
90+
return nil, &InvalidEncodeError{reflect.TypeOf(v)}
7791
}
7892

79-
enc.traverseStruct(val, make([]byte, 0, 64), -1)
93+
if kind == reflect.Struct && val.Type() != timeType {
94+
enc.traverseStruct(val, make([]byte, 0, 64), -1)
95+
} else {
96+
enc.setFieldByType(val, make([]byte, 0, 64), -1)
97+
}
8098

8199
if len(enc.errs) == 0 {
82100
return enc.values, nil

0 commit comments

Comments
 (0)