neoneo-go/pkg/smartcontract/manifest/permission_test.go
2021-02-09 22:31:26 +03:00

216 lines
6.7 KiB
Go

package manifest
import (
"encoding/json"
"fmt"
"reflect"
"testing"
"github.com/nspcc-dev/neo-go/internal/random"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require"
)
func TestNewPermission(t *testing.T) {
require.Panics(t, func() { NewPermission(PermissionWildcard, util.Uint160{}) })
require.Panics(t, func() { NewPermission(PermissionHash) })
require.Panics(t, func() { NewPermission(PermissionHash, 1) })
require.Panics(t, func() { NewPermission(PermissionGroup) })
require.Panics(t, func() { NewPermission(PermissionGroup, util.Uint160{}) })
}
func TestPermissionIsValid(t *testing.T) {
p := Permission{}
require.NoError(t, p.IsValid())
p.Methods.Add("")
require.Error(t, p.IsValid())
p.Methods.Value = nil
p.Methods.Add("qwerty")
require.NoError(t, p.IsValid())
p.Methods.Add("poiuyt")
require.NoError(t, p.IsValid())
p.Methods.Add("qwerty")
require.Error(t, p.IsValid())
}
func TestPermissionsAreValid(t *testing.T) {
p := Permissions{}
require.NoError(t, p.AreValid())
p = append(p, Permission{Methods: WildStrings{Value: []string{""}}})
require.Error(t, p.AreValid())
p = p[:0]
p = append(p, *NewPermission(PermissionHash, util.Uint160{1, 2, 3}))
require.NoError(t, p.AreValid())
priv0, err := keys.NewPrivateKey()
require.NoError(t, err)
priv1, err := keys.NewPrivateKey()
require.NoError(t, err)
p = append(p, *NewPermission(PermissionGroup, priv0.PublicKey()))
require.NoError(t, p.AreValid())
p = append(p, *NewPermission(PermissionGroup, priv1.PublicKey()))
require.NoError(t, p.AreValid())
p = append(p, *NewPermission(PermissionWildcard))
require.NoError(t, p.AreValid())
p = append(p, *NewPermission(PermissionHash, util.Uint160{3, 2, 1}))
require.NoError(t, p.AreValid())
p = append(p, *NewPermission(PermissionWildcard))
require.Error(t, p.AreValid())
p = append(p[:len(p)-1], *NewPermission(PermissionHash, util.Uint160{1, 2, 3}))
require.Error(t, p.AreValid())
p = append(p[:len(p)-1], *NewPermission(PermissionGroup, priv0.PublicKey()))
require.Error(t, p.AreValid())
}
func TestPermission_MarshalJSON(t *testing.T) {
t.Run("wildcard", func(t *testing.T) {
expected := NewPermission(PermissionWildcard)
expected.Methods.Restrict()
testMarshalUnmarshal(t, expected, NewPermission(PermissionWildcard))
})
t.Run("group", func(t *testing.T) {
expected := NewPermission(PermissionWildcard)
expected.Contract.Type = PermissionGroup
priv, err := keys.NewPrivateKey()
require.NoError(t, err)
expected.Contract.Value = priv.PublicKey()
expected.Methods.Add("method1")
expected.Methods.Add("method2")
testMarshalUnmarshal(t, expected, NewPermission(PermissionWildcard))
})
t.Run("hash", func(t *testing.T) {
expected := NewPermission(PermissionWildcard)
expected.Contract.Type = PermissionHash
expected.Contract.Value = random.Uint160()
testMarshalUnmarshal(t, expected, NewPermission(PermissionWildcard))
})
}
func TestPermissionDesc_MarshalJSON(t *testing.T) {
t.Run("uint160 with 0x", func(t *testing.T) {
u := random.Uint160()
s := u.StringLE()
js := []byte(fmt.Sprintf(`"0x%s"`, s))
d := new(PermissionDesc)
require.NoError(t, json.Unmarshal(js, d))
require.Equal(t, u, d.Value.(util.Uint160))
})
t.Run("invalid uint160", func(t *testing.T) {
d := new(PermissionDesc)
s := random.String(util.Uint160Size * 2)
js := []byte(fmt.Sprintf(`"ok%s"`, s))
require.Error(t, json.Unmarshal(js, d))
js = []byte(fmt.Sprintf(`"%s"`, s))
require.Error(t, json.Unmarshal(js, d))
})
t.Run("invalid public key", func(t *testing.T) {
d := new(PermissionDesc)
s := random.String(65)
s = "k" + s // not a hex
js := []byte(fmt.Sprintf(`"%s"`, s))
require.Error(t, json.Unmarshal(js, d))
})
t.Run("not a string", func(t *testing.T) {
d := new(PermissionDesc)
js := []byte(`123`)
require.Error(t, json.Unmarshal(js, d))
})
t.Run("invalid string", func(t *testing.T) {
d := new(PermissionDesc)
js := []byte(`"invalid length"`)
require.Error(t, json.Unmarshal(js, d))
})
}
func testMarshalUnmarshal(t *testing.T, expected, actual interface{}) {
data, err := json.Marshal(expected)
require.NoError(t, err)
require.NoError(t, json.Unmarshal(data, actual))
require.Equal(t, expected, actual)
}
func TestPermission_ToStackItemFromStackItem(t *testing.T) {
t.Run("wildcard", func(t *testing.T) {
p := NewPermission(PermissionWildcard)
expected := stackitem.NewStruct([]stackitem.Item{
stackitem.Null{},
stackitem.Null{},
})
CheckToFromStackItem(t, p, expected)
})
t.Run("hash", func(t *testing.T) {
p := NewPermission(PermissionHash, util.Uint160{1, 2, 3})
p.Methods = WildStrings{Value: []string{"a"}}
expected := stackitem.NewStruct([]stackitem.Item{
stackitem.NewByteArray(util.Uint160{1, 2, 3}.BytesBE()),
stackitem.NewArray([]stackitem.Item{
stackitem.NewByteArray([]byte("a")),
}),
})
CheckToFromStackItem(t, p, expected)
})
t.Run("group", func(t *testing.T) {
pk, _ := keys.NewPrivateKey()
p := NewPermission(PermissionGroup, pk.PublicKey())
expected := stackitem.NewStruct([]stackitem.Item{
stackitem.NewByteArray(pk.PublicKey().Bytes()),
stackitem.Null{},
})
CheckToFromStackItem(t, p, expected)
})
}
type Interoperable interface {
ToStackItem() stackitem.Item
FromStackItem(stackitem.Item) error
}
func CheckToFromStackItem(t *testing.T, source Interoperable, expected stackitem.Item) {
actual := source.ToStackItem()
require.Equal(t, expected, actual)
actualSource := reflect.New(reflect.TypeOf(source).Elem()).Interface().(Interoperable)
require.NoError(t, actualSource.FromStackItem(actual))
require.Equal(t, source, actualSource)
}
func TestPermission_FromStackItemErrors(t *testing.T) {
errCases := map[string]stackitem.Item{
"not a struct": stackitem.NewArray([]stackitem.Item{}),
"invalid length": stackitem.NewStruct([]stackitem.Item{}),
"invalid contract type": stackitem.NewStruct([]stackitem.Item{stackitem.NewArray([]stackitem.Item{}), stackitem.NewBool(false)}),
"invalid contract length": stackitem.NewStruct([]stackitem.Item{stackitem.NewByteArray([]byte{1, 2, 3}), stackitem.NewBool(false)}),
"invalid contract pubkey": stackitem.NewStruct([]stackitem.Item{stackitem.NewByteArray(make([]byte, 33)), stackitem.NewBool(false)}),
"invalid methods type": stackitem.NewStruct([]stackitem.Item{stackitem.Null{}, stackitem.NewBool(false)}),
"invalid method name": stackitem.NewStruct([]stackitem.Item{stackitem.Null{}, stackitem.NewArray([]stackitem.Item{stackitem.NewArray([]stackitem.Item{})})}),
}
for name, errCase := range errCases {
t.Run(name, func(t *testing.T) {
p := new(Permission)
require.Error(t, p.FromStackItem(errCase))
})
}
}