Home | History | Annotate | Download | only in multipart
      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