blob: facf5d04eeb11dbac9c05e580729bfa1d8e612ef [file] [log] [blame]
Miek Gieben40c74492011-01-20 12:51:15 -05001// Copyright 2009 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
5package base32
6
7import (
8 "bytes"
Russ Coxc2049d22011-11-01 22:04:37 -04009 "io"
Miek Gieben40c74492011-01-20 12:51:15 -050010 "io/ioutil"
Miek Gieben40c74492011-01-20 12:51:15 -050011 "testing"
12)
13
14type testpair struct {
15 decoded, encoded string
16}
17
18var pairs = []testpair{
19 // RFC 4648 examples
20 {"", ""},
21 {"f", "MY======"},
22 {"fo", "MZXQ===="},
23 {"foo", "MZXW6==="},
24 {"foob", "MZXW6YQ="},
25 {"fooba", "MZXW6YTB"},
26 {"foobar", "MZXW6YTBOI======"},
27
Miek Gieben40c74492011-01-20 12:51:15 -050028 // Wikipedia examples, converted to base32
29 {"sure.", "ON2XEZJO"},
30 {"sure", "ON2XEZI="},
31 {"sur", "ON2XE==="},
32 {"su", "ON2Q===="},
33 {"leasure.", "NRSWC43VOJSS4==="},
34 {"easure.", "MVQXG5LSMUXA===="},
35 {"asure.", "MFZXK4TFFY======"},
36 {"sure.", "ON2XEZJO"},
37}
38
39var bigtest = testpair{
40 "Twas brillig, and the slithy toves",
41 "KR3WC4ZAMJZGS3DMNFTSYIDBNZSCA5DIMUQHG3DJORUHSIDUN53GK4Y=",
42}
43
44func testEqual(t *testing.T, msg string, args ...interface{}) bool {
45 if args[len(args)-2] != args[len(args)-1] {
46 t.Errorf(msg, args...)
47 return false
48 }
49 return true
50}
51
52func TestEncode(t *testing.T) {
53 for _, p := range pairs {
54 buf := make([]byte, StdEncoding.EncodedLen(len(p.decoded)))
55 StdEncoding.Encode(buf, []byte(p.decoded))
56 testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded)
57 }
58}
59
60func TestEncoder(t *testing.T) {
61 for _, p := range pairs {
62 bb := &bytes.Buffer{}
63 encoder := NewEncoder(StdEncoding, bb)
64 encoder.Write([]byte(p.decoded))
65 encoder.Close()
66 testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded)
67 }
68}
69
70func TestEncoderBuffering(t *testing.T) {
71 input := []byte(bigtest.decoded)
72 for bs := 1; bs <= 12; bs++ {
73 bb := &bytes.Buffer{}
74 encoder := NewEncoder(StdEncoding, bb)
75 for pos := 0; pos < len(input); pos += bs {
76 end := pos + bs
77 if end > len(input) {
78 end = len(input)
79 }
80 n, err := encoder.Write(input[pos:end])
Russ Coxc2049d22011-11-01 22:04:37 -040081 testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, error(nil))
Miek Gieben40c74492011-01-20 12:51:15 -050082 testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
83 }
84 err := encoder.Close()
Russ Coxc2049d22011-11-01 22:04:37 -040085 testEqual(t, "Close gave error %v, want %v", err, error(nil))
Miek Gieben40c74492011-01-20 12:51:15 -050086 testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, bb.String(), bigtest.encoded)
87 }
88}
89
90func TestDecode(t *testing.T) {
91 for _, p := range pairs {
92 dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
93 count, end, err := StdEncoding.decode(dbuf, []byte(p.encoded))
Russ Coxc2049d22011-11-01 22:04:37 -040094 testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, error(nil))
Miek Gieben40c74492011-01-20 12:51:15 -050095 testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded))
96 if len(p.encoded) > 0 {
97 testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '='))
98 }
99 testEqual(t, "Decode(%q) = %q, want %q", p.encoded,
100 string(dbuf[0:count]),
101 p.decoded)
102 }
103}
104
105func TestDecoder(t *testing.T) {
106 for _, p := range pairs {
107 decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
108 dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
109 count, err := decoder.Read(dbuf)
Russ Coxc2049d22011-11-01 22:04:37 -0400110 if err != nil && err != io.EOF {
Miek Gieben40c74492011-01-20 12:51:15 -0500111 t.Fatal("Read failed", err)
112 }
113 testEqual(t, "Read from %q = length %v, want %v", p.encoded, count, len(p.decoded))
114 testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
Russ Coxc2049d22011-11-01 22:04:37 -0400115 if err != io.EOF {
Miek Gieben40c74492011-01-20 12:51:15 -0500116 count, err = decoder.Read(dbuf)
117 }
Russ Coxc2049d22011-11-01 22:04:37 -0400118 testEqual(t, "Read from %q = %v, want %v", p.encoded, err, io.EOF)
Miek Gieben40c74492011-01-20 12:51:15 -0500119 }
120}
121
122func TestDecoderBuffering(t *testing.T) {
123 for bs := 1; bs <= 12; bs++ {
124 decoder := NewDecoder(StdEncoding, bytes.NewBufferString(bigtest.encoded))
125 buf := make([]byte, len(bigtest.decoded)+12)
126 var total int
127 for total = 0; total < len(bigtest.decoded); {
128 n, err := decoder.Read(buf[total : total+bs])
Russ Coxc2049d22011-11-01 22:04:37 -0400129 testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, error(nil))
Miek Gieben40c74492011-01-20 12:51:15 -0500130 total += n
131 }
132 testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded)
133 }
134}
135
136func TestDecodeCorrupt(t *testing.T) {
137 type corrupt struct {
138 e string
139 p int
140 }
141 examples := []corrupt{
142 {"!!!!", 0},
143 {"x===", 0},
144 {"AA=A====", 2},
145 {"AAA=AAAA", 3},
146 {"MMMMMMMMM", 8},
147 {"MMMMMM", 0},
148 }
149
150 for _, e := range examples {
151 dbuf := make([]byte, StdEncoding.DecodedLen(len(e.e)))
152 _, err := StdEncoding.Decode(dbuf, []byte(e.e))
153 switch err := err.(type) {
154 case CorruptInputError:
155 testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
156 default:
157 t.Error("Decoder failed to detect corruption in", e)
158 }
159 }
160}
161
162func TestBig(t *testing.T) {
163 n := 3*1000 + 1
164 raw := make([]byte, n)
165 const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
166 for i := 0; i < n; i++ {
167 raw[i] = alpha[i%len(alpha)]
168 }
169 encoded := new(bytes.Buffer)
170 w := NewEncoder(StdEncoding, encoded)
171 nn, err := w.Write(raw)
172 if nn != n || err != nil {
173 t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
174 }
175 err = w.Close()
176 if err != nil {
177 t.Fatalf("Encoder.Close() = %v want nil", err)
178 }
179 decoded, err := ioutil.ReadAll(NewDecoder(StdEncoding, encoded))
180 if err != nil {
181 t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err)
182 }
183
184 if !bytes.Equal(raw, decoded) {
185 var i int
186 for i = 0; i < len(decoded) && i < len(raw); i++ {
187 if decoded[i] != raw[i] {
188 break
189 }
190 }
191 t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
192 }
193}