Even more tests/benchmarks, less repetition in-code
This commit is contained in:
@@ -3,6 +3,7 @@ package multibase
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -36,6 +37,7 @@ var encodedSamples = map[Encoding]string{
|
||||
Base32hexPad: "t8him6pbeehp62r39f9ii0pbmclp7it38d5n6e89144======",
|
||||
Base32hexPadUpper: "T8HIM6PBEEHP62R39F9II0PBMCLP7IT38D5N6E89144======",
|
||||
Base58BTC: "z36UQrhJq9fNDS7DiAHM9YXqDHMPfr4EMArvt",
|
||||
Base58Flickr: "Z36tpRGiQ9Endr7dHahm9xwQdhmoER4emaRVT",
|
||||
Base64: "mRGVjZW50cmFsaXplIGV2ZXJ5dGhpbmchISE",
|
||||
Base64url: "uRGVjZW50cmFsaXplIGV2ZXJ5dGhpbmchISE",
|
||||
Base64pad: "MRGVjZW50cmFsaXplIGV2ZXJ5dGhpbmchISE=",
|
||||
@@ -49,7 +51,7 @@ func testEncode(t *testing.T, encoding Encoding, bytes []byte, expected string)
|
||||
return
|
||||
}
|
||||
if actual != expected {
|
||||
t.Errorf("encoding failed for %c (%d), expected: %s, got: %s", encoding, encoding, expected, actual)
|
||||
t.Errorf("encoding failed for %c (%d / %s), expected: %s, got: %s", encoding, encoding, EncodingToStr[encoding], expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,25 +70,53 @@ func testDecode(t *testing.T, expectedEncoding Encoding, expectedBytes []byte, d
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
for encoding, data := range encodedSamples {
|
||||
testEncode(t, encoding, sampleBytes, data)
|
||||
for encoding := range EncodingToStr {
|
||||
testEncode(t, encoding, sampleBytes, encodedSamples[encoding])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
for encoding, data := range encodedSamples {
|
||||
testDecode(t, encoding, sampleBytes, data)
|
||||
for encoding := range EncodingToStr {
|
||||
testDecode(t, encoding, sampleBytes, encodedSamples[encoding])
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundTrip(t *testing.T) {
|
||||
buf := make([]byte, 37+16) // sufficiently large prime number of bytes (37) + another 16 to test leading 0s
|
||||
|
||||
for base := range EncodingToStr {
|
||||
if int(base) == 0 {
|
||||
// skip identity: any byte goes there
|
||||
continue
|
||||
}
|
||||
|
||||
_, _, err := Decode(string(base) + "\u00A0")
|
||||
if err == nil {
|
||||
t.Fatal(EncodingToStr[base] + " decode should fail on low-unicode")
|
||||
}
|
||||
|
||||
_, _, err = Decode(string(base) + "\u1F4A8")
|
||||
if err == nil {
|
||||
t.Fatal(EncodingToStr[base] + " decode should fail on emoji")
|
||||
}
|
||||
|
||||
_, _, err = Decode(string(base) + "!")
|
||||
if err == nil {
|
||||
t.Fatal(EncodingToStr[base] + " decode should fail on punctuation")
|
||||
}
|
||||
|
||||
_, _, err = Decode(string(base) + "\xA0")
|
||||
if err == nil {
|
||||
t.Fatal(EncodingToStr[base] + " decode should fail on high-latin1")
|
||||
}
|
||||
}
|
||||
|
||||
buf := make([]byte, 137+16) // sufficiently large prime number of bytes + another 16 to test leading 0s
|
||||
rand.Read(buf[16:])
|
||||
|
||||
for base := range EncodingToStr {
|
||||
|
||||
// test roundtrip from the full zero-prefixed buffer down to a single byte
|
||||
for i := 0; i <= len(buf)-1; i++ {
|
||||
for i := 0; i < len(buf); i++ {
|
||||
|
||||
// use a copy to verify we are not overwriting the supplied buffer
|
||||
newBuf := make([]byte, len(buf)-i)
|
||||
@@ -114,14 +144,17 @@ func TestRoundTrip(t *testing.T) {
|
||||
t.Fatal("input wasnt the same as output", buf[i:], out)
|
||||
}
|
||||
|
||||
// When we have 3 leading zeroes, and this is a case-insensitive codec
|
||||
// semi-randomly swap case in enc and try again
|
||||
// When we have 3 leading zeroes, do a few extra tests
|
||||
// ( choice of leading zeroes is arbitrary - just cutting down on test permutations )
|
||||
|
||||
if i == 13 {
|
||||
|
||||
// if this is a case-insensitive codec semi-randomly swap case in enc and try again
|
||||
name := EncodingToStr[base]
|
||||
if name[len(name)-5:] == "upper" || Encodings[name+"upper"] > 0 {
|
||||
caseTamperedEnc := []byte(enc)
|
||||
|
||||
for _, j := range []int{3, 5, 8, 13, 21, 23, 29} {
|
||||
for _, j := range []int{3, 5, 8, 13, 21, 23, 29, 47, 52} {
|
||||
if caseTamperedEnc[j] >= 65 && caseTamperedEnc[j] <= 90 {
|
||||
caseTamperedEnc[j] += 32
|
||||
} else if caseTamperedEnc[j] >= 97 && caseTamperedEnc[j] <= 122 {
|
||||
@@ -138,49 +171,77 @@ func TestRoundTrip(t *testing.T) {
|
||||
t.Fatal("got wrong encoding out")
|
||||
}
|
||||
if !bytes.Equal(buf[i:], out) {
|
||||
t.Fatal("input wasnt the same as output", buf[i:], out)
|
||||
t.Fatal("input wasn't the same as output", buf[i:], out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that nothing overflows
|
||||
maxValueBuf := make([]byte, 131)
|
||||
for i := 0; i < len(maxValueBuf); i++ {
|
||||
maxValueBuf[i] = 0xFF
|
||||
}
|
||||
|
||||
for base := range EncodingToStr {
|
||||
|
||||
// test roundtrip from the complete buffer down to a single byte
|
||||
for i := 0; i < len(maxValueBuf); i++ {
|
||||
|
||||
enc, err := Encode(base, maxValueBuf[i:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
e, out, err := Decode(enc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if e != base {
|
||||
t.Fatal("got wrong encoding out")
|
||||
}
|
||||
|
||||
if !bytes.Equal(maxValueBuf[i:], out) {
|
||||
t.Fatal("input wasn't the same as output", maxValueBuf[i:], out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, _, err := Decode("")
|
||||
if err == nil {
|
||||
t.Fatal("shouldnt be able to decode empty string")
|
||||
t.Fatal("shouldn't be able to decode empty string")
|
||||
}
|
||||
}
|
||||
|
||||
var benchmarkBuf [36]byte // typical CID size
|
||||
var benchmarkCodecs []string
|
||||
|
||||
func init() {
|
||||
rand.Read(benchmarkBuf[:])
|
||||
|
||||
benchmarkCodecs = make([]string, 0, len(Encodings))
|
||||
for n := range Encodings {
|
||||
|
||||
// // Only bench b36 and b58
|
||||
// if len(n) < 6 || (n[4:6] != "36" && n[4:6] != "58") {
|
||||
// continue
|
||||
// }
|
||||
|
||||
benchmarkCodecs = append(benchmarkCodecs, n)
|
||||
}
|
||||
sort.Strings(benchmarkCodecs)
|
||||
}
|
||||
|
||||
func BenchmarkRoundTrip(b *testing.B) {
|
||||
buf := make([]byte, 32)
|
||||
rand.Read(buf)
|
||||
b.ResetTimer()
|
||||
|
||||
bases := map[string]Encoding{
|
||||
"Identity": Identity,
|
||||
"Base2": Base2,
|
||||
"Base16": Base16,
|
||||
"Base16Upper": Base16Upper,
|
||||
"Base32": Base32,
|
||||
"Base32Upper": Base32Upper,
|
||||
"Base32pad": Base32pad,
|
||||
"Base32padUpper": Base32padUpper,
|
||||
"Base32hex": Base32hex,
|
||||
"Base32hexUpper": Base32hexUpper,
|
||||
"Base32hexPad": Base32hexPad,
|
||||
"Base32hexPadUpper": Base32hexPadUpper,
|
||||
"Base58Flickr": Base58Flickr,
|
||||
"Base58BTC": Base58BTC,
|
||||
"Base64": Base64,
|
||||
"Base64url": Base64url,
|
||||
"Base64pad": Base64pad,
|
||||
"Base64urlPad": Base64urlPad,
|
||||
}
|
||||
|
||||
for name, base := range bases {
|
||||
for _, name := range benchmarkCodecs {
|
||||
b.Run(name, func(b *testing.B) {
|
||||
base := Encodings[name]
|
||||
for i := 0; i < b.N; i++ {
|
||||
enc, err := Encode(base, buf)
|
||||
enc, err := Encode(base, benchmarkBuf[:])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -194,8 +255,40 @@ func BenchmarkRoundTrip(b *testing.B) {
|
||||
b.Fatal("got wrong encoding out")
|
||||
}
|
||||
|
||||
if !bytes.Equal(buf, out) {
|
||||
b.Fatal("input wasnt the same as output", buf, out)
|
||||
if !bytes.Equal(benchmarkBuf[:], out) {
|
||||
b.Fatal("input wasnt the same as output", benchmarkBuf, out)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncode(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
|
||||
for _, name := range benchmarkCodecs {
|
||||
b.Run(name, func(b *testing.B) {
|
||||
base := Encodings[name]
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := Encode(base, benchmarkBuf[:])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecode(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
|
||||
for _, name := range benchmarkCodecs {
|
||||
b.Run(name, func(b *testing.B) {
|
||||
enc, _ := Encode(Encodings[name], benchmarkBuf[:])
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, err := Decode(enc)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user