package form_test import ( "errors" "net/url" "strings" "testing" "github.com/google/go-cmp/cmp" "source.toby3d.me/toby3d/form" ) type ( TestResult struct { Skip any `form:"-"` PtrStruct *Struct `form:"ptrStruct"` PtrStructs *Structs `form:"ptrStructs"` NullStruct NullStruct `form:"nullstruct,omitempty"` Struct Struct `form:"struct"` Empty string `form:"empty"` String string `form:"string"` NotFormTag string `json:"notFormTag"` ArrayStruct []Struct `form:"arrayStruct[]"` ArrayPtrStruct []*Struct `form:"arrayPtrStruct[]"` Ints []int `form:"ints[]"` Structs Structs `form:"structs"` Bytes []byte `form:"bytes"` Uint uint `form:"uint"` Int int `form:"int"` Float float32 `form:"float"` Bool bool `form:"bool"` } Struct struct { uid string `form:"-"` } Structs []Struct NullStruct struct { uid string `form:"-"` } ) func TestUnmarshal(t *testing.T) { t.Parallel() t.Run("valid", func(t *testing.T) { t.Parallel() args, err := url.ParseQuery(`skip=dontTouchMe` + `&bool=true` + `&string=hello+world` + `&int=42` + `&uint=420` + `&float=4.2` + // `&interface=a1b2c3` + // TODO(toby3d) `&struct=abc` + `&ptrStruct=123` + `&arrayStruct[]=abc` + `&arrayStruct[]=123` + `&arrayPtrStruct[]=321` + `&arrayPtrStruct[]=bca` + `&ints[]=240` + `&ints[]=420` + `&bytes=sampletext` + `¬FormTag=dontParseMe` + `&structs=123+abc` + `&ptrStructs=bca+321`) if err != nil { t.Fatal(err) } in := new(TestResult) if err := form.Unmarshal([]byte(args.Encode()), in); err != nil { t.Fatal(err) } out := TestResult{ Skip: nil, Bool: true, Float: 4.2, Int: 42, // Interface: []byte("a1b2c3"), // TODO(toby3d) PtrStruct: &Struct{uid: "123"}, String: "hello world", Struct: Struct{uid: "abc"}, Uint: 420, ArrayStruct: []Struct{ {uid: "abc"}, {uid: "123"}, }, ArrayPtrStruct: []*Struct{ {uid: "321"}, {uid: "bca"}, }, Ints: []int{240, 420}, Empty: "", Bytes: []byte("sampletext"), NotFormTag: "", NullStruct: NullStruct{uid: ""}, Structs: Structs{ {uid: "123"}, {uid: "abc"}, }, PtrStructs: &Structs{ {uid: "bca"}, {uid: "321"}, }, } opts := []cmp.Option{ cmp.AllowUnexported(Struct{}, NullStruct{}), } if !cmp.Equal(&out, in, opts...) { t.Errorf("Unmarshal(%s, &in)\n%+s", args.Encode(), cmp.Diff(&out, in, opts...)) } }) t.Run("invalid", func(t *testing.T) { t.Parallel() args, err := url.ParseQuery("arrayStruct[]=wtf") if err != nil { t.Fatal(err) } in := new(TestResult) if err := form.Unmarshal([]byte(args.Encode()), in); err == nil { t.Errorf("Unmarshal(%s, &in) = %#+v, want error", args.Encode(), err) } }) } func (s *Structs) UnmarshalForm(v []byte) error { for _, f := range strings.Fields(string(v)) { *s = append(*s, Struct{uid: f}) } return nil } func (s Structs) GoString() string { out := make([]string, len(s)) for i := range s { out[i] = s[i].uid } return "Structs(" + strings.Join(out, ", ") + ")" } func (s *Struct) UnmarshalForm(v []byte) error { src := string(v) switch src { case "123", "abc", "321", "bca": s.uid = string(v) return nil } return errors.New("Struct: dough!") } func (ns *NullStruct) UnmarshalForm(v []byte) error { if src := string(v); src != "" { ns.uid = src return nil } return errors.New("NullStruct: dough!") } func (s Struct) GoString() string { return "Struct(" + s.uid + ")" }