| // Copyright 2010 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package multipart |
| |
| import ( |
| "bytes" |
| "fmt" |
| "io" |
| "json" |
| "regexp" |
| "strings" |
| "testing" |
| ) |
| |
| func TestHorizontalWhitespace(t *testing.T) { |
| if !onlyHorizontalWhitespace(" \t") { |
| t.Error("expected pass") |
| } |
| if onlyHorizontalWhitespace("foo bar") { |
| t.Error("expected failure") |
| } |
| } |
| |
| func TestBoundaryLine(t *testing.T) { |
| boundary := "myBoundary" |
| prefix := "--" + boundary |
| if !isBoundaryDelimiterLine("--myBoundary\r\n", prefix) { |
| t.Error("expected") |
| } |
| if !isBoundaryDelimiterLine("--myBoundary \r\n", prefix) { |
| t.Error("expected") |
| } |
| if !isBoundaryDelimiterLine("--myBoundary \n", prefix) { |
| t.Error("expected") |
| } |
| if isBoundaryDelimiterLine("--myBoundary bogus \n", prefix) { |
| t.Error("expected fail") |
| } |
| if isBoundaryDelimiterLine("--myBoundary bogus--", prefix) { |
| t.Error("expected fail") |
| } |
| } |
| |
| func escapeString(v string) string { |
| bytes, _ := json.Marshal(v) |
| return string(bytes) |
| } |
| |
| func expectEq(t *testing.T, expected, actual, what string) { |
| if expected == actual { |
| return |
| } |
| t.Errorf("Unexpected value for %s; got %s (len %d) but expected: %s (len %d)", |
| what, escapeString(actual), len(actual), escapeString(expected), len(expected)) |
| } |
| |
| func TestFormName(t *testing.T) { |
| p := new(Part) |
| p.Header = make(map[string]string) |
| tests := [...][2]string{ |
| {`form-data; name="foo"`, "foo"}, |
| {` form-data ; name=foo`, "foo"}, |
| {`FORM-DATA;name="foo"`, "foo"}, |
| {` FORM-DATA ; name="foo"`, "foo"}, |
| {` FORM-DATA ; name="foo"`, "foo"}, |
| {` FORM-DATA ; name=foo`, "foo"}, |
| {` FORM-DATA ; filename="foo.txt"; name=foo; baz=quux`, "foo"}, |
| } |
| for _, test := range tests { |
| p.Header["Content-Disposition"] = test[0] |
| expected := test[1] |
| actual := p.FormName() |
| if actual != expected { |
| t.Errorf("expected \"%s\"; got: \"%s\"", expected, actual) |
| } |
| } |
| } |
| |
| func TestMultipart(t *testing.T) { |
| testBody := ` |
| This is a multi-part message. This line is ignored. |
| --MyBoundary |
| Header1: value1 |
| HEADER2: value2 |
| foo-bar: baz |
| |
| My value |
| The end. |
| --MyBoundary |
| Header1: value1b |
| HEADER2: value2b |
| foo-bar: bazb |
| |
| Line 1 |
| Line 2 |
| Line 3 ends in a newline, but just one. |
| |
| --MyBoundary |
| |
| never read data |
| --MyBoundary-- |
| ` |
| testBody = regexp.MustCompile("\n").ReplaceAllString(testBody, "\r\n") |
| bodyReader := strings.NewReader(testBody) |
| |
| reader := NewReader(bodyReader, "MyBoundary") |
| buf := new(bytes.Buffer) |
| |
| // Part1 |
| part, err := reader.NextPart() |
| if part == nil || err != nil { |
| t.Error("Expected part1") |
| return |
| } |
| if part.Header["Header1"] != "value1" { |
| t.Error("Expected Header1: value") |
| } |
| if part.Header["foo-bar"] != "baz" { |
| t.Error("Expected foo-bar: baz") |
| } |
| buf.Reset() |
| io.Copy(buf, part) |
| expectEq(t, "My value\r\nThe end.", |
| buf.String(), "Value of first part") |
| |
| // Part2 |
| part, err = reader.NextPart() |
| if part == nil || err != nil { |
| t.Error("Expected part2") |
| return |
| } |
| if part.Header["foo-bar"] != "bazb" { |
| t.Error("Expected foo-bar: bazb") |
| } |
| buf.Reset() |
| io.Copy(buf, part) |
| expectEq(t, "Line 1\r\nLine 2\r\nLine 3 ends in a newline, but just one.\r\n", |
| buf.String(), "Value of second part") |
| |
| // Part3 |
| part, err = reader.NextPart() |
| if part == nil || err != nil { |
| t.Error("Expected part3 without errors") |
| return |
| } |
| |
| // Non-existent part4 |
| part, err = reader.NextPart() |
| if part != nil { |
| t.Error("Didn't expect a third part.") |
| } |
| if err != nil { |
| t.Errorf("Unexpected error getting third part: %v", err) |
| } |
| } |
| |
| func TestVariousTextLineEndings(t *testing.T) { |
| tests := [...]string{ |
| "Foo\nBar", |
| "Foo\nBar\n", |
| "Foo\r\nBar", |
| "Foo\r\nBar\r\n", |
| "Foo\rBar", |
| "Foo\rBar\r", |
| "\x00\x01\x02\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10", |
| } |
| |
| for testNum, expectedBody := range tests { |
| body := "--BOUNDARY\r\n" + |
| "Content-Disposition: form-data; name=\"value\"\r\n" + |
| "\r\n" + |
| expectedBody + |
| "\r\n--BOUNDARY--\r\n" |
| bodyReader := strings.NewReader(body) |
| |
| reader := NewReader(bodyReader, "BOUNDARY") |
| buf := new(bytes.Buffer) |
| part, err := reader.NextPart() |
| if part == nil { |
| t.Errorf("Expected a body part on text %d", testNum) |
| continue |
| } |
| if err != nil { |
| t.Errorf("Unexpected error on text %d: %v", testNum, err) |
| continue |
| } |
| written, err := io.Copy(buf, part) |
| expectEq(t, expectedBody, buf.String(), fmt.Sprintf("test %d", testNum)) |
| if err != nil { |
| t.Errorf("Error copying multipart; bytes=%v, error=%v", written, err) |
| } |
| |
| part, err = reader.NextPart() |
| if part != nil { |
| t.Errorf("Unexpected part in test %d", testNum) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error in test %d: %v", testNum, err) |
| } |
| |
| } |
| } |