Source file
src/net/netip/netip_pkg_test.go
1
2
3
4
5 package netip
6
7 import (
8 "bytes"
9 "encoding"
10 "encoding/json"
11 "strings"
12 "testing"
13 )
14
15 var (
16 mustPrefix = MustParsePrefix
17 mustIP = MustParseAddr
18 )
19
20 func TestPrefixValid(t *testing.T) {
21 v4 := MustParseAddr("1.2.3.4")
22 v6 := MustParseAddr("::1")
23 tests := []struct {
24 ipp Prefix
25 want bool
26 }{
27 {PrefixFrom(v4, -2), false},
28 {PrefixFrom(v4, -1), false},
29 {PrefixFrom(v4, 0), true},
30 {PrefixFrom(v4, 32), true},
31 {PrefixFrom(v4, 33), false},
32
33 {PrefixFrom(v6, -2), false},
34 {PrefixFrom(v6, -1), false},
35 {PrefixFrom(v6, 0), true},
36 {PrefixFrom(v6, 32), true},
37 {PrefixFrom(v6, 128), true},
38 {PrefixFrom(v6, 129), false},
39
40 {PrefixFrom(Addr{}, -2), false},
41 {PrefixFrom(Addr{}, -1), false},
42 {PrefixFrom(Addr{}, 0), false},
43 {PrefixFrom(Addr{}, 32), false},
44 {PrefixFrom(Addr{}, 128), false},
45 }
46 for _, tt := range tests {
47 got := tt.ipp.IsValid()
48 if got != tt.want {
49 t.Errorf("(%v).IsValid() = %v want %v", tt.ipp, got, tt.want)
50 }
51
52
53 invalid := PrefixFrom(tt.ipp.Addr(), -1)
54 if !got && tt.ipp != invalid {
55 t.Errorf("(%v == %v) = false, want true", tt.ipp, invalid)
56 }
57 }
58 }
59
60 var nextPrevTests = []struct {
61 ip Addr
62 next Addr
63 prev Addr
64 }{
65 {mustIP("10.0.0.1"), mustIP("10.0.0.2"), mustIP("10.0.0.0")},
66 {mustIP("10.0.0.255"), mustIP("10.0.1.0"), mustIP("10.0.0.254")},
67 {mustIP("127.0.0.1"), mustIP("127.0.0.2"), mustIP("127.0.0.0")},
68 {mustIP("254.255.255.255"), mustIP("255.0.0.0"), mustIP("254.255.255.254")},
69 {mustIP("255.255.255.255"), Addr{}, mustIP("255.255.255.254")},
70 {mustIP("0.0.0.0"), mustIP("0.0.0.1"), Addr{}},
71 {mustIP("::"), mustIP("::1"), Addr{}},
72 {mustIP("::%x"), mustIP("::1%x"), Addr{}},
73 {mustIP("::1"), mustIP("::2"), mustIP("::")},
74 {mustIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"), Addr{}, mustIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe")},
75 }
76
77 func TestIPNextPrev(t *testing.T) {
78 doNextPrev(t)
79
80 for _, ip := range []Addr{
81 mustIP("0.0.0.0"),
82 mustIP("::"),
83 } {
84 got := ip.Prev()
85 if !got.isZero() {
86 t.Errorf("IP(%v).Prev = %v; want zero", ip, got)
87 }
88 }
89
90 var allFF [16]byte
91 for i := range allFF {
92 allFF[i] = 0xff
93 }
94
95 for _, ip := range []Addr{
96 mustIP("255.255.255.255"),
97 AddrFrom16(allFF),
98 } {
99 got := ip.Next()
100 if !got.isZero() {
101 t.Errorf("IP(%v).Next = %v; want zero", ip, got)
102 }
103 }
104 }
105
106 func BenchmarkIPNextPrev(b *testing.B) {
107 for i := 0; i < b.N; i++ {
108 doNextPrev(b)
109 }
110 }
111
112 func doNextPrev(t testing.TB) {
113 for _, tt := range nextPrevTests {
114 gnext, gprev := tt.ip.Next(), tt.ip.Prev()
115 if gnext != tt.next {
116 t.Errorf("IP(%v).Next = %v; want %v", tt.ip, gnext, tt.next)
117 }
118 if gprev != tt.prev {
119 t.Errorf("IP(%v).Prev = %v; want %v", tt.ip, gprev, tt.prev)
120 }
121 if !tt.ip.Next().isZero() && tt.ip.Next().Prev() != tt.ip {
122 t.Errorf("IP(%v).Next.Prev = %v; want %v", tt.ip, tt.ip.Next().Prev(), tt.ip)
123 }
124 if !tt.ip.Prev().isZero() && tt.ip.Prev().Next() != tt.ip {
125 t.Errorf("IP(%v).Prev.Next = %v; want %v", tt.ip, tt.ip.Prev().Next(), tt.ip)
126 }
127 }
128 }
129
130 func TestIPBitLen(t *testing.T) {
131 tests := []struct {
132 ip Addr
133 want int
134 }{
135 {Addr{}, 0},
136 {mustIP("0.0.0.0"), 32},
137 {mustIP("10.0.0.1"), 32},
138 {mustIP("::"), 128},
139 {mustIP("fed0::1"), 128},
140 {mustIP("::ffff:10.0.0.1"), 128},
141 }
142 for _, tt := range tests {
143 got := tt.ip.BitLen()
144 if got != tt.want {
145 t.Errorf("BitLen(%v) = %d; want %d", tt.ip, got, tt.want)
146 }
147 }
148 }
149
150 func TestPrefixContains(t *testing.T) {
151 tests := []struct {
152 ipp Prefix
153 ip Addr
154 want bool
155 }{
156 {mustPrefix("9.8.7.6/0"), mustIP("9.8.7.6"), true},
157 {mustPrefix("9.8.7.6/16"), mustIP("9.8.7.6"), true},
158 {mustPrefix("9.8.7.6/16"), mustIP("9.8.6.4"), true},
159 {mustPrefix("9.8.7.6/16"), mustIP("9.9.7.6"), false},
160 {mustPrefix("9.8.7.6/32"), mustIP("9.8.7.6"), true},
161 {mustPrefix("9.8.7.6/32"), mustIP("9.8.7.7"), false},
162 {mustPrefix("9.8.7.6/32"), mustIP("9.8.7.7"), false},
163 {mustPrefix("::1/0"), mustIP("::1"), true},
164 {mustPrefix("::1/0"), mustIP("::2"), true},
165 {mustPrefix("::1/127"), mustIP("::1"), true},
166 {mustPrefix("::1/127"), mustIP("::2"), false},
167 {mustPrefix("::1/128"), mustIP("::1"), true},
168 {mustPrefix("::1/127"), mustIP("::2"), false},
169
170 {Prefix{mustIP("1.2.3.4").WithZone("a"), 32}, mustIP("1.2.3.4"), true},
171 {Prefix{mustIP("::1").WithZone("a"), 128}, mustIP("::1"), true},
172
173 {mustPrefix("::1/0"), Addr{}, false},
174 {mustPrefix("1.2.3.4/0"), Addr{}, false},
175
176 {PrefixFrom(mustIP("::1"), 129), mustIP("::1"), false},
177 {PrefixFrom(mustIP("1.2.3.4"), 33), mustIP("1.2.3.4"), false},
178 {PrefixFrom(Addr{}, 0), mustIP("1.2.3.4"), false},
179 {PrefixFrom(Addr{}, 32), mustIP("1.2.3.4"), false},
180 {PrefixFrom(Addr{}, 128), mustIP("::1"), false},
181
182 {mustPrefix("::1/0"), mustIP("1.2.3.4"), false},
183 {mustPrefix("1.2.3.4/0"), mustIP("::1"), false},
184 }
185 for _, tt := range tests {
186 got := tt.ipp.Contains(tt.ip)
187 if got != tt.want {
188 t.Errorf("(%v).Contains(%v) = %v want %v", tt.ipp, tt.ip, got, tt.want)
189 }
190 }
191 }
192
193 func TestParseIPError(t *testing.T) {
194 tests := []struct {
195 ip string
196 errstr string
197 }{
198 {
199 ip: "localhost",
200 },
201 {
202 ip: "500.0.0.1",
203 errstr: "field has value >255",
204 },
205 {
206 ip: "::gggg%eth0",
207 errstr: "must have at least one digit",
208 },
209 {
210 ip: "fe80::1cc0:3e8c:119f:c2e1%",
211 errstr: "zone must be a non-empty string",
212 },
213 {
214 ip: "%eth0",
215 errstr: "missing IPv6 address",
216 },
217 }
218 for _, test := range tests {
219 t.Run(test.ip, func(t *testing.T) {
220 _, err := ParseAddr(test.ip)
221 if err == nil {
222 t.Fatal("no error")
223 }
224 if _, ok := err.(parseAddrError); !ok {
225 t.Errorf("error type is %T, want parseIPError", err)
226 }
227 if test.errstr == "" {
228 test.errstr = "unable to parse IP"
229 }
230 if got := err.Error(); !strings.Contains(got, test.errstr) {
231 t.Errorf("error is missing substring %q: %s", test.errstr, got)
232 }
233 })
234 }
235 }
236
237 func TestParseAddrPort(t *testing.T) {
238 tests := []struct {
239 in string
240 want AddrPort
241 wantErr bool
242 }{
243 {in: "1.2.3.4:1234", want: AddrPort{mustIP("1.2.3.4"), 1234}},
244 {in: "1.1.1.1:123456", wantErr: true},
245 {in: "1.1.1.1:-123", wantErr: true},
246 {in: "[::1]:1234", want: AddrPort{mustIP("::1"), 1234}},
247 {in: "[1.2.3.4]:1234", wantErr: true},
248 {in: "fe80::1:1234", wantErr: true},
249 {in: ":0", wantErr: true},
250 }
251 for _, test := range tests {
252 t.Run(test.in, func(t *testing.T) {
253 got, err := ParseAddrPort(test.in)
254 if err != nil {
255 if test.wantErr {
256 return
257 }
258 t.Fatal(err)
259 }
260 if got != test.want {
261 t.Errorf("got %v; want %v", got, test.want)
262 }
263 if got.String() != test.in {
264 t.Errorf("String = %q; want %q", got.String(), test.in)
265 }
266 })
267
268 t.Run(test.in+"/AppendTo", func(t *testing.T) {
269 got, err := ParseAddrPort(test.in)
270 if err == nil {
271 testAppendToMarshal(t, got)
272 }
273 })
274
275
276
277
278 t.Run(test.in+"/Marshal", func(t *testing.T) {
279 var got AddrPort
280 jsin := `"` + test.in + `"`
281 err := json.Unmarshal([]byte(jsin), &got)
282 if err != nil {
283 if test.wantErr {
284 return
285 }
286 t.Fatal(err)
287 }
288 if got != test.want {
289 t.Errorf("got %v; want %v", got, test.want)
290 }
291 gotb, err := json.Marshal(got)
292 if err != nil {
293 t.Fatal(err)
294 }
295 if string(gotb) != jsin {
296 t.Errorf("Marshal = %q; want %q", string(gotb), jsin)
297 }
298 })
299 }
300 }
301
302 func TestAddrPortMarshalUnmarshal(t *testing.T) {
303 tests := []struct {
304 in string
305 want AddrPort
306 }{
307 {"", AddrPort{}},
308 }
309
310 for _, test := range tests {
311 t.Run(test.in, func(t *testing.T) {
312 orig := `"` + test.in + `"`
313
314 var ipp AddrPort
315 if err := json.Unmarshal([]byte(orig), &ipp); err != nil {
316 t.Fatalf("failed to unmarshal: %v", err)
317 }
318
319 ippb, err := json.Marshal(ipp)
320 if err != nil {
321 t.Fatalf("failed to marshal: %v", err)
322 }
323
324 back := string(ippb)
325 if orig != back {
326 t.Errorf("Marshal = %q; want %q", back, orig)
327 }
328
329 testAppendToMarshal(t, ipp)
330 })
331 }
332 }
333
334 type appendMarshaler interface {
335 encoding.TextMarshaler
336 AppendTo([]byte) []byte
337 }
338
339
340
341 func testAppendToMarshal(t *testing.T, x appendMarshaler) {
342 t.Helper()
343 m, err := x.MarshalText()
344 if err != nil {
345 t.Fatalf("(%v).MarshalText: %v", x, err)
346 }
347 a := make([]byte, 0, len(m))
348 a = x.AppendTo(a)
349 if !bytes.Equal(m, a) {
350 t.Errorf("(%v).MarshalText = %q, (%v).AppendTo = %q", x, m, x, a)
351 }
352 }
353
354 func TestIPv6Accessor(t *testing.T) {
355 var a [16]byte
356 for i := range a {
357 a[i] = uint8(i) + 1
358 }
359 ip := AddrFrom16(a)
360 for i := range a {
361 if got, want := ip.v6(uint8(i)), uint8(i)+1; got != want {
362 t.Errorf("v6(%v) = %v; want %v", i, got, want)
363 }
364 }
365 }
366
View as plain text