1package magna
2
3import (
4 "testing"
5
6 "github.com/stretchr/testify/assert"
7)
8
9func BenchmarkDecodeDomainSimple(b *testing.B) {
10 input := []byte{3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0}
11 for i := 0; i < b.N; i++ {
12 _, _, _ = decode_domain(input, 0)
13 }
14}
15
16func BenchmarkDecodeDomainCompressed(b *testing.B) {
17 input := []byte{
18 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', 0x00,
19 0x03, 'f', 'o', 'o', 0xc0, 0x00,
20 }
21 offset := 13
22 b.ResetTimer()
23 for i := 0; i < b.N; i++ {
24 _, _, _ = decode_domain(input, offset)
25 }
26}
27
28func BenchmarkEncodeDomainSimple(b *testing.B) {
29 domain := "www.example.com"
30 offsets := make(map[string]uint16)
31 out := make([]byte, 0, 64)
32 b.ResetTimer()
33 for i := 0; i < b.N; i++ {
34 _ = encode_domain(out[:0], domain, &offsets)
35 for k := range offsets {
36 delete(offsets, k)
37 }
38 }
39}
40
41func BenchmarkEncodeDomainWithCompression(b *testing.B) {
42 domain1 := "www.example.com"
43 domain2 := "mail.example.com"
44 offsets := make(map[string]uint16)
45 out := make([]byte, 0, 128)
46 b.ResetTimer()
47 for i := 0; i < b.N; i++ {
48 tempOut := encode_domain(out[:0], domain1, &offsets)
49 _ = encode_domain(tempOut, domain2, &offsets)
50 for k := range offsets {
51 delete(offsets, k)
52 }
53 }
54}
55
56func TestDecodeDomain(t *testing.T) {
57 tests := []struct {
58 name string
59 offset int
60 input []byte
61 expectedDomain string
62 expectedOffset int
63 expectedError error
64 }{
65 {
66 name: "Simple domain",
67 input: []byte{3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0},
68 expectedDomain: "www.example.com",
69 expectedOffset: 17,
70 expectedError: nil,
71 },
72 {
73 name: "Domain with compression",
74 offset: 17,
75 input: []byte{3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0, 3, 'f', 'o', 'o', 0xC0, 0},
76 expectedDomain: "foo.www.example.com",
77 expectedOffset: 23,
78 expectedError: nil,
79 },
80 {
81 name: "Invalid label length",
82 input: []byte{64, 'x'},
83 expectedDomain: "",
84 expectedOffset: 2,
85 expectedError: &InvalidLabelError{Length: 64},
86 },
87 {
88 name: "Compression loop",
89 input: []byte{0xC0, 0, 0xC0, 0},
90 expectedDomain: "",
91 expectedOffset: 4,
92 expectedError: &DomainCompressionError{},
93 },
94 {
95 name: "Truncated input",
96 input: []byte{3, 'w', 'w'},
97 expectedDomain: "",
98 expectedOffset: 3,
99 expectedError: &BufferOverflowError{Length: 3, Offset: 4},
100 },
101 }
102
103 for _, tt := range tests {
104 t.Run(tt.name, func(t *testing.T) {
105 domain, offset, err := decode_domain(tt.input, tt.offset)
106
107 t.Log(tt.name)
108 assert.Equal(t, tt.expectedError, err)
109 assert.Equal(t, tt.expectedDomain, domain)
110 assert.Equal(t, tt.expectedOffset, offset)
111 })
112 }
113}
114
115func TestEncodeDomain(t *testing.T) {
116 tests := []struct {
117 name string
118 input string
119 offsets map[string]uint16
120 expected []byte
121 newOffsets map[string]uint16
122 }{
123 {
124 name: "Simple domain",
125 input: "example.com",
126 offsets: make(map[string]uint16),
127 expected: []byte{7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0},
128 newOffsets: map[string]uint16{"example.com": 0, "com": 8},
129 },
130 {
131 name: "Domain with existing offset",
132 input: "test.example.com",
133 offsets: map[string]uint16{"example.com": 10},
134 expected: []byte{4, 't', 'e', 's', 't', 0xC0, 0x0A},
135 newOffsets: map[string]uint16{"test.example.com": 0, "example.com": 10},
136 },
137 {
138 name: "Multiple subdomains",
139 input: "a.b.c.d",
140 offsets: make(map[string]uint16),
141 expected: []byte{1, 'a', 1, 'b', 1, 'c', 1, 'd', 0},
142 newOffsets: map[string]uint16{"a.b.c.d": 0, "b.c.d": 2, "c.d": 4, "d": 6},
143 },
144 }
145
146 for _, tt := range tests {
147 t.Run(tt.name, func(t *testing.T) {
148 result := encode_domain([]byte{}, tt.input, &tt.offsets)
149 assert.Equal(t, tt.expected, result, "Encoded domain does not match expected output")
150 assert.Equal(t, tt.newOffsets, tt.offsets, "Offsets map does not match expected state")
151 })
152 }
153}
154
155func FuzzDecodeDomain(f *testing.F) {
156 testcases := [][]byte{
157 {
158 0x03, 0x63, 0x6f, 0x6d, 0x00,
159 },
160 {
161 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x01, 0x63, 0xC0, 0x00,
162 },
163 {
164 0x03, 0x63, 0x6f, 0x6d, 0xC0, 0x00,
165 },
166 }
167 for _, tc := range testcases {
168 f.Add(tc)
169 }
170 f.Fuzz(func(t *testing.T, msg []byte) {
171 decode_domain(msg, 0)
172 })
173}