libgo: Update to Go 1.3 release.
[official-gcc.git] / libgo / go / mime / multipart / quotedprintable_test.go
blobc4de3eb756634e4b10ab683409f24cff0cc317b1
1 // Copyright 2012 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.
5 package multipart
7 import (
8 "bufio"
9 "bytes"
10 "errors"
11 "flag"
12 "fmt"
13 "io"
14 "os/exec"
15 "regexp"
16 "sort"
17 "strings"
18 "testing"
19 "time"
22 func TestQuotedPrintable(t *testing.T) {
23 tests := []struct {
24 in, want string
25 err interface{}
27 {in: "", want: ""},
28 {in: "foo bar", want: "foo bar"},
29 {in: "foo bar=3D", want: "foo bar="},
30 {in: "foo bar=\n", want: "foo bar"},
31 {in: "foo bar\n", want: "foo bar\n"}, // somewhat lax.
32 {in: "foo bar=0", want: "foo bar", err: io.ErrUnexpectedEOF},
33 {in: "foo bar=ab", want: "foo bar", err: "multipart: invalid quoted-printable hex byte 0x61"},
34 {in: "foo bar=0D=0A", want: "foo bar\r\n"},
35 {in: " A B \r\n C ", want: " A B\r\n C"},
36 {in: " A B =\r\n C ", want: " A B C"},
37 {in: " A B =\n C ", want: " A B C"}, // lax. treating LF as CRLF
38 {in: "foo=\nbar", want: "foobar"},
39 {in: "foo\x00bar", want: "foo", err: "multipart: invalid unescaped byte 0x00 in quoted-printable body"},
40 {in: "foo bar\xff", want: "foo bar", err: "multipart: invalid unescaped byte 0xff in quoted-printable body"},
42 // Equal sign.
43 {in: "=3D30\n", want: "=30\n"},
44 {in: "=00=FF0=\n", want: "\x00\xff0"},
46 // Trailing whitespace
47 {in: "foo \n", want: "foo\n"},
48 {in: "foo \n\nfoo =\n\nfoo=20\n\n", want: "foo\n\nfoo \nfoo \n\n"},
50 // Tests that we allow bare \n and \r through, despite it being strictly
51 // not permitted per RFC 2045, Section 6.7 Page 22 bullet (4).
52 {in: "foo\nbar", want: "foo\nbar"},
53 {in: "foo\rbar", want: "foo\rbar"},
54 {in: "foo\r\nbar", want: "foo\r\nbar"},
56 // Different types of soft line-breaks.
57 {in: "foo=\r\nbar", want: "foobar"},
58 {in: "foo=\nbar", want: "foobar"},
59 {in: "foo=\rbar", want: "foo", err: "multipart: invalid quoted-printable hex byte 0x0d"},
60 {in: "foo=\r\r\r \nbar", want: "foo", err: `multipart: invalid bytes after =: "\r\r\r \n"`},
62 // Example from RFC 2045:
63 {in: "Now's the time =\n" + "for all folk to come=\n" + " to the aid of their country.",
64 want: "Now's the time for all folk to come to the aid of their country."},
66 for _, tt := range tests {
67 var buf bytes.Buffer
68 _, err := io.Copy(&buf, newQuotedPrintableReader(strings.NewReader(tt.in)))
69 if got := buf.String(); got != tt.want {
70 t.Errorf("for %q, got %q; want %q", tt.in, got, tt.want)
72 switch verr := tt.err.(type) {
73 case nil:
74 if err != nil {
75 t.Errorf("for %q, got unexpected error: %v", tt.in, err)
77 case string:
78 if got := fmt.Sprint(err); got != verr {
79 t.Errorf("for %q, got error %q; want %q", tt.in, got, verr)
81 case error:
82 if err != verr {
83 t.Errorf("for %q, got error %q; want %q", tt.in, err, verr)
90 func everySequence(base, alpha string, length int, fn func(string)) {
91 if len(base) == length {
92 fn(base)
93 return
95 for i := 0; i < len(alpha); i++ {
96 everySequence(base+alpha[i:i+1], alpha, length, fn)
100 var useQprint = flag.Bool("qprint", false, "Compare against the 'qprint' program.")
102 var badSoftRx = regexp.MustCompile(`=([^\r\n]+?\n)|([^\r\n]+$)|(\r$)|(\r[^\n]+\n)|( \r\n)`)
104 func TestQPExhaustive(t *testing.T) {
105 if *useQprint {
106 _, err := exec.LookPath("qprint")
107 if err != nil {
108 t.Fatalf("Error looking for qprint: %v", err)
112 var buf bytes.Buffer
113 res := make(map[string]int)
114 everySequence("", "0A \r\n=", 6, func(s string) {
115 if strings.HasSuffix(s, "=") || strings.Contains(s, "==") {
116 return
118 buf.Reset()
119 _, err := io.Copy(&buf, newQuotedPrintableReader(strings.NewReader(s)))
120 if err != nil {
121 errStr := err.Error()
122 if strings.Contains(errStr, "invalid bytes after =:") {
123 errStr = "invalid bytes after ="
125 res[errStr]++
126 if strings.Contains(errStr, "invalid quoted-printable hex byte ") {
127 if strings.HasSuffix(errStr, "0x20") && (strings.Contains(s, "=0 ") || strings.Contains(s, "=A ") || strings.Contains(s, "= ")) {
128 return
130 if strings.HasSuffix(errStr, "0x3d") && (strings.Contains(s, "=0=") || strings.Contains(s, "=A=")) {
131 return
133 if strings.HasSuffix(errStr, "0x0a") || strings.HasSuffix(errStr, "0x0d") {
134 // bunch of cases; since whitespace at the end of a line before \n is removed.
135 return
138 if strings.Contains(errStr, "unexpected EOF") {
139 return
141 if errStr == "invalid bytes after =" && badSoftRx.MatchString(s) {
142 return
144 t.Errorf("decode(%q) = %v", s, err)
145 return
147 if *useQprint {
148 cmd := exec.Command("qprint", "-d")
149 cmd.Stdin = strings.NewReader(s)
150 stderr, err := cmd.StderrPipe()
151 if err != nil {
152 panic(err)
154 qpres := make(chan interface{}, 2)
155 go func() {
156 br := bufio.NewReader(stderr)
157 s, _ := br.ReadString('\n')
158 if s != "" {
159 qpres <- errors.New(s)
160 if cmd.Process != nil {
161 // It can get stuck on invalid input, like:
162 // echo -n "0000= " | qprint -d
163 cmd.Process.Kill()
167 go func() {
168 want, err := cmd.Output()
169 if err == nil {
170 qpres <- want
173 select {
174 case got := <-qpres:
175 if want, ok := got.([]byte); ok {
176 if string(want) != buf.String() {
177 t.Errorf("go decode(%q) = %q; qprint = %q", s, want, buf.String())
179 } else {
180 t.Logf("qprint -d(%q) = %v", s, got)
182 case <-time.After(5 * time.Second):
183 t.Logf("qprint timeout on %q", s)
186 res["OK"]++
188 var outcomes []string
189 for k, v := range res {
190 outcomes = append(outcomes, fmt.Sprintf("%v: %d", k, v))
192 sort.Strings(outcomes)
193 got := strings.Join(outcomes, "\n")
194 want := `OK: 21576
195 invalid bytes after =: 3397
196 multipart: invalid quoted-printable hex byte 0x0a: 1400
197 multipart: invalid quoted-printable hex byte 0x0d: 2700
198 multipart: invalid quoted-printable hex byte 0x20: 2490
199 multipart: invalid quoted-printable hex byte 0x3d: 440
200 unexpected EOF: 3122`
201 if got != want {
202 t.Errorf("Got:\n%s\nWant:\n%s", got, want)