1
2
3
4
5 package binding
6
7 import (
8 "bytes"
9 "io"
10 "mime/multipart"
11 "net/http"
12 "testing"
13
14 "github.com/stretchr/testify/assert"
15 )
16
17 func TestFormMultipartBindingBindOneFile(t *testing.T) {
18 var s struct {
19 FileValue multipart.FileHeader `form:"file"`
20 FilePtr *multipart.FileHeader `form:"file"`
21 SliceValues []multipart.FileHeader `form:"file"`
22 SlicePtrs []*multipart.FileHeader `form:"file"`
23 ArrayValues [1]multipart.FileHeader `form:"file"`
24 ArrayPtrs [1]*multipart.FileHeader `form:"file"`
25 }
26 file := testFile{"file", "file1", []byte("hello")}
27
28 req := createRequestMultipartFiles(t, file)
29 err := FormMultipart.Bind(req, &s)
30 assert.NoError(t, err)
31
32 assertMultipartFileHeader(t, &s.FileValue, file)
33 assertMultipartFileHeader(t, s.FilePtr, file)
34 assert.Len(t, s.SliceValues, 1)
35 assertMultipartFileHeader(t, &s.SliceValues[0], file)
36 assert.Len(t, s.SlicePtrs, 1)
37 assertMultipartFileHeader(t, s.SlicePtrs[0], file)
38 assertMultipartFileHeader(t, &s.ArrayValues[0], file)
39 assertMultipartFileHeader(t, s.ArrayPtrs[0], file)
40 }
41
42 func TestFormMultipartBindingBindTwoFiles(t *testing.T) {
43 var s struct {
44 SliceValues []multipart.FileHeader `form:"file"`
45 SlicePtrs []*multipart.FileHeader `form:"file"`
46 ArrayValues [2]multipart.FileHeader `form:"file"`
47 ArrayPtrs [2]*multipart.FileHeader `form:"file"`
48 }
49 files := []testFile{
50 {"file", "file1", []byte("hello")},
51 {"file", "file2", []byte("world")},
52 }
53
54 req := createRequestMultipartFiles(t, files...)
55 err := FormMultipart.Bind(req, &s)
56 assert.NoError(t, err)
57
58 assert.Len(t, s.SliceValues, len(files))
59 assert.Len(t, s.SlicePtrs, len(files))
60 assert.Len(t, s.ArrayValues, len(files))
61 assert.Len(t, s.ArrayPtrs, len(files))
62
63 for i, file := range files {
64 assertMultipartFileHeader(t, &s.SliceValues[i], file)
65 assertMultipartFileHeader(t, s.SlicePtrs[i], file)
66 assertMultipartFileHeader(t, &s.ArrayValues[i], file)
67 assertMultipartFileHeader(t, s.ArrayPtrs[i], file)
68 }
69 }
70
71 func TestFormMultipartBindingBindError(t *testing.T) {
72 files := []testFile{
73 {"file", "file1", []byte("hello")},
74 {"file", "file2", []byte("world")},
75 }
76
77 for _, tt := range []struct {
78 name string
79 s any
80 }{
81 {"wrong type", &struct {
82 Files int `form:"file"`
83 }{}},
84 {"wrong array size", &struct {
85 Files [1]*multipart.FileHeader `form:"file"`
86 }{}},
87 {"wrong slice type", &struct {
88 Files []int `form:"file"`
89 }{}},
90 } {
91 req := createRequestMultipartFiles(t, files...)
92 err := FormMultipart.Bind(req, tt.s)
93 assert.Error(t, err)
94 }
95 }
96
97 type testFile struct {
98 Fieldname string
99 Filename string
100 Content []byte
101 }
102
103 func createRequestMultipartFiles(t *testing.T, files ...testFile) *http.Request {
104 var body bytes.Buffer
105
106 mw := multipart.NewWriter(&body)
107 for _, file := range files {
108 fw, err := mw.CreateFormFile(file.Fieldname, file.Filename)
109 assert.NoError(t, err)
110
111 n, err := fw.Write(file.Content)
112 assert.NoError(t, err)
113 assert.Equal(t, len(file.Content), n)
114 }
115 err := mw.Close()
116 assert.NoError(t, err)
117
118 req, err := http.NewRequest("POST", "/", &body)
119 assert.NoError(t, err)
120
121 req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+mw.Boundary())
122 return req
123 }
124
125 func assertMultipartFileHeader(t *testing.T, fh *multipart.FileHeader, file testFile) {
126 assert.Equal(t, file.Filename, fh.Filename)
127 assert.Equal(t, int64(len(file.Content)), fh.Size)
128
129 fl, err := fh.Open()
130 assert.NoError(t, err)
131
132 body, err := io.ReadAll(fl)
133 assert.NoError(t, err)
134 assert.Equal(t, string(file.Content), string(body))
135
136 err = fl.Close()
137 assert.NoError(t, err)
138 }
139
View as plain text