Skip to content

Commit

Permalink
add SB64 type
Browse files Browse the repository at this point in the history
  • Loading branch information
zamicol committed May 26, 2023
1 parent b14bb3f commit f8fb284
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
22 changes: 22 additions & 0 deletions base64.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,25 @@ func MustDecode(b64 string) B64 {
}
return b
}

// sB64 is useful for map keys since currently in Go []byte is not allowed to be
// a map key but string is. The type really should be []byte and not string,
// but Go does not yet support this. See https://github.com/golang/go/issues/283
// and https://github.com/google/go-cmp/issues/67. SB64 will be deprecated
// if/when Go supports []byte keys.
//
// From https://go.dev/blog/strings >[A] string holds arbitrary bytes. It is not
// required to hold Unicode text, UTF-8 text, or any other predefined format. As
// far as the content of a string is concerned, it is exactly equivalent to a
// slice of bytes.
type SB64 string

// String implements fmt.Stringer
func (b SB64) String() string {
return B64(b).String()
}

// GoString implements fmt.GoString
func (b SB64) GoString() string {
return b.String()
}
50 changes: 50 additions & 0 deletions base64_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package coze

import (
"bytes"
"crypto/rand"
"encoding/json"
"fmt"
"testing"
)

// B64 of nil is "" while B64 of 0 is "AA".
Expand Down Expand Up @@ -127,3 +130,50 @@ func ExampleB64_non_strict_decode() {
// invalid character '\n' in string literal
// invalid character '\r' in string literal
}

// ExampleSB64 demonstrates using SB64 as a map key and that fmt prints "RFC
// 4648 base 64 URI canonical with padding truncated" properly.
func ExampleSB64() {
b := MustDecode("zVzgRU3WFpnrlVJAnI4ZU1Od4Agl5Zd4jIP79oubOW0")
b2 := MustDecode("vZIAk8rjcSIKZKokGylCtVoI3DXvFYJn4XNWzf_C_FA")

lp := make(map[SB64]B64)
lp[SB64(b)] = B64(b2)

fmt.Printf("%s\n", SB64(b))
fmt.Printf("%s\n", lp)
fmt.Printf("%+v\n", lp)
fmt.Printf("%#v\n", lp)

// Output:
// zVzgRU3WFpnrlVJAnI4ZU1Od4Agl5Zd4jIP79oubOW0
// map[zVzgRU3WFpnrlVJAnI4ZU1Od4Agl5Zd4jIP79oubOW0:vZIAk8rjcSIKZKokGylCtVoI3DXvFYJn4XNWzf_C_FA]
// map[zVzgRU3WFpnrlVJAnI4ZU1Od4Agl5Zd4jIP79oubOW0:vZIAk8rjcSIKZKokGylCtVoI3DXvFYJn4XNWzf_C_FA]
// map[coze.SB64]coze.B64{zVzgRU3WFpnrlVJAnI4ZU1Od4Agl5Zd4jIP79oubOW0:vZIAk8rjcSIKZKokGylCtVoI3DXvFYJn4XNWzf_C_FA}
}

// FuzzCastB64ToString ensures that casting to and from B64 and string does not
// cause unexpected issues (issues like replacing bytes with the unicode
// replacement character).
// https://go.dev/security/fuzz/
// https://go.dev/doc/tutorial/fuzz
func FuzzCastB64ToString(f *testing.F) {
f.Add(100)
f.Fuzz(func(t *testing.T, a int) {
var b B64
var err error
for i := 0; i < a; i++ {
b = make([]byte, 32)
_, err = rand.Read(b)
if err != nil {
t.Fatal(err)
}

s := string(b)
bb := B64(s)
if !bytes.Equal(b, bb) {
t.Fatalf("Casting to string: %s failed when converting back B64.", s)
}
}
})
}

0 comments on commit f8fb284

Please sign in to comment.