feat: initial Multibase

This commit is contained in:
Derrick Hammer 2024-01-03 03:48:19 -05:00
parent 3d4fdfb9e3
commit ee15a298a4
Signed by: pcfreak30
GPG Key ID: C997C339BE476FF2
2 changed files with 329 additions and 0 deletions

72
cid/multibase.go Normal file
View File

@ -0,0 +1,72 @@
package cid
import (
"errors"
"git.lumeweb.com/LumeWeb/libs5-go/internal/bases"
"github.com/multiformats/go-multibase"
)
var (
errMultibaseEncodingNotSupported = errors.New("multibase encoding not supported")
errMultibaseDecodeZeroLength = errors.New("cannot decode multibase for zero length string")
)
type Encoder interface {
ToBytes() []byte
}
type multibaseImpl struct {
Multibase
encoder Encoder
}
type Multibase interface {
ToHex() (string, error)
ToBase32() (string, error)
ToBase64Url() (string, error)
ToBase58() (string, error)
ToString() (string, error)
}
var _ Multibase = (*multibaseImpl)(nil)
func NewMultibase(encoder Encoder) Multibase {
return &multibaseImpl{encoder: encoder}
}
func DecodeString(data string) (bytes []byte, err error) {
if len(data) == 0 {
return nil, errMultibaseDecodeZeroLength
}
switch data[0] {
case 'z', 'f', 'u', 'b':
_, bytes, err = multibase.Decode(data)
case ':':
bytes = []byte(data)
default:
err = errMultibaseEncodingNotSupported
}
return bytes, err
}
func (m *multibaseImpl) ToHex() (string, error) {
return bases.ToHex(m.encoder.ToBytes())
}
func (m *multibaseImpl) ToBase32() (string, error) {
return bases.ToBase32(m.encoder.ToBytes())
}
func (m *multibaseImpl) ToBase64Url() (string, error) {
return bases.ToBase64Url(m.encoder.ToBytes())
}
func (m *multibaseImpl) ToBase58() (string, error) {
return bases.ToBase58BTC(m.encoder.ToBytes())
}
func (m *multibaseImpl) ToString() (string, error) {
return m.ToBase58()
}

257
cid/multibase_test.go Normal file
View File

@ -0,0 +1,257 @@
package cid
import (
"git.lumeweb.com/LumeWeb/libs5-go/internal/testdata"
"reflect"
"testing"
)
type encoder struct {
Multibase
data []byte
}
func (e *encoder) ToBytes() []byte {
return e.data
}
func newEncoder(data []byte) encoder {
e := &encoder{data: data}
m := NewMultibase(e)
e.Multibase = m
return *e
}
func TestDecodeString(t *testing.T) {
type args struct {
data string
}
tests := []struct {
name string
args args
wantBytes []byte
wantErr bool
}{
{
name: "TestValidMultibase_z",
args: args{data: testdata.MediaBase58CID},
wantBytes: testdata.MediaCIDBytes, // Adjust this based on the expected output of multibase.Decode("zabc")
wantErr: false,
},
{
name: "TestValidMultibase_f",
args: args{data: testdata.MediaBase16CID},
wantBytes: testdata.MediaCIDBytes, // Adjust this based on the expected output of multibase.Decode("fxyz")
wantErr: false,
},
{
name: "TestValidMultibase_u",
args: args{data: testdata.MediaBase64CID},
wantBytes: testdata.MediaCIDBytes, // Adjust this based on the expected output of multibase.Decode("uhello")
wantErr: false,
},
{
name: "TestValidMultibase_b",
args: args{data: testdata.MediaBase32CID},
wantBytes: testdata.MediaCIDBytes, // Adjust this based on the expected output of multibase.Decode("bworld")
wantErr: false,
},
/* {
name: "TestColonPrefix",
args: args{data: ":data"},
wantBytes: []byte(":data"),
wantErr: false,
},*/
{
name: "TestUnsupportedPrefix",
args: args{data: "xunsupported"},
wantBytes: nil,
wantErr: true,
},
{
name: "TestEmptyInput",
args: args{data: ""},
wantBytes: nil,
wantErr: true,
}, /*
{
name: "TestColonOnlyInput",
args: args{data: ":"},
wantBytes: []byte(":"),
wantErr: false,
},*/
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotBytes, err := DecodeString(tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("DecodeString() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotBytes, tt.wantBytes) {
t.Errorf("DecodeString() gotBytes = %v, want %v", gotBytes, tt.wantBytes)
}
})
}
}
func TestMultibase_ToBase32(t *testing.T) {
tests := []struct {
name string
encoder encoder
want string
wantErr bool
}{
{
name: "Is Raw CID",
encoder: newEncoder(testdata.RawCIDBytes),
want: testdata.RawBase32CID,
wantErr: false,
}, {
name: "Is Media CID",
encoder: newEncoder(testdata.MediaCIDBytes),
want: testdata.MediaBase32CID,
wantErr: false,
}, {
name: "Is Resolver CID",
encoder: newEncoder(testdata.ResolverCIDBytes),
want: testdata.ResolverBase32CID,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.encoder.ToBase32()
if (err != nil) != tt.wantErr {
t.Errorf("ToBase32() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("ToBase32() got = %v, want %v", got, tt.want)
}
})
}
}
func TestMultibase_ToBase58(t *testing.T) {
tests := []struct {
name string
encoder encoder
want string
wantErr bool
}{
{
name: "Is Raw CID",
encoder: newEncoder(testdata.RawCIDBytes),
want: testdata.RawBase58CID,
wantErr: false,
}, {
name: "Is Media CID",
encoder: newEncoder(testdata.MediaCIDBytes),
want: testdata.MediaBase58CID,
wantErr: false,
},
{
name: "Is Resolver CID",
encoder: newEncoder(testdata.ResolverCIDBytes),
want: testdata.ResolverBase58CID,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.encoder.ToBase58()
if (err != nil) != tt.wantErr {
t.Errorf("ToBase58() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("ToBase58() got = %v, want %v", got, tt.want)
}
})
}
}
func TestMultibase_ToBase64Url(t *testing.T) {
tests := []struct {
name string
encoder encoder
want string
wantErr bool
}{
{
name: "Is Raw CID",
encoder: newEncoder(testdata.RawCIDBytes),
want: testdata.RawBase64CID,
wantErr: false,
}, {
name: "Is Media CID",
encoder: newEncoder(testdata.MediaCIDBytes),
want: testdata.MediaBase64CID,
wantErr: false,
},
{
name: "Is Resolver CID",
encoder: newEncoder(testdata.ResolverCIDBytes),
want: testdata.ResolverBase64CID,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.encoder.ToBase64Url()
if (err != nil) != tt.wantErr {
t.Errorf("ToBase64Url() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("ToBase64Url() got = %v, want %v", got, tt.want)
}
})
}
}
func TestMultibase_ToHex(t *testing.T) {
tests := []struct {
name string
encoder encoder
want string
wantErr bool
}{
{
name: "Is Raw CID",
encoder: newEncoder(testdata.RawCIDBytes),
want: testdata.RawBase16CID,
wantErr: false,
}, {
name: "Is Media CID",
encoder: newEncoder(testdata.MediaCIDBytes),
want: testdata.MediaBase16CID,
wantErr: false,
},
{
name: "Is Resolver CID",
encoder: newEncoder(testdata.ResolverCIDBytes),
want: testdata.ResolverBase16CID,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.encoder.ToHex()
if (err != nil) != tt.wantErr {
t.Errorf("ToHex() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("ToHex() got = %v, want %v", got, tt.want)
}
})
}
}
func TestMultibase_ToString(t *testing.T) {
TestMultibase_ToBase58(t)
}