mirror of https://github.com/docker/cli.git
Merge pull request #436 from thaJeztah/improve-singular-plural-message
Singularize / pluralize "argument(s)" in error message
This commit is contained in:
commit
3b8cf20a0c
|
@ -20,11 +20,11 @@ func TestCheckpointCreateErrors(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{"too-few-arguments"},
|
args: []string{"too-few-arguments"},
|
||||||
expectedError: "requires exactly 2 argument(s)",
|
expectedError: "requires exactly 2 arguments",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: []string{"too", "many", "arguments"},
|
args: []string{"too", "many", "arguments"},
|
||||||
expectedError: "requires exactly 2 argument(s)",
|
expectedError: "requires exactly 2 arguments",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: []string{"foo", "bar"},
|
args: []string{"foo", "bar"},
|
||||||
|
|
|
@ -20,11 +20,11 @@ func TestCheckpointRemoveErrors(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{"too-few-arguments"},
|
args: []string{"too-few-arguments"},
|
||||||
expectedError: "requires exactly 2 argument(s)",
|
expectedError: "requires exactly 2 arguments",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: []string{"too", "many", "arguments"},
|
args: []string{"too", "many", "arguments"},
|
||||||
expectedError: "requires exactly 2 argument(s)",
|
expectedError: "requires exactly 2 arguments",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: []string{"foo", "bar"},
|
args: []string{"foo", "bar"},
|
||||||
|
|
|
@ -26,10 +26,10 @@ func TestConfigCreateErrors(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{"too_few"},
|
args: []string{"too_few"},
|
||||||
expectedError: "requires exactly 2 argument(s)",
|
expectedError: "requires exactly 2 arguments",
|
||||||
},
|
},
|
||||||
{args: []string{"too", "many", "arguments"},
|
{args: []string{"too", "many", "arguments"},
|
||||||
expectedError: "requires exactly 2 argument(s)",
|
expectedError: "requires exactly 2 arguments",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: []string{"name", filepath.Join("testdata", configDataFile)},
|
args: []string{"name", filepath.Join("testdata", configDataFile)},
|
||||||
|
|
|
@ -20,7 +20,7 @@ func TestConfigRemoveErrors(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{},
|
args: []string{},
|
||||||
expectedError: "requires at least 1 argument(s).",
|
expectedError: "requires at least 1 argument.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: []string{"foo"},
|
args: []string{"foo"},
|
||||||
|
|
|
@ -25,7 +25,7 @@ func TestNewHistoryCommandErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "wrong-args",
|
name: "wrong-args",
|
||||||
args: []string{},
|
args: []string{},
|
||||||
expectedError: "requires exactly 1 argument(s).",
|
expectedError: "requires exactly 1 argument.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "client-error",
|
name: "client-error",
|
||||||
|
|
|
@ -24,7 +24,7 @@ func TestNewImportCommandErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "wrong-args",
|
name: "wrong-args",
|
||||||
args: []string{},
|
args: []string{},
|
||||||
expectedError: "requires at least 1 argument(s).",
|
expectedError: "requires at least 1 argument.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "import-failed",
|
name: "import-failed",
|
||||||
|
|
|
@ -22,7 +22,7 @@ func TestNewInspectCommandErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "wrong-args",
|
name: "wrong-args",
|
||||||
args: []string{},
|
args: []string{},
|
||||||
expectedError: "requires at least 1 argument(s).",
|
expectedError: "requires at least 1 argument.",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
|
|
@ -25,7 +25,7 @@ func TestNewImagesCommandErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "wrong-args",
|
name: "wrong-args",
|
||||||
args: []string{"arg1", "arg2"},
|
args: []string{"arg1", "arg2"},
|
||||||
expectedError: "requires at most 1 argument(s).",
|
expectedError: "requires at most 1 argument.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "failed-list",
|
name: "failed-list",
|
||||||
|
|
|
@ -27,7 +27,7 @@ func TestNewLoadCommandErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "wrong-args",
|
name: "wrong-args",
|
||||||
args: []string{"arg"},
|
args: []string{"arg"},
|
||||||
expectedError: "accepts no argument(s).",
|
expectedError: "accepts no arguments.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "input-to-terminal",
|
name: "input-to-terminal",
|
||||||
|
|
|
@ -25,7 +25,7 @@ func TestNewPruneCommandErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "wrong-args",
|
name: "wrong-args",
|
||||||
args: []string{"something"},
|
args: []string{"something"},
|
||||||
expectedError: "accepts no argument(s).",
|
expectedError: "accepts no arguments.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "prune-error",
|
name: "prune-error",
|
||||||
|
|
|
@ -19,7 +19,7 @@ func TestNewPullCommandErrors(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "wrong-args",
|
name: "wrong-args",
|
||||||
expectedError: "requires exactly 1 argument(s).",
|
expectedError: "requires exactly 1 argument.",
|
||||||
args: []string{},
|
args: []string{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,7 @@ func TestNewPushCommandErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "wrong-args",
|
name: "wrong-args",
|
||||||
args: []string{},
|
args: []string{},
|
||||||
expectedError: "requires exactly 1 argument(s).",
|
expectedError: "requires exactly 1 argument.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid-name",
|
name: "invalid-name",
|
||||||
|
|
|
@ -29,7 +29,7 @@ func TestNewRemoveCommandErrors(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "wrong args",
|
name: "wrong args",
|
||||||
expectedError: "requires at least 1 argument(s).",
|
expectedError: "requires at least 1 argument.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ImageRemove fail",
|
name: "ImageRemove fail",
|
||||||
|
|
|
@ -26,7 +26,7 @@ func TestNewSaveCommandErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "wrong args",
|
name: "wrong args",
|
||||||
args: []string{},
|
args: []string{},
|
||||||
expectedError: "requires at least 1 argument(s).",
|
expectedError: "requires at least 1 argument.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "output to terminal",
|
name: "output to terminal",
|
||||||
|
|
|
@ -15,7 +15,7 @@ func TestCliNewTagCommandErrors(t *testing.T) {
|
||||||
{"image1"},
|
{"image1"},
|
||||||
{"image1", "image2", "image3"},
|
{"image1", "image2", "image3"},
|
||||||
}
|
}
|
||||||
expectedError := "\"tag\" requires exactly 2 argument(s)."
|
expectedError := "\"tag\" requires exactly 2 arguments."
|
||||||
for _, args := range testCases {
|
for _, args := range testCases {
|
||||||
cmd := NewTagCommand(test.NewFakeCli(&fakeClient{}))
|
cmd := NewTagCommand(test.NewFakeCli(&fakeClient{}))
|
||||||
cmd.SetArgs(args)
|
cmd.SetArgs(args)
|
||||||
|
|
|
@ -19,7 +19,7 @@ func TestNetworkConnectErrors(t *testing.T) {
|
||||||
expectedError string
|
expectedError string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
expectedError: "requires exactly 2 argument(s)",
|
expectedError: "requires exactly 2 arguments",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: []string{"toto", "titi"},
|
args: []string{"toto", "titi"},
|
||||||
|
|
|
@ -17,7 +17,7 @@ func TestNetworkDisconnectErrors(t *testing.T) {
|
||||||
expectedError string
|
expectedError string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
expectedError: "requires exactly 2 argument(s)",
|
expectedError: "requires exactly 2 arguments",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: []string{"toto", "titi"},
|
args: []string{"toto", "titi"},
|
||||||
|
|
|
@ -27,10 +27,10 @@ func TestSecretCreateErrors(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{"too_few"},
|
args: []string{"too_few"},
|
||||||
expectedError: "requires exactly 2 argument(s)",
|
expectedError: "requires exactly 2 arguments",
|
||||||
},
|
},
|
||||||
{args: []string{"too", "many", "arguments"},
|
{args: []string{"too", "many", "arguments"},
|
||||||
expectedError: "requires exactly 2 argument(s)",
|
expectedError: "requires exactly 2 arguments",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: []string{"name", filepath.Join("testdata", secretDataFile)},
|
args: []string{"name", filepath.Join("testdata", secretDataFile)},
|
||||||
|
|
|
@ -20,7 +20,7 @@ func TestSecretRemoveErrors(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{},
|
args: []string{},
|
||||||
expectedError: "requires at least 1 argument(s).",
|
expectedError: "requires at least 1 argument.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: []string{"foo"},
|
args: []string{"foo"},
|
||||||
|
|
|
@ -21,7 +21,7 @@ func TestSwarmLeaveErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "too-many-args",
|
name: "too-many-args",
|
||||||
args: []string{"foo"},
|
args: []string{"foo"},
|
||||||
expectedError: "accepts no argument(s)",
|
expectedError: "accepts no arguments",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "leave-failed",
|
name: "leave-failed",
|
||||||
|
|
|
@ -29,7 +29,7 @@ func TestSwarmUnlockKeyErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "too-many-args",
|
name: "too-many-args",
|
||||||
args: []string{"foo"},
|
args: []string{"foo"},
|
||||||
expectedError: "accepts no argument(s)",
|
expectedError: "accepts no arguments",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "swarm-inspect-rotate-failed",
|
name: "swarm-inspect-rotate-failed",
|
||||||
|
|
|
@ -25,7 +25,7 @@ func TestSwarmUnlockErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "too-many-args",
|
name: "too-many-args",
|
||||||
args: []string{"foo"},
|
args: []string{"foo"},
|
||||||
expectedError: "accepts no argument(s)",
|
expectedError: "accepts no arguments",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "is-not-part-of-a-swarm",
|
name: "is-not-part-of-a-swarm",
|
||||||
|
|
|
@ -30,7 +30,7 @@ func TestSwarmUpdateErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "too-many-args",
|
name: "too-many-args",
|
||||||
args: []string{"foo"},
|
args: []string{"foo"},
|
||||||
expectedError: "accepts no argument(s)",
|
expectedError: "accepts no arguments",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "swarm-inspect-error",
|
name: "swarm-inspect-error",
|
||||||
|
|
|
@ -31,7 +31,7 @@ func TestVolumeCreateErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: []string{"too", "many"},
|
args: []string{"too", "many"},
|
||||||
expectedError: "requires at most 1 argument(s)",
|
expectedError: "requires at most 1 argument",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
volumeCreateFunc: func(createBody volumetypes.VolumesCreateBody) (types.Volume, error) {
|
volumeCreateFunc: func(createBody volumetypes.VolumesCreateBody) (types.Volume, error) {
|
||||||
|
|
|
@ -18,7 +18,7 @@ func NoArgs(cmd *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.Errorf(
|
return errors.Errorf(
|
||||||
"\"%s\" accepts no argument(s).\nSee '%s --help'.\n\nUsage: %s\n\n%s",
|
"%q accepts no arguments.\nSee '%s --help'.\n\nUsage: %s\n\n%s",
|
||||||
cmd.CommandPath(),
|
cmd.CommandPath(),
|
||||||
cmd.CommandPath(),
|
cmd.CommandPath(),
|
||||||
cmd.UseLine(),
|
cmd.UseLine(),
|
||||||
|
@ -33,9 +33,10 @@ func RequiresMinArgs(min int) cobra.PositionalArgs {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.Errorf(
|
return errors.Errorf(
|
||||||
"\"%s\" requires at least %d argument(s).\nSee '%s --help'.\n\nUsage: %s\n\n%s",
|
"%q requires at least %d %s.\nSee '%s --help'.\n\nUsage: %s\n\n%s",
|
||||||
cmd.CommandPath(),
|
cmd.CommandPath(),
|
||||||
min,
|
min,
|
||||||
|
pluralize("argument", min),
|
||||||
cmd.CommandPath(),
|
cmd.CommandPath(),
|
||||||
cmd.UseLine(),
|
cmd.UseLine(),
|
||||||
cmd.Short,
|
cmd.Short,
|
||||||
|
@ -50,9 +51,10 @@ func RequiresMaxArgs(max int) cobra.PositionalArgs {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.Errorf(
|
return errors.Errorf(
|
||||||
"\"%s\" requires at most %d argument(s).\nSee '%s --help'.\n\nUsage: %s\n\n%s",
|
"%q requires at most %d %s.\nSee '%s --help'.\n\nUsage: %s\n\n%s",
|
||||||
cmd.CommandPath(),
|
cmd.CommandPath(),
|
||||||
max,
|
max,
|
||||||
|
pluralize("argument", max),
|
||||||
cmd.CommandPath(),
|
cmd.CommandPath(),
|
||||||
cmd.UseLine(),
|
cmd.UseLine(),
|
||||||
cmd.Short,
|
cmd.Short,
|
||||||
|
@ -67,10 +69,11 @@ func RequiresRangeArgs(min int, max int) cobra.PositionalArgs {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.Errorf(
|
return errors.Errorf(
|
||||||
"\"%s\" requires at least %d and at most %d argument(s).\nSee '%s --help'.\n\nUsage: %s\n\n%s",
|
"%q requires at least %d and at most %d %s.\nSee '%s --help'.\n\nUsage: %s\n\n%s",
|
||||||
cmd.CommandPath(),
|
cmd.CommandPath(),
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
|
pluralize("argument", max),
|
||||||
cmd.CommandPath(),
|
cmd.CommandPath(),
|
||||||
cmd.UseLine(),
|
cmd.UseLine(),
|
||||||
cmd.Short,
|
cmd.Short,
|
||||||
|
@ -85,12 +88,20 @@ func ExactArgs(number int) cobra.PositionalArgs {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.Errorf(
|
return errors.Errorf(
|
||||||
"\"%s\" requires exactly %d argument(s).\nSee '%s --help'.\n\nUsage: %s\n\n%s",
|
"%q requires exactly %d %s.\nSee '%s --help'.\n\nUsage: %s\n\n%s",
|
||||||
cmd.CommandPath(),
|
cmd.CommandPath(),
|
||||||
number,
|
number,
|
||||||
|
pluralize("argument", number),
|
||||||
cmd.CommandPath(),
|
cmd.CommandPath(),
|
||||||
cmd.UseLine(),
|
cmd.UseLine(),
|
||||||
cmd.Short,
|
cmd.Short,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pluralize(word string, number int) string {
|
||||||
|
if number == 1 {
|
||||||
|
return word
|
||||||
|
}
|
||||||
|
return word + "s"
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRequiresNoArgs(t *testing.T) {
|
||||||
|
testCases := []testCase{
|
||||||
|
{
|
||||||
|
validateFunc: NoArgs,
|
||||||
|
expectedError: "no error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"foo"},
|
||||||
|
validateFunc: NoArgs,
|
||||||
|
expectedError: "accepts no arguments.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
runTestCases(t, testCases)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRequiresMinArgs(t *testing.T) {
|
||||||
|
testCases := []testCase{
|
||||||
|
{
|
||||||
|
validateFunc: RequiresMinArgs(0),
|
||||||
|
expectedError: "no error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validateFunc: RequiresMinArgs(1),
|
||||||
|
expectedError: "at least 1 argument.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"foo"},
|
||||||
|
validateFunc: RequiresMinArgs(2),
|
||||||
|
expectedError: "at least 2 arguments.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
runTestCases(t, testCases)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRequiresMaxArgs(t *testing.T) {
|
||||||
|
testCases := []testCase{
|
||||||
|
{
|
||||||
|
validateFunc: RequiresMaxArgs(0),
|
||||||
|
expectedError: "no error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"foo", "bar"},
|
||||||
|
validateFunc: RequiresMaxArgs(1),
|
||||||
|
expectedError: "at most 1 argument.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"foo", "bar", "baz"},
|
||||||
|
validateFunc: RequiresMaxArgs(2),
|
||||||
|
expectedError: "at most 2 arguments.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
runTestCases(t, testCases)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRequiresRangeArgs(t *testing.T) {
|
||||||
|
testCases := []testCase{
|
||||||
|
{
|
||||||
|
validateFunc: RequiresRangeArgs(0, 0),
|
||||||
|
expectedError: "no error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validateFunc: RequiresRangeArgs(0, 1),
|
||||||
|
expectedError: "no error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"foo", "bar"},
|
||||||
|
validateFunc: RequiresRangeArgs(0, 1),
|
||||||
|
expectedError: "at most 1 argument.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"foo", "bar", "baz"},
|
||||||
|
validateFunc: RequiresRangeArgs(0, 2),
|
||||||
|
expectedError: "at most 2 arguments.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validateFunc: RequiresRangeArgs(1, 2),
|
||||||
|
expectedError: "at least 1 ",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
runTestCases(t, testCases)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExactArgs(t *testing.T) {
|
||||||
|
testCases := []testCase{
|
||||||
|
{
|
||||||
|
validateFunc: ExactArgs(0),
|
||||||
|
expectedError: "no error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validateFunc: ExactArgs(1),
|
||||||
|
expectedError: "exactly 1 argument.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validateFunc: ExactArgs(2),
|
||||||
|
expectedError: "exactly 2 arguments.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
runTestCases(t, testCases)
|
||||||
|
}
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
args []string
|
||||||
|
validateFunc cobra.PositionalArgs
|
||||||
|
expectedError string
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTestCases(t *testing.T, testCases []testCase) {
|
||||||
|
for _, tc := range testCases {
|
||||||
|
cmd := newDummyCommand(tc.validateFunc)
|
||||||
|
cmd.SetArgs(tc.args)
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
|
||||||
|
err := cmd.Execute()
|
||||||
|
|
||||||
|
require.Error(t, err, "Expected an error: %s", tc.expectedError)
|
||||||
|
assert.Contains(t, err.Error(), tc.expectedError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDummyCommand(validationFunc cobra.PositionalArgs) *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "dummy",
|
||||||
|
Args: validationFunc,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
return errors.New("no error")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
}
|
Loading…
Reference in New Issue