diff --git a/commands/init.go b/commands/init.go index 16cdd43e..ce60b7a4 100644 --- a/commands/init.go +++ b/commands/init.go @@ -28,6 +28,7 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "strings" "github.com/fnproject/cli/common" @@ -389,14 +390,14 @@ func (a *initFnCmd) bindFn(fn *modelsV2.Fn) { } } -// ValidateFuncName checks if the func name is valid, the name can't contain a colon and -// must be all lowercase +// ValidateFuncName checks if the func name is valid, the name can only contain alphanumerical +// lowercase characters, separated by ., _ or -. func ValidateFuncName(name string) error { - if strings.Contains(name, ":") { - return errors.New("Function name cannot contain a colon") - } - if strings.ToLower(name) != name { - return errors.New("Function name must be lowercase") + // Match multiple groups of lowercase charaters and numbers, followed by 0 or 1 instances + // of the separators; the string also needs to end with a character or a number (not separator) + isValid := regexp.MustCompile(`^([a-z0-9]+[._-]?)*[a-z0-9]$`).MatchString + if !isValid(name) { + return errors.New("Function name cannot contain spaces, start with separators or contain uppercase letters") } return nil } diff --git a/init_test.go b/init_test.go index e02cbbb1..7acb1db7 100644 --- a/init_test.go +++ b/init_test.go @@ -58,17 +58,110 @@ func TestInit(t *testing.T) { } } -func funcNameValidation(name string, t *testing.T) { - err := commands.ValidateFuncName("fooFunc") - if err == nil { - t.Error("Expected validation error for function name") +func TestFuncNameValidation(t *testing.T) { + tc := []struct { + name string + value string + errExpected bool + }{ + { + name: "strings only", + value: "somename", + errExpected: false, + }, + { + name: "numbers only", + value: "12345", + errExpected: false, + }, + { + name: "uppercase letters", + value: "HelloFuncName", + errExpected: true, + }, + { + name: "starts with separator", + value: ".myfunc", + errExpected: true, + }, + { + name: "starts with separator (*)", + value: "*myfunc", + errExpected: true, + }, + { + name: "starts with separator (-)", + value: "-myfunc", + errExpected: true, + }, + { + name: "ends with separator", + value: "myfunc-", + errExpected: true, + }, + { + name: "ends with separator (.)", + value: "myfunc.", + errExpected: true, + }, + { + name: "ends with separator (*)", + value: "myfunc*", + errExpected: true, + }, + { + name: "contains spaces", + value: "my func blah", + errExpected: true, + }, + { + name: "hypen in name", + value: "my-func-blah", + errExpected: false, + }, + { + name: "underscore in name", + value: "my_funcblah", + errExpected: false, + }, + { + name: "dot in name", + value: "my.funcblah", + errExpected: false, + }, + { + name: "multiple separators in row", + value: "my___funcblah", + errExpected: true, + }, + { + name: "multiple different separators in row", + value: "my_.funcblah", + errExpected: true, + }, + { + name: "multiple separators in the name", + value: "my_func-blah.test", + errExpected: false, + }, } -} - -func TestFuncNameWithUpperCase(t *testing.T) { - funcNameValidation("fooMyFunc", t) -} -func TestFuncNameWithColon(t *testing.T) { - funcNameValidation("foo:myfunc", t) + t.Log("Test func name validation") + { + for i, tst := range tc { + t.Logf("\tTest %d: \t%s", i, tst.name) + { + err := commands.ValidateFuncName(tst.value) + if err != nil { + if !tst.errExpected { + t.Fatalf("\tValidateFuncName failed : got unexpected error [%v]\n", err) + } + } else { + if tst.errExpected { + t.Fatalf("\tValidateFuncName failed : error expected for value '%s' but was nil\n", tst.value) + } + } + } + } + } }