1 // Copyright 2015 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 quotedprintable 6 7 import ( 8 "bytes" 9 "io/ioutil" 10 "strings" 11 "testing" 12 ) 13 14 func TestWriter(t *testing.T) { 15 testWriter(t, false) 16 } 17 18 func TestWriterBinary(t *testing.T) { 19 testWriter(t, true) 20 } 21 22 func testWriter(t *testing.T, binary bool) { 23 tests := []struct { 24 in, want, wantB string 25 }{ 26 {in: "", want: ""}, 27 {in: "foo bar", want: "foo bar"}, 28 {in: "foo bar=", want: "foo bar=3D"}, 29 {in: "foo bar\r", want: "foo bar\r\n", wantB: "foo bar=0D"}, 30 {in: "foo bar\r\r", want: "foo bar\r\n\r\n", wantB: "foo bar=0D=0D"}, 31 {in: "foo bar\n", want: "foo bar\r\n", wantB: "foo bar=0A"}, 32 {in: "foo bar\r\n", want: "foo bar\r\n", wantB: "foo bar=0D=0A"}, 33 {in: "foo bar\r\r\n", want: "foo bar\r\n\r\n", wantB: "foo bar=0D=0D=0A"}, 34 {in: "foo bar ", want: "foo bar=20"}, 35 {in: "foo bar\t", want: "foo bar=09"}, 36 {in: "foo bar ", want: "foo bar =20"}, 37 {in: "foo bar \n", want: "foo bar=20\r\n", wantB: "foo bar =0A"}, 38 {in: "foo bar \r", want: "foo bar=20\r\n", wantB: "foo bar =0D"}, 39 {in: "foo bar \r\n", want: "foo bar=20\r\n", wantB: "foo bar =0D=0A"}, 40 {in: "foo bar \n", want: "foo bar =20\r\n", wantB: "foo bar =0A"}, 41 {in: "foo bar \n ", want: "foo bar =20\r\n=20", wantB: "foo bar =0A=20"}, 42 {in: "Hola Seor!", want: "=C2=A1Hola Se=C3=B1or!"}, 43 { 44 in: "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~", 45 want: "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~", 46 }, 47 { 48 in: strings.Repeat("a", 75), 49 want: strings.Repeat("a", 75), 50 }, 51 { 52 in: strings.Repeat("a", 76), 53 want: strings.Repeat("a", 75) + "=\r\na", 54 }, 55 { 56 in: strings.Repeat("a", 72) + "=", 57 want: strings.Repeat("a", 72) + "=3D", 58 }, 59 { 60 in: strings.Repeat("a", 73) + "=", 61 want: strings.Repeat("a", 73) + "=\r\n=3D", 62 }, 63 { 64 in: strings.Repeat("a", 74) + "=", 65 want: strings.Repeat("a", 74) + "=\r\n=3D", 66 }, 67 { 68 in: strings.Repeat("a", 75) + "=", 69 want: strings.Repeat("a", 75) + "=\r\n=3D", 70 }, 71 { 72 in: strings.Repeat(" ", 73), 73 want: strings.Repeat(" ", 72) + "=20", 74 }, 75 { 76 in: strings.Repeat(" ", 74), 77 want: strings.Repeat(" ", 73) + "=\r\n=20", 78 }, 79 { 80 in: strings.Repeat(" ", 75), 81 want: strings.Repeat(" ", 74) + "=\r\n=20", 82 }, 83 { 84 in: strings.Repeat(" ", 76), 85 want: strings.Repeat(" ", 75) + "=\r\n=20", 86 }, 87 { 88 in: strings.Repeat(" ", 77), 89 want: strings.Repeat(" ", 75) + "=\r\n =20", 90 }, 91 } 92 93 for _, tt := range tests { 94 buf := new(bytes.Buffer) 95 w := NewWriter(buf) 96 97 want := tt.want 98 if binary { 99 w.Binary = true 100 if tt.wantB != "" { 101 want = tt.wantB 102 } 103 } 104 105 if _, err := w.Write([]byte(tt.in)); err != nil { 106 t.Errorf("Write(%q): %v", tt.in, err) 107 continue 108 } 109 if err := w.Close(); err != nil { 110 t.Errorf("Close(): %v", err) 111 continue 112 } 113 got := buf.String() 114 if got != want { 115 t.Errorf("Write(%q), got:\n%q\nwant:\n%q", tt.in, got, want) 116 } 117 } 118 } 119 120 func TestRoundTrip(t *testing.T) { 121 buf := new(bytes.Buffer) 122 w := NewWriter(buf) 123 if _, err := w.Write(testMsg); err != nil { 124 t.Fatalf("Write: %v", err) 125 } 126 if err := w.Close(); err != nil { 127 t.Fatalf("Close: %v", err) 128 } 129 130 r := NewReader(buf) 131 gotBytes, err := ioutil.ReadAll(r) 132 if err != nil { 133 t.Fatalf("Error while reading from Reader: %v", err) 134 } 135 got := string(gotBytes) 136 if got != string(testMsg) { 137 t.Errorf("Encoding and decoding changed the message, got:\n%s", got) 138 } 139 } 140 141 // From http://fr.wikipedia.org/wiki/Quoted-Printable 142 var testMsg = []byte("Quoted-Printable (QP) est un format d'encodage de donnes codes sur 8 bits, qui utilise exclusivement les caractres alphanumriques imprimables du code ASCII (7 bits).\r\n" + 143 "\r\n" + 144 "En effet, les diffrents codages comprennent de nombreux caractres qui ne sont pas reprsentables en ASCII (par exemple les caractres accentus), ainsi que des caractres dits non-imprimables .\r\n" + 145 "\r\n" + 146 "L'encodage Quoted-Printable permet de remdier ce problme, en procdant de la manire suivante :\r\n" + 147 "\r\n" + 148 "Un octet correspondant un caractre imprimable de l'ASCII sauf le signe gal (donc un caractre de code ASCII entre 33 et 60 ou entre 62 et 126) ou aux caractres de saut de ligne (codes ASCII 13 et 10) ou une suite de tabulations et espaces non situes en fin de ligne (de codes ASCII respectifs 9 et 32) est reprsent tel quel.\r\n" + 149 "Un octet qui ne correspond pas la dfinition ci-dessus (caractre non imprimable de l'ASCII, tabulation ou espaces non suivies d'un caractre imprimable avant la fin de la ligne ou signe gal) est reprsent par un signe gal, suivi de son numro, exprim en hexadcimal.\r\n" + 150 "Enfin, un signe gal suivi par un saut de ligne (donc la suite des trois caractres de codes ASCII 61, 13 et 10) peut tre insr n'importe o, afin de limiter la taille des lignes produites si ncessaire. Une limite de 76 caractres par ligne est gnralement respecte.\r\n") 151 152 func BenchmarkWriter(b *testing.B) { 153 for i := 0; i < b.N; i++ { 154 w := NewWriter(ioutil.Discard) 155 w.Write(testMsg) 156 w.Close() 157 } 158 } 159