cli: add Required field for flags

Close #2861

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
This commit is contained in:
Ekaterina Pavlova 2024-07-05 01:34:40 +03:00
parent acde7bd0de
commit 39559b90e2
19 changed files with 261 additions and 276 deletions

View file

@ -348,3 +348,14 @@ func GetSignersAccounts(senderAcc *wallet.Account, wall *wallet.Wallet, signers
} }
return signersAccounts, nil return signersAccounts, nil
} }
// EnsureNotEmpty returns a function that checks if the flag with the given name
// is not empty.
func EnsureNotEmpty(flagName string) func(*cli.Context, string) error {
return func(ctx *cli.Context, name string) error {
if ctx.String(flagName) == "" {
return cli.Exit(fmt.Errorf("required flag --%s is empty", flagName), 1)
}
return nil
}
}

View file

@ -55,11 +55,14 @@ func TestNEP11Import(t *testing.T) {
"--wallet", walletPath, "--wallet", walletPath,
} }
// missing token hash // missing token hash
e.RunWithError(t, args...) e.RunWithErrorCheck(t, `Required flag "token" not set`, args...)
// excessive parameters // excessive parameters
e.RunWithError(t, append(args, "--token", nnsContractHash.StringLE(), "something")...) e.RunWithError(t, append(args, "--token", nnsContractHash.StringLE(), "something")...)
// empty token hash
e.RunWithErrorCheck(t, `invalid value "" for flag -token: zero length string`, append(args, "--token", "")...)
// good: non-divisible // good: non-divisible
e.Run(t, append(args, "--token", nnsContractHash.StringLE())...) e.Run(t, append(args, "--token", nnsContractHash.StringLE())...)
@ -229,7 +232,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOf", cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOf",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
} }
e.RunWithError(t, cmdOwnerOf...) e.RunWithErrorCheck(t, `Required flag "token" not set`, cmdOwnerOf...)
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE()) cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE())
// ownerOf: missing token ID // ownerOf: missing token ID
@ -244,11 +247,11 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf", cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
} }
e.RunWithError(t, cmdTokensOf...) e.RunWithErrorCheck(t, `Required flags "token, address" not set`, cmdTokensOf...)
cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE()) cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE())
// tokensOf: missing owner address // tokensOf: missing owner address
e.RunWithError(t, cmdTokensOf...) e.RunWithErrorCheck(t, `Required flag "address" not set`, cmdTokensOf...)
cmdTokensOf = append(cmdTokensOf, "--address", nftOwnerAddr) cmdTokensOf = append(cmdTokensOf, "--address", nftOwnerAddr)
// tokensOf: good // tokensOf: good
@ -260,7 +263,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
"neo-go", "wallet", "nep11", "properties", "neo-go", "wallet", "nep11", "properties",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
} }
e.RunWithError(t, cmdProperties...) e.RunWithErrorCheck(t, `Required flag "token" not set`, cmdProperties...)
cmdProperties = append(cmdProperties, "--token", h.StringLE()) cmdProperties = append(cmdProperties, "--token", h.StringLE())
// properties: no token ID // properties: no token ID
@ -286,7 +289,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens", cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
} }
e.RunWithError(t, cmdTokens...) e.RunWithErrorCheck(t, `Required flag "token" not set`, cmdTokens...)
cmdTokens = append(cmdTokens, "--token", h.StringLE()) cmdTokens = append(cmdTokens, "--token", h.StringLE())
// tokens: excessive parameters // tokens: excessive parameters
@ -514,7 +517,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOfD", cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOfD",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
} }
e.RunWithError(t, cmdOwnerOf...) e.RunWithErrorCheck(t, `Required flag "token" not set`, cmdOwnerOf...)
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE()) cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE())
// ownerOfD: missing token ID // ownerOfD: missing token ID
@ -529,11 +532,11 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf", cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
} }
e.RunWithError(t, cmdTokensOf...) e.RunWithErrorCheck(t, `Required flags "token, address" not set`, cmdTokensOf...)
cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE()) cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE())
// tokensOf: missing owner address // tokensOf: missing owner address
e.RunWithError(t, cmdTokensOf...) e.RunWithErrorCheck(t, `Required flag "address" not set`, cmdTokensOf...)
cmdTokensOf = append(cmdTokensOf, "--address", testcli.ValidatorAddr) cmdTokensOf = append(cmdTokensOf, "--address", testcli.ValidatorAddr)
// tokensOf: good // tokensOf: good
@ -547,7 +550,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
"neo-go", "wallet", "nep11", "properties", "neo-go", "wallet", "nep11", "properties",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
} }
e.RunWithError(t, cmdProperties...) e.RunWithErrorCheck(t, `Required flag "token" not set`, cmdProperties...)
cmdProperties = append(cmdProperties, "--token", h.StringLE()) cmdProperties = append(cmdProperties, "--token", h.StringLE())
// properties: no token ID // properties: no token ID
@ -580,7 +583,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens", cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
} }
e.RunWithError(t, cmdTokens...) e.RunWithErrorCheck(t, `Required flag "token" not set`, cmdTokens...)
cmdTokens = append(cmdTokens, "--token", h.StringLE()) cmdTokens = append(cmdTokens, "--token", h.StringLE())
// tokens: good, several tokens // tokens: good, several tokens

View file

@ -113,7 +113,7 @@ func TestNEP17Balance(t *testing.T) {
e.CheckEOF(t) e.CheckEOF(t)
}) })
t.Run("Bad wallet", func(t *testing.T) { t.Run("Bad wallet", func(t *testing.T) {
e.RunWithError(t, append(cmdbalance, "--wallet", "/dev/null")...) e.RunWithError(t, append(cmdbalance, "--wallet", "/dev/null", "-r", "test")...)
}) })
} }
@ -136,7 +136,7 @@ func TestNEP17Transfer(t *testing.T) {
as := append([]string{}, args[:8]...) as := append([]string{}, args[:8]...)
as = append(as, args[10:]...) as = append(as, args[10:]...)
e.In.WriteString("one\r") e.In.WriteString("one\r")
e.RunWithError(t, as...) e.RunWithErrorCheck(t, `Required flag "to" not set`, as...)
e.In.Reset() e.In.Reset()
}) })
@ -326,7 +326,7 @@ func TestNEP17ImportToken(t *testing.T) {
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath) e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath)
// missing token hash // missing token hash
e.RunWithError(t, "neo-go", "wallet", "nep17", "import", e.RunWithErrorCheck(t, `Required flag "token" not set`, "neo-go", "wallet", "nep17", "import",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", walletPath) "--wallet", walletPath)

View file

@ -14,6 +14,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input" "github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config"
@ -86,9 +87,11 @@ var Network = []cli.Flag{
// RPC is a set of flags used for RPC connections (endpoint and timeout). // RPC is a set of flags used for RPC connections (endpoint and timeout).
var RPC = []cli.Flag{ var RPC = []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: RPCEndpointFlag, Name: RPCEndpointFlag,
Aliases: []string{"r"}, Aliases: []string{"r"},
Usage: "RPC node address", Usage: "RPC node address",
Required: true,
Action: cmdargs.EnsureNotEmpty("rpc-endpoint"),
}, },
&cli.DurationFlag{ &cli.DurationFlag{
Name: "timeout", Name: "timeout",
@ -131,7 +134,6 @@ var Debug = &cli.BoolFlag{
Usage: "Enable debug logging (LOTS of output, overrides configuration)", Usage: "Enable debug logging (LOTS of output, overrides configuration)",
} }
var errNoEndpoint = errors.New("no RPC endpoint specified, use option '--" + RPCEndpointFlag + "' or '-r'")
var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash") var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash")
var errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag") var errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag")
var errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location") var errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location")
@ -167,9 +169,6 @@ func GetTimeoutContext(ctx *cli.Context) (context.Context, func()) {
// GetRPCClient returns an RPC client instance for the given Context. // GetRPCClient returns an RPC client instance for the given Context.
func GetRPCClient(gctx context.Context, ctx *cli.Context) (*rpcclient.Client, cli.ExitCoder) { func GetRPCClient(gctx context.Context, ctx *cli.Context) (*rpcclient.Client, cli.ExitCoder) {
endpoint := ctx.String(RPCEndpointFlag) endpoint := ctx.String(RPCEndpointFlag)
if len(endpoint) == 0 {
return nil, cli.Exit(errNoEndpoint, 1)
}
c, err := rpcclient.New(gctx, endpoint, rpcclient.Options{}) c, err := rpcclient.New(gctx, endpoint, rpcclient.Options{})
if err != nil { if err != nil {
return nil, cli.Exit(err, 1) return nil, cli.Exit(err, 1)

View file

@ -101,14 +101,14 @@ func NewCommands() []*cli.Command {
{ {
Name: "dump", Name: "dump",
Usage: "Dump blocks (starting with block #1) to the file", Usage: "Dump blocks (starting with block #1) to the file",
UsageText: "neo-go db dump -o file [-s start] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]", UsageText: "neo-go db dump [-o file] [-s start] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]",
Action: dumpDB, Action: dumpDB,
Flags: cfgCountOutFlags, Flags: cfgCountOutFlags,
}, },
{ {
Name: "restore", Name: "restore",
Usage: "Restore blocks from the file", Usage: "Restore blocks from the file",
UsageText: "neo-go db restore -i file [--dump] [-n] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]", UsageText: "neo-go db restore [-i file] [--dump] [-n] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]",
Action: restoreDB, Action: restoreDB,
Flags: cfgCountInFlags, Flags: cfgCountInFlags,
}, },

View file

@ -56,13 +56,13 @@ func TestCalcHash(t *testing.T) {
cmd := []string{"neo-go", "contract", "calc-hash"} cmd := []string{"neo-go", "contract", "calc-hash"}
t.Run("no sender", func(t *testing.T) { t.Run("no sender", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--in", nefPath, "--manifest", manifestPath)...) e.RunWithErrorCheck(t, `Required flag "sender" not set`, append(cmd, "--in", nefPath, "--manifest", manifestPath)...)
}) })
t.Run("no nef file", func(t *testing.T) { t.Run("no nef file", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--manifest", manifestPath)...) e.RunWithErrorCheck(t, `Required flag "in" not set`, append(cmd, "--sender", sender.StringLE(), "--manifest", manifestPath)...)
}) })
t.Run("no manifest file", func(t *testing.T) { t.Run("no manifest file", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--in", nefPath)...) e.RunWithErrorCheck(t, `Required flag "manifest" not set`, append(cmd, "--sender", sender.StringLE(), "--in", nefPath)...)
}) })
t.Run("invalid nef path", func(t *testing.T) { t.Run("invalid nef path", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), e.RunWithError(t, append(cmd, "--sender", sender.StringLE(),
@ -289,7 +289,7 @@ func TestContractInitAndCompile(t *testing.T) {
e := testcli.NewExecutor(t, false) e := testcli.NewExecutor(t, false)
t.Run("no path is provided", func(t *testing.T) { t.Run("no path is provided", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "init") e.RunWithErrorCheck(t, `Required flag "name" not set`, "neo-go", "contract", "init")
}) })
t.Run("invalid path", func(t *testing.T) { t.Run("invalid path", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "init", "--name", "\x00") e.RunWithError(t, "neo-go", "contract", "init", "--name", "\x00")
@ -313,7 +313,7 @@ func TestContractInitAndCompile(t *testing.T) {
manifestPath := filepath.Join(tmpDir, "testcontract.manifest.json") manifestPath := filepath.Join(tmpDir, "testcontract.manifest.json")
cmd := []string{"neo-go", "contract", "compile"} cmd := []string{"neo-go", "contract", "compile"}
t.Run("missing source", func(t *testing.T) { t.Run("missing source", func(t *testing.T) {
e.RunWithError(t, cmd...) e.RunWithErrorCheck(t, `Required flag "in" not set`, cmd...)
}) })
cmd = append(cmd, "--in", srcPath, "--out", nefPath, "--manifest", manifestPath) cmd = append(cmd, "--in", srcPath, "--out", nefPath, "--manifest", manifestPath)
@ -487,10 +487,10 @@ func TestDeployWithSigners(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "deploy", e.RunWithError(t, "neo-go", "contract", "deploy",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
"--in", "", "--manifest", manifestName) "--in", nefName, "--manifest", manifestName)
}) })
t.Run("missing manifest", func(t *testing.T) { t.Run("missing manifest", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "deploy", e.RunWithErrorCheck(t, "required flag --manifest is empty", "neo-go", "contract", "deploy",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
"--in", nefName, "--manifest", "") "--in", nefName, "--manifest", "")
@ -517,7 +517,7 @@ func TestDeployWithSigners(t *testing.T) {
"[", "str1", "str2", "]") "[", "str1", "str2", "]")
}) })
t.Run("missing RPC", func(t *testing.T) { t.Run("missing RPC", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "deploy", e.RunWithErrorCheck(t, `Required flag "rpc-endpoint" not set`, "neo-go", "contract", "deploy",
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
"--in", nefName, "--manifest", manifestName, "--in", nefName, "--manifest", manifestName,
"[", "str1", "str2", "]") "[", "str1", "str2", "]")
@ -548,28 +548,29 @@ func TestContractManifestGroups(t *testing.T) {
"--out", nefName, "--manifest", manifestName) "--out", nefName, "--manifest", manifestName)
t.Run("missing wallet", func(t *testing.T) { t.Run("missing wallet", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group") e.RunWithErrorCheck(t, `Required flags "sender, address, nef, manifest" not set`, "neo-go", "contract", "manifest", "add-group")
}) })
t.Run("invalid wallet", func(t *testing.T) { t.Run("invalid wallet", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group", e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
"--wallet", t.TempDir()) "--wallet", t.TempDir(), "--sender", testcli.TestWalletAccount, "--address", testcli.TestWalletAccount,
"--nef", nefName, "--manifest", manifestName)
}) })
t.Run("invalid sender", func(t *testing.T) { t.Run("invalid sender", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group", e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount, "--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
"--sender", "not-a-sender") "--sender", "not-a-sender", "--nef", nefName, "--manifest", manifestName)
}) })
t.Run("invalid NEF file", func(t *testing.T) { t.Run("invalid NEF file", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group", e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount, "--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
"--sender", testcli.TestWalletAccount, "--nef", tmpDir) "--sender", testcli.TestWalletAccount, "--nef", tmpDir, "--manifest", manifestName)
}) })
t.Run("corrupted NEF file", func(t *testing.T) { t.Run("corrupted NEF file", func(t *testing.T) {
f := filepath.Join(tmpDir, "invalid.nef") f := filepath.Join(tmpDir, "invalid.nef")
require.NoError(t, os.WriteFile(f, []byte{1, 2, 3}, os.ModePerm)) require.NoError(t, os.WriteFile(f, []byte{1, 2, 3}, os.ModePerm))
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group", e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount, "--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
"--sender", testcli.TestWalletAccount, "--nef", f) "--sender", testcli.TestWalletAccount, "--nef", f, "--manifest", manifestName)
}) })
t.Run("invalid manifest file", func(t *testing.T) { t.Run("invalid manifest file", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group", e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
@ -630,9 +631,17 @@ func TestContract_TestInvokeScript(t *testing.T) {
"--out", goodNef, "--manifest", manifestName) "--out", goodNef, "--manifest", manifestName)
t.Run("missing in", func(t *testing.T) { t.Run("missing in", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "testinvokescript", e.RunWithErrorCheck(t, `Required flag "in" not set`, "neo-go", "contract", "testinvokescript",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0]) "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
}) })
t.Run("empty in", func(t *testing.T) {
e.RunWithErrorCheck(t, "required flag --in is empty", "neo-go", "contract", "testinvokescript", "-i", "",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
})
t.Run("empty rpc", func(t *testing.T) {
e.RunWithErrorCheck(t, "required flag --rpc-endpoint is empty", "neo-go", "contract", "testinvokescript", "-i", goodNef,
"--rpc-endpoint", "")
})
t.Run("unexisting in", func(t *testing.T) { t.Run("unexisting in", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "testinvokescript", e.RunWithError(t, "neo-go", "contract", "testinvokescript",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
@ -723,7 +732,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
t.Run("check calc hash", func(t *testing.T) { t.Run("check calc hash", func(t *testing.T) {
// missing sender // missing sender
e.RunWithError(t, "neo-go", "contract", "calc-hash", e.RunWithErrorCheck(t, `Required flag "sender" not set`, "neo-go", "contract", "calc-hash",
"--in", nefName, "--in", nefName,
"--manifest", manifestName) "--manifest", manifestName)
@ -755,7 +764,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
e.RunWithError(t, append(cmd, "--", "notahash")...) e.RunWithError(t, append(cmd, "--", "notahash")...)
}) })
t.Run("missing RPC address", func(t *testing.T) { t.Run("missing RPC address", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "testinvokefunction", e.RunWithErrorCheck(t, `Required flag "rpc-endpoint" not set`, "neo-go", "contract", "testinvokefunction",
h.StringLE(), "getValue") h.StringLE(), "getValue")
}) })
@ -1038,7 +1047,7 @@ func TestContractInspect(t *testing.T) {
cmd := []string{"neo-go", "contract", "inspect"} cmd := []string{"neo-go", "contract", "inspect"}
t.Run("missing input", func(t *testing.T) { t.Run("missing input", func(t *testing.T) {
e.RunWithError(t, cmd...) e.RunWithErrorCheck(t, `Required flag "in" not set`, cmd...)
}) })
t.Run("with raw '.go'", func(t *testing.T) { t.Run("with raw '.go'", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--in", srcPath)...) e.RunWithError(t, append(cmd, "--in", srcPath)...)

View file

@ -24,12 +24,14 @@ var generatorFlags = []cli.Flag{
Aliases: []string{"m"}, Aliases: []string{"m"},
Required: true, Required: true,
Usage: "Read contract manifest (*.manifest.json) file", Usage: "Read contract manifest (*.manifest.json) file",
Action: cmdargs.EnsureNotEmpty("manifest"),
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "out", Name: "out",
Aliases: []string{"o"}, Aliases: []string{"o"},
Required: true, Required: true,
Usage: "Output of the compiled wrapper", Usage: "Output of the compiled wrapper",
Action: cmdargs.EnsureNotEmpty("out"),
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "hash", Name: "hash",

View file

@ -1,4 +1,4 @@
package smartcontract package smartcontract_test
import ( import (
"bytes" "bytes"
@ -6,14 +6,13 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"github.com/nspcc-dev/neo-go/internal/testcli"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
) )
func TestGenerate(t *testing.T) { func TestGenerate(t *testing.T) {
@ -124,8 +123,7 @@ func TestGenerate(t *testing.T) {
0x04, 0x08, 0x15, 0x16, 0x23, 0x42, 0x43, 0x44, 0x00, 0x01, 0x04, 0x08, 0x15, 0x16, 0x23, 0x42, 0x43, 0x44, 0x00, 0x01,
0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, 0x03, 0x04, 0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, 0x03, 0x04,
} }
app := cli.NewApp() e := testcli.NewExecutor(t, false)
app.Commands = []*cli.Command{generateWrapperCmd}
rawCfg := `package: wrapper rawCfg := `package: wrapper
hash: ` + h.StringLE() + ` hash: ` + h.StringLE() + `
@ -144,12 +142,12 @@ callflags:
cfgPath := filepath.Join(t.TempDir(), "binding.yml") cfgPath := filepath.Join(t.TempDir(), "binding.yml")
require.NoError(t, os.WriteFile(cfgPath, []byte(rawCfg), os.ModePerm)) require.NoError(t, os.WriteFile(cfgPath, []byte(rawCfg), os.ModePerm))
require.NoError(t, app.Run([]string{"", "generate-wrapper", e.Run(t, []string{"", "contract", "generate-wrapper",
"--manifest", manifestFile, "--manifest", manifestFile,
"--config", cfgPath, "--config", cfgPath,
"--out", outFile, "--out", outFile,
"--hash", h.StringLE(), "--hash", h.StringLE(),
})) }...)
const expected = `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT. const expected = `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
@ -234,11 +232,11 @@ func MyFunc(in map[int]mycontract.Input) []mycontract.Output {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, expected, string(data)) require.Equal(t, expected, string(data))
require.NoError(t, app.Run([]string{"", "generate-wrapper", e.Run(t, []string{"", "contract", "generate-wrapper",
"--manifest", manifestFile, "--manifest", manifestFile,
"--config", cfgPath, "--config", cfgPath,
"--out", outFile, "--out", outFile,
})) }...)
expectedWithDynamicHash := `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT. expectedWithDynamicHash := `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package wrapper contains wrappers for MyContract contract. // Package wrapper contains wrappers for MyContract contract.
@ -350,13 +348,12 @@ func TestGenerateValidPackageName(t *testing.T) {
0x04, 0x08, 0x15, 0x16, 0x23, 0x42, 0x43, 0x44, 0x00, 0x01, 0x04, 0x08, 0x15, 0x16, 0x23, 0x42, 0x43, 0x44, 0x00, 0x01,
0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, 0x03, 0x04, 0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xBE, 0xEF, 0x03, 0x04,
} }
app := cli.NewApp() e := testcli.NewExecutor(t, false)
app.Commands = []*cli.Command{generateWrapperCmd, generateRPCWrapperCmd} e.Run(t, []string{"", "contract", "generate-wrapper",
require.NoError(t, app.Run([]string{"", "generate-wrapper",
"--manifest", manifestFile, "--manifest", manifestFile,
"--out", outFile, "--out", outFile,
"--hash", "0x" + h.StringLE(), "--hash", "0x" + h.StringLE(),
})) }...)
data, err := os.ReadFile(outFile) data, err := os.ReadFile(outFile)
require.NoError(t, err) require.NoError(t, err)
@ -378,11 +375,11 @@ func Get() int {
return neogointernal.CallWithToken(Hash, "get", int(contract.ReadOnly)).(int) return neogointernal.CallWithToken(Hash, "get", int(contract.ReadOnly)).(int)
} }
`, string(data)) `, string(data))
require.NoError(t, app.Run([]string{"", "generate-rpcwrapper", e.Run(t, []string{"", "contract", "generate-rpcwrapper",
"--manifest", manifestFile, "--manifest", manifestFile,
"--out", outFile, "--out", outFile,
"--hash", "0x" + h.StringLE(), "--hash", "0x" + h.StringLE(),
})) }...)
data, err = os.ReadFile(outFile) data, err = os.ReadFile(outFile)
require.NoError(t, err) require.NoError(t, err)
@ -431,17 +428,16 @@ const rewriteExpectedOutputs = false
func TestGenerateRPCBindings(t *testing.T) { func TestGenerateRPCBindings(t *testing.T) {
tmpDir := t.TempDir() tmpDir := t.TempDir()
app := cli.NewApp() e := testcli.NewExecutor(t, false)
app.Commands = []*cli.Command{generateWrapperCmd, generateRPCWrapperCmd}
var checkBinding = func(manifest string, hash string, good string) { var checkBinding = func(manifest string, hash string, good string) {
t.Run(manifest, func(t *testing.T) { t.Run(manifest, func(t *testing.T) {
outFile := filepath.Join(tmpDir, "out.go") outFile := filepath.Join(tmpDir, "out.go")
require.NoError(t, app.Run([]string{"", "generate-rpcwrapper", e.Run(t, []string{"", "contract", "generate-rpcwrapper",
"--manifest", manifest, "--manifest", manifest,
"--out", outFile, "--out", outFile,
"--hash", hash, "--hash", hash,
})) }...)
data, err := os.ReadFile(outFile) data, err := os.ReadFile(outFile)
require.NoError(t, err) require.NoError(t, err)
@ -478,8 +474,7 @@ func TestGenerateRPCBindings(t *testing.T) {
func TestAssistedRPCBindings(t *testing.T) { func TestAssistedRPCBindings(t *testing.T) {
tmpDir := t.TempDir() tmpDir := t.TempDir()
app := cli.NewApp() e := testcli.NewExecutor(t, false)
app.Commands = NewCommands()
var checkBinding = func(source string, hasDefinedHash bool, guessEventTypes bool, suffix ...string) { var checkBinding = func(source string, hasDefinedHash bool, guessEventTypes bool, suffix ...string) {
testName := source testName := source
@ -510,7 +505,7 @@ func TestAssistedRPCBindings(t *testing.T) {
if guessEventTypes { if guessEventTypes {
cmd = append(cmd, "--guess-eventtypes") cmd = append(cmd, "--guess-eventtypes")
} }
require.NoError(t, app.Run(cmd)) e.Run(t, cmd...)
cmds := []string{"", "contract", "generate-rpcwrapper", cmds := []string{"", "contract", "generate-rpcwrapper",
"--config", bindingF, "--config", bindingF,
@ -520,7 +515,7 @@ func TestAssistedRPCBindings(t *testing.T) {
if hasDefinedHash { if hasDefinedHash {
cmds = append(cmds, "--hash", "0x00112233445566778899aabbccddeeff00112233") cmds = append(cmds, "--hash", "0x00112233445566778899aabbccddeeff00112233")
} }
require.NoError(t, app.Run(cmds)) e.Run(t, cmds...)
data, err := os.ReadFile(outFile) data, err := os.ReadFile(outFile)
require.NoError(t, err) require.NoError(t, err)
@ -548,28 +543,22 @@ func TestAssistedRPCBindings(t *testing.T) {
} }
func TestGenerate_Errors(t *testing.T) { func TestGenerate_Errors(t *testing.T) {
app := cli.NewApp() e := testcli.NewExecutor(t, false)
app.Commands = []*cli.Command{generateWrapperCmd} args := []string{"neo-go", "contract", "generate-wrapper"}
app.ExitErrHandler = func(*cli.Context, error) {}
checkError := func(t *testing.T, msg string, args ...string) {
// cli.ExitError doesn't implement wraping properly, so we check for an error message.
err := app.Run(append([]string{"", "generate-wrapper"}, args...))
require.True(t, strings.Contains(err.Error(), msg), "got: %v", err)
}
t.Run("invalid hash", func(t *testing.T) { t.Run("invalid hash", func(t *testing.T) {
checkError(t, "invalid contract hash", "--hash", "xxx", "--manifest", "yyy", "--out", "zzz") e.RunWithErrorCheckExit(t, "invalid contract hash", append(args, "--hash", "xxx", "--manifest", "yyy", "--out", "zzz")...)
}) })
t.Run("missing manifest argument", func(t *testing.T) { t.Run("missing manifest argument", func(t *testing.T) {
checkError(t, "Required flag \"manifest\" not set", "--hash", util.Uint160{}.StringLE(), "--out", "zzz") e.RunWithErrorCheck(t, `Required flag "manifest" not set`, append(args, "--hash", util.Uint160{}.StringLE(), "--out", "zzz")...)
}) })
t.Run("missing manifest file", func(t *testing.T) { t.Run("missing manifest file", func(t *testing.T) {
checkError(t, "can't read contract manifest", "--manifest", "notexists", "--hash", util.Uint160{}.StringLE(), "--out", "zzz") e.RunWithErrorCheckExit(t, "can't read contract manifest", append(args, "--manifest", "notexists", "--hash", util.Uint160{}.StringLE(), "--out", "zzz")...)
}) })
t.Run("empty manifest", func(t *testing.T) { t.Run("empty manifest", func(t *testing.T) {
manifestFile := filepath.Join(t.TempDir(), "invalid.json") manifestFile := filepath.Join(t.TempDir(), "invalid.json")
require.NoError(t, os.WriteFile(manifestFile, []byte("[]"), os.ModePerm)) require.NoError(t, os.WriteFile(manifestFile, []byte("[]"), os.ModePerm))
checkError(t, "json: cannot unmarshal array into Go value of type manifest.Manifest", "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(), "--out", "zzz") e.RunWithErrorCheckExit(t, "json: cannot unmarshal array into Go value of type manifest.Manifest", append(args, "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(), "--out", "zzz")...)
}) })
t.Run("invalid manifest", func(t *testing.T) { t.Run("invalid manifest", func(t *testing.T) {
manifestFile := filepath.Join(t.TempDir(), "invalid.json") manifestFile := filepath.Join(t.TempDir(), "invalid.json")
@ -577,7 +566,7 @@ func TestGenerate_Errors(t *testing.T) {
rawManifest, err := json.Marshal(m) rawManifest, err := json.Marshal(m)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, os.WriteFile(manifestFile, rawManifest, os.ModePerm)) require.NoError(t, os.WriteFile(manifestFile, rawManifest, os.ModePerm))
checkError(t, "ABI: no methods", "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(), "--out", "zzz") e.RunWithErrorCheckExit(t, "ABI: no methods", append(args, "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(), "--out", "zzz")...)
}) })
manifestFile := filepath.Join(t.TempDir(), "manifest.json") manifestFile := filepath.Join(t.TempDir(), "manifest.json")
@ -593,9 +582,8 @@ func TestGenerate_Errors(t *testing.T) {
require.NoError(t, os.WriteFile(manifestFile, rawManifest, os.ModePerm)) require.NoError(t, os.WriteFile(manifestFile, rawManifest, os.ModePerm))
t.Run("missing config", func(t *testing.T) { t.Run("missing config", func(t *testing.T) {
checkError(t, "can't read config file", e.RunWithErrorCheckExit(t, "can't read config file", append(args, "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(),
"--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(), "--config", filepath.Join(t.TempDir(), "not.exists.yml"), "--out", "zzz")...)
"--config", filepath.Join(t.TempDir(), "not.exists.yml"), "--out", "zzz")
}) })
t.Run("invalid config", func(t *testing.T) { t.Run("invalid config", func(t *testing.T) {
rawCfg := `package: wrapper rawCfg := `package: wrapper
@ -605,23 +593,13 @@ callflags:
cfgPath := filepath.Join(t.TempDir(), "binding.yml") cfgPath := filepath.Join(t.TempDir(), "binding.yml")
require.NoError(t, os.WriteFile(cfgPath, []byte(rawCfg), os.ModePerm)) require.NoError(t, os.WriteFile(cfgPath, []byte(rawCfg), os.ModePerm))
checkError(t, "can't parse config file", e.RunWithErrorCheckExit(t, "can't parse config file", append(args, "--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(),
"--manifest", manifestFile, "--hash", util.Uint160{}.StringLE(), "--config", cfgPath, "--out", "zzz")...)
"--config", cfgPath, "--out", "zzz")
}) })
} }
func TestCompile_GuessEventTypes(t *testing.T) { func TestCompile_GuessEventTypes(t *testing.T) {
app := cli.NewApp() e := testcli.NewExecutor(t, false)
app.Commands = NewCommands()
app.ExitErrHandler = func(*cli.Context, error) {}
checkError := func(t *testing.T, msg string, args ...string) {
// cli.ExitError doesn't implement wraping properly, so we check for an error message.
err := app.Run(args)
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), msg), "got: %v", err)
}
check := func(t *testing.T, source string, expectedErrText string) { check := func(t *testing.T, source string, expectedErrText string) {
tmpDir := t.TempDir() tmpDir := t.TempDir()
configFile := filepath.Join(source, "invalid.yml") configFile := filepath.Join(source, "invalid.yml")
@ -636,7 +614,7 @@ func TestCompile_GuessEventTypes(t *testing.T) {
"--out", nefF, "--out", nefF,
"--guess-eventtypes", "--guess-eventtypes",
} }
checkError(t, expectedErrText, cmd...) e.RunWithErrorCheckExit(t, expectedErrText, cmd...)
} }
t.Run("not declared in manifest", func(t *testing.T) { t.Run("not declared in manifest", func(t *testing.T) {
@ -664,10 +642,7 @@ func TestCompile_GuessEventTypes(t *testing.T) {
} }
func TestGenerateRPCBindings_Errors(t *testing.T) { func TestGenerateRPCBindings_Errors(t *testing.T) {
app := cli.NewApp() e := testcli.NewExecutor(t, false)
app.Commands = NewCommands()
app.ExitErrHandler = func(*cli.Context, error) {}
t.Run("duplicating resulting fields", func(t *testing.T) { t.Run("duplicating resulting fields", func(t *testing.T) {
check := func(t *testing.T, packageName string, autogen bool, expectedError string) { check := func(t *testing.T, packageName string, autogen bool, expectedError string) {
tmpDir := t.TempDir() tmpDir := t.TempDir()
@ -687,16 +662,14 @@ func TestGenerateRPCBindings_Errors(t *testing.T) {
if autogen { if autogen {
cmd = append(cmd, "--guess-eventtypes") cmd = append(cmd, "--guess-eventtypes")
} }
require.NoError(t, app.Run(cmd)) e.Run(t, cmd...)
cmds := []string{"", "contract", "generate-rpcwrapper", cmds := []string{"", "contract", "generate-rpcwrapper",
"--config", bindingF, "--config", bindingF,
"--manifest", manifestF, "--manifest", manifestF,
"--out", out, "--out", out,
} }
err := app.Run(cmds) e.RunWithErrorCheckExit(t, expectedError, cmds...)
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), expectedError), err.Error())
} }
t.Run("event", func(t *testing.T) { t.Run("event", func(t *testing.T) {

View file

@ -2,7 +2,6 @@ package smartcontract
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"os" "os"
@ -75,10 +74,6 @@ func manifestAddGroup(ctx *cli.Context) error {
} }
func readNEFFile(filename string) (*nef.File, []byte, error) { func readNEFFile(filename string) (*nef.File, []byte, error) {
if len(filename) == 0 {
return nil, nil, errors.New("no nef file was provided")
}
f, err := os.ReadFile(filename) f, err := os.ReadFile(filename)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -96,10 +91,6 @@ func readNEFFile(filename string) (*nef.File, []byte, error) {
// it for validness against the provided contract hash. If empty hash is specified // it for validness against the provided contract hash. If empty hash is specified
// then no hash-related manifest groups check is performed. // then no hash-related manifest groups check is performed.
func readManifest(filename string, hash util.Uint160) (*manifest.Manifest, []byte, error) { func readManifest(filename string, hash util.Uint160) (*manifest.Manifest, []byte, error) {
if len(filename) == 0 {
return nil, nil, errNoManifestFile
}
manifestBytes, err := os.ReadFile(filename) manifestBytes, err := os.ReadFile(filename)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err

View file

@ -40,14 +40,11 @@ const (
) )
var ( var (
errNoInput = errors.New("no input file was found, specify an input file with the '--in or -i' flag") errNoConfFile = errors.New("no config file was found, specify a config file with the '--config' or '-c' flag")
errNoConfFile = errors.New("no config file was found, specify a config file with the '--config' or '-c' flag") errNoMethod = errors.New("no method specified for function invocation command")
errNoManifestFile = errors.New("no manifest file was found, specify manifest file with '--manifest' or '-m' flag") errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument")
errNoMethod = errors.New("no method specified for function invocation command") errFileExist = errors.New("A file with given smart-contract name already exists")
errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument") addressFlag = &flags.AddressFlag{
errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag")
errFileExist = errors.New("A file with given smart-contract name already exists")
addressFlag = &flags.AddressFlag{
Name: addressFlagName, Name: addressFlagName,
Aliases: []string{addressFlagAlias}, Aliases: []string{addressFlagAlias},
Usage: "Address to use as transaction signee (and gas source)", Usage: "Address to use as transaction signee (and gas source)",
@ -82,9 +79,11 @@ func RuntimeNotify(args []any) {
func NewCommands() []*cli.Command { func NewCommands() []*cli.Command {
testInvokeScriptFlags := []cli.Flag{ testInvokeScriptFlags := []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "in", Name: "in",
Aliases: []string{"i"}, Aliases: []string{"i"},
Usage: "Input location of the .nef file that needs to be invoked", Required: true,
Usage: "Input location of the .nef file that needs to be invoked",
Action: cmdargs.EnsureNotEmpty("in"),
}, },
options.Historic, options.Historic,
} }
@ -103,36 +102,47 @@ func NewCommands() []*cli.Command {
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...) invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
deployFlags := append(invokeFunctionFlags, []cli.Flag{ deployFlags := append(invokeFunctionFlags, []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "in", Name: "in",
Aliases: []string{"i"}, Aliases: []string{"i"},
Usage: "Input file for the smart contract (*.nef)", Required: true,
Usage: "Input file for the smart contract (*.nef)",
Action: cmdargs.EnsureNotEmpty("in"),
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "manifest", Name: "manifest",
Aliases: []string{"m"}, Aliases: []string{"m"},
Usage: "Manifest input file (*.manifest.json)", Required: true,
Usage: "Manifest input file (*.manifest.json)",
Action: cmdargs.EnsureNotEmpty("manifest"),
}, },
}...) }...)
manifestAddGroupFlags := append([]cli.Flag{ manifestAddGroupFlags := append([]cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "sender", Name: "sender",
Aliases: []string{"s"}, Aliases: []string{"s"},
Usage: "Deploy transaction sender", Required: true,
Usage: "Deploy transaction sender",
Action: cmdargs.EnsureNotEmpty("sender"),
}, },
&flags.AddressFlag{ &flags.AddressFlag{
Name: addressFlagName, // use the same name for handler code unification. Name: addressFlagName, // use the same name for handler code unification.
Aliases: []string{addressFlagAlias}, Aliases: []string{addressFlagAlias},
Usage: "Account to sign group with", Required: true,
Usage: "Account to sign group with",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "nef", Name: "nef",
Aliases: []string{"n"}, Aliases: []string{"n"},
Usage: "Path to the NEF file", Required: true,
Usage: "Path to the NEF file",
Action: cmdargs.EnsureNotEmpty("nef"),
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "manifest", Name: "manifest",
Aliases: []string{"m"}, Aliases: []string{"m"},
Usage: "Path to the manifest", Required: true,
Usage: "Path to the manifest",
Action: cmdargs.EnsureNotEmpty("manifest"),
}, },
}, options.Wallet...) }, options.Wallet...)
return []*cli.Command{{ return []*cli.Command{{
@ -154,9 +164,11 @@ func NewCommands() []*cli.Command {
Action: contractCompile, Action: contractCompile,
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "in", Name: "in",
Aliases: []string{"i"}, Aliases: []string{"i"},
Usage: "Input file for the smart contract to be compiled (*.go file or directory)", Required: true,
Usage: "Input file for the smart contract to be compiled (*.go file or directory)",
Action: cmdargs.EnsureNotEmpty("in"),
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "out", Name: "out",
@ -273,9 +285,11 @@ func NewCommands() []*cli.Command {
Action: initSmartContract, Action: initSmartContract,
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "name", Name: "name",
Aliases: []string{"n"}, Aliases: []string{"n"},
Usage: "Name of the smart-contract to be initialized", Required: true,
Usage: "Name of the smart-contract to be initialized",
Action: cmdargs.EnsureNotEmpty("name"),
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: "skip-details", Name: "skip-details",
@ -296,9 +310,11 @@ func NewCommands() []*cli.Command {
Usage: "Compile input file (it should be go code then)", Usage: "Compile input file (it should be go code then)",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "in", Name: "in",
Aliases: []string{"i"}, Aliases: []string{"i"},
Usage: "Input file of the program (either .go or .nef)", Required: true,
Usage: "Input file of the program (either .go or .nef)",
Action: cmdargs.EnsureNotEmpty("in"),
}, },
}, },
}, },
@ -309,18 +325,23 @@ func NewCommands() []*cli.Command {
Action: calcHash, Action: calcHash,
Flags: []cli.Flag{ Flags: []cli.Flag{
&flags.AddressFlag{ &flags.AddressFlag{
Name: "sender", Name: "sender",
Aliases: []string{"s"}, Aliases: []string{"s"},
Usage: "Sender script hash or address", Required: true,
Usage: "Sender script hash or address",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "in", Name: "in",
Usage: "Path to NEF file", Required: true,
Usage: "Path to NEF file",
Action: cmdargs.EnsureNotEmpty("in"),
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "manifest", Name: "manifest",
Aliases: []string{"m"}, Aliases: []string{"m"},
Usage: "Path to manifest file", Required: true,
Usage: "Path to manifest file",
Action: cmdargs.EnsureNotEmpty("manifest"),
}, },
}, },
}, },
@ -347,9 +368,6 @@ func initSmartContract(ctx *cli.Context) error {
return err return err
} }
contractName := ctx.String("name") contractName := ctx.String("name")
if contractName == "" {
return cli.Exit(errNoSmartContractName, 1)
}
// Check if the file already exists, if yes, exit // Check if the file already exists, if yes, exit
if _, err := os.Stat(contractName); err == nil { if _, err := os.Stat(contractName); err == nil {
@ -424,9 +442,6 @@ func contractCompile(ctx *cli.Context) error {
return err return err
} }
src := ctx.String("in") src := ctx.String("in")
if len(src) == 0 {
return cli.Exit(errNoInput, 1)
}
manifestFile := ctx.String("manifest") manifestFile := ctx.String("manifest")
confFile := ctx.String("config") confFile := ctx.String("config")
debugFile := ctx.String("debug") debugFile := ctx.String("debug")
@ -508,18 +523,9 @@ func calcHash(ctx *cli.Context) error {
return err return err
} }
sender := ctx.Generic("sender").(*flags.Address) sender := ctx.Generic("sender").(*flags.Address)
if !sender.IsSet {
return cli.Exit("sender is not set", 1)
}
p := ctx.String("in") p := ctx.String("in")
if p == "" {
return cli.Exit(errors.New("no .nef file was provided"), 1)
}
mpath := ctx.String("manifest") mpath := ctx.String("manifest")
if mpath == "" {
return cli.Exit(errors.New("no manifest file provided"), 1)
}
f, err := os.ReadFile(p) f, err := os.ReadFile(p)
if err != nil { if err != nil {
return cli.Exit(fmt.Errorf("can't read .nef file: %w", err), 1) return cli.Exit(fmt.Errorf("can't read .nef file: %w", err), 1)
@ -680,10 +686,6 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
func testInvokeScript(ctx *cli.Context) error { func testInvokeScript(ctx *cli.Context) error {
src := ctx.String("in") src := ctx.String("in")
if len(src) == 0 {
return cli.Exit(errNoInput, 1)
}
b, err := os.ReadFile(src) b, err := os.ReadFile(src)
if err != nil { if err != nil {
return cli.Exit(err, 1) return cli.Exit(err, 1)
@ -739,9 +741,6 @@ func inspect(ctx *cli.Context) error {
} }
in := ctx.String("in") in := ctx.String("in")
compile := ctx.Bool("compile") compile := ctx.Bool("compile")
if len(in) == 0 {
return cli.Exit(errNoInput, 1)
}
var ( var (
b []byte b []byte
err error err error

View file

@ -16,7 +16,11 @@ import (
// NewCommands returns util commands for neo-go CLI. // NewCommands returns util commands for neo-go CLI.
func NewCommands() []*cli.Command { func NewCommands() []*cli.Command {
txDumpFlags := append([]cli.Flag{}, options.RPC...) // By default, RPC flag is required. sendtx and txdump may be called without provided rpc-endpoint.
rpcFlagOriginal, _ := options.RPC[0].(*cli.StringFlag)
rpcFlag := *rpcFlagOriginal
rpcFlag.Required = false
txDumpFlags := append([]cli.Flag{&rpcFlag}, options.RPC[1:]...)
txSendFlags := append(txDumpFlags, txctx.AwaitFlag) txSendFlags := append(txDumpFlags, txctx.AwaitFlag)
txCancelFlags := append([]cli.Flag{ txCancelFlags := append([]cli.Flag{
&flags.AddressFlag{ &flags.AddressFlag{

View file

@ -39,7 +39,7 @@ func TestRegisterCandidate(t *testing.T) {
e.CheckEOF(t) e.CheckEOF(t)
// missing address // missing address
e.RunWithError(t, "neo-go", "wallet", "candidate", "register", e.RunWithErrorCheck(t, `Required flag "address" not set`, "neo-go", "wallet", "candidate", "register",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet) "--wallet", testcli.ValidatorWallet)
@ -131,7 +131,7 @@ func TestRegisterCandidate(t *testing.T) {
}) })
// missing address // missing address
e.RunWithError(t, "neo-go", "wallet", "candidate", "unregister", e.RunWithErrorCheck(t, `Required flag "address" not set`, "neo-go", "wallet", "candidate", "unregister",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet) "--wallet", testcli.ValidatorWallet)
// additional argument // additional argument
@ -153,7 +153,7 @@ func TestRegisterCandidate(t *testing.T) {
require.Equal(t, 0, len(vs)) require.Equal(t, 0, len(vs))
// query voter: missing address // query voter: missing address
e.RunWithError(t, "neo-go", "query", "voter") e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
// Excessive parameters. // Excessive parameters.
e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], validatorAddress, validatorAddress) e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], validatorAddress, validatorAddress)
e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something") e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something")

View file

@ -79,10 +79,10 @@ func TestSignMultisigTx(t *testing.T) {
"--out", txPath) "--out", txPath)
// missing wallet // missing wallet
e.RunWithError(t, "neo-go", "wallet", "sign") e.RunWithErrorCheck(t, `Required flag "in" not set`, "neo-go", "wallet", "sign")
// missing in // missing in
e.RunWithError(t, "neo-go", "wallet", "sign", e.RunWithErrorCheck(t, `Required flag "in" not set`, "neo-go", "wallet", "sign",
"--wallet", wallet2Path) "--wallet", wallet2Path)
// missing address // missing address

View file

@ -25,12 +25,14 @@ import (
func newNEP11Commands() []*cli.Command { func newNEP11Commands() []*cli.Command {
maxIters := strconv.Itoa(config.DefaultMaxIteratorResultItems) maxIters := strconv.Itoa(config.DefaultMaxIteratorResultItems)
tokenAddressFlag := &flags.AddressFlag{ tokenAddressFlag := &flags.AddressFlag{
Name: "token", Name: "token",
Usage: "Token contract address or hash in LE", Usage: "Token contract address or hash in LE",
Required: true,
} }
ownerAddressFlag := &flags.AddressFlag{ ownerAddressFlag := &flags.AddressFlag{
Name: "address", Name: "address",
Usage: "NFT owner address or hash in LE", Usage: "NFT owner address or hash in LE",
Required: true,
} }
tokenID := &cli.StringFlag{ tokenID := &cli.StringFlag{
Name: "id", Name: "id",
@ -71,7 +73,7 @@ func newNEP11Commands() []*cli.Command {
{ {
Name: "import", Name: "import",
Usage: "Import NEP-11 token to a wallet", Usage: "Import NEP-11 token to a wallet",
UsageText: "import -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --token <hash>", UsageText: "import -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] --token <hash>",
Action: importNEP11Token, Action: importNEP11Token,
Flags: importFlags, Flags: importFlags,
}, },
@ -101,7 +103,7 @@ func newNEP11Commands() []*cli.Command {
{ {
Name: "transfer", Name: "transfer",
Usage: "Transfer NEP-11 tokens", Usage: "Transfer NEP-11 tokens",
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [--await] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]", UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [--await] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
Action: transferNEP11, Action: transferNEP11,
Flags: transferFlags, Flags: transferFlags,
Description: `Transfers specified NEP-11 token with optional cosigners list attached to Description: `Transfers specified NEP-11 token with optional cosigners list attached to
@ -246,10 +248,6 @@ func printNEP11Owner(ctx *cli.Context, divisible bool) error {
return err return err
} }
tokenHash := ctx.Generic("token").(*flags.Address) tokenHash := ctx.Generic("token").(*flags.Address)
if !tokenHash.IsSet {
return cli.Exit("token contract hash was not set", 1)
}
tokenID := ctx.String("id") tokenID := ctx.String("id")
if tokenID == "" { if tokenID == "" {
return cli.Exit(errors.New("token ID should be specified"), 1) return cli.Exit(errors.New("token ID should be specified"), 1)
@ -291,15 +289,7 @@ func printNEP11Owner(ctx *cli.Context, divisible bool) error {
func printNEP11TokensOf(ctx *cli.Context) error { func printNEP11TokensOf(ctx *cli.Context) error {
var err error var err error
tokenHash := ctx.Generic("token").(*flags.Address) tokenHash := ctx.Generic("token").(*flags.Address)
if !tokenHash.IsSet {
return cli.Exit("token contract hash was not set", 1)
}
acc := ctx.Generic("address").(*flags.Address) acc := ctx.Generic("address").(*flags.Address)
if !acc.IsSet {
return cli.Exit("owner address flag was not set", 1)
}
gctx, cancel := options.GetTimeoutContext(ctx) gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel() defer cancel()
@ -326,10 +316,6 @@ func printNEP11Tokens(ctx *cli.Context) error {
return err return err
} }
tokenHash := ctx.Generic("token").(*flags.Address) tokenHash := ctx.Generic("token").(*flags.Address)
if !tokenHash.IsSet {
return cli.Exit("token contract hash was not set", 1)
}
gctx, cancel := options.GetTimeoutContext(ctx) gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel() defer cancel()
@ -356,10 +342,6 @@ func printNEP11Properties(ctx *cli.Context) error {
return err return err
} }
tokenHash := ctx.Generic("token").(*flags.Address) tokenHash := ctx.Generic("token").(*flags.Address)
if !tokenHash.IsSet {
return cli.Exit("token contract hash was not set", 1)
}
tokenID := ctx.String("id") tokenID := ctx.String("id")
if tokenID == "" { if tokenID == "" {
return cli.Exit(errors.New("token ID should be specified"), 1) return cli.Exit(errors.New("token ID should be specified"), 1)

View file

@ -57,8 +57,9 @@ var (
walletPathFlag, walletPathFlag,
walletConfigFlag, walletConfigFlag,
&flags.AddressFlag{ &flags.AddressFlag{
Name: "token", Name: "token",
Usage: "Token contract address or hash in LE", Usage: "Token contract address or hash in LE",
Required: true,
}, },
}, options.RPC...) }, options.RPC...)
baseTransferFlags = []cli.Flag{ baseTransferFlags = []cli.Flag{
@ -120,7 +121,7 @@ func newNEP17Commands() []*cli.Command {
{ {
Name: "import", Name: "import",
Usage: "Import NEP-17 token to a wallet", Usage: "Import NEP-17 token to a wallet",
UsageText: "import -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --token <hash>", UsageText: "import -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] --token <hash>",
Action: importNEP17Token, Action: importNEP17Token,
Flags: importFlags, Flags: importFlags,
}, },
@ -150,7 +151,7 @@ func newNEP17Commands() []*cli.Command {
{ {
Name: "transfer", Name: "transfer",
Usage: "Transfer NEP-17 tokens", Usage: "Transfer NEP-17 tokens",
UsageText: "transfer -w wallet [--wallet-config path] [--await] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]", UsageText: "transfer -w wallet [--wallet-config path] [--await] --rpc-endpoint <node> [--timeout <time>] --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
Action: transferNEP17, Action: transferNEP17,
Flags: transferFlags, Flags: transferFlags,
Description: `Transfers specified NEP-17 token amount with optional 'data' parameter and cosigners Description: `Transfers specified NEP-17 token amount with optional 'data' parameter and cosigners
@ -394,9 +395,6 @@ func importNEPToken(ctx *cli.Context, standard string) error {
defer wall.Close() defer wall.Close()
tokenHashFlag := ctx.Generic("token").(*flags.Address) tokenHashFlag := ctx.Generic("token").(*flags.Address)
if !tokenHashFlag.IsSet {
return cli.Exit("token contract hash was not set", 1)
}
tokenHash := tokenHashFlag.Uint160() tokenHash := tokenHashFlag.Uint160()
for _, t := range wall.Extra.Tokens { for _, t := range wall.Extra.Tokens {
@ -648,9 +646,6 @@ func transferNEP(ctx *cli.Context, standard string) error {
} }
toFlag := ctx.Generic("to").(*flags.Address) toFlag := ctx.Generic("to").(*flags.Address)
if !toFlag.IsSet {
return cli.Exit(errors.New("missing receiver address (--to)"), 1)
}
to := toFlag.Uint160() to := toFlag.Uint160()
token, err := getMatchingToken(ctx, wall, ctx.String("token"), standard) token, err := getMatchingToken(ctx, wall, ctx.String("token"), standard)
if err != nil { if err != nil {

View file

@ -20,7 +20,7 @@ func newValidatorCommands() []*cli.Command {
{ {
Name: "register", Name: "register",
Usage: "Register as a new candidate", Usage: "Register as a new candidate",
UsageText: "register -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]", UsageText: "register -w <path> -r <rpc> [-s timeout] -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
Action: handleRegister, Action: handleRegister,
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
walletPathFlag, walletPathFlag,
@ -31,16 +31,17 @@ func newValidatorCommands() []*cli.Command {
txctx.ForceFlag, txctx.ForceFlag,
txctx.AwaitFlag, txctx.AwaitFlag,
&flags.AddressFlag{ &flags.AddressFlag{
Name: "address", Name: "address",
Aliases: []string{"a"}, Aliases: []string{"a"},
Usage: "Address to register", Required: true,
Usage: "Address to register",
}, },
}, options.RPC...), }, options.RPC...),
}, },
{ {
Name: "unregister", Name: "unregister",
Usage: "Unregister self as a candidate", Usage: "Unregister self as a candidate",
UsageText: "unregister -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]", UsageText: "unregister -w <path> -r <rpc> [-s timeout] -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
Action: handleUnregister, Action: handleUnregister,
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
walletPathFlag, walletPathFlag,
@ -51,9 +52,10 @@ func newValidatorCommands() []*cli.Command {
txctx.ForceFlag, txctx.ForceFlag,
txctx.AwaitFlag, txctx.AwaitFlag,
&flags.AddressFlag{ &flags.AddressFlag{
Name: "address", Name: "address",
Aliases: []string{"a"}, Required: true,
Usage: "Address to unregister", Aliases: []string{"a"},
Usage: "Address to unregister",
}, },
}, options.RPC...), }, options.RPC...),
}, },
@ -75,9 +77,10 @@ func newValidatorCommands() []*cli.Command {
txctx.ForceFlag, txctx.ForceFlag,
txctx.AwaitFlag, txctx.AwaitFlag,
&flags.AddressFlag{ &flags.AddressFlag{
Name: "address", Name: "address",
Aliases: []string{"a"}, Required: true,
Usage: "Address to vote from", Aliases: []string{"a"},
Usage: "Address to vote from",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "candidate", Name: "candidate",
@ -112,9 +115,6 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w
defer wall.Close() defer wall.Close()
addrFlag := ctx.Generic("address").(*flags.Address) addrFlag := ctx.Generic("address").(*flags.Address)
if !addrFlag.IsSet {
return cli.Exit("address was not provided", 1)
}
addr := addrFlag.Uint160() addr := addrFlag.Uint160()
acc, err := options.GetUnlockedAccount(wall, addr, pass) acc, err := options.GetUnlockedAccount(wall, addr, pass)
if err != nil { if err != nil {

View file

@ -66,16 +66,19 @@ var (
Usage: "Decrypt encrypted keys.", Usage: "Decrypt encrypted keys.",
} }
inFlag = &cli.StringFlag{ inFlag = &cli.StringFlag{
Name: "in", Name: "in",
Usage: "File with JSON transaction", Required: true,
Usage: "File with JSON transaction",
Action: cmdargs.EnsureNotEmpty("in"),
} }
fromAddrFlag = &flags.AddressFlag{ fromAddrFlag = &flags.AddressFlag{
Name: "from", Name: "from",
Usage: "Address to send an asset from", Usage: "Address to send an asset from",
} }
toAddrFlag = &flags.AddressFlag{ toAddrFlag = &flags.AddressFlag{
Name: "to", Name: "to",
Usage: "Address to send an asset to", Usage: "Address to send an asset to",
Required: true,
} }
) )
@ -90,9 +93,10 @@ func NewCommands() []*cli.Command {
txctx.ForceFlag, txctx.ForceFlag,
txctx.AwaitFlag, txctx.AwaitFlag,
&flags.AddressFlag{ &flags.AddressFlag{
Name: "address", Name: "address",
Aliases: []string{"a"}, Aliases: []string{"a"},
Usage: "Address to claim GAS for", Required: true,
Usage: "Address to claim GAS for",
}, },
} }
claimFlags = append(claimFlags, options.RPC...) claimFlags = append(claimFlags, options.RPC...)
@ -108,7 +112,12 @@ func NewCommands() []*cli.Command {
Usage: "Address to use", Usage: "Address to use",
}, },
} }
signFlags = append(signFlags, options.RPC...) // By default, RPC flag is required. signtx may be called without provided rpc-endpoint.
rpcFlagOriginal, _ := options.RPC[0].(*cli.StringFlag)
rpcFlag := *rpcFlagOriginal
rpcFlag.Required = false
signFlags = append(signFlags, &rpcFlag)
signFlags = append(signFlags, options.RPC[1:]...)
return []*cli.Command{{ return []*cli.Command{{
Name: "wallet", Name: "wallet",
Usage: "Create, open and manage a Neo wallet", Usage: "Create, open and manage a Neo wallet",
@ -138,7 +147,7 @@ func NewCommands() []*cli.Command {
{ {
Name: "change-password", Name: "change-password",
Usage: "Change password for accounts", Usage: "Change password for accounts",
UsageText: "neo-go wallet change-password -w wallet -a address", UsageText: "neo-go wallet change-password -w wallet [-a address]",
Action: changePassword, Action: changePassword,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
@ -158,9 +167,11 @@ func NewCommands() []*cli.Command {
walletPathFlag, walletPathFlag,
walletConfigFlag, walletConfigFlag,
&cli.StringFlag{ &cli.StringFlag{
Name: "out", Name: "out",
Aliases: []string{"o"}, Aliases: []string{"o"},
Usage: "Where to write converted wallet", Required: true,
Usage: "Where to write converted wallet",
Action: cmdargs.EnsureNotEmpty("out"),
}, },
}, },
}, },
@ -274,7 +285,7 @@ func NewCommands() []*cli.Command {
{ {
Name: "import-deployed", Name: "import-deployed",
Usage: "Import deployed contract", Usage: "Import deployed contract",
UsageText: "import-deployed -w wallet [--wallet-config path] --wif <wif> --contract <hash> [--name <account_name>]", UsageText: "import-deployed -w wallet [--wallet-config path] --wif <wif> --contract <hash> --rpc-endpoint <endpoint> [-s <timeout>] [--name <account_name>]",
Action: importDeployed, Action: importDeployed,
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
walletPathFlag, walletPathFlag,
@ -286,9 +297,10 @@ func NewCommands() []*cli.Command {
Usage: "Optional account name", Usage: "Optional account name",
}, },
&flags.AddressFlag{ &flags.AddressFlag{
Name: "contract", Name: "contract",
Aliases: []string{"c"}, Aliases: []string{"c"},
Usage: "Contract hash or address", Required: true,
Usage: "Contract hash or address",
}, },
}, options.RPC...), }, options.RPC...),
}, },
@ -302,9 +314,10 @@ func NewCommands() []*cli.Command {
walletConfigFlag, walletConfigFlag,
txctx.ForceFlag, txctx.ForceFlag,
&flags.AddressFlag{ &flags.AddressFlag{
Name: "address", Name: "address",
Aliases: []string{"a"}, Aliases: []string{"a"},
Usage: "Account address or hash in LE form to be removed", Required: true,
Usage: "Account address or hash in LE form to be removed",
}, },
}, },
}, },
@ -432,9 +445,6 @@ func convertWallet(ctx *cli.Context) error {
} }
out := ctx.String("out") out := ctx.String("out")
if len(out) == 0 {
return cli.Exit("missing out path", 1)
}
newWallet, err := wallet.NewWallet(out) newWallet, err := wallet.NewWallet(out)
if err != nil { if err != nil {
return cli.Exit(err, 1) return cli.Exit(err, 1)
@ -634,9 +644,6 @@ func importDeployed(ctx *cli.Context) error {
defer wall.Close() defer wall.Close()
rawHash := ctx.Generic("contract").(*flags.Address) rawHash := ctx.Generic("contract").(*flags.Address)
if !rawHash.IsSet {
return cli.Exit("contract hash was not provided", 1)
}
var label *string var label *string
if ctx.IsSet("name") { if ctx.IsSet("name") {
@ -730,9 +737,6 @@ func removeAccount(ctx *cli.Context) error {
defer wall.Close() defer wall.Close()
addr := ctx.Generic("address").(*flags.Address) addr := ctx.Generic("address").(*flags.Address)
if !addr.IsSet {
return cli.Exit("valid account address must be provided", 1)
}
acc := wall.GetAccount(addr.Uint160()) acc := wall.GetAccount(addr.Uint160())
if acc == nil { if acc == nil {
return cli.Exit("account wasn't found", 1) return cli.Exit("account wasn't found", 1)

View file

@ -40,10 +40,10 @@ func TestWalletAccountRemove(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
t.Run("missing wallet", func(t *testing.T) { t.Run("missing wallet", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "remove") e.RunWithErrorCheck(t, `Required flag "address" not set`, "neo-go", "wallet", "remove")
}) })
t.Run("missing address", func(t *testing.T) { t.Run("missing address", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "remove", "--wallet", walletPath) e.RunWithErrorCheck(t, `Required flag "address" not set`, "neo-go", "wallet", "remove", "--wallet", walletPath)
}) })
t.Run("invalid address", func(t *testing.T) { t.Run("invalid address", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "remove", "--wallet", walletPath, e.RunWithError(t, "neo-go", "wallet", "remove", "--wallet", walletPath,
@ -109,7 +109,7 @@ func TestWalletChangePassword(t *testing.T) {
e.In.WriteString("pass\r") e.In.WriteString("pass\r")
e.In.WriteString("pass1\r") e.In.WriteString("pass1\r")
e.In.WriteString("pass2\r") e.In.WriteString("pass2\r")
e.RunWithError(t, "neo-go", "wallet", "change-password", "--wallet", walletPath) e.RunWithError(t, "neo-go", "wallet", "change-password", "--wallet", walletPath, "--address", addr1)
}) })
t.Run("good, multiaccount", func(t *testing.T) { t.Run("good, multiaccount", func(t *testing.T) {
e.In.WriteString("pass\r") e.In.WriteString("pass\r")
@ -593,7 +593,7 @@ func TestWalletClaimGas(t *testing.T) {
"--address", testcli.TestWalletAccount) "--address", testcli.TestWalletAccount)
}) })
t.Run("missing address", func(t *testing.T) { t.Run("missing address", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "claim", e.RunWithErrorCheck(t, `Required flag "address" not set`, "neo-go", "wallet", "claim",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.TestWalletPath) "--wallet", testcli.TestWalletPath)
}) })
@ -605,7 +605,7 @@ func TestWalletClaimGas(t *testing.T) {
}) })
t.Run("missing endpoint", func(t *testing.T) { t.Run("missing endpoint", func(t *testing.T) {
e.In.WriteString("testpass\r") e.In.WriteString("testpass\r")
e.RunWithError(t, "neo-go", "wallet", "claim", e.RunWithErrorCheck(t, `Required flag "rpc-endpoint" not set`, "neo-go", "wallet", "claim",
"--wallet", testcli.TestWalletPath, "--wallet", testcli.TestWalletPath,
"--address", testcli.TestWalletAccount) "--address", testcli.TestWalletAccount)
}) })
@ -711,19 +711,19 @@ func TestWalletImportDeployed(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
t.Run("missing wallet", func(t *testing.T) { t.Run("missing wallet", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "import-deployed") e.RunWithErrorCheck(t, `Required flag "contract" not set`, "neo-go", "wallet", "import-deployed", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
}) })
t.Run("missing contract sh", func(t *testing.T) { t.Run("missing contract sh", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "import-deployed", e.RunWithErrorCheck(t, `Required flag "contract" not set`, "neo-go", "wallet", "import-deployed",
"--wallet", walletPath) "--wallet", walletPath, "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
}) })
t.Run("missing WIF", func(t *testing.T) { t.Run("missing WIF", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "import-deployed", e.RunWithError(t, "neo-go", "wallet", "import-deployed",
"--wallet", walletPath, "--contract", h.StringLE()) "--wallet", walletPath, "--contract", h.StringLE(), "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
}) })
t.Run("missing endpoint", func(t *testing.T) { t.Run("missing endpoint", func(t *testing.T) {
e.In.WriteString("acc\rpass\rpass\r") e.In.WriteString("acc\rpass\rpass\r")
e.RunWithError(t, "neo-go", "wallet", "import-deployed", e.RunWithErrorCheck(t, `Required flag "rpc-endpoint" not set`, "neo-go", "wallet", "import-deployed",
"--wallet", walletPath, "--contract", h.StringLE(), "--wallet", walletPath, "--contract", h.StringLE(),
"--wif", priv.WIF()) "--wif", priv.WIF())
}) })
@ -1107,11 +1107,11 @@ func TestWalletConvert(t *testing.T) {
outPath := filepath.Join(tmpDir, "wallet.json") outPath := filepath.Join(tmpDir, "wallet.json")
cmd := []string{"neo-go", "wallet", "convert"} cmd := []string{"neo-go", "wallet", "convert"}
t.Run("missing wallet", func(t *testing.T) { t.Run("missing wallet", func(t *testing.T) {
e.RunWithError(t, cmd...) e.RunWithErrorCheck(t, `Required flag "out" not set`, cmd...)
}) })
cmd = append(cmd, "--wallet", "testdata/testwallet_NEO2.json") cmd = append(cmd, "--wallet", "testdata/testwallet_NEO2.json")
t.Run("missing out path", func(t *testing.T) { t.Run("missing out path", func(t *testing.T) {
e.RunWithError(t, cmd...) e.RunWithErrorCheck(t, `Required flag "out" not set`, cmd...)
}) })
t.Run("invalid out path", func(t *testing.T) { t.Run("invalid out path", func(t *testing.T) {
dir := t.TempDir() dir := t.TempDir()

View file

@ -273,13 +273,26 @@ func checkExit(t *testing.T, ch <-chan int, code int) {
} }
} }
// RunWithError runs command and checks that is exits with error. // RunWithError runs command and checks that is exits with error and exit code 1.
func (e *Executor) RunWithError(t *testing.T, args ...string) { func (e *Executor) RunWithError(t *testing.T, args ...string) {
ch := setExitFunc() ch := setExitFunc()
require.Error(t, e.run(args...)) require.Error(t, e.run(args...))
checkExit(t, ch, 1) checkExit(t, ch, 1)
} }
// RunWithErrorCheckExit runs command and checks that is exits with error and exit code 1.
func (e *Executor) RunWithErrorCheckExit(t *testing.T, msg string, args ...string) {
ch := setExitFunc()
require.ErrorContains(t, e.run(args...), msg)
checkExit(t, ch, 1)
}
// RunWithErrorCheck runs command and checks that there were errors with the specified message. Exit code is not checked.
func (e *Executor) RunWithErrorCheck(t *testing.T, msg string, args ...string) {
err := e.run(args...)
require.ErrorContains(t, err, msg)
}
// Run runs command and checks that there were no errors. // Run runs command and checks that there were no errors.
func (e *Executor) Run(t *testing.T, args ...string) { func (e *Executor) Run(t *testing.T, args ...string) {
ch := setExitFunc() ch := setExitFunc()