@@ -3,6 +3,7 @@ package multibase
3
3
import (
4
4
"bytes"
5
5
"math/rand"
6
+ "sort"
6
7
"testing"
7
8
)
8
9
@@ -36,6 +37,7 @@ var encodedSamples = map[Encoding]string{
36
37
Base32hexPad : "t8him6pbeehp62r39f9ii0pbmclp7it38d5n6e89144======" ,
37
38
Base32hexPadUpper : "T8HIM6PBEEHP62R39F9II0PBMCLP7IT38D5N6E89144======" ,
38
39
Base58BTC : "z36UQrhJq9fNDS7DiAHM9YXqDHMPfr4EMArvt" ,
40
+ Base58Flickr : "Z36tpRGiQ9Endr7dHahm9xwQdhmoER4emaRVT" ,
39
41
Base64 : "mRGVjZW50cmFsaXplIGV2ZXJ5dGhpbmchISE" ,
40
42
Base64url : "uRGVjZW50cmFsaXplIGV2ZXJ5dGhpbmchISE" ,
41
43
Base64pad : "MRGVjZW50cmFsaXplIGV2ZXJ5dGhpbmchISE=" ,
@@ -49,7 +51,7 @@ func testEncode(t *testing.T, encoding Encoding, bytes []byte, expected string)
49
51
return
50
52
}
51
53
if actual != expected {
52
- t .Errorf ("encoding failed for %c (%d), expected: %s, got: %s" , encoding , encoding , expected , actual )
54
+ t .Errorf ("encoding failed for %c (%d / %s ), expected: %s, got: %s" , encoding , encoding , EncodingToStr [ encoding ] , expected , actual )
53
55
}
54
56
}
55
57
@@ -68,25 +70,53 @@ func testDecode(t *testing.T, expectedEncoding Encoding, expectedBytes []byte, d
68
70
}
69
71
70
72
func TestEncode (t * testing.T ) {
71
- for encoding , data := range encodedSamples {
72
- testEncode (t , encoding , sampleBytes , data )
73
+ for encoding := range EncodingToStr {
74
+ testEncode (t , encoding , sampleBytes , encodedSamples [ encoding ] )
73
75
}
74
76
}
75
77
76
78
func TestDecode (t * testing.T ) {
77
- for encoding , data := range encodedSamples {
78
- testDecode (t , encoding , sampleBytes , data )
79
+ for encoding := range EncodingToStr {
80
+ testDecode (t , encoding , sampleBytes , encodedSamples [ encoding ] )
79
81
}
80
82
}
81
83
82
84
func TestRoundTrip (t * testing.T ) {
83
- buf := make ([]byte , 37 + 16 ) // sufficiently large prime number of bytes (37) + another 16 to test leading 0s
85
+
86
+ for base := range EncodingToStr {
87
+ if int (base ) == 0 {
88
+ // skip identity: any byte goes there
89
+ continue
90
+ }
91
+
92
+ _ , _ , err := Decode (string (base ) + "\u00A0 " )
93
+ if err == nil {
94
+ t .Fatal (EncodingToStr [base ] + " decode should fail on low-unicode" )
95
+ }
96
+
97
+ _ , _ , err = Decode (string (base ) + "\u1F4A 8" )
98
+ if err == nil {
99
+ t .Fatal (EncodingToStr [base ] + " decode should fail on emoji" )
100
+ }
101
+
102
+ _ , _ , err = Decode (string (base ) + "!" )
103
+ if err == nil {
104
+ t .Fatal (EncodingToStr [base ] + " decode should fail on punctuation" )
105
+ }
106
+
107
+ _ , _ , err = Decode (string (base ) + "\xA0 " )
108
+ if err == nil {
109
+ t .Fatal (EncodingToStr [base ] + " decode should fail on high-latin1" )
110
+ }
111
+ }
112
+
113
+ buf := make ([]byte , 137 + 16 ) // sufficiently large prime number of bytes + another 16 to test leading 0s
84
114
rand .Read (buf [16 :])
85
115
86
116
for base := range EncodingToStr {
87
117
88
118
// test roundtrip from the full zero-prefixed buffer down to a single byte
89
- for i := 0 ; i <= len (buf )- 1 ; i ++ {
119
+ for i := 0 ; i < len (buf ); i ++ {
90
120
91
121
// use a copy to verify we are not overwriting the supplied buffer
92
122
newBuf := make ([]byte , len (buf )- i )
@@ -114,14 +144,17 @@ func TestRoundTrip(t *testing.T) {
114
144
t .Fatal ("input wasnt the same as output" , buf [i :], out )
115
145
}
116
146
117
- // When we have 3 leading zeroes, and this is a case-insensitive codec
118
- // semi-randomly swap case in enc and try again
147
+ // When we have 3 leading zeroes, do a few extra tests
148
+ // ( choice of leading zeroes is arbitrary - just cutting down on test permutations )
149
+
119
150
if i == 13 {
151
+
152
+ // if this is a case-insensitive codec semi-randomly swap case in enc and try again
120
153
name := EncodingToStr [base ]
121
154
if name [len (name )- 5 :] == "upper" || Encodings [name + "upper" ] > 0 {
122
155
caseTamperedEnc := []byte (enc )
123
156
124
- for _ , j := range []int {3 , 5 , 8 , 13 , 21 , 23 , 29 } {
157
+ for _ , j := range []int {3 , 5 , 8 , 13 , 21 , 23 , 29 , 47 , 52 } {
125
158
if caseTamperedEnc [j ] >= 65 && caseTamperedEnc [j ] <= 90 {
126
159
caseTamperedEnc [j ] += 32
127
160
} else if caseTamperedEnc [j ] >= 97 && caseTamperedEnc [j ] <= 122 {
@@ -138,49 +171,77 @@ func TestRoundTrip(t *testing.T) {
138
171
t .Fatal ("got wrong encoding out" )
139
172
}
140
173
if ! bytes .Equal (buf [i :], out ) {
141
- t .Fatal ("input wasnt the same as output" , buf [i :], out )
174
+ t .Fatal ("input wasn't the same as output" , buf [i :], out )
142
175
}
143
176
}
144
177
}
145
178
}
146
179
}
147
180
181
+ // Test that nothing overflows
182
+ maxValueBuf := make ([]byte , 131 )
183
+ for i := 0 ; i < len (maxValueBuf ); i ++ {
184
+ maxValueBuf [i ] = 0xFF
185
+ }
186
+
187
+ for base := range EncodingToStr {
188
+
189
+ // test roundtrip from the complete buffer down to a single byte
190
+ for i := 0 ; i < len (maxValueBuf ); i ++ {
191
+
192
+ enc , err := Encode (base , maxValueBuf [i :])
193
+ if err != nil {
194
+ t .Fatal (err )
195
+ }
196
+
197
+ e , out , err := Decode (enc )
198
+ if err != nil {
199
+ t .Fatal (err )
200
+ }
201
+
202
+ if e != base {
203
+ t .Fatal ("got wrong encoding out" )
204
+ }
205
+
206
+ if ! bytes .Equal (maxValueBuf [i :], out ) {
207
+ t .Fatal ("input wasn't the same as output" , maxValueBuf [i :], out )
208
+ }
209
+ }
210
+ }
211
+
148
212
_ , _ , err := Decode ("" )
149
213
if err == nil {
150
- t .Fatal ("shouldnt be able to decode empty string" )
214
+ t .Fatal ("shouldn't be able to decode empty string" )
151
215
}
152
216
}
153
217
218
+ var benchmarkBuf [36 ]byte // typical CID size
219
+ var benchmarkCodecs []string
220
+
221
+ func init () {
222
+ rand .Read (benchmarkBuf [:])
223
+
224
+ benchmarkCodecs = make ([]string , 0 , len (Encodings ))
225
+ for n := range Encodings {
226
+
227
+ // // Only bench b36 and b58
228
+ // if len(n) < 6 || (n[4:6] != "36" && n[4:6] != "58") {
229
+ // continue
230
+ // }
231
+
232
+ benchmarkCodecs = append (benchmarkCodecs , n )
233
+ }
234
+ sort .Strings (benchmarkCodecs )
235
+ }
236
+
154
237
func BenchmarkRoundTrip (b * testing.B ) {
155
- buf := make ([]byte , 32 )
156
- rand .Read (buf )
157
238
b .ResetTimer ()
158
239
159
- bases := map [string ]Encoding {
160
- "Identity" : Identity ,
161
- "Base2" : Base2 ,
162
- "Base16" : Base16 ,
163
- "Base16Upper" : Base16Upper ,
164
- "Base32" : Base32 ,
165
- "Base32Upper" : Base32Upper ,
166
- "Base32pad" : Base32pad ,
167
- "Base32padUpper" : Base32padUpper ,
168
- "Base32hex" : Base32hex ,
169
- "Base32hexUpper" : Base32hexUpper ,
170
- "Base32hexPad" : Base32hexPad ,
171
- "Base32hexPadUpper" : Base32hexPadUpper ,
172
- "Base58Flickr" : Base58Flickr ,
173
- "Base58BTC" : Base58BTC ,
174
- "Base64" : Base64 ,
175
- "Base64url" : Base64url ,
176
- "Base64pad" : Base64pad ,
177
- "Base64urlPad" : Base64urlPad ,
178
- }
179
-
180
- for name , base := range bases {
240
+ for _ , name := range benchmarkCodecs {
181
241
b .Run (name , func (b * testing.B ) {
242
+ base := Encodings [name ]
182
243
for i := 0 ; i < b .N ; i ++ {
183
- enc , err := Encode (base , buf )
244
+ enc , err := Encode (base , benchmarkBuf [:] )
184
245
if err != nil {
185
246
b .Fatal (err )
186
247
}
@@ -194,8 +255,40 @@ func BenchmarkRoundTrip(b *testing.B) {
194
255
b .Fatal ("got wrong encoding out" )
195
256
}
196
257
197
- if ! bytes .Equal (buf , out ) {
198
- b .Fatal ("input wasnt the same as output" , buf , out )
258
+ if ! bytes .Equal (benchmarkBuf [:], out ) {
259
+ b .Fatal ("input wasnt the same as output" , benchmarkBuf , out )
260
+ }
261
+ }
262
+ })
263
+ }
264
+ }
265
+
266
+ func BenchmarkEncode (b * testing.B ) {
267
+ b .ResetTimer ()
268
+
269
+ for _ , name := range benchmarkCodecs {
270
+ b .Run (name , func (b * testing.B ) {
271
+ base := Encodings [name ]
272
+ for i := 0 ; i < b .N ; i ++ {
273
+ _ , err := Encode (base , benchmarkBuf [:])
274
+ if err != nil {
275
+ b .Fatal (err )
276
+ }
277
+ }
278
+ })
279
+ }
280
+ }
281
+
282
+ func BenchmarkDecode (b * testing.B ) {
283
+ b .ResetTimer ()
284
+
285
+ for _ , name := range benchmarkCodecs {
286
+ b .Run (name , func (b * testing.B ) {
287
+ enc , _ := Encode (Encodings [name ], benchmarkBuf [:])
288
+ for i := 0 ; i < b .N ; i ++ {
289
+ _ , _ , err := Decode (enc )
290
+ if err != nil {
291
+ b .Fatal (err )
199
292
}
200
293
}
201
294
})
0 commit comments