1 // Copyright 2011 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 multipart 6 7 import ( 8 "bytes" 9 "io/ioutil" 10 "strings" 11 "testing" 12 ) 13 14 func TestWriter(t *testing.T) { 15 fileContents := []byte("my file contents") 16 17 var b bytes.Buffer 18 w := NewWriter(&b) 19 { 20 part, err := w.CreateFormFile("myfile", "my-file.txt") 21 if err != nil { 22 t.Fatalf("CreateFormFile: %v", err) 23 } 24 part.Write(fileContents) 25 err = w.WriteField("key", "val") 26 if err != nil { 27 t.Fatalf("WriteField: %v", err) 28 } 29 part.Write([]byte("val")) 30 err = w.Close() 31 if err != nil { 32 t.Fatalf("Close: %v", err) 33 } 34 s := b.String() 35 if len(s) == 0 { 36 t.Fatal("String: unexpected empty result") 37 } 38 if s[0] == '\r' || s[0] == '\n' { 39 t.Fatal("String: unexpected newline") 40 } 41 } 42 43 r := NewReader(&b, w.Boundary()) 44 45 part, err := r.NextPart() 46 if err != nil { 47 t.Fatalf("part 1: %v", err) 48 } 49 if g, e := part.FormName(), "myfile"; g != e { 50 t.Errorf("part 1: want form name %q, got %q", e, g) 51 } 52 slurp, err := ioutil.ReadAll(part) 53 if err != nil { 54 t.Fatalf("part 1: ReadAll: %v", err) 55 } 56 if e, g := string(fileContents), string(slurp); e != g { 57 t.Errorf("part 1: want contents %q, got %q", e, g) 58 } 59 60 part, err = r.NextPart() 61 if err != nil { 62 t.Fatalf("part 2: %v", err) 63 } 64 if g, e := part.FormName(), "key"; g != e { 65 t.Errorf("part 2: want form name %q, got %q", e, g) 66 } 67 slurp, err = ioutil.ReadAll(part) 68 if err != nil { 69 t.Fatalf("part 2: ReadAll: %v", err) 70 } 71 if e, g := "val", string(slurp); e != g { 72 t.Errorf("part 2: want contents %q, got %q", e, g) 73 } 74 75 part, err = r.NextPart() 76 if part != nil || err == nil { 77 t.Fatalf("expected end of parts; got %v, %v", part, err) 78 } 79 } 80 81 func TestWriterSetBoundary(t *testing.T) { 82 var b bytes.Buffer 83 w := NewWriter(&b) 84 tests := []struct { 85 b string 86 ok bool 87 }{ 88 {"abc", true}, 89 {"", false}, 90 {"ungltig", false}, 91 {"!", false}, 92 {strings.Repeat("x", 69), true}, 93 {strings.Repeat("x", 70), false}, 94 {"bad!ascii!", false}, 95 {"my-separator", true}, 96 } 97 for i, tt := range tests { 98 err := w.SetBoundary(tt.b) 99 got := err == nil 100 if got != tt.ok { 101 t.Errorf("%d. boundary %q = %v (%v); want %v", i, tt.b, got, err, tt.ok) 102 } else if tt.ok { 103 got := w.Boundary() 104 if got != tt.b { 105 t.Errorf("boundary = %q; want %q", got, tt.b) 106 } 107 } 108 } 109 w.Close() 110 if got := b.String(); !strings.Contains(got, "\r\n--my-separator--\r\n") { 111 t.Errorf("expected my-separator in output. got: %q", got) 112 } 113 } 114 115 func TestWriterBoundaryGoroutines(t *testing.T) { 116 // Verify there's no data race accessing any lazy boundary if it's used by 117 // different goroutines. This was previously broken by 118 // https://codereview.appspot.com/95760043/ and reverted in 119 // https://codereview.appspot.com/117600043/ 120 w := NewWriter(ioutil.Discard) 121 done := make(chan int) 122 go func() { 123 w.CreateFormField("foo") 124 done <- 1 125 }() 126 w.Boundary() 127 <-done 128 } 129