Parse any of address in CLI; more tests

This commit is contained in:
Alex Peters
2022-09-07 15:46:27 +02:00
parent 089076d065
commit 2567927d09
8 changed files with 630 additions and 62 deletions

View File

@@ -73,6 +73,7 @@ func GenesisStoreCodeCmd(defaultNodeHome string, genesisMutator GenesisMutator)
cmd.Flags().String(flagInstantiateByEverybody, "", "Everybody can instantiate a contract from the code, optional")
cmd.Flags().String(flagInstantiateNobody, "", "Nobody except the governance process can instantiate a contract from the code, optional")
cmd.Flags().String(flagInstantiateByAddress, "", "Only this address can instantiate a contract instance from the code, optional")
cmd.Flags().StringSlice(flagInstantiateByAnyOfAddress, []string{}, "Any of the addresses can instantiate a contract from the code, optional")
cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory")
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)")

View File

@@ -597,27 +597,33 @@ func ProposalUnpinCodesCmd() *cobra.Command {
return cmd
}
func parseAccessConfig(config string) (types.AccessConfig, error) {
switch config {
func parseAccessConfig(raw string) (types.AccessConfig, error) {
switch raw {
case "nobody":
return types.AllowNobody, nil
case "everybody":
return types.AllowEverybody, nil
default:
address, err := sdk.AccAddressFromBech32(config)
if err != nil {
return types.AccessConfig{}, fmt.Errorf("unable to parse address %s", config)
parts := strings.Split(raw, ",")
addrs := make([]sdk.AccAddress, len(parts))
for i, v := range parts {
addr, err := sdk.AccAddressFromBech32(v)
if err != nil {
return types.AccessConfig{}, fmt.Errorf("unable to parse address %q: %s", v, err)
}
addrs[i] = addr
}
return types.AccessTypeOnlyAddress.With(address), nil
cfg := types.AccessTypeAnyOfAddresses.With(addrs...)
return cfg, cfg.ValidateBasic()
}
}
func parseAccessConfigUpdates(args []string) ([]types.AccessConfigUpdate, error) {
updates := make([]types.AccessConfigUpdate, len(args))
for i, c := range args {
// format: code_id,access_config
// access_config: nobody|everybody|address
parts := strings.Split(c, ",")
// format: code_id:access_config
// access_config: nobody|everybody|address(es)
parts := strings.Split(c, ":")
if len(parts) != 2 {
return nil, fmt.Errorf("invalid format")
}
@@ -642,15 +648,15 @@ func parseAccessConfigUpdates(args []string) ([]types.AccessConfigUpdate, error)
func ProposalUpdateInstantiateConfigCmd() *cobra.Command {
bech32Prefix := sdk.GetConfig().GetBech32AccountAddrPrefix()
cmd := &cobra.Command{
Use: "update-instantiate-config [code-id,permission]...",
Use: "update-instantiate-config [code-id:permission]...",
Short: "Submit an update instantiate config proposal.",
Args: cobra.MinimumNArgs(1),
Long: strings.TrimSpace(
fmt.Sprintf(`Submit an update instantiate config proposal for multiple code ids.
Example:
$ %s tx gov submit-proposal update-instantiate-config 1,nobody 2,everybody 3,%s1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm
`, version.AppName, bech32Prefix)),
$ %s tx gov submit-proposal update-instantiate-config 1:nobody 2:everybody 3:%s1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm,%s1vx8knpllrj7n963p9ttd80w47kpacrhuts497x
`, version.AppName, bech32Prefix, bech32Prefix)),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {

View File

@@ -0,0 +1,85 @@
package cli
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/CosmWasm/wasmd/x/wasm/types"
)
func TestParseAccessConfigUpdates(t *testing.T) {
specs := map[string]struct {
src []string
exp []types.AccessConfigUpdate
expErr bool
}{
"nobody": {
src: []string{"1:nobody"},
exp: []types.AccessConfigUpdate{{
CodeID: 1,
InstantiatePermission: types.AccessConfig{Permission: types.AccessTypeNobody},
}},
},
"everybody": {
src: []string{"1:everybody"},
exp: []types.AccessConfigUpdate{{
CodeID: 1,
InstantiatePermission: types.AccessConfig{Permission: types.AccessTypeEverybody},
}},
},
"any of addresses - single": {
src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
exp: []types.AccessConfigUpdate{
{
CodeID: 1,
InstantiatePermission: types.AccessConfig{
Permission: types.AccessTypeAnyOfAddresses,
Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
},
},
},
},
"any of addresses - multiple": {
src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
exp: []types.AccessConfigUpdate{
{
CodeID: 1,
InstantiatePermission: types.AccessConfig{
Permission: types.AccessTypeAnyOfAddresses,
Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x", "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
},
},
},
},
"multiple code ids with different permissions": {
src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", "2:nobody"},
exp: []types.AccessConfigUpdate{
{
CodeID: 1,
InstantiatePermission: types.AccessConfig{
Permission: types.AccessTypeAnyOfAddresses,
Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x", "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
},
}, {
CodeID: 2,
InstantiatePermission: types.AccessConfig{
Permission: types.AccessTypeNobody,
},
},
},
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
got, gotErr := parseAccessConfigUpdates(spec.src)
if spec.expErr {
require.Error(t, gotErr)
return
}
require.NoError(t, gotErr)
assert.Equal(t, spec.exp, got)
})
}
}

View File

@@ -19,15 +19,16 @@ import (
)
const (
flagAmount = "amount"
flagLabel = "label"
flagAdmin = "admin"
flagNoAdmin = "no-admin"
flagRunAs = "run-as"
flagInstantiateByEverybody = "instantiate-everybody"
flagInstantiateNobody = "instantiate-nobody"
flagInstantiateByAddress = "instantiate-only-address"
flagUnpinCode = "unpin-code"
flagAmount = "amount"
flagLabel = "label"
flagAdmin = "admin"
flagNoAdmin = "no-admin"
flagRunAs = "run-as"
flagInstantiateByEverybody = "instantiate-everybody"
flagInstantiateNobody = "instantiate-nobody"
flagInstantiateByAddress = "instantiate-only-address"
flagInstantiateByAnyOfAddress = "instantiate-anyof-addresses"
flagUnpinCode = "unpin-code"
)
// GetTxCmd returns the transaction commands for this module
@@ -75,7 +76,8 @@ func StoreCodeCmd() *cobra.Command {
cmd.Flags().String(flagInstantiateByEverybody, "", "Everybody can instantiate a contract from the code, optional")
cmd.Flags().String(flagInstantiateNobody, "", "Nobody except the governance process can instantiate a contract from the code, optional")
cmd.Flags().String(flagInstantiateByAddress, "", "Only this address can instantiate a contract instance from the code, optional")
cmd.Flags().String(flagInstantiateByAddress, "", "Deprecated: Only this address can instantiate a contract from the code, optional")
cmd.Flags().StringSlice(flagInstantiateByAnyOfAddress, []string{}, "Any of the addresses can instantiate a contract from the code, optional")
flags.AddTxFlagsToCmd(cmd)
return cmd
}
@@ -97,47 +99,9 @@ func parseStoreCodeArgs(file string, sender sdk.AccAddress, flags *flag.FlagSet)
return types.MsgStoreCode{}, fmt.Errorf("invalid input file. Use wasm binary or gzip")
}
var perm *types.AccessConfig
onlyAddrStr, err := flags.GetString(flagInstantiateByAddress)
perm, err := parseAccessConfigFlags(flags)
if err != nil {
return types.MsgStoreCode{}, fmt.Errorf("instantiate by address: %s", err)
}
if onlyAddrStr != "" {
allowedAddr, err := sdk.AccAddressFromBech32(onlyAddrStr)
if err != nil {
return types.MsgStoreCode{}, sdkerrors.Wrap(err, flagInstantiateByAddress)
}
x := types.AccessTypeOnlyAddress.With(allowedAddr)
perm = &x
} else {
everybodyStr, err := flags.GetString(flagInstantiateByEverybody)
if err != nil {
return types.MsgStoreCode{}, fmt.Errorf("instantiate by everybody: %s", err)
}
if everybodyStr != "" {
ok, err := strconv.ParseBool(everybodyStr)
if err != nil {
return types.MsgStoreCode{}, fmt.Errorf("boolean value expected for instantiate by everybody: %s", err)
}
if ok {
perm = &types.AllowEverybody
}
}
nobodyStr, err := flags.GetString(flagInstantiateNobody)
if err != nil {
return types.MsgStoreCode{}, fmt.Errorf("instantiate by nobody: %s", err)
}
if nobodyStr != "" {
ok, err := strconv.ParseBool(nobodyStr)
if err != nil {
return types.MsgStoreCode{}, fmt.Errorf("boolean value expected for instantiate by nobody: %s", err)
}
if ok {
perm = &types.AllowNobody
}
}
return types.MsgStoreCode{}, err
}
msg := types.MsgStoreCode{
@@ -148,6 +112,65 @@ func parseStoreCodeArgs(file string, sender sdk.AccAddress, flags *flag.FlagSet)
return msg, nil
}
func parseAccessConfigFlags(flags *flag.FlagSet) (*types.AccessConfig, error) {
addrs, err := flags.GetStringSlice(flagInstantiateByAnyOfAddress)
if err != nil {
return nil, fmt.Errorf("flag any of: %s", err)
}
if len(addrs) != 0 {
acceptedAddrs := make([]sdk.AccAddress, len(addrs))
for i, v := range addrs {
acceptedAddrs[i], err = sdk.AccAddressFromBech32(v)
if err != nil {
return nil, fmt.Errorf("parse %q: %w", v, err)
}
}
x := types.AccessTypeAnyOfAddresses.With(acceptedAddrs...)
return &x, nil
}
onlyAddrStr, err := flags.GetString(flagInstantiateByAddress)
if err != nil {
return nil, fmt.Errorf("instantiate by address: %s", err)
}
if onlyAddrStr != "" {
allowedAddr, err := sdk.AccAddressFromBech32(onlyAddrStr)
if err != nil {
return nil, sdkerrors.Wrap(err, flagInstantiateByAddress)
}
x := types.AccessTypeOnlyAddress.With(allowedAddr)
return &x, nil
}
everybodyStr, err := flags.GetString(flagInstantiateByEverybody)
if err != nil {
return nil, fmt.Errorf("instantiate by everybody: %s", err)
}
if everybodyStr != "" {
ok, err := strconv.ParseBool(everybodyStr)
if err != nil {
return nil, fmt.Errorf("boolean value expected for instantiate by everybody: %s", err)
}
if ok {
return &types.AllowEverybody, nil
}
}
nobodyStr, err := flags.GetString(flagInstantiateNobody)
if err != nil {
return nil, fmt.Errorf("instantiate by nobody: %s", err)
}
if nobodyStr != "" {
ok, err := strconv.ParseBool(nobodyStr)
if err != nil {
return nil, fmt.Errorf("boolean value expected for instantiate by nobody: %s", err)
}
if ok {
return &types.AllowNobody, nil
}
}
return nil, nil
}
// InstantiateContractCmd will instantiate a contract from previously uploaded code.
func InstantiateContractCmd() *cobra.Command {
cmd := &cobra.Command{

View File

@@ -0,0 +1,59 @@
package cli
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/CosmWasm/wasmd/x/wasm/types"
)
func TestParseAccessConfigFlags(t *testing.T) {
specs := map[string]struct {
args []string
expCfg *types.AccessConfig
expErr bool
}{
"nobody": {
args: []string{"--instantiate-nobody=true"},
expCfg: &types.AccessConfig{Permission: types.AccessTypeNobody},
},
"everybody": {
args: []string{"--instantiate-everybody=true"},
expCfg: &types.AccessConfig{Permission: types.AccessTypeEverybody},
},
"only address": {
args: []string{"--instantiate-only-address=cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
expCfg: &types.AccessConfig{Permission: types.AccessTypeOnlyAddress, Address: "cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
},
"only address - invalid": {
args: []string{"--instantiate-only-address=foo"},
expErr: true,
},
"any of address": {
args: []string{"--instantiate-anyof-addresses=cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
expCfg: &types.AccessConfig{Permission: types.AccessTypeAnyOfAddresses, Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x", "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"}},
},
"any of address - invalid": {
args: []string{"--instantiate-anyof-addresses=cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,foo"},
expErr: true,
},
"not set": {
args: []string{},
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
flags := StoreCodeCmd().Flags()
require.NoError(t, flags.Parse(spec.args))
gotCfg, gotErr := parseAccessConfigFlags(flags)
if spec.expErr {
require.Error(t, gotErr)
return
}
require.NoError(t, gotErr)
assert.Equal(t, spec.expCfg, gotCfg)
})
}
}

View File

@@ -0,0 +1,311 @@
package keeper
import (
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/assert"
"github.com/CosmWasm/wasmd/x/wasm/types"
)
func TestDefaultAuthzPolicyCanCreateCode(t *testing.T) {
myActorAddress := RandomAccountAddress(t)
otherAddress := RandomAccountAddress(t)
specs := map[string]struct {
config types.AccessConfig
actor sdk.AccAddress
exp bool
panics bool
}{
"nobody": {
config: types.AllowNobody,
exp: false,
},
"everybody": {
config: types.AllowEverybody,
exp: true,
},
"only address - same": {
config: types.AccessTypeOnlyAddress.With(myActorAddress),
exp: true,
},
"only address - different": {
config: types.AccessTypeOnlyAddress.With(otherAddress),
exp: false,
},
"any address - included": {
config: types.AccessTypeAnyOfAddresses.With(otherAddress, myActorAddress),
exp: true,
},
"any address - not included": {
config: types.AccessTypeAnyOfAddresses.With(otherAddress),
exp: false,
},
"undefined config - panics": {
config: types.AccessConfig{},
panics: true,
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
policy := DefaultAuthorizationPolicy{}
if !spec.panics {
got := policy.CanCreateCode(spec.config, myActorAddress)
assert.Equal(t, spec.exp, got)
return
}
assert.Panics(t, func() {
policy.CanCreateCode(spec.config, myActorAddress)
})
})
}
}
func TestDefaultAuthzPolicyCanInstantiateContract(t *testing.T) {
myActorAddress := RandomAccountAddress(t)
otherAddress := RandomAccountAddress(t)
specs := map[string]struct {
config types.AccessConfig
actor sdk.AccAddress
exp bool
panics bool
}{
"nobody": {
config: types.AllowNobody,
exp: false,
},
"everybody": {
config: types.AllowEverybody,
exp: true,
},
"only address - same": {
config: types.AccessTypeOnlyAddress.With(myActorAddress),
exp: true,
},
"only address - different": {
config: types.AccessTypeOnlyAddress.With(otherAddress),
exp: false,
},
"any address - included": {
config: types.AccessTypeAnyOfAddresses.With(otherAddress, myActorAddress),
exp: true,
},
"any address - not included": {
config: types.AccessTypeAnyOfAddresses.With(otherAddress),
exp: false,
},
"undefined config - panics": {
config: types.AccessConfig{},
panics: true,
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
policy := DefaultAuthorizationPolicy{}
if !spec.panics {
got := policy.CanInstantiateContract(spec.config, myActorAddress)
assert.Equal(t, spec.exp, got)
return
}
assert.Panics(t, func() {
policy.CanInstantiateContract(spec.config, myActorAddress)
})
})
}
}
func TestDefaultAuthzPolicyCanModifyContract(t *testing.T) {
myActorAddress := RandomAccountAddress(t)
otherAddress := RandomAccountAddress(t)
specs := map[string]struct {
admin sdk.AccAddress
exp bool
}{
"same as actor": {
admin: myActorAddress,
exp: true,
},
"different admin": {
admin: otherAddress,
exp: false,
},
"no admin": {
exp: false,
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
policy := DefaultAuthorizationPolicy{}
got := policy.CanModifyContract(spec.admin, myActorAddress)
assert.Equal(t, spec.exp, got)
})
}
}
func TestDefaultAuthzPolicyCanModifyCodeAccessConfig(t *testing.T) {
myActorAddress := RandomAccountAddress(t)
otherAddress := RandomAccountAddress(t)
specs := map[string]struct {
admin sdk.AccAddress
subset bool
exp bool
}{
"same as actor - subset": {
admin: myActorAddress,
subset: true,
exp: true,
},
"same as actor - not subset": {
admin: myActorAddress,
subset: false,
exp: false,
},
"different admin": {
admin: otherAddress,
exp: false,
},
"no admin": {
exp: false,
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
policy := DefaultAuthorizationPolicy{}
got := policy.CanModifyCodeAccessConfig(spec.admin, myActorAddress, spec.subset)
assert.Equal(t, spec.exp, got)
})
}
}
func TestGovAuthzPolicyCanCreateCode(t *testing.T) {
myActorAddress := RandomAccountAddress(t)
otherAddress := RandomAccountAddress(t)
specs := map[string]struct {
config types.AccessConfig
actor sdk.AccAddress
}{
"nobody": {
config: types.AllowNobody,
},
"everybody": {
config: types.AllowEverybody,
},
"only address - same": {
config: types.AccessTypeOnlyAddress.With(myActorAddress),
},
"only address - different": {
config: types.AccessTypeOnlyAddress.With(otherAddress),
},
"any address - included": {
config: types.AccessTypeAnyOfAddresses.With(otherAddress, myActorAddress),
},
"any address - not included": {
config: types.AccessTypeAnyOfAddresses.With(otherAddress),
},
"undefined config - panics": {
config: types.AccessConfig{},
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
policy := GovAuthorizationPolicy{}
got := policy.CanCreateCode(spec.config, myActorAddress)
assert.True(t, got)
})
}
}
func TestGovAuthzPolicyCanInstantiateContract(t *testing.T) {
myActorAddress := RandomAccountAddress(t)
otherAddress := RandomAccountAddress(t)
specs := map[string]struct {
config types.AccessConfig
actor sdk.AccAddress
}{
"nobody": {
config: types.AllowNobody,
},
"everybody": {
config: types.AllowEverybody,
},
"only address - same": {
config: types.AccessTypeOnlyAddress.With(myActorAddress),
},
"only address - different": {
config: types.AccessTypeOnlyAddress.With(otherAddress),
},
"any address - included": {
config: types.AccessTypeAnyOfAddresses.With(otherAddress, myActorAddress),
},
"any address - not included": {
config: types.AccessTypeAnyOfAddresses.With(otherAddress),
},
"undefined config - panics": {
config: types.AccessConfig{},
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
policy := GovAuthorizationPolicy{}
got := policy.CanInstantiateContract(spec.config, myActorAddress)
assert.True(t, got)
})
}
}
func TestGovAuthzPolicyCanModifyContract(t *testing.T) {
myActorAddress := RandomAccountAddress(t)
otherAddress := RandomAccountAddress(t)
specs := map[string]struct {
admin sdk.AccAddress
}{
"same as actor": {
admin: myActorAddress,
},
"different admin": {
admin: otherAddress,
},
"no admin": {},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
policy := GovAuthorizationPolicy{}
got := policy.CanModifyContract(spec.admin, myActorAddress)
assert.True(t, got)
})
}
}
func TestGovAuthzPolicyCanModifyCodeAccessConfig(t *testing.T) {
myActorAddress := RandomAccountAddress(t)
otherAddress := RandomAccountAddress(t)
specs := map[string]struct {
admin sdk.AccAddress
subset bool
}{
"same as actor - subset": {
admin: myActorAddress,
subset: true,
},
"same as actor - not subset": {
admin: myActorAddress,
subset: false,
},
"different admin": {
admin: otherAddress,
},
"no admin": {},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
policy := GovAuthorizationPolicy{}
got := policy.CanModifyCodeAccessConfig(spec.admin, myActorAddress, spec.subset)
assert.True(t, got)
})
}
}

View File

@@ -162,6 +162,7 @@ func validateAccessType(i interface{}) error {
return sdkerrors.Wrapf(ErrInvalid, "unknown type: %q", a)
}
// ValidateBasic performs basic validation
func (a AccessConfig) ValidateBasic() error {
switch a.Permission {
case AccessTypeUnspecified:
@@ -203,6 +204,8 @@ func assertValidAddresses(addrs []string) error {
return nil
}
// Allowed returns if permission includes the actor.
// Actor address must be valid and not nil
func (a AccessConfig) Allowed(actor sdk.AccAddress) bool {
switch a.Permission {
case AccessTypeNobody:

View File

@@ -224,3 +224,83 @@ func TestParamsUnmarshalJson(t *testing.T) {
})
}
}
func TestAccessTypeWith(t *testing.T) {
myAddress := sdk.AccAddress(randBytes(SDKAddrLen))
myOtherAddress := sdk.AccAddress(randBytes(SDKAddrLen))
specs := map[string]struct {
src AccessType
addrs []sdk.AccAddress
exp AccessConfig
expPanic bool
}{
"nobody": {
src: AccessTypeNobody,
exp: AccessConfig{Permission: AccessTypeNobody},
},
"nobody with address": {
src: AccessTypeNobody,
addrs: []sdk.AccAddress{myAddress},
exp: AccessConfig{Permission: AccessTypeNobody},
},
"everybody": {
src: AccessTypeEverybody,
exp: AccessConfig{Permission: AccessTypeEverybody},
},
"everybody with address": {
src: AccessTypeEverybody,
addrs: []sdk.AccAddress{myAddress},
exp: AccessConfig{Permission: AccessTypeEverybody},
},
"only address without address": {
src: AccessTypeOnlyAddress,
expPanic: true,
},
"only address with address": {
src: AccessTypeOnlyAddress,
addrs: []sdk.AccAddress{myAddress},
exp: AccessConfig{Permission: AccessTypeOnlyAddress, Address: myAddress.String()},
},
"only address with invalid address": {
src: AccessTypeOnlyAddress,
addrs: []sdk.AccAddress{nil},
expPanic: true,
},
"any of address without address": {
src: AccessTypeAnyOfAddresses,
expPanic: true,
},
"any of address with single address": {
src: AccessTypeAnyOfAddresses,
addrs: []sdk.AccAddress{myAddress},
exp: AccessConfig{Permission: AccessTypeAnyOfAddresses, Addresses: []string{myAddress.String()}},
},
"any of address with multiple addresses": {
src: AccessTypeAnyOfAddresses,
addrs: []sdk.AccAddress{myAddress, myOtherAddress},
exp: AccessConfig{Permission: AccessTypeAnyOfAddresses, Addresses: []string{myAddress.String(), myOtherAddress.String()}},
},
"any of address with duplicate addresses": {
src: AccessTypeAnyOfAddresses,
addrs: []sdk.AccAddress{myAddress, myAddress},
expPanic: true,
},
"any of address with invalid address": {
src: AccessTypeAnyOfAddresses,
addrs: []sdk.AccAddress{nil},
expPanic: true,
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
if !spec.expPanic {
got := spec.src.With(spec.addrs...)
assert.Equal(t, spec.exp, got)
return
}
assert.Panics(t, func() {
spec.src.With(spec.addrs...)
})
})
}
}