@@ -6,13 +6,192 @@ import (
66 "encoding/json"
77 "fmt"
88 "io"
9+ "mime/multipart"
910 "net/http"
1011 "strings"
1112 "sync"
1213 "testing"
1314 "time"
1415)
1516
17+ // TestMultipartBodySummary 测试 multipartBodySummary 函数
18+ func TestMultipartBodySummary (t * testing.T ) {
19+ // buildMultipart 辅助函数:构造 multipart body 和 Content-Type
20+ buildMultipart := func (fields map [string ]string , files map [string ]string ) (* bytes.Buffer , string ) {
21+ var buf bytes.Buffer
22+ writer := multipart .NewWriter (& buf )
23+ for name , value := range fields {
24+ _ = writer .WriteField (name , value )
25+ }
26+ for fieldName , fileName := range files {
27+ part , _ := writer .CreateFormFile (fieldName , fileName )
28+ _ , _ = part .Write ([]byte ("fake file content" ))
29+ }
30+ _ = writer .Close ()
31+ return & buf , writer .FormDataContentType ()
32+ }
33+
34+ tests := []struct {
35+ name string
36+ buildInput func () (* bytes.Buffer , string )
37+ checkResult func (t * testing.T , result string )
38+ }{
39+ {
40+ name : "单个文本字段" ,
41+ buildInput : func () (* bytes.Buffer , string ) {
42+ return buildMultipart (map [string ]string {"username" : "alice" }, nil )
43+ },
44+ checkResult : func (t * testing.T , result string ) {
45+ if result != "username=alice" {
46+ t .Errorf ("期望 'username=alice',实际 '%s'" , result )
47+ }
48+ },
49+ },
50+ {
51+ name : "多个文本字段" ,
52+ buildInput : func () (* bytes.Buffer , string ) {
53+ var buf bytes.Buffer
54+ writer := multipart .NewWriter (& buf )
55+ // 按顺序写入以保证顺序一致
56+ _ = writer .WriteField ("name" , "bob" )
57+ _ = writer .WriteField ("age" , "30" )
58+ _ = writer .Close ()
59+ return & buf , writer .FormDataContentType ()
60+ },
61+ checkResult : func (t * testing.T , result string ) {
62+ if result != "name=bob&age=30" {
63+ t .Errorf ("期望 'name=bob&age=30',实际 '%s'" , result )
64+ }
65+ },
66+ },
67+ {
68+ name : "单个文件上传" ,
69+ buildInput : func () (* bytes.Buffer , string ) {
70+ return buildMultipart (nil , map [string ]string {"avatar" : "photo.png" })
71+ },
72+ checkResult : func (t * testing.T , result string ) {
73+ if result != "avatar=@photo.png" {
74+ t .Errorf ("期望 'avatar=@photo.png',实际 '%s'" , result )
75+ }
76+ },
77+ },
78+ {
79+ name : "混合字段和文件" ,
80+ buildInput : func () (* bytes.Buffer , string ) {
81+ var buf bytes.Buffer
82+ writer := multipart .NewWriter (& buf )
83+ _ = writer .WriteField ("title" , "my doc" )
84+ part , _ := writer .CreateFormFile ("file" , "document.pdf" )
85+ _ , _ = part .Write ([]byte ("pdf content" ))
86+ _ = writer .Close ()
87+ return & buf , writer .FormDataContentType ()
88+ },
89+ checkResult : func (t * testing.T , result string ) {
90+ if result != "title=my doc&file=@document.pdf" {
91+ t .Errorf ("期望 'title=my doc&file=@document.pdf',实际 '%s'" , result )
92+ }
93+ },
94+ },
95+ {
96+ name : "无效的Content-Type" ,
97+ buildInput : func () (* bytes.Buffer , string ) {
98+ return bytes .NewBufferString ("some data" ), "text/plain"
99+ },
100+ checkResult : func (t * testing.T , result string ) {
101+ if result != "" {
102+ t .Errorf ("无效 Content-Type 应返回空字符串,实际 '%s'" , result )
103+ }
104+ },
105+ },
106+ {
107+ name : "无boundary的Content-Type" ,
108+ buildInput : func () (* bytes.Buffer , string ) {
109+ return bytes .NewBufferString ("some data" ), "multipart/form-data"
110+ },
111+ checkResult : func (t * testing.T , result string ) {
112+ if result != "" {
113+ t .Errorf ("无 boundary 应返回空字符串,实际 '%s'" , result )
114+ }
115+ },
116+ },
117+ {
118+ name : "无法解析的Content-Type" ,
119+ buildInput : func () (* bytes.Buffer , string ) {
120+ return bytes .NewBufferString ("data" ), ";;;invalid;;;"
121+ },
122+ checkResult : func (t * testing.T , result string ) {
123+ if result != "" {
124+ t .Errorf ("无法解析的 Content-Type 应返回空字符串,实际 '%s'" , result )
125+ }
126+ },
127+ },
128+ {
129+ name : "boundary不匹配的无效body" ,
130+ buildInput : func () (* bytes.Buffer , string ) {
131+ return bytes .NewBufferString ("not a valid multipart body" ),
132+ "multipart/form-data; boundary=nonexistent"
133+ },
134+ checkResult : func (t * testing.T , result string ) {
135+ // 没有有效的 part,应返回空字符串(parts 为空,Join 后为 "")
136+ if result != "" {
137+ t .Errorf ("无效 body 应返回空字符串,实际 '%s'" , result )
138+ }
139+ },
140+ },
141+ {
142+ name : "空的multipart body" ,
143+ buildInput : func () (* bytes.Buffer , string ) {
144+ var buf bytes.Buffer
145+ writer := multipart .NewWriter (& buf )
146+ _ = writer .Close () // 关闭但不写入任何 part
147+ return & buf , writer .FormDataContentType ()
148+ },
149+ checkResult : func (t * testing.T , result string ) {
150+ if result != "" {
151+ t .Errorf ("空 multipart body 应返回空字符串,实际 '%s'" , result )
152+ }
153+ },
154+ },
155+ {
156+ name : "多个文件上传" ,
157+ buildInput : func () (* bytes.Buffer , string ) {
158+ var buf bytes.Buffer
159+ writer := multipart .NewWriter (& buf )
160+ part1 , _ := writer .CreateFormFile ("file1" , "a.txt" )
161+ _ , _ = part1 .Write ([]byte ("aaa" ))
162+ part2 , _ := writer .CreateFormFile ("file2" , "b.jpg" )
163+ _ , _ = part2 .Write ([]byte ("bbb" ))
164+ _ = writer .Close ()
165+ return & buf , writer .FormDataContentType ()
166+ },
167+ checkResult : func (t * testing.T , result string ) {
168+ if result != "file1=@a.txt&file2=@b.jpg" {
169+ t .Errorf ("期望 'file1=@a.txt&file2=@b.jpg',实际 '%s'" , result )
170+ }
171+ },
172+ },
173+ {
174+ name : "字段值为空字符串" ,
175+ buildInput : func () (* bytes.Buffer , string ) {
176+ return buildMultipart (map [string ]string {"empty" : "" }, nil )
177+ },
178+ checkResult : func (t * testing.T , result string ) {
179+ if result != "empty=" {
180+ t .Errorf ("期望 'empty=',实际 '%s'" , result )
181+ }
182+ },
183+ },
184+ }
185+
186+ for _ , tt := range tests {
187+ t .Run (tt .name , func (t * testing.T ) {
188+ buf , contentType := tt .buildInput ()
189+ result := multipartBodySummary (buf , contentType )
190+ tt .checkResult (t , result )
191+ })
192+ }
193+ }
194+
16195// TestStat_Methods 测试 Stat 的基础方法:String、Print、RequestBody、ResponseBody
17196func TestStat_Methods (t * testing.T ) {
18197 stat := & Stat {
@@ -381,6 +560,66 @@ func TestServeLoad(t *testing.T) {
381560 }
382561 },
383562 },
563+ {
564+ name : "multipart/form-data请求_summary成功" ,
565+ buildReq : func () (* http.Request , * ResponseWriter , * bytes.Buffer ) {
566+ // 构造有效的 multipart body
567+ var body bytes.Buffer
568+ writer := multipart .NewWriter (& body )
569+ _ = writer .WriteField ("username" , "alice" )
570+ part , _ := writer .CreateFormFile ("avatar" , "photo.png" )
571+ _ , _ = part .Write ([]byte ("fake image data" ))
572+ _ = writer .Close ()
573+
574+ contentType := writer .FormDataContentType ()
575+ req , _ := http .NewRequest ("POST" , "/upload" , nil )
576+ req .Header .Set ("Content-Type" , contentType )
577+ req .RemoteAddr = "10.0.0.1:9090"
578+ w := & ResponseWriter {
579+ StatusCode : 200 ,
580+ Content : bytes .NewBufferString (`{"ok":true}` ),
581+ }
582+ buf := bytes .NewBuffer (body .Bytes ())
583+ return req , w , buf
584+ },
585+ checkFunc : func (t * testing.T , stat * Stat ) {
586+ bodyStr , ok := stat .Request .Body .(string )
587+ if ! ok {
588+ t .Fatalf ("multipart 请求体应为字符串,实际类型 %T" , stat .Request .Body )
589+ }
590+ if ! strings .Contains (bodyStr , "username=alice" ) {
591+ t .Errorf ("应包含 'username=alice',实际 '%s'" , bodyStr )
592+ }
593+ if ! strings .Contains (bodyStr , "avatar=@photo.png" ) {
594+ t .Errorf ("应包含 'avatar=@photo.png',实际 '%s'" , bodyStr )
595+ }
596+ },
597+ },
598+ {
599+ name : "multipart/form-data请求_summary失败回退" ,
600+ buildReq : func () (* http.Request , * ResponseWriter , * bytes.Buffer ) {
601+ // 构造 Content-Type 是 multipart/form-data 但 body 内容无效的情况
602+ contentType := "multipart/form-data; boundary=invalidboundary"
603+ req , _ := http .NewRequest ("POST" , "/upload" , nil )
604+ req .Header .Set ("Content-Type" , contentType )
605+ req .RemoteAddr = "10.0.0.1:9090"
606+ w := & ResponseWriter {
607+ StatusCode : 400 ,
608+ Content : bytes .NewBufferString ("bad request" ),
609+ }
610+ buf := bytes .NewBufferString ("this is not valid multipart data" )
611+ return req , w , buf
612+ },
613+ checkFunc : func (t * testing.T , stat * Stat ) {
614+ bodyStr , ok := stat .Request .Body .(string )
615+ if ! ok {
616+ t .Fatalf ("无效 multipart 请求体应为字符串,实际类型 %T" , stat .Request .Body )
617+ }
618+ if bodyStr != "(multipart)" {
619+ t .Errorf ("期望 '(multipart)',实际 '%s'" , bodyStr )
620+ }
621+ },
622+ },
384623 }
385624
386625 for _ , tt := range tests {
0 commit comments