github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/reference/regexp_test.go (about)

     1  package reference
     2  
     3  import (
     4  	"regexp"
     5  	"strings"
     6  	"testing"
     7  )
     8  
     9  type regexpMatch struct {
    10  	input string
    11  	match bool
    12  	subs  []string
    13  }
    14  
    15  func checkRegexp(t *testing.T, r *regexp.Regexp, m regexpMatch) {
    16  	matches := r.FindStringSubmatch(m.input)
    17  	if m.match && matches != nil {
    18  		if len(matches) != (r.NumSubexp()+1) || matches[0] != m.input {
    19  			t.Fatalf("Bad match result %#v for %q", matches, m.input)
    20  		}
    21  		if len(matches) < (len(m.subs) + 1) {
    22  			t.Errorf("Expected %d sub matches, only have %d for %q", len(m.subs), len(matches)-1, m.input)
    23  		}
    24  		for i := range m.subs {
    25  			if m.subs[i] != matches[i+1] {
    26  				t.Errorf("Unexpected submatch %d: %q, expected %q for %q", i+1, matches[i+1], m.subs[i], m.input)
    27  			}
    28  		}
    29  	} else if m.match {
    30  		t.Errorf("Expected match for %q", m.input)
    31  	} else if matches != nil {
    32  		t.Errorf("Unexpected match for %q", m.input)
    33  	}
    34  }
    35  
    36  func TestHostRegexp(t *testing.T) {
    37  	hostcases := []regexpMatch{
    38  		{
    39  			input: "test.com",
    40  			match: true,
    41  		},
    42  		{
    43  			input: "test.com:10304",
    44  			match: true,
    45  		},
    46  		{
    47  			input: "test.com:http",
    48  			match: false,
    49  		},
    50  		{
    51  			input: "localhost",
    52  			match: true,
    53  		},
    54  		{
    55  			input: "localhost:8080",
    56  			match: true,
    57  		},
    58  		{
    59  			input: "a",
    60  			match: true,
    61  		},
    62  		{
    63  			input: "a.b",
    64  			match: true,
    65  		},
    66  		{
    67  			input: "ab.cd.com",
    68  			match: true,
    69  		},
    70  		{
    71  			input: "a-b.com",
    72  			match: true,
    73  		},
    74  		{
    75  			input: "-ab.com",
    76  			match: false,
    77  		},
    78  		{
    79  			input: "ab-.com",
    80  			match: false,
    81  		},
    82  		{
    83  			input: "ab.c-om",
    84  			match: true,
    85  		},
    86  		{
    87  			input: "ab.-com",
    88  			match: false,
    89  		},
    90  		{
    91  			input: "ab.com-",
    92  			match: false,
    93  		},
    94  		{
    95  			input: "0101.com",
    96  			match: true, // TODO(dmcgowan): valid if this should be allowed
    97  		},
    98  		{
    99  			input: "001a.com",
   100  			match: true,
   101  		},
   102  		{
   103  			input: "b.gbc.io:443",
   104  			match: true,
   105  		},
   106  		{
   107  			input: "b.gbc.io",
   108  			match: true,
   109  		},
   110  		{
   111  			input: "xn--n3h.com", // ☃.com in punycode
   112  			match: true,
   113  		},
   114  	}
   115  	r := regexp.MustCompile(`^` + hostnameRegexp.String() + `$`)
   116  	for i := range hostcases {
   117  		checkRegexp(t, r, hostcases[i])
   118  	}
   119  }
   120  
   121  func TestFullNameRegexp(t *testing.T) {
   122  	if anchoredNameRegexp.NumSubexp() != 2 {
   123  		t.Fatalf("anchored name regexp should have two submatches: %v, %v != 2",
   124  			anchoredNameRegexp, anchoredNameRegexp.NumSubexp())
   125  	}
   126  
   127  	testcases := []regexpMatch{
   128  		{
   129  			input: "",
   130  			match: false,
   131  		},
   132  		{
   133  			input: "short",
   134  			match: true,
   135  			subs:  []string{"", "short"},
   136  		},
   137  		{
   138  			input: "simple/name",
   139  			match: true,
   140  			subs:  []string{"simple", "name"},
   141  		},
   142  		{
   143  			input: "library/ubuntu",
   144  			match: true,
   145  			subs:  []string{"library", "ubuntu"},
   146  		},
   147  		{
   148  			input: "docker/stevvooe/app",
   149  			match: true,
   150  			subs:  []string{"docker", "stevvooe/app"},
   151  		},
   152  		{
   153  			input: "aa/aa/aa/aa/aa/aa/aa/aa/aa/bb/bb/bb/bb/bb/bb",
   154  			match: true,
   155  			subs:  []string{"aa", "aa/aa/aa/aa/aa/aa/aa/aa/bb/bb/bb/bb/bb/bb"},
   156  		},
   157  		{
   158  			input: "aa/aa/bb/bb/bb",
   159  			match: true,
   160  			subs:  []string{"aa", "aa/bb/bb/bb"},
   161  		},
   162  		{
   163  			input: "a/a/a/a",
   164  			match: true,
   165  			subs:  []string{"a", "a/a/a"},
   166  		},
   167  		{
   168  			input: "a/a/a/a/",
   169  			match: false,
   170  		},
   171  		{
   172  			input: "a//a/a",
   173  			match: false,
   174  		},
   175  		{
   176  			input: "a",
   177  			match: true,
   178  			subs:  []string{"", "a"},
   179  		},
   180  		{
   181  			input: "a/aa",
   182  			match: true,
   183  			subs:  []string{"a", "aa"},
   184  		},
   185  		{
   186  			input: "a/aa/a",
   187  			match: true,
   188  			subs:  []string{"a", "aa/a"},
   189  		},
   190  		{
   191  			input: "foo.com",
   192  			match: true,
   193  			subs:  []string{"", "foo.com"},
   194  		},
   195  		{
   196  			input: "foo.com/",
   197  			match: false,
   198  		},
   199  		{
   200  			input: "foo.com:8080/bar",
   201  			match: true,
   202  			subs:  []string{"foo.com:8080", "bar"},
   203  		},
   204  		{
   205  			input: "foo.com:http/bar",
   206  			match: false,
   207  		},
   208  		{
   209  			input: "foo.com/bar",
   210  			match: true,
   211  			subs:  []string{"foo.com", "bar"},
   212  		},
   213  		{
   214  			input: "foo.com/bar/baz",
   215  			match: true,
   216  			subs:  []string{"foo.com", "bar/baz"},
   217  		},
   218  		{
   219  			input: "localhost:8080/bar",
   220  			match: true,
   221  			subs:  []string{"localhost:8080", "bar"},
   222  		},
   223  		{
   224  			input: "sub-dom1.foo.com/bar/baz/quux",
   225  			match: true,
   226  			subs:  []string{"sub-dom1.foo.com", "bar/baz/quux"},
   227  		},
   228  		{
   229  			input: "blog.foo.com/bar/baz",
   230  			match: true,
   231  			subs:  []string{"blog.foo.com", "bar/baz"},
   232  		},
   233  		{
   234  			input: "a^a",
   235  			match: false,
   236  		},
   237  		{
   238  			input: "aa/asdf$$^/aa",
   239  			match: false,
   240  		},
   241  		{
   242  			input: "asdf$$^/aa",
   243  			match: false,
   244  		},
   245  		{
   246  			input: "aa-a/a",
   247  			match: true,
   248  			subs:  []string{"aa-a", "a"},
   249  		},
   250  		{
   251  			input: strings.Repeat("a/", 128) + "a",
   252  			match: true,
   253  			subs:  []string{"a", strings.Repeat("a/", 127) + "a"},
   254  		},
   255  		{
   256  			input: "a-/a/a/a",
   257  			match: false,
   258  		},
   259  		{
   260  			input: "foo.com/a-/a/a",
   261  			match: false,
   262  		},
   263  		{
   264  			input: "-foo/bar",
   265  			match: false,
   266  		},
   267  		{
   268  			input: "foo/bar-",
   269  			match: false,
   270  		},
   271  		{
   272  			input: "foo-/bar",
   273  			match: false,
   274  		},
   275  		{
   276  			input: "foo/-bar",
   277  			match: false,
   278  		},
   279  		{
   280  			input: "_foo/bar",
   281  			match: false,
   282  		},
   283  		{
   284  			input: "foo_bar",
   285  			match: true,
   286  			subs:  []string{"", "foo_bar"},
   287  		},
   288  		{
   289  			input: "foo_bar.com",
   290  			match: true,
   291  			subs:  []string{"", "foo_bar.com"},
   292  		},
   293  		{
   294  			input: "foo_bar.com:8080",
   295  			match: false,
   296  		},
   297  		{
   298  			input: "foo_bar.com:8080/app",
   299  			match: false,
   300  		},
   301  		{
   302  			input: "foo.com/foo_bar",
   303  			match: true,
   304  			subs:  []string{"foo.com", "foo_bar"},
   305  		},
   306  		{
   307  			input: "____/____",
   308  			match: false,
   309  		},
   310  		{
   311  			input: "_docker/_docker",
   312  			match: false,
   313  		},
   314  		{
   315  			input: "docker_/docker_",
   316  			match: false,
   317  		},
   318  		{
   319  			input: "b.gcr.io/test.example.com/my-app",
   320  			match: true,
   321  			subs:  []string{"b.gcr.io", "test.example.com/my-app"},
   322  		},
   323  		{
   324  			input: "xn--n3h.com/myimage", // ☃.com in punycode
   325  			match: true,
   326  			subs:  []string{"xn--n3h.com", "myimage"},
   327  		},
   328  		{
   329  			input: "xn--7o8h.com/myimage", // 🐳.com in punycode
   330  			match: true,
   331  			subs:  []string{"xn--7o8h.com", "myimage"},
   332  		},
   333  		{
   334  			input: "example.com/xn--7o8h.com/myimage", // 🐳.com in punycode
   335  			match: true,
   336  			subs:  []string{"example.com", "xn--7o8h.com/myimage"},
   337  		},
   338  		{
   339  			input: "example.com/some_separator__underscore/myimage",
   340  			match: true,
   341  			subs:  []string{"example.com", "some_separator__underscore/myimage"},
   342  		},
   343  		{
   344  			input: "example.com/__underscore/myimage",
   345  			match: false,
   346  		},
   347  		{
   348  			input: "example.com/..dots/myimage",
   349  			match: false,
   350  		},
   351  		{
   352  			input: "example.com/.dots/myimage",
   353  			match: false,
   354  		},
   355  		{
   356  			input: "example.com/nodouble..dots/myimage",
   357  			match: false,
   358  		},
   359  		{
   360  			input: "example.com/nodouble..dots/myimage",
   361  			match: false,
   362  		},
   363  		{
   364  			input: "docker./docker",
   365  			match: false,
   366  		},
   367  		{
   368  			input: ".docker/docker",
   369  			match: false,
   370  		},
   371  		{
   372  			input: "docker-/docker",
   373  			match: false,
   374  		},
   375  		{
   376  			input: "-docker/docker",
   377  			match: false,
   378  		},
   379  		{
   380  			input: "do..cker/docker",
   381  			match: false,
   382  		},
   383  		{
   384  			input: "do__cker:8080/docker",
   385  			match: false,
   386  		},
   387  		{
   388  			input: "do__cker/docker",
   389  			match: true,
   390  			subs:  []string{"", "do__cker/docker"},
   391  		},
   392  		{
   393  			input: "b.gcr.io/test.example.com/my-app",
   394  			match: true,
   395  			subs:  []string{"b.gcr.io", "test.example.com/my-app"},
   396  		},
   397  		{
   398  			input: "registry.io/foo/project--id.module--name.ver---sion--name",
   399  			match: true,
   400  			subs:  []string{"registry.io", "foo/project--id.module--name.ver---sion--name"},
   401  		},
   402  	}
   403  	for i := range testcases {
   404  		checkRegexp(t, anchoredNameRegexp, testcases[i])
   405  	}
   406  }
   407  
   408  func TestReferenceRegexp(t *testing.T) {
   409  	if ReferenceRegexp.NumSubexp() != 3 {
   410  		t.Fatalf("anchored name regexp should have three submatches: %v, %v != 3",
   411  			ReferenceRegexp, ReferenceRegexp.NumSubexp())
   412  	}
   413  
   414  	testcases := []regexpMatch{
   415  		{
   416  			input: "registry.com:8080/myapp:tag",
   417  			match: true,
   418  			subs:  []string{"registry.com:8080/myapp", "tag", ""},
   419  		},
   420  		{
   421  			input: "registry.com:8080/myapp@sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912",
   422  			match: true,
   423  			subs:  []string{"registry.com:8080/myapp", "", "sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912"},
   424  		},
   425  		{
   426  			input: "registry.com:8080/myapp:tag2@sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912",
   427  			match: true,
   428  			subs:  []string{"registry.com:8080/myapp", "tag2", "sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912"},
   429  		},
   430  		{
   431  			input: "registry.com:8080/myapp@sha256:badbadbadbad",
   432  			match: false,
   433  		},
   434  		{
   435  			input: "registry.com:8080/myapp:invalid~tag",
   436  			match: false,
   437  		},
   438  		{
   439  			input: "bad_hostname.com:8080/myapp:tag",
   440  			match: false,
   441  		},
   442  		{
   443  			input:// localhost treated as name, missing tag with 8080 as tag
   444  			"localhost:8080@sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912",
   445  			match: true,
   446  			subs:  []string{"localhost", "8080", "sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912"},
   447  		},
   448  		{
   449  			input: "localhost:8080/name@sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912",
   450  			match: true,
   451  			subs:  []string{"localhost:8080/name", "", "sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912"},
   452  		},
   453  		{
   454  			input: "localhost:http/name@sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912",
   455  			match: false,
   456  		},
   457  		{
   458  			// localhost will be treated as an image name without a host
   459  			input: "localhost@sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912",
   460  			match: true,
   461  			subs:  []string{"localhost", "", "sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912"},
   462  		},
   463  		{
   464  			input: "registry.com:8080/myapp@bad",
   465  			match: false,
   466  		},
   467  		{
   468  			input: "registry.com:8080/myapp@2bad",
   469  			match: false, // TODO(dmcgowan): Support this as valid
   470  		},
   471  	}
   472  
   473  	for i := range testcases {
   474  		checkRegexp(t, ReferenceRegexp, testcases[i])
   475  	}
   476  
   477  }