Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…pc-client into metadata
  • Loading branch information
yrong committed Jul 1, 2024
2 parents d5320d6 + bfb99b8 commit ef6e10e
Show file tree
Hide file tree
Showing 4 changed files with 338 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ require (
github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
github.com/go-ole/go-ole v1.2.1 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa
github.com/gtank/merlin v0.1.1 // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
github.com/kr/text v0.2.0 // indirect
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64=
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
Expand Down
84 changes: 84 additions & 0 deletions types/generic_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package types_test

import (
"testing"

. "github.com/snowfork/go-substrate-rpc-client/v4/types"

fuzz "github.com/google/gofuzz"
. "github.com/snowfork/go-substrate-rpc-client/v4/types/codec"
. "github.com/snowfork/go-substrate-rpc-client/v4/types/test_utils"
"github.com/stretchr/testify/assert"
)

var (
optionFuzzOpts = []FuzzOpt{
WithFuzzFuncs(func(o *Option[U64], c fuzz.Continue) {
if c.RandBool() {
*o = NewEmptyOption[U64]()
return
}

var u U64

c.Fuzz(&u)

*o = NewOption[U64](u)
}),
}
)

func TestOption_EncodeDecode(t *testing.T) {
AssertRoundTripFuzz[Option[U64]](t, 100, optionFuzzOpts...)
AssertEncodeEmptyObj[Option[U64]](t, 1)

testOptionEncodeLen[U64](11, t)

accountID := newTestAccountID()
testOptionEncodeLen[AccountID](accountID, t)

testOptionEncodeLen[ItemDetails](testInstanceDetails, t)
}

func testOptionEncodeLen[T any](testVal T, t *testing.T) {
valEnc, err := Encode(testVal)
assert.NoError(t, err)

opt := NewOption[T](testVal)
optEnc, err := Encode(opt)

assert.Equal(t, len(optEnc), len(valEnc)+1)
}

func TestOption_OptionMethods(t *testing.T) {
testOptionMethods[U64](11, t)

accountID := newTestAccountID()

testOptionMethods[*AccountID](&accountID, t)
testOptionMethods[AccountID](accountID, t)

testOptionMethods[*ItemDetails](&testInstanceDetails, t)
testOptionMethods[ItemDetails](testInstanceDetails, t)
}

func testOptionMethods[T any](testVal T, t *testing.T) {
o := NewEmptyOption[T]()

var emptyVal T

hasValue, value := o.Unwrap()
assert.False(t, hasValue)
assert.Equal(t, emptyVal, value)

o.SetSome(testVal)

hasValue, value = o.Unwrap()
assert.True(t, hasValue)
assert.Equal(t, testVal, value)

o.SetNone()
hasValue, value = o.Unwrap()
assert.False(t, hasValue)
assert.Equal(t, emptyVal, value)
}
252 changes: 252 additions & 0 deletions types/test_utils/test_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
// Go Substrate RPC Client (GSRPC) provides APIs and types around Polkadot and any Substrate-based chain RPC calls
//
// Copyright 2019 Centrifuge GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package testutils

import (
"bytes"
"fmt"
"reflect"
"testing"

fuzz "github.com/google/gofuzz"
"github.com/snowfork/go-substrate-rpc-client/v4/scale"
"github.com/snowfork/go-substrate-rpc-client/v4/types/codec"
"github.com/stretchr/testify/assert"
"golang.org/x/crypto/blake2b"
)

type FuzzOpt func(f *fuzz.Fuzzer)

func WithNilChance(p float64) FuzzOpt {
return func(f *fuzz.Fuzzer) {
f.NilChance(p)
}
}

func WithFuzzFuncs(fuzzFns ...any) FuzzOpt {
return func(f *fuzz.Fuzzer) {
f.Funcs(fuzzFns...)
}
}

func WithNumElements(atLeast, atMost int) FuzzOpt {
return func(f *fuzz.Fuzzer) {
f.NumElements(atLeast, atMost)
}
}

func WithMaxDepth(depth int) FuzzOpt {
return func(f *fuzz.Fuzzer) {
f.MaxDepth(depth)
}
}

func CombineFuzzOpts(optsSlice ...[]FuzzOpt) []FuzzOpt {
var o []FuzzOpt

for _, opts := range optsSlice {
o = append(o, opts...)
}

return o
}

func AssertRoundTripFuzz[T any](t *testing.T, fuzzCount int, fuzzOpts ...FuzzOpt) {
f := fuzz.New().NilChance(0)

for _, opt := range fuzzOpts {
opt(f)
}

for i := 0; i < fuzzCount; i++ {
var fuzzData T

f.Fuzz(&fuzzData)

AssertRoundtrip(t, fuzzData)
}
}

func AssertDecodeNilData[T any](t *testing.T) {
var obj T

err := scale.NewDecoder(bytes.NewReader(nil)).Decode(&obj)
assert.NotNil(t, err)
}

func AssertEncodeEmptyObj[T any](t *testing.T, expectedByteLen int) {
var obj T

var buffer = bytes.Buffer{}

err := scale.NewEncoder(&buffer).Encode(obj)
assert.Nil(t, err)
assert.Len(t, buffer.Bytes(), expectedByteLen)
}

type EncodedLengthAssert struct {
Input interface{}
Expected int
}

func AssertEqual(t *testing.T, a interface{}, b interface{}) {
if reflect.DeepEqual(a, b) {
return
}
t.Errorf("Received %#v (type %v), expected %#v (type %v)", a, reflect.TypeOf(a), b, reflect.TypeOf(b))
}

func AssertRoundtrip(t *testing.T, value interface{}) {
var buffer = bytes.Buffer{}
err := scale.NewEncoder(&buffer).Encode(value)
assert.NoError(t, err)
target := reflect.New(reflect.TypeOf(value))
err = scale.NewDecoder(&buffer).Decode(target.Interface())
assert.NoError(t, err)
AssertEqual(t, target.Elem().Interface(), value)
}

func AssertEncodedLength(t *testing.T, encodedLengthAsserts []EncodedLengthAssert) {
for _, test := range encodedLengthAsserts {
result, err := codec.EncodedLength(test.Input)
if err != nil {
t.Errorf("Encoded length error for input %v: %v\n", test.Input, err)
}
if result != test.Expected {
t.Errorf("Fail, input %v, expected %v, result %v\n", test.Input, test.Expected, result)
}
}
}

type EncodingAssert struct {
Input interface{}
Expected []byte
}

func AssertEncode(t *testing.T, encodingAsserts []EncodingAssert) {
for _, test := range encodingAsserts {
result, err := codec.Encode(test.Input)
if err != nil {
t.Errorf("Encoding error for input %v: %v\n", test.Input, err)
}

if !bytes.Equal(result, test.Expected) {
t.Errorf("Fail, input %v, expected %#x, result %#x\n", test.Input, test.Expected, result)
}
}
}

type DecodingAssert struct {
Input []byte
Expected interface{}
}

func AssertDecode(t *testing.T, decodingAsserts []DecodingAssert) {
for _, test := range decodingAsserts {
target := reflect.New(reflect.TypeOf(test.Expected))
err := codec.Decode(test.Input, target.Interface())
if err != nil {
t.Errorf("Encoding error for input %v: %v\n", test.Input, err)
}
AssertEqual(t, target.Elem().Interface(), test.Expected)
}
}

type HashAssert struct {
Input interface{}
Expected []byte
}

func AssertHash(t *testing.T, hashAsserts []HashAssert) {
for _, test := range hashAsserts {
enc, err := codec.Encode(test.Input)

if err != nil {
t.Errorf("Couldn't encode input %v: %s", test.Input, err)
}

result := blake2b.Sum256(enc)

if !bytes.Equal(result[:], test.Expected) {
t.Errorf("Fail, input %v, expected %#x, result %#x\n", test.Input, test.Expected, result)
}
}
}

type EncodeToHexAssert struct {
Input interface{}
Expected string
}

func AssertEncodeToHex(t *testing.T, encodeToHexAsserts []EncodeToHexAssert) {
for _, test := range encodeToHexAsserts {
result, err := codec.EncodeToHex(test.Input)
if err != nil {
t.Errorf("Hex error for input %v: %v\n", test.Input, err)
}
if result != test.Expected {
t.Errorf("Fail, input %v, expected %v, result %v\n", test.Input, test.Expected, result)
}
}
}

type StringAssert struct {
Input interface{}
Expected string
}

func AssertString(t *testing.T, stringAsserts []StringAssert) {
for _, test := range stringAsserts {
result := fmt.Sprintf("%v", test.Input)
if result != test.Expected {
t.Errorf("Fail, input %v, expected %v, result %v\n", test.Input, test.Expected, result)
}
}
}

type EqAssert struct {
Input interface{}
Other interface{}
Expected bool
}

func AssertEq(t *testing.T, eqAsserts []EqAssert) {
for _, test := range eqAsserts {
result := codec.Eq(test.Input, test.Other)
if result != test.Expected {
t.Errorf("Fail, input %v, other %v, expected %v, result %v\n", test.Input, test.Other, test.Expected, result)
}
}
}

type jsonMarshalerUnmarshaler[T any] interface {
UnmarshalJSON([]byte) error
MarshalJSON() ([]byte, error)

*T // helper type that allows us to instantiate a non-nil T
}

func AssertJSONRoundTrip[T any, U jsonMarshalerUnmarshaler[T]](t *testing.T, value U) {
b, err := value.MarshalJSON()
assert.NoError(t, err)

tt := U(new(T))
err = tt.UnmarshalJSON(b)
assert.NoError(t, err)

AssertEqual(t, value, tt)
}

0 comments on commit ef6e10e

Please sign in to comment.