OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / net / publicsuffix / list_test.go
1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package publicsuffix
6
7 import (
8         "sort"
9         "strings"
10         "testing"
11 )
12
13 func TestNodeLabel(t *testing.T) {
14         for i, want := range nodeLabels {
15                 got := nodeLabel(uint32(i))
16                 if got != want {
17                         t.Errorf("%d: got %q, want %q", i, got, want)
18                 }
19         }
20 }
21
22 func TestFind(t *testing.T) {
23         testCases := []string{
24                 "",
25                 "a",
26                 "a0",
27                 "aaaa",
28                 "ao",
29                 "ap",
30                 "ar",
31                 "aro",
32                 "arp",
33                 "arpa",
34                 "arpaa",
35                 "arpb",
36                 "az",
37                 "b",
38                 "b0",
39                 "ba",
40                 "z",
41                 "zu",
42                 "zv",
43                 "zw",
44                 "zx",
45                 "zy",
46                 "zz",
47                 "zzzz",
48         }
49         for _, tc := range testCases {
50                 got := find(tc, 0, numTLD)
51                 want := notFound
52                 for i := uint32(0); i < numTLD; i++ {
53                         if tc == nodeLabel(i) {
54                                 want = i
55                                 break
56                         }
57                 }
58                 if got != want {
59                         t.Errorf("%q: got %d, want %d", tc, got, want)
60                 }
61         }
62 }
63
64 func TestICANN(t *testing.T) {
65         testCases := map[string]bool{
66                 "foo.org":            true,
67                 "foo.co.uk":          true,
68                 "foo.dyndns.org":     false,
69                 "foo.go.dyndns.org":  false,
70                 "foo.blogspot.co.uk": false,
71                 "foo.intranet":       false,
72         }
73         for domain, want := range testCases {
74                 _, got := PublicSuffix(domain)
75                 if got != want {
76                         t.Errorf("%q: got %v, want %v", domain, got, want)
77                 }
78         }
79 }
80
81 var publicSuffixTestCases = []struct {
82         domain, want string
83 }{
84         // Empty string.
85         {"", ""},
86
87         // The .ao rules are:
88         // ao
89         // ed.ao
90         // gv.ao
91         // og.ao
92         // co.ao
93         // pb.ao
94         // it.ao
95         {"ao", "ao"},
96         {"www.ao", "ao"},
97         {"pb.ao", "pb.ao"},
98         {"www.pb.ao", "pb.ao"},
99         {"www.xxx.yyy.zzz.pb.ao", "pb.ao"},
100
101         // The .ar rules are:
102         // ar
103         // com.ar
104         // edu.ar
105         // gob.ar
106         // gov.ar
107         // int.ar
108         // mil.ar
109         // net.ar
110         // org.ar
111         // tur.ar
112         // blogspot.com.ar
113         {"ar", "ar"},
114         {"www.ar", "ar"},
115         {"nic.ar", "ar"},
116         {"www.nic.ar", "ar"},
117         {"com.ar", "com.ar"},
118         {"www.com.ar", "com.ar"},
119         {"blogspot.com.ar", "blogspot.com.ar"},
120         {"www.blogspot.com.ar", "blogspot.com.ar"},
121         {"www.xxx.yyy.zzz.blogspot.com.ar", "blogspot.com.ar"},
122         {"logspot.com.ar", "com.ar"},
123         {"zlogspot.com.ar", "com.ar"},
124         {"zblogspot.com.ar", "com.ar"},
125
126         // The .arpa rules are:
127         // arpa
128         // e164.arpa
129         // in-addr.arpa
130         // ip6.arpa
131         // iris.arpa
132         // uri.arpa
133         // urn.arpa
134         {"arpa", "arpa"},
135         {"www.arpa", "arpa"},
136         {"urn.arpa", "urn.arpa"},
137         {"www.urn.arpa", "urn.arpa"},
138         {"www.xxx.yyy.zzz.urn.arpa", "urn.arpa"},
139
140         // The relevant {kobe,kyoto}.jp rules are:
141         // jp
142         // *.kobe.jp
143         // !city.kobe.jp
144         // kyoto.jp
145         // ide.kyoto.jp
146         {"jp", "jp"},
147         {"kobe.jp", "jp"},
148         {"c.kobe.jp", "c.kobe.jp"},
149         {"b.c.kobe.jp", "c.kobe.jp"},
150         {"a.b.c.kobe.jp", "c.kobe.jp"},
151         {"city.kobe.jp", "kobe.jp"},
152         {"www.city.kobe.jp", "kobe.jp"},
153         {"kyoto.jp", "kyoto.jp"},
154         {"test.kyoto.jp", "kyoto.jp"},
155         {"ide.kyoto.jp", "ide.kyoto.jp"},
156         {"b.ide.kyoto.jp", "ide.kyoto.jp"},
157         {"a.b.ide.kyoto.jp", "ide.kyoto.jp"},
158
159         // The .tw rules are:
160         // tw
161         // edu.tw
162         // gov.tw
163         // mil.tw
164         // com.tw
165         // net.tw
166         // org.tw
167         // idv.tw
168         // game.tw
169         // ebiz.tw
170         // club.tw
171         // 網路.tw (xn--zf0ao64a.tw)
172         // 組織.tw (xn--uc0atv.tw)
173         // 商業.tw (xn--czrw28b.tw)
174         // blogspot.tw
175         {"tw", "tw"},
176         {"aaa.tw", "tw"},
177         {"www.aaa.tw", "tw"},
178         {"xn--czrw28b.aaa.tw", "tw"},
179         {"edu.tw", "edu.tw"},
180         {"www.edu.tw", "edu.tw"},
181         {"xn--czrw28b.edu.tw", "edu.tw"},
182         {"xn--czrw28b.tw", "xn--czrw28b.tw"},
183         {"www.xn--czrw28b.tw", "xn--czrw28b.tw"},
184         {"xn--uc0atv.xn--czrw28b.tw", "xn--czrw28b.tw"},
185         {"xn--kpry57d.tw", "tw"},
186
187         // The .uk rules are:
188         // uk
189         // ac.uk
190         // co.uk
191         // gov.uk
192         // ltd.uk
193         // me.uk
194         // net.uk
195         // nhs.uk
196         // org.uk
197         // plc.uk
198         // police.uk
199         // *.sch.uk
200         // blogspot.co.uk
201         {"uk", "uk"},
202         {"aaa.uk", "uk"},
203         {"www.aaa.uk", "uk"},
204         {"mod.uk", "uk"},
205         {"www.mod.uk", "uk"},
206         {"sch.uk", "uk"},
207         {"mod.sch.uk", "mod.sch.uk"},
208         {"www.sch.uk", "www.sch.uk"},
209         {"blogspot.co.uk", "blogspot.co.uk"},
210         {"blogspot.nic.uk", "uk"},
211         {"blogspot.sch.uk", "blogspot.sch.uk"},
212
213         // The .рф rules are
214         // рф (xn--p1ai)
215         {"xn--p1ai", "xn--p1ai"},
216         {"aaa.xn--p1ai", "xn--p1ai"},
217         {"www.xxx.yyy.xn--p1ai", "xn--p1ai"},
218
219         // The .bd rules are:
220         // *.bd
221         {"bd", "bd"},
222         {"www.bd", "www.bd"},
223         {"zzz.bd", "zzz.bd"},
224         {"www.zzz.bd", "zzz.bd"},
225         {"www.xxx.yyy.zzz.bd", "zzz.bd"},
226
227         // There are no .nosuchtld rules.
228         {"nosuchtld", "nosuchtld"},
229         {"foo.nosuchtld", "nosuchtld"},
230         {"bar.foo.nosuchtld", "nosuchtld"},
231 }
232
233 func BenchmarkPublicSuffix(b *testing.B) {
234         for i := 0; i < b.N; i++ {
235                 for _, tc := range publicSuffixTestCases {
236                         List.PublicSuffix(tc.domain)
237                 }
238         }
239 }
240
241 func TestPublicSuffix(t *testing.T) {
242         for _, tc := range publicSuffixTestCases {
243                 got := List.PublicSuffix(tc.domain)
244                 if got != tc.want {
245                         t.Errorf("%q: got %q, want %q", tc.domain, got, tc.want)
246                 }
247         }
248 }
249
250 func TestSlowPublicSuffix(t *testing.T) {
251         for _, tc := range publicSuffixTestCases {
252                 got := slowPublicSuffix(tc.domain)
253                 if got != tc.want {
254                         t.Errorf("%q: got %q, want %q", tc.domain, got, tc.want)
255                 }
256         }
257 }
258
259 // slowPublicSuffix implements the canonical (but O(number of rules)) public
260 // suffix algorithm described at http://publicsuffix.org/list/.
261 //
262 // 1. Match domain against all rules and take note of the matching ones.
263 // 2. If no rules match, the prevailing rule is "*".
264 // 3. If more than one rule matches, the prevailing rule is the one which is an exception rule.
265 // 4. If there is no matching exception rule, the prevailing rule is the one with the most labels.
266 // 5. If the prevailing rule is a exception rule, modify it by removing the leftmost label.
267 // 6. The public suffix is the set of labels from the domain which directly match the labels of the prevailing rule (joined by dots).
268 // 7. The registered or registrable domain is the public suffix plus one additional label.
269 //
270 // This function returns the public suffix, not the registrable domain, and so
271 // it stops after step 6.
272 func slowPublicSuffix(domain string) string {
273         match := func(rulePart, domainPart string) bool {
274                 switch rulePart[0] {
275                 case '*':
276                         return true
277                 case '!':
278                         return rulePart[1:] == domainPart
279                 }
280                 return rulePart == domainPart
281         }
282
283         domainParts := strings.Split(domain, ".")
284         var matchingRules [][]string
285
286 loop:
287         for _, rule := range rules {
288                 ruleParts := strings.Split(rule, ".")
289                 if len(domainParts) < len(ruleParts) {
290                         continue
291                 }
292                 for i := range ruleParts {
293                         rulePart := ruleParts[len(ruleParts)-1-i]
294                         domainPart := domainParts[len(domainParts)-1-i]
295                         if !match(rulePart, domainPart) {
296                                 continue loop
297                         }
298                 }
299                 matchingRules = append(matchingRules, ruleParts)
300         }
301         if len(matchingRules) == 0 {
302                 matchingRules = append(matchingRules, []string{"*"})
303         } else {
304                 sort.Sort(byPriority(matchingRules))
305         }
306         prevailing := matchingRules[0]
307         if prevailing[0][0] == '!' {
308                 prevailing = prevailing[1:]
309         }
310         if prevailing[0][0] == '*' {
311                 replaced := domainParts[len(domainParts)-len(prevailing)]
312                 prevailing = append([]string{replaced}, prevailing[1:]...)
313         }
314         return strings.Join(prevailing, ".")
315 }
316
317 type byPriority [][]string
318
319 func (b byPriority) Len() int      { return len(b) }
320 func (b byPriority) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
321 func (b byPriority) Less(i, j int) bool {
322         if b[i][0][0] == '!' {
323                 return true
324         }
325         if b[j][0][0] == '!' {
326                 return false
327         }
328         return len(b[i]) > len(b[j])
329 }
330
331 // eTLDPlusOneTestCases come from
332 // https://github.com/publicsuffix/list/blob/master/tests/test_psl.txt
333 var eTLDPlusOneTestCases = []struct {
334         domain, want string
335 }{
336         // Empty input.
337         {"", ""},
338         // Unlisted TLD.
339         {"example", ""},
340         {"example.example", "example.example"},
341         {"b.example.example", "example.example"},
342         {"a.b.example.example", "example.example"},
343         // TLD with only 1 rule.
344         {"biz", ""},
345         {"domain.biz", "domain.biz"},
346         {"b.domain.biz", "domain.biz"},
347         {"a.b.domain.biz", "domain.biz"},
348         // TLD with some 2-level rules.
349         {"com", ""},
350         {"example.com", "example.com"},
351         {"b.example.com", "example.com"},
352         {"a.b.example.com", "example.com"},
353         {"uk.com", ""},
354         {"example.uk.com", "example.uk.com"},
355         {"b.example.uk.com", "example.uk.com"},
356         {"a.b.example.uk.com", "example.uk.com"},
357         {"test.ac", "test.ac"},
358         // TLD with only 1 (wildcard) rule.
359         {"mm", ""},
360         {"c.mm", ""},
361         {"b.c.mm", "b.c.mm"},
362         {"a.b.c.mm", "b.c.mm"},
363         // More complex TLD.
364         {"jp", ""},
365         {"test.jp", "test.jp"},
366         {"www.test.jp", "test.jp"},
367         {"ac.jp", ""},
368         {"test.ac.jp", "test.ac.jp"},
369         {"www.test.ac.jp", "test.ac.jp"},
370         {"kyoto.jp", ""},
371         {"test.kyoto.jp", "test.kyoto.jp"},
372         {"ide.kyoto.jp", ""},
373         {"b.ide.kyoto.jp", "b.ide.kyoto.jp"},
374         {"a.b.ide.kyoto.jp", "b.ide.kyoto.jp"},
375         {"c.kobe.jp", ""},
376         {"b.c.kobe.jp", "b.c.kobe.jp"},
377         {"a.b.c.kobe.jp", "b.c.kobe.jp"},
378         {"city.kobe.jp", "city.kobe.jp"},
379         {"www.city.kobe.jp", "city.kobe.jp"},
380         // TLD with a wildcard rule and exceptions.
381         {"ck", ""},
382         {"test.ck", ""},
383         {"b.test.ck", "b.test.ck"},
384         {"a.b.test.ck", "b.test.ck"},
385         {"www.ck", "www.ck"},
386         {"www.www.ck", "www.ck"},
387         // US K12.
388         {"us", ""},
389         {"test.us", "test.us"},
390         {"www.test.us", "test.us"},
391         {"ak.us", ""},
392         {"test.ak.us", "test.ak.us"},
393         {"www.test.ak.us", "test.ak.us"},
394         {"k12.ak.us", ""},
395         {"test.k12.ak.us", "test.k12.ak.us"},
396         {"www.test.k12.ak.us", "test.k12.ak.us"},
397         // Punycoded IDN labels
398         {"xn--85x722f.com.cn", "xn--85x722f.com.cn"},
399         {"xn--85x722f.xn--55qx5d.cn", "xn--85x722f.xn--55qx5d.cn"},
400         {"www.xn--85x722f.xn--55qx5d.cn", "xn--85x722f.xn--55qx5d.cn"},
401         {"shishi.xn--55qx5d.cn", "shishi.xn--55qx5d.cn"},
402         {"xn--55qx5d.cn", ""},
403         {"xn--85x722f.xn--fiqs8s", "xn--85x722f.xn--fiqs8s"},
404         {"www.xn--85x722f.xn--fiqs8s", "xn--85x722f.xn--fiqs8s"},
405         {"shishi.xn--fiqs8s", "shishi.xn--fiqs8s"},
406         {"xn--fiqs8s", ""},
407 }
408
409 func TestEffectiveTLDPlusOne(t *testing.T) {
410         for _, tc := range eTLDPlusOneTestCases {
411                 got, _ := EffectiveTLDPlusOne(tc.domain)
412                 if got != tc.want {
413                         t.Errorf("%q: got %q, want %q", tc.domain, got, tc.want)
414                 }
415         }
416 }