github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/src/mime/mediatype_test.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package mime 6 7 import ( 8 "reflect" 9 "testing" 10 ) 11 12 func TestConsumeToken(t *testing.T) { 13 tests := [...][3]string{ 14 {"foo bar", "foo", " bar"}, 15 {"bar", "bar", ""}, 16 {"", "", ""}, 17 {" foo", "", " foo"}, 18 } 19 for _, test := range tests { 20 token, rest := consumeToken(test[0]) 21 expectedToken := test[1] 22 expectedRest := test[2] 23 if token != expectedToken { 24 t.Errorf("expected to consume token '%s', not '%s' from '%s'", 25 expectedToken, token, test[0]) 26 } else if rest != expectedRest { 27 t.Errorf("expected to have left '%s', not '%s' after reading token '%s' from '%s'", 28 expectedRest, rest, token, test[0]) 29 } 30 } 31 } 32 33 func TestConsumeValue(t *testing.T) { 34 tests := [...][3]string{ 35 {"foo bar", "foo", " bar"}, 36 {"bar", "bar", ""}, 37 {" bar ", "", " bar "}, 38 {`"My value"end`, "My value", "end"}, 39 {`"My value" end`, "My value", " end"}, 40 {`"\\" rest`, "\\", " rest"}, 41 {`"My \" value"end`, "My \" value", "end"}, 42 {`"\" rest`, "", `"\" rest`}, 43 } 44 for _, test := range tests { 45 value, rest := consumeValue(test[0]) 46 expectedValue := test[1] 47 expectedRest := test[2] 48 if value != expectedValue { 49 t.Errorf("expected to consume value [%s], not [%s] from [%s]", 50 expectedValue, value, test[0]) 51 } else if rest != expectedRest { 52 t.Errorf("expected to have left [%s], not [%s] after reading value [%s] from [%s]", 53 expectedRest, rest, value, test[0]) 54 } 55 } 56 } 57 58 func TestConsumeMediaParam(t *testing.T) { 59 tests := [...][4]string{ 60 {" ; foo=bar", "foo", "bar", ""}, 61 {"; foo=bar", "foo", "bar", ""}, 62 {";foo=bar", "foo", "bar", ""}, 63 {";FOO=bar", "foo", "bar", ""}, 64 {`;foo="bar"`, "foo", "bar", ""}, 65 {`;foo="bar"; `, "foo", "bar", "; "}, 66 {`;foo="bar"; foo=baz`, "foo", "bar", "; foo=baz"}, 67 {` ; boundary=----CUT;`, "boundary", "----CUT", ";"}, 68 {` ; key=value; blah="value";name="foo" `, "key", "value", `; blah="value";name="foo" `}, 69 {`; blah="value";name="foo" `, "blah", "value", `;name="foo" `}, 70 {`;name="foo" `, "name", "foo", ` `}, 71 } 72 for _, test := range tests { 73 param, value, rest := consumeMediaParam(test[0]) 74 expectedParam := test[1] 75 expectedValue := test[2] 76 expectedRest := test[3] 77 if param != expectedParam { 78 t.Errorf("expected to consume param [%s], not [%s] from [%s]", 79 expectedParam, param, test[0]) 80 } else if value != expectedValue { 81 t.Errorf("expected to consume value [%s], not [%s] from [%s]", 82 expectedValue, value, test[0]) 83 } else if rest != expectedRest { 84 t.Errorf("expected to have left [%s], not [%s] after reading [%s/%s] from [%s]", 85 expectedRest, rest, param, value, test[0]) 86 } 87 } 88 } 89 90 type mediaTypeTest struct { 91 in string 92 t string 93 p map[string]string 94 } 95 96 func TestParseMediaType(t *testing.T) { 97 // Convenience map initializer 98 m := func(s ...string) map[string]string { 99 sm := make(map[string]string) 100 for i := 0; i < len(s); i += 2 { 101 sm[s[i]] = s[i+1] 102 } 103 return sm 104 } 105 106 nameFoo := map[string]string{"name": "foo"} 107 tests := []mediaTypeTest{ 108 {`form-data; name="foo"`, "form-data", nameFoo}, 109 {` form-data ; name=foo`, "form-data", nameFoo}, 110 {`FORM-DATA;name="foo"`, "form-data", nameFoo}, 111 {` FORM-DATA ; name="foo"`, "form-data", nameFoo}, 112 {` FORM-DATA ; name="foo"`, "form-data", nameFoo}, 113 114 {`form-data; key=value; blah="value";name="foo" `, 115 "form-data", 116 m("key", "value", "blah", "value", "name", "foo")}, 117 118 {`foo; key=val1; key=the-key-appears-again-which-is-bogus`, 119 "", m()}, 120 121 // From RFC 2231: 122 {`application/x-stuff; title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A`, 123 "application/x-stuff", 124 m("title", "This is ***fun***")}, 125 126 {`message/external-body; access-type=URL; ` + 127 `URL*0="ftp://";` + 128 `URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"`, 129 "message/external-body", 130 m("access-type", "URL", 131 "url", "ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar")}, 132 133 {`application/x-stuff; ` + 134 `title*0*=us-ascii'en'This%20is%20even%20more%20; ` + 135 `title*1*=%2A%2A%2Afun%2A%2A%2A%20; ` + 136 `title*2="isn't it!"`, 137 "application/x-stuff", 138 m("title", "This is even more ***fun*** isn't it!")}, 139 140 // Tests from http://greenbytes.de/tech/tc2231/ 141 // TODO(bradfitz): add the rest of the tests from that site. 142 {`attachment; filename="f\oo.html"`, 143 "attachment", 144 m("filename", "foo.html")}, 145 {`attachment; filename="\"quoting\" tested.html"`, 146 "attachment", 147 m("filename", `"quoting" tested.html`)}, 148 {`attachment; filename="Here's a semicolon;.html"`, 149 "attachment", 150 m("filename", "Here's a semicolon;.html")}, 151 {`attachment; foo="\"\\";filename="foo.html"`, 152 "attachment", 153 m("foo", "\"\\", "filename", "foo.html")}, 154 {`attachment; filename=foo.html`, 155 "attachment", 156 m("filename", "foo.html")}, 157 {`attachment; filename=foo.html ;`, 158 "attachment", 159 m("filename", "foo.html")}, 160 {`attachment; filename='foo.html'`, 161 "attachment", 162 m("filename", "foo.html")}, 163 {`attachment; filename="foo-%41.html"`, 164 "attachment", 165 m("filename", "foo-%41.html")}, 166 {`attachment; filename="foo-%\41.html"`, 167 "attachment", 168 m("filename", "foo-%41.html")}, 169 {`filename=foo.html`, 170 "", m()}, 171 {`x=y; filename=foo.html`, 172 "", m()}, 173 {`"foo; filename=bar;baz"; filename=qux`, 174 "", m()}, 175 {`inline; attachment; filename=foo.html`, 176 "", m()}, 177 {`attachment; filename="foo.html".txt`, 178 "", m()}, 179 {`attachment; filename="bar`, 180 "", m()}, 181 {`attachment; creation-date="Wed, 12 Feb 1997 16:29:51 -0500"`, 182 "attachment", 183 m("creation-date", "Wed, 12 Feb 1997 16:29:51 -0500")}, 184 {`foobar`, "foobar", m()}, 185 {`attachment; filename* =UTF-8''foo-%c3%a4.html`, 186 "attachment", 187 m("filename", "foo-ä.html")}, 188 {`attachment; filename*=UTF-8''A-%2541.html`, 189 "attachment", 190 m("filename", "A-%41.html")}, 191 {`attachment; filename*0="foo."; filename*1="html"`, 192 "attachment", 193 m("filename", "foo.html")}, 194 {`attachment; filename*0*=UTF-8''foo-%c3%a4; filename*1=".html"`, 195 "attachment", 196 m("filename", "foo-ä.html")}, 197 {`attachment; filename*0="foo"; filename*01="bar"`, 198 "attachment", 199 m("filename", "foo")}, 200 {`attachment; filename*0="foo"; filename*2="bar"`, 201 "attachment", 202 m("filename", "foo")}, 203 {`attachment; filename*1="foo"; filename*2="bar"`, 204 "attachment", m()}, 205 {`attachment; filename*1="bar"; filename*0="foo"`, 206 "attachment", 207 m("filename", "foobar")}, 208 {`attachment; filename="foo-ae.html"; filename*=UTF-8''foo-%c3%a4.html`, 209 "attachment", 210 m("filename", "foo-ä.html")}, 211 {`attachment; filename*=UTF-8''foo-%c3%a4.html; filename="foo-ae.html"`, 212 "attachment", 213 m("filename", "foo-ä.html")}, 214 215 // Browsers also just send UTF-8 directly without RFC 2231, 216 // at least when the source page is served with UTF-8. 217 {`form-data; firstname="Брэд"; lastname="Фицпатрик"`, 218 "form-data", 219 m("firstname", "Брэд", "lastname", "Фицпатрик")}, 220 } 221 for _, test := range tests { 222 mt, params, err := ParseMediaType(test.in) 223 if err != nil { 224 if test.t != "" { 225 t.Errorf("for input %q, unexpected error: %v", test.in, err) 226 continue 227 } 228 continue 229 } 230 if g, e := mt, test.t; g != e { 231 t.Errorf("for input %q, expected type %q, got %q", 232 test.in, e, g) 233 continue 234 } 235 if len(params) == 0 && len(test.p) == 0 { 236 continue 237 } 238 if !reflect.DeepEqual(params, test.p) { 239 t.Errorf("for input %q, wrong params.\n"+ 240 "expected: %#v\n"+ 241 " got: %#v", 242 test.in, test.p, params) 243 } 244 } 245 } 246 247 type badMediaTypeTest struct { 248 in string 249 err string 250 } 251 252 var badMediaTypeTests = []badMediaTypeTest{ 253 {"bogus ;=========", "mime: invalid media parameter"}, 254 {"bogus/<script>alert</script>", "mime: expected token after slash"}, 255 {"bogus/bogus<script>alert</script>", "mime: unexpected content after media subtype"}, 256 } 257 258 func TestParseMediaTypeBogus(t *testing.T) { 259 for _, tt := range badMediaTypeTests { 260 mt, params, err := ParseMediaType(tt.in) 261 if err == nil { 262 t.Errorf("ParseMediaType(%q) = nil error; want parse error", tt.in) 263 continue 264 } 265 if err.Error() != tt.err { 266 t.Errorf("ParseMediaType(%q) = err %q; want %q", tt.in, err.Error(), tt.err) 267 } 268 if params != nil { 269 t.Errorf("ParseMediaType(%q): got non-nil params on error", tt.in) 270 } 271 if mt != "" { 272 t.Errorf("ParseMediaType(%q): got non-empty media type string on error", tt.in) 273 } 274 } 275 } 276 277 type formatTest struct { 278 typ string 279 params map[string]string 280 want string 281 } 282 283 var formatTests = []formatTest{ 284 {"noslash", nil, ""}, 285 {"foo bar/baz", nil, ""}, 286 {"foo/bar baz", nil, ""}, 287 {"foo/BAR", nil, "foo/bar"}, 288 {"foo/BAR", map[string]string{"X": "Y"}, "foo/bar; x=Y"}, 289 {"foo/BAR", map[string]string{"space": "With space"}, `foo/bar; space="With space"`}, 290 {"foo/BAR", map[string]string{"quote": `With "quote`}, `foo/bar; quote="With \"quote"`}, 291 {"foo/BAR", map[string]string{"bslash": `With \backslash`}, `foo/bar; bslash="With \\backslash"`}, 292 {"foo/BAR", map[string]string{"both": `With \backslash and "quote`}, `foo/bar; both="With \\backslash and \"quote"`}, 293 {"foo/BAR", map[string]string{"": "empty attribute"}, ""}, 294 {"foo/BAR", map[string]string{"bad attribute": "baz"}, ""}, 295 {"foo/BAR", map[string]string{"nonascii": "not an ascii character: ä"}, ""}, 296 {"foo/bar", map[string]string{"a": "av", "b": "bv", "c": "cv"}, "foo/bar; a=av; b=bv; c=cv"}, 297 } 298 299 func TestFormatMediaType(t *testing.T) { 300 for i, tt := range formatTests { 301 got := FormatMediaType(tt.typ, tt.params) 302 if got != tt.want { 303 t.Errorf("%d. FormatMediaType(%q, %v) = %q; want %q", i, tt.typ, tt.params, got, tt.want) 304 } 305 } 306 }