7 "github.com/mjl-/mox/dns"
10func TestRecord(t *testing.T) {
11 good := func(txt string, want Record) {
13 r, _, err := ParseRecord(txt)
15 t.Fatalf("parse: %s", err)
17 if !reflect.DeepEqual(r, &want) {
18 t.Fatalf("want %#v, got %#v", want, *r)
22 bad := func(txt string) {
24 r, _, err := ParseRecord(txt)
26 t.Fatalf("parse, expected error, got record %v", r)
30 good("v=STSv1; id=20160831085700Z;", Record{Version: "STSv1", ID: "20160831085700Z"})
31 good("v=STSv1; \t id=20160831085700Z \t;", Record{Version: "STSv1", ID: "20160831085700Z"})
32 good("v=STSv1; id=a", Record{Version: "STSv1", ID: "a"})
33 good("v=STSv1; id=a; more=a; ext=2", Record{Version: "STSv1", ID: "a", Extensions: []Pair{{"more", "a"}, {"ext", "2"}}})
38 bad("v=STSv1") // missing id
39 bad("v=STSv1;") // missing id
40 bad("v=STSv1; ext=1") // missing id
41 bad("v=STSv1; id=") // empty id
42 bad("v=STSv1; id=012345678901234567890123456789012") // id too long
43 bad("v=STSv1; id=test-123") // invalid id
44 bad("v=STSv1; id=a; more=") // empty value in extension
45 bad("v=STSv1; id=a; a12345678901234567890123456789012=1") // extension name too long
46 bad("v=STSv1; id=a; 1%=a") // invalid extension name
47 bad("v=STSv1; id=a; test==") // invalid extension name
48 bad("v=STSv1; id=a;;") // additional semicolon
50 const want = `v=STSv1; id=a; more=a; ext=2`
51 record := Record{Version: "STSv1", ID: "a", Extensions: []Pair{{"more", "a"}, {"ext", "2"}}}
52 got := record.String()
54 t.Fatalf("record string, got %q, want %q", got, want)
58func TestParsePolicy(t *testing.T) {
59 good := func(s string, want Policy) {
61 p, err := ParsePolicy(s)
63 t.Fatalf("parse policy: %s", err)
65 if !reflect.DeepEqual(p, &want) {
66 t.Fatalf("want %v, got %v", want, p)
74mx: mx.backup-example.com
81 {Domain: dns.Domain{ASCII: "mx1.example.com"}},
82 {Domain: dns.Domain{ASCII: "mx2.example.com"}},
83 {Domain: dns.Domain{ASCII: "mx.backup-example.com"}},
85 MaxAgeSeconds: 1296000,
88 good("version: STSv1\nmode: enforce \nmx: *.example.com \nmax_age: 0 \n",
93 {Wildcard: true, Domain: dns.Domain{ASCII: "example.com"}},
98 good("version:STSv1\r\nmode:\tenforce\r\nmx: \t\t *.example.com\nmax_age: 1\nmore:ext e ns ion",
103 {Wildcard: true, Domain: dns.Domain{ASCII: "example.com"}},
106 Extensions: []Pair{{"more", "ext e ns ion"}},
110 bad := func(s string) {
112 p, err := ParsePolicy(s)
114 t.Fatalf("parsing policy did not fail: %v", p)
118 bad("") // missing version
119 bad("version:STSv0\nmode:none\nmax_age:0") // bad version
120 bad("version:STSv10\nmode:none\nmax_age:0") // bad version
121 bad("version:STSv2\nmode:none\nmax_age:0") // bad version
122 bad("version:STSv1\nmax_age:0\nmx:example.com") // missing mode
123 bad("version:STSv1\nmode:none") // missing max_age
124 bad("version:STSv1\nmax_age:0\nmode:enforce") // missing mx for mode
125 bad("version:STSv1\nmax_age:0\nmode:testing") // missing mx for mode
126 bad("max_age:0\nmode:none") // missing version
127 bad("version:STSv1\nmode:none\nmax_age:01234567890") // max_age too long
128 bad("version:STSv1\nmode:bad\nmax_age:1") // bad mode
129 bad("version:STSv1\nmode:none\nmax_age:a") // bad max_age
130 bad("version:STSv1\nmode:enforce\nmax_age:0\nmx:") // missing value
131 bad("version:STSv1\nmode:enforce\nmax_age:0\nmx:*.*.example") // bad mx
132 bad("version:STSv1\nmode:enforce\nmax_age:0\nmx:**.example") // bad mx
133 bad("version:STSv1\nmode:enforce\nmax_age:0\nmx:**.example-") // bad mx
134 bad("version:STSv1\nmode:enforce\nmax_age:0\nmx:test.example-") // bad mx
135 bad("version:STSv1\nmode:none\nmax_age:0\next:") // empty extension
136 bad("version:STSv1\nmode:none\nmax_age:0\na12345678901234567890123456789012:123") // long extension name
137 bad("version:STSv1\nmode:none\nmax_age:0\n_bad:test") // bad ext name
138 bad("version:STSv1\nmode:none\nmax_age:0\nmx: møx.example") // invalid u-label in mx
144 {Domain: dns.Domain{ASCII: "mx1.example.com"}},
145 {Domain: dns.Domain{ASCII: "mx2.example.com"}},
146 {Domain: dns.Domain{ASCII: "mx.backup-example.com"}},
148 MaxAgeSeconds: 1296000,
150 want := `version: STSv1
155mx: mx.backup-example.com
157 got := policy.String()
159 t.Fatalf("policy string, got %q, want %q", got, want)
163func FuzzParseRecord(f *testing.F) {
164 f.Add("v=STSv1; id=20160831085700Z;")
165 f.Add("v=STSv1; \t id=20160831085700Z \t;")
166 f.Add("v=STSv1; id=a")
167 f.Add("v=STSv1; id=a; more=a; ext=2")
172 f.Add("v=STSv1") // missing id
173 f.Add("v=STSv1;") // missing id
174 f.Add("v=STSv1; ext=1") // missing id
175 f.Add("v=STSv1; id=") // empty id
176 f.Add("v=STSv1; id=012345678901234567890123456789012") // id too long
177 f.Add("v=STSv1; id=test-123") // invalid id
178 f.Add("v=STSv1; id=a; more=") // empty value in extension
179 f.Add("v=STSv1; id=a; a12345678901234567890123456789012=1") // extension name too long
180 f.Add("v=STSv1; id=a; 1%=a") // invalid extension name
181 f.Add("v=STSv1; id=a; test==") // invalid extension name
182 f.Add("v=STSv1; id=a;;") // additional semicolon
184 f.Fuzz(func(t *testing.T, s string) {
185 r, _, err := ParseRecord(s)
192func FuzzParsePolicy(f *testing.F) {
193 f.Add(`version: STSv1
197mx: mx.backup-example.com
200 f.Add(`version: STSv1
205 f.Add("version:STSv1\r\nmode:\tenforce\r\nmx: \t\t *.example.com\nmax_age: 1\nmore:ext e ns ion")
207 f.Add("") // missing version
208 f.Add("version:STSv0\nmode:none\nmax_age:0") // bad version
209 f.Add("version:STSv10\nmode:none\nmax_age:0") // bad version
210 f.Add("version:STSv2\nmode:none\nmax_age:0") // bad version
211 f.Add("version:STSv1\nmax_age:0\nmx:example.com") // missing mode
212 f.Add("version:STSv1\nmode:none") // missing max_age
213 f.Add("version:STSv1\nmax_age:0\nmode:enforce") // missing mx for mode
214 f.Add("version:STSv1\nmax_age:0\nmode:testing") // missing mx for mode
215 f.Add("max_age:0\nmode:none") // missing version
216 f.Add("version:STSv1\nmode:none\nmax_age:0 ") // trailing whitespace
217 f.Add("version:STSv1\nmode:none\nmax_age:01234567890") // max_age too long
218 f.Add("version:STSv1\nmode:bad\nmax_age:1") // bad mode
219 f.Add("version:STSv1\nmode:none\nmax_age:a") // bad max_age
220 f.Add("version:STSv1\nmode:enforce\nmax_age:0\nmx:") // missing value
221 f.Add("version:STSv1\nmode:enforce\nmax_age:0\nmx:*.*.example") // bad mx
222 f.Add("version:STSv1\nmode:enforce\nmax_age:0\nmx:**.example") // bad mx
223 f.Add("version:STSv1\nmode:enforce\nmax_age:0\nmx:**.example-") // bad mx
224 f.Add("version:STSv1\nmode:enforce\nmax_age:0\nmx:test.example-") // bad mx
225 f.Add("version:STSv1\nmode:none\nmax_age:0\next:") // empty extension
226 f.Add("version:STSv1\nmode:none\nmax_age:0\next:abc ") // trailing space
227 f.Add("version:STSv1\nmode:none\nmax_age:0\next:a\t") // invalid char
228 f.Add("version:STSv1\nmode:none\nmax_age:0\na12345678901234567890123456789012:123") // long extension name
229 f.Add("version:STSv1\nmode:none\nmax_age:0\n_bad:test") // bad ext name
231 f.Fuzz(func(t *testing.T, s string) {
232 r, err := ParsePolicy(s)