1package dns
2
3import "testing"
4
5func TestCompareDomainName(t *testing.T) {
6	s1 := "www.miek.nl."
7	s2 := "miek.nl."
8	s3 := "www.bla.nl."
9	s4 := "nl.www.bla."
10	s5 := "nl."
11	s6 := "miek.nl."
12
13	if CompareDomainName(s1, s2) != 2 {
14		t.Errorf("%s with %s should be %d", s1, s2, 2)
15	}
16	if CompareDomainName(s1, s3) != 1 {
17		t.Errorf("%s with %s should be %d", s1, s3, 1)
18	}
19	if CompareDomainName(s3, s4) != 0 {
20		t.Errorf("%s with %s should be %d", s3, s4, 0)
21	}
22	// Non qualified tests
23	if CompareDomainName(s1, s5) != 1 {
24		t.Errorf("%s with %s should be %d", s1, s5, 1)
25	}
26	if CompareDomainName(s1, s6) != 2 {
27		t.Errorf("%s with %s should be %d", s1, s5, 2)
28	}
29
30	if CompareDomainName(s1, ".") != 0 {
31		t.Errorf("%s with %s should be %d", s1, s5, 0)
32	}
33	if CompareDomainName(".", ".") != 0 {
34		t.Errorf("%s with %s should be %d", ".", ".", 0)
35	}
36	if CompareDomainName("test.com.", "TEST.COM.") != 2 {
37		t.Errorf("test.com. and TEST.COM. should be an exact match")
38	}
39}
40
41func TestSplit(t *testing.T) {
42	splitter := map[string]int{
43		"www.miek.nl.":    3,
44		"www.miek.nl":     3,
45		"www..miek.nl":    4,
46		`www\.miek.nl.`:   2,
47		`www\\.miek.nl.`:  3,
48		`www\\\.miek.nl.`: 2,
49		".":               0,
50		"nl.":             1,
51		"nl":              1,
52		"com.":            1,
53		".com.":           2,
54	}
55	for s, i := range splitter {
56		if x := len(Split(s)); x != i {
57			t.Errorf("labels should be %d, got %d: %s %v", i, x, s, Split(s))
58		}
59	}
60}
61
62func TestSplit2(t *testing.T) {
63	splitter := map[string][]int{
64		"www.miek.nl.": {0, 4, 9},
65		"www.miek.nl":  {0, 4, 9},
66		"nl":           {0},
67	}
68	for s, i := range splitter {
69		x := Split(s)
70		switch len(i) {
71		case 1:
72			if x[0] != i[0] {
73				t.Errorf("labels should be %v, got %v: %s", i, x, s)
74			}
75		default:
76			if x[0] != i[0] || x[1] != i[1] || x[2] != i[2] {
77				t.Errorf("labels should be %v, got %v: %s", i, x, s)
78			}
79		}
80	}
81}
82
83func TestNextLabel(t *testing.T) {
84	type next struct {
85		string
86		int
87	}
88	nexts := map[next]int{
89		{"", 1}:             0,
90		{"www.miek.nl.", 0}: 4,
91		{"www.miek.nl.", 4}: 9,
92		{"www.miek.nl.", 9}: 12,
93	}
94	for s, i := range nexts {
95		x, ok := NextLabel(s.string, s.int)
96		if i != x {
97			t.Errorf("label should be %d, got %d, %t: next %d, %s", i, x, ok, s.int, s.string)
98		}
99	}
100}
101
102func TestPrevLabel(t *testing.T) {
103	type prev struct {
104		string
105		int
106	}
107	prever := map[prev]int{
108		{"", 1}:             0,
109		{"www.miek.nl.", 0}: 12,
110		{"www.miek.nl.", 1}: 9,
111		{"www.miek.nl.", 2}: 4,
112
113		{"www.miek.nl", 0}: 11,
114		{"www.miek.nl", 1}: 9,
115		{"www.miek.nl", 2}: 4,
116
117		{"www.miek.nl.", 5}: 0,
118		{"www.miek.nl", 5}:  0,
119
120		{"www.miek.nl.", 3}: 0,
121		{"www.miek.nl", 3}:  0,
122	}
123	for s, i := range prever {
124		x, ok := PrevLabel(s.string, s.int)
125		if i != x {
126			t.Errorf("label should be %d, got %d, %t: previous %d, %s", i, x, ok, s.int, s.string)
127		}
128	}
129}
130
131func TestCountLabel(t *testing.T) {
132	splitter := map[string]int{
133		"www.miek.nl.": 3,
134		"www.miek.nl":  3,
135		"nl":           1,
136		".":            0,
137	}
138	for s, i := range splitter {
139		x := CountLabel(s)
140		if x != i {
141			t.Errorf("CountLabel should have %d, got %d", i, x)
142		}
143	}
144}
145
146func TestSplitDomainName(t *testing.T) {
147	labels := map[string][]string{
148		"miek.nl":       {"miek", "nl"},
149		".":             nil,
150		"www.miek.nl.":  {"www", "miek", "nl"},
151		"www.miek.nl":   {"www", "miek", "nl"},
152		"www..miek.nl":  {"www", "", "miek", "nl"},
153		`www\.miek.nl`:  {`www\.miek`, "nl"},
154		`www\\.miek.nl`: {`www\\`, "miek", "nl"},
155		".www.miek.nl.": {"", "www", "miek", "nl"},
156	}
157domainLoop:
158	for domain, splits := range labels {
159		parts := SplitDomainName(domain)
160		if len(parts) != len(splits) {
161			t.Errorf("SplitDomainName returned %v for %s, expected %v", parts, domain, splits)
162			continue domainLoop
163		}
164		for i := range parts {
165			if parts[i] != splits[i] {
166				t.Errorf("SplitDomainName returned %v for %s, expected %v", parts, domain, splits)
167				continue domainLoop
168			}
169		}
170	}
171}
172
173func TestIsDomainName(t *testing.T) {
174	type ret struct {
175		ok  bool
176		lab int
177	}
178	names := map[string]*ret{
179		"..":                     {false, 1},
180		"@.":                     {true, 1},
181		"www.example.com":        {true, 3},
182		"www.e%ample.com":        {true, 3},
183		"www.example.com.":       {true, 3},
184		"mi\\k.nl.":              {true, 2},
185		"mi\\k.nl":               {true, 2},
186		longestDomain:            {true, 4},
187		longestUnprintableDomain: {true, 4},
188	}
189	for d, ok := range names {
190		l, k := IsDomainName(d)
191		if ok.ok != k || ok.lab != l {
192			t.Errorf(" got %v %d for %s ", k, l, d)
193			t.Errorf("have %v %d for %s ", ok.ok, ok.lab, d)
194		}
195	}
196}
197
198func TestIsFqdnEscaped(t *testing.T) {
199	for s, expect := range map[string]bool{
200		".":                  true,
201		"\\.":                false,
202		"\\\\.":              true,
203		"\\\\\\.":            false,
204		"\\\\\\\\.":          true,
205		"a.":                 true,
206		"a\\.":               false,
207		"a\\\\.":             true,
208		"a\\\\\\.":           false,
209		"ab.":                true,
210		"ab\\.":              false,
211		"ab\\\\.":            true,
212		"ab\\\\\\.":          false,
213		"..":                 true,
214		".\\.":               false,
215		".\\\\.":             true,
216		".\\\\\\.":           false,
217		"example.org.":       true,
218		"example.org\\.":     false,
219		"example.org\\\\.":   true,
220		"example.org\\\\\\.": false,
221		"example\\.org.":     true,
222		"example\\\\.org.":   true,
223		"example\\\\\\.org.": true,
224		"\\example.org.":     true,
225		"\\\\example.org.":   true,
226		"\\\\\\example.org.": true,
227	} {
228		if got := IsFqdn(s); got != expect {
229			t.Errorf("IsFqdn(%q) = %t, expected %t", s, got, expect)
230		}
231	}
232}
233
234func TestCanonicalName(t *testing.T) {
235	for s, expect := range map[string]string{
236		"":                 ".",
237		".":                ".",
238		"tld":              "tld.",
239		"tld.":             "tld.",
240		"example.test":     "example.test.",
241		"Lower.CASE.test.": "lower.case.test.",
242		"*.Test":           "*.test.",
243	} {
244		if got := CanonicalName(s); got != expect {
245			t.Errorf("CanonicalName(%q) = %q, expected %q", s, got, expect)
246		}
247	}
248}
249
250func BenchmarkSplitLabels(b *testing.B) {
251	for i := 0; i < b.N; i++ {
252		Split("www.example.com.")
253	}
254}
255
256func BenchmarkLenLabels(b *testing.B) {
257	for i := 0; i < b.N; i++ {
258		CountLabel("www.example.com.")
259	}
260}
261
262func BenchmarkCompareDomainName(b *testing.B) {
263	b.ReportAllocs()
264	for i := 0; i < b.N; i++ {
265		CompareDomainName("www.example.com.", "aa.example.com.")
266	}
267}
268
269func BenchmarkIsSubDomain(b *testing.B) {
270	b.ReportAllocs()
271	for i := 0; i < b.N; i++ {
272		IsSubDomain("www.example.com.", "aa.example.com.")
273		IsSubDomain("example.com.", "aa.example.com.")
274		IsSubDomain("miek.nl.", "aa.example.com.")
275	}
276}
277
278func BenchmarkNextLabelSimple(b *testing.B) {
279	b.ReportAllocs()
280	for i := 0; i < b.N; i++ {
281		NextLabel("www.example.com", 0)
282		NextLabel("www.example.com", 5)
283		NextLabel("www.example.com", 12)
284	}
285}
286
287func BenchmarkPrevLabelSimple(b *testing.B) {
288	b.ReportAllocs()
289	for i := 0; i < b.N; i++ {
290		PrevLabel("www.example.com", 0)
291		PrevLabel("www.example.com", 5)
292		PrevLabel("www.example.com", 12)
293	}
294}
295
296func BenchmarkNextLabelComplex(b *testing.B) {
297	b.ReportAllocs()
298	for i := 0; i < b.N; i++ {
299		NextLabel(`www\.example.com`, 0)
300		NextLabel(`www\\.example.com`, 0)
301		NextLabel(`www\\\.example.com`, 0)
302	}
303}
304
305func BenchmarkPrevLabelComplex(b *testing.B) {
306	b.ReportAllocs()
307	for i := 0; i < b.N; i++ {
308		PrevLabel(`www\.example.com`, 10)
309		PrevLabel(`www\\.example.com`, 10)
310		PrevLabel(`www\\\.example.com`, 10)
311	}
312}
313
314func BenchmarkNextLabelMixed(b *testing.B) {
315	b.ReportAllocs()
316	for i := 0; i < b.N; i++ {
317		NextLabel("www.example.com", 0)
318		NextLabel(`www\.example.com`, 0)
319		NextLabel("www.example.com", 5)
320		NextLabel(`www\\.example.com`, 0)
321		NextLabel("www.example.com", 12)
322		NextLabel(`www\\\.example.com`, 0)
323	}
324}
325
326func BenchmarkPrevLabelMixed(b *testing.B) {
327	b.ReportAllocs()
328	for i := 0; i < b.N; i++ {
329		PrevLabel("www.example.com", 0)
330		PrevLabel(`www\.example.com`, 10)
331		PrevLabel("www.example.com", 5)
332		PrevLabel(`www\\.example.com`, 10)
333		PrevLabel("www.example.com", 12)
334		PrevLabel(`www\\\.example.com`, 10)
335	}
336}
337