package reference import ( "regexp" "strconv" "strings" "testing" ) var ( // regexpTestcases is a unified set of testcases for // TestValidateRepositoryName and TestRepositoryNameRegexp. // Some of them are valid inputs for one and not the other. regexpTestcases = []struct { // input is the repository name or name component testcase input string // err is the error expected from ValidateRepositoryName, or nil err error // invalid should be true if the testcase is *not* expected to // match RepositoryNameRegexp invalid bool }{ { input: "", err: ErrRepositoryNameEmpty, invalid: true, }, { input: "short", err: ErrRepositoryNameMissingHostname, }, { input: "simple/name", }, { input: "library/ubuntu", }, { input: "docker/stevvooe/app", }, { input: "aa/aa/aa/aa/aa/aa/aa/aa/aa/bb/bb/bb/bb/bb/bb", }, { input: "aa/aa/bb/bb/bb", }, { input: "a/a/a/b/b", }, { input: "a/a/a/a/", err: ErrRepositoryNameComponentInvalid, invalid: true, }, { input: "a//a/a", err: ErrRepositoryNameComponentInvalid, invalid: true, }, { input: "a", err: ErrRepositoryNameMissingHostname, }, { input: "a/aa", }, { input: "aa/a", }, { input: "a/aa/a", }, { input: "foo.com/", err: ErrRepositoryNameComponentInvalid, invalid: true, }, { input: "foo.com:8080/bar", }, { input: "foo.com/bar", }, { input: "foo.com/bar/baz", }, { input: "foo.com/bar/baz/quux", }, { input: "blog.foo.com/bar/baz", }, { input: "asdf", err: ErrRepositoryNameMissingHostname, }, { input: "aa/asdf$$^/aa", err: ErrRepositoryNameComponentInvalid, invalid: true, }, { input: "asdf$$^/aa", err: ErrRepositoryNameHostnameInvalid, invalid: true, }, { input: "aa-a/aa", }, { input: "aa/aa", }, { input: "a-a/a-a", }, { input: "a", err: ErrRepositoryNameMissingHostname, }, { input: "a/image", }, { input: "a-/a/a/a", err: ErrRepositoryNameHostnameInvalid, invalid: true, }, { input: "a/a-/a/a/a", err: ErrRepositoryNameComponentInvalid, invalid: true, }, { // total length = 255 input: "a/" + strings.Repeat("a", 253), }, { // total length = 256 input: "b/" + strings.Repeat("a", 254), err: ErrRepositoryNameLong, }, { input: "-foo/bar", err: ErrRepositoryNameHostnameInvalid, invalid: true, }, { input: "foo/bar-", err: ErrRepositoryNameComponentInvalid, invalid: true, }, { input: "foo-/bar", err: ErrRepositoryNameHostnameInvalid, invalid: true, }, { input: "foo/-bar", err: ErrRepositoryNameComponentInvalid, invalid: true, }, { input: "_foo/bar", err: ErrRepositoryNameHostnameInvalid, invalid: true, }, { input: "foo/bar_", err: ErrRepositoryNameComponentInvalid, invalid: true, }, { input: "____/____", err: ErrRepositoryNameHostnameInvalid, invalid: true, }, { input: "_docker/_docker", err: ErrRepositoryNameHostnameInvalid, invalid: true, }, { input: "docker_/docker_", err: ErrRepositoryNameHostnameInvalid, invalid: true, }, { input: "do__cker/docker", err: ErrRepositoryNameComponentInvalid, invalid: true, }, { input: "docker./docker", err: ErrRepositoryNameComponentInvalid, invalid: true, }, { input: ".docker/docker", err: ErrRepositoryNameComponentInvalid, invalid: true, }, { input: "do..cker/docker", err: ErrRepositoryNameComponentInvalid, invalid: true, }, { input: "docker-/docker", err: ErrRepositoryNameComponentInvalid, invalid: true, }, { input: "-docker/docker", err: ErrRepositoryNameComponentInvalid, }, { input: "xn--n3h.com/myimage", // http://☃.com in punycode err: ErrRepositoryNameHostnameInvalid, invalid: true, }, { input: "xn--7o8h.com/myimage", // http://🐳.com in punycode err: ErrRepositoryNameHostnameInvalid, invalid: true, }, { input: "b.gcr.io/test.example.com/my-app", // embedded domain component }, { input: "xn--n3h.com/myimage", // http://☃.com in punycode }, { input: "xn--7o8h.com/myimage", // http://🐳.com in punycode }, { input: "registry.io/foo/project--id.module--name.ver---sion--name", // image with hostname }, } ) // TestValidateRepositoryName tests the ValidateRepositoryName function, // which uses RepositoryNameComponentAnchoredRegexp for validation func TestValidateRepositoryName(t *testing.T) { for _, testcase := range regexpTestcases { failf := func(format string, v ...interface{}) { t.Logf(strconv.Quote(testcase.input)+": "+format, v...) t.Fail() } if _, err := NewRepository(testcase.input); err != testcase.err { if testcase.err != nil { if err != nil { failf("unexpected error for invalid repository: got %v, expected %v", err, testcase.err) } else { failf("expected invalid repository: %v", testcase.err) } } else { if err != nil { // Wrong error returned. failf("unexpected error validating repository name: %v, expected %v", err, testcase.err) } else { failf("unexpected error validating repository name: %v", err) } } } } } func TestRepositoryNameRegexp(t *testing.T) { AnchoredRepositoryNameRegexp := regexp.MustCompile(`^` + RepositoryNameRegexp.String() + `$`) for _, testcase := range regexpTestcases { failf := func(format string, v ...interface{}) { t.Logf(strconv.Quote(testcase.input)+": "+format, v...) t.Fail() } matches := AnchoredRepositoryNameRegexp.MatchString(testcase.input) if matches == testcase.invalid { if testcase.invalid { failf("expected invalid repository name %s", testcase.input) } else { failf("expected valid repository name %s", testcase.input) } } } }