Source file
src/net/netip/netip_test.go
1
2
3
4
5 package netip_test
6
7 import (
8 "bytes"
9 "encoding/json"
10 "flag"
11 "fmt"
12 "internal/intern"
13 "internal/testenv"
14 "net"
15 . "net/netip"
16 "reflect"
17 "slices"
18 "sort"
19 "strings"
20 "testing"
21 )
22
23 var long = flag.Bool("long", false, "run long tests")
24
25 type uint128 = Uint128
26
27 var (
28 mustPrefix = MustParsePrefix
29 mustIP = MustParseAddr
30 mustIPPort = MustParseAddrPort
31 )
32
33 func TestParseAddr(t *testing.T) {
34 var validIPs = []struct {
35 in string
36 ip Addr
37 str string
38 wantErr string
39 }{
40
41 {
42 in: "0.0.0.0",
43 ip: MkAddr(Mk128(0, 0xffff00000000), Z4),
44 },
45
46 {
47 in: "192.168.140.255",
48 ip: MkAddr(Mk128(0, 0xffffc0a88cff), Z4),
49 },
50
51 {
52 in: "010.000.015.001",
53 wantErr: `ParseAddr("010.000.015.001"): IPv4 field has octet with leading zero`,
54 },
55
56 {
57 in: "000001.00000002.00000003.000000004",
58 wantErr: `ParseAddr("000001.00000002.00000003.000000004"): IPv4 field has octet with leading zero`,
59 },
60
61 {
62 in: "::ffff:1.2.03.4",
63 wantErr: `ParseAddr("::ffff:1.2.03.4"): ParseAddr("1.2.03.4"): IPv4 field has octet with leading zero (at "1.2.03.4")`,
64 },
65
66 {
67 in: "::",
68 ip: MkAddr(Mk128(0, 0), Z6noz),
69 },
70
71 {
72 in: "::1",
73 ip: MkAddr(Mk128(0, 1), Z6noz),
74 },
75
76 {
77 in: "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b",
78 ip: MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd96626b430b), Z6noz),
79 },
80
81 {
82 in: "fd7a:115c::626b:430b",
83 ip: MkAddr(Mk128(0xfd7a115c00000000, 0x00000000626b430b), Z6noz),
84 },
85
86 {
87 in: "fd7a:115c:a1e0:ab12:4843:cd96::",
88 ip: MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd9600000000), Z6noz),
89 },
90
91 {
92 in: "fd7a:115c:a1e0:ab12:4843:cd96:626b::",
93 ip: MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd96626b0000), Z6noz),
94 str: "fd7a:115c:a1e0:ab12:4843:cd96:626b:0",
95 },
96
97 {
98 in: "fd7a:115c:a1e0::4843:cd96:626b:430b",
99 ip: MkAddr(Mk128(0xfd7a115ca1e00000, 0x4843cd96626b430b), Z6noz),
100 str: "fd7a:115c:a1e0:0:4843:cd96:626b:430b",
101 },
102
103 {
104 in: "::ffff:192.168.140.255",
105 ip: MkAddr(Mk128(0, 0x0000ffffc0a88cff), Z6noz),
106 str: "::ffff:192.168.140.255",
107 },
108
109 {
110 in: "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b%eth0",
111 ip: MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd96626b430b), intern.Get("eth0")),
112 },
113
114 {
115 in: "1:2::ffff:192.168.140.255%eth1",
116 ip: MkAddr(Mk128(0x0001000200000000, 0x0000ffffc0a88cff), intern.Get("eth1")),
117 str: "1:2::ffff:c0a8:8cff%eth1",
118 },
119
120 {
121 in: "::ffff:192.168.140.255%eth1",
122 ip: MkAddr(Mk128(0, 0x0000ffffc0a88cff), intern.Get("eth1")),
123 str: "::ffff:192.168.140.255%eth1",
124 },
125
126 {
127 in: "FD9E:1A04:F01D::1",
128 ip: MkAddr(Mk128(0xfd9e1a04f01d0000, 0x1), Z6noz),
129 str: "fd9e:1a04:f01d::1",
130 },
131 }
132
133 for _, test := range validIPs {
134 t.Run(test.in, func(t *testing.T) {
135 got, err := ParseAddr(test.in)
136 if err != nil {
137 if err.Error() == test.wantErr {
138 return
139 }
140 t.Fatal(err)
141 }
142 if test.wantErr != "" {
143 t.Fatalf("wanted error %q; got none", test.wantErr)
144 }
145 if got != test.ip {
146 t.Errorf("got %#v, want %#v", got, test.ip)
147 }
148
149
150 got2, err := ParseAddr(test.in)
151 if err != nil {
152 t.Fatal(err)
153 }
154 if got != got2 {
155 t.Errorf("ParseAddr(%q) got 2 different results: %#v, %#v", test.in, got, got2)
156 }
157
158
159 s := got.String()
160 got3, err := ParseAddr(s)
161 if err != nil {
162 t.Fatal(err)
163 }
164 if got != got3 {
165 t.Errorf("ParseAddr(%q) != ParseAddr(ParseIP(%q).String()). Got %#v, want %#v", test.in, test.in, got3, got)
166 }
167
168
169 slow, err := parseIPSlow(test.in)
170 if err != nil {
171 t.Fatal(err)
172 }
173 if got != slow {
174 t.Errorf("ParseAddr(%q) = %#v, parseIPSlow(%q) = %#v", test.in, got, test.in, slow)
175 }
176
177
178 s = got.String()
179 wants := test.str
180 if wants == "" {
181 wants = test.in
182 }
183 if s != wants {
184 t.Errorf("ParseAddr(%q).String() got %q, want %q", test.in, s, wants)
185 }
186
187
188 TestAppendToMarshal(t, got)
189
190
191
192
193
194 js := `"` + test.in + `"`
195 var jsgot Addr
196 if err := json.Unmarshal([]byte(js), &jsgot); err != nil {
197 t.Fatal(err)
198 }
199 if jsgot != got {
200 t.Errorf("json.Unmarshal(%q) = %#v, want %#v", test.in, jsgot, got)
201 }
202 jsb, err := json.Marshal(jsgot)
203 if err != nil {
204 t.Fatal(err)
205 }
206 jswant := `"` + wants + `"`
207 jsback := string(jsb)
208 if jsback != jswant {
209 t.Errorf("Marshal(Unmarshal(%q)) = %s, want %s", test.in, jsback, jswant)
210 }
211 })
212 }
213
214 var invalidIPs = []string{
215
216 "",
217
218 "bad",
219
220
221 "1234",
222
223 "1.2.3.4%eth0",
224
225 ".1.2.3",
226 "1.2.3.",
227 "1..2.3",
228
229 "1.2.3.4.5",
230
231 "0300.0250.0214.0377",
232
233 "0xc0.0xa8.0x8c.0xff",
234
235 "192.168.12345",
236
237
238 "127.0.1",
239
240 "192.1234567",
241
242
243 "127.1",
244
245 "192.168.300.1",
246
247 "192.168.0.1.5.6",
248
249 "1:2:3:4:5:6:7",
250
251 "1:2:3:4:5:6:7:8:9",
252
253 "1:2:3:4::5:6:7:8",
254
255 "fe801::1",
256
257 "fe80:tail:scal:e::",
258
259 "fe80::1%",
260
261 "ffff:ffff:ffff:ffff:ffff:ffff:ffff:192.168.140.255",
262
263 "ffff::ffff:ffff:ffff:ffff:ffff:ffff:192.168.140.255",
264
265 "::ffff:192.168.140.bad",
266
267 "fe80::1::1",
268
269 "fe80:1?:1",
270
271 "fe80:",
272 }
273
274 for _, s := range invalidIPs {
275 t.Run(s, func(t *testing.T) {
276 got, err := ParseAddr(s)
277 if err == nil {
278 t.Errorf("ParseAddr(%q) = %#v, want error", s, got)
279 }
280
281 slow, err := parseIPSlow(s)
282 if err == nil {
283 t.Errorf("parseIPSlow(%q) = %#v, want error", s, slow)
284 }
285
286 std := net.ParseIP(s)
287 if std != nil {
288 t.Errorf("net.ParseIP(%q) = %#v, want error", s, std)
289 }
290
291 if s == "" {
292
293
294 return
295 }
296 var jsgot Addr
297 js := []byte(`"` + s + `"`)
298 if err := json.Unmarshal(js, &jsgot); err == nil {
299 t.Errorf("json.Unmarshal(%q) = %#v, want error", s, jsgot)
300 }
301 })
302 }
303 }
304
305 func TestAddrFromSlice(t *testing.T) {
306 tests := []struct {
307 ip []byte
308 wantAddr Addr
309 wantOK bool
310 }{
311 {
312 ip: []byte{10, 0, 0, 1},
313 wantAddr: mustIP("10.0.0.1"),
314 wantOK: true,
315 },
316 {
317 ip: []byte{0xfe, 0x80, 15: 0x01},
318 wantAddr: mustIP("fe80::01"),
319 wantOK: true,
320 },
321 {
322 ip: []byte{0, 1, 2},
323 wantAddr: Addr{},
324 wantOK: false,
325 },
326 {
327 ip: nil,
328 wantAddr: Addr{},
329 wantOK: false,
330 },
331 }
332 for _, tt := range tests {
333 addr, ok := AddrFromSlice(tt.ip)
334 if ok != tt.wantOK || addr != tt.wantAddr {
335 t.Errorf("AddrFromSlice(%#v) = %#v, %v, want %#v, %v", tt.ip, addr, ok, tt.wantAddr, tt.wantOK)
336 }
337 }
338 }
339
340 func TestIPv4Constructors(t *testing.T) {
341 if AddrFrom4([4]byte{1, 2, 3, 4}) != MustParseAddr("1.2.3.4") {
342 t.Errorf("don't match")
343 }
344 }
345
346 func TestAddrMarshalUnmarshalBinary(t *testing.T) {
347 tests := []struct {
348 ip string
349 wantSize int
350 }{
351 {"", 0},
352 {"1.2.3.4", 4},
353 {"fd7a:115c:a1e0:ab12:4843:cd96:626b:430b", 16},
354 {"::ffff:c000:0280", 16},
355 {"::ffff:c000:0280%eth0", 20},
356 }
357 for _, tc := range tests {
358 var ip Addr
359 if len(tc.ip) > 0 {
360 ip = mustIP(tc.ip)
361 }
362 b, err := ip.MarshalBinary()
363 if err != nil {
364 t.Fatal(err)
365 }
366 if len(b) != tc.wantSize {
367 t.Fatalf("%q encoded to size %d; want %d", tc.ip, len(b), tc.wantSize)
368 }
369 var ip2 Addr
370 if err := ip2.UnmarshalBinary(b); err != nil {
371 t.Fatal(err)
372 }
373 if ip != ip2 {
374 t.Fatalf("got %v; want %v", ip2, ip)
375 }
376 }
377
378
379 for _, n := range []int{3, 5} {
380 var ip2 Addr
381 if err := ip2.UnmarshalBinary(bytes.Repeat([]byte{1}, n)); err == nil {
382 t.Fatalf("unmarshaled from unexpected IP length %d", n)
383 }
384 }
385 }
386
387 func TestAddrPortMarshalTextString(t *testing.T) {
388 tests := []struct {
389 in AddrPort
390 want string
391 }{
392 {mustIPPort("1.2.3.4:80"), "1.2.3.4:80"},
393 {mustIPPort("[::]:80"), "[::]:80"},
394 {mustIPPort("[1::CAFE]:80"), "[1::cafe]:80"},
395 {mustIPPort("[1::CAFE%en0]:80"), "[1::cafe%en0]:80"},
396 {mustIPPort("[::FFFF:192.168.140.255]:80"), "[::ffff:192.168.140.255]:80"},
397 {mustIPPort("[::FFFF:192.168.140.255%en0]:80"), "[::ffff:192.168.140.255%en0]:80"},
398 }
399 for i, tt := range tests {
400 if got := tt.in.String(); got != tt.want {
401 t.Errorf("%d. for (%v, %v) String = %q; want %q", i, tt.in.Addr(), tt.in.Port(), got, tt.want)
402 }
403 mt, err := tt.in.MarshalText()
404 if err != nil {
405 t.Errorf("%d. for (%v, %v) MarshalText error: %v", i, tt.in.Addr(), tt.in.Port(), err)
406 continue
407 }
408 if string(mt) != tt.want {
409 t.Errorf("%d. for (%v, %v) MarshalText = %q; want %q", i, tt.in.Addr(), tt.in.Port(), mt, tt.want)
410 }
411 }
412 }
413
414 func TestAddrPortMarshalUnmarshalBinary(t *testing.T) {
415 tests := []struct {
416 ipport string
417 wantSize int
418 }{
419 {"1.2.3.4:51820", 4 + 2},
420 {"[fd7a:115c:a1e0:ab12:4843:cd96:626b:430b]:80", 16 + 2},
421 {"[::ffff:c000:0280]:65535", 16 + 2},
422 {"[::ffff:c000:0280%eth0]:1", 20 + 2},
423 }
424 for _, tc := range tests {
425 var ipport AddrPort
426 if len(tc.ipport) > 0 {
427 ipport = mustIPPort(tc.ipport)
428 }
429 b, err := ipport.MarshalBinary()
430 if err != nil {
431 t.Fatal(err)
432 }
433 if len(b) != tc.wantSize {
434 t.Fatalf("%q encoded to size %d; want %d", tc.ipport, len(b), tc.wantSize)
435 }
436 var ipport2 AddrPort
437 if err := ipport2.UnmarshalBinary(b); err != nil {
438 t.Fatal(err)
439 }
440 if ipport != ipport2 {
441 t.Fatalf("got %v; want %v", ipport2, ipport)
442 }
443 }
444
445
446 for _, n := range []int{3, 7} {
447 var ipport2 AddrPort
448 if err := ipport2.UnmarshalBinary(bytes.Repeat([]byte{1}, n)); err == nil {
449 t.Fatalf("unmarshaled from unexpected length %d", n)
450 }
451 }
452 }
453
454 func TestPrefixMarshalTextString(t *testing.T) {
455 tests := []struct {
456 in Prefix
457 want string
458 }{
459 {mustPrefix("1.2.3.4/24"), "1.2.3.4/24"},
460 {mustPrefix("fd7a:115c:a1e0:ab12:4843:cd96:626b:430b/118"), "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b/118"},
461 {mustPrefix("::ffff:c000:0280/96"), "::ffff:192.0.2.128/96"},
462 {mustPrefix("::ffff:192.168.140.255/8"), "::ffff:192.168.140.255/8"},
463 {PrefixFrom(mustIP("::ffff:c000:0280").WithZone("eth0"), 37), "::ffff:192.0.2.128/37"},
464 }
465 for i, tt := range tests {
466 if got := tt.in.String(); got != tt.want {
467 t.Errorf("%d. for %v String = %q; want %q", i, tt.in, got, tt.want)
468 }
469 mt, err := tt.in.MarshalText()
470 if err != nil {
471 t.Errorf("%d. for %v MarshalText error: %v", i, tt.in, err)
472 continue
473 }
474 if string(mt) != tt.want {
475 t.Errorf("%d. for %v MarshalText = %q; want %q", i, tt.in, mt, tt.want)
476 }
477 }
478 }
479
480 func TestPrefixMarshalUnmarshalBinary(t *testing.T) {
481 type testCase struct {
482 prefix Prefix
483 wantSize int
484 }
485 tests := []testCase{
486 {mustPrefix("1.2.3.4/24"), 4 + 1},
487 {mustPrefix("fd7a:115c:a1e0:ab12:4843:cd96:626b:430b/118"), 16 + 1},
488 {mustPrefix("::ffff:c000:0280/96"), 16 + 1},
489 {PrefixFrom(mustIP("::ffff:c000:0280").WithZone("eth0"), 37), 16 + 1},
490 }
491 tests = append(tests,
492 testCase{PrefixFrom(tests[0].prefix.Addr(), 33), tests[0].wantSize},
493 testCase{PrefixFrom(tests[1].prefix.Addr(), 129), tests[1].wantSize})
494 for _, tc := range tests {
495 prefix := tc.prefix
496 b, err := prefix.MarshalBinary()
497 if err != nil {
498 t.Fatal(err)
499 }
500 if len(b) != tc.wantSize {
501 t.Fatalf("%q encoded to size %d; want %d", tc.prefix, len(b), tc.wantSize)
502 }
503 var prefix2 Prefix
504 if err := prefix2.UnmarshalBinary(b); err != nil {
505 t.Fatal(err)
506 }
507 if prefix != prefix2 {
508 t.Fatalf("got %v; want %v", prefix2, prefix)
509 }
510 }
511
512
513 for _, n := range []int{3, 6} {
514 var prefix2 Prefix
515 if err := prefix2.UnmarshalBinary(bytes.Repeat([]byte{1}, n)); err == nil {
516 t.Fatalf("unmarshaled from unexpected length %d", n)
517 }
518 }
519 }
520
521 func TestAddrMarshalUnmarshal(t *testing.T) {
522
523
524
525 orig := `""`
526 var ip Addr
527 if err := json.Unmarshal([]byte(orig), &ip); err != nil {
528 t.Fatalf("Unmarshal(%q) got error %v", orig, err)
529 }
530 if ip != (Addr{}) {
531 t.Errorf("Unmarshal(%q) is not the zero Addr", orig)
532 }
533
534 jsb, err := json.Marshal(ip)
535 if err != nil {
536 t.Fatalf("Marshal(%v) got error %v", ip, err)
537 }
538 back := string(jsb)
539 if back != orig {
540 t.Errorf("Marshal(Unmarshal(%q)) got %q, want %q", orig, back, orig)
541 }
542 }
543
544 func TestAddrFrom16(t *testing.T) {
545 tests := []struct {
546 name string
547 in [16]byte
548 want Addr
549 }{
550 {
551 name: "v6-raw",
552 in: [...]byte{15: 1},
553 want: MkAddr(Mk128(0, 1), Z6noz),
554 },
555 {
556 name: "v4-raw",
557 in: [...]byte{10: 0xff, 11: 0xff, 12: 1, 13: 2, 14: 3, 15: 4},
558 want: MkAddr(Mk128(0, 0xffff01020304), Z6noz),
559 },
560 }
561 for _, tt := range tests {
562 t.Run(tt.name, func(t *testing.T) {
563 got := AddrFrom16(tt.in)
564 if got != tt.want {
565 t.Errorf("got %#v; want %#v", got, tt.want)
566 }
567 })
568 }
569 }
570
571 func TestIPProperties(t *testing.T) {
572 var (
573 nilIP Addr
574
575 unicast4 = mustIP("192.0.2.1")
576 unicast6 = mustIP("2001:db8::1")
577 unicastZone6 = mustIP("2001:db8::1%eth0")
578 unicast6Unassigned = mustIP("4000::1")
579
580 multicast4 = mustIP("224.0.0.1")
581 multicast6 = mustIP("ff02::1")
582 multicastZone6 = mustIP("ff02::1%eth0")
583
584 llu4 = mustIP("169.254.0.1")
585 llu6 = mustIP("fe80::1")
586 llu6Last = mustIP("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
587 lluZone6 = mustIP("fe80::1%eth0")
588
589 loopback4 = mustIP("127.0.0.1")
590
591 ilm6 = mustIP("ff01::1")
592 ilmZone6 = mustIP("ff01::1%eth0")
593
594 private4a = mustIP("10.0.0.1")
595 private4b = mustIP("172.16.0.1")
596 private4c = mustIP("192.168.1.1")
597 private6 = mustIP("fd00::1")
598 )
599
600 tests := []struct {
601 name string
602 ip Addr
603 globalUnicast bool
604 interfaceLocalMulticast bool
605 linkLocalMulticast bool
606 linkLocalUnicast bool
607 loopback bool
608 multicast bool
609 private bool
610 unspecified bool
611 }{
612 {
613 name: "nil",
614 ip: nilIP,
615 },
616 {
617 name: "unicast v4Addr",
618 ip: unicast4,
619 globalUnicast: true,
620 },
621 {
622 name: "unicast v6Addr",
623 ip: unicast6,
624 globalUnicast: true,
625 },
626 {
627 name: "unicast v6AddrZone",
628 ip: unicastZone6,
629 globalUnicast: true,
630 },
631 {
632 name: "unicast v6Addr unassigned",
633 ip: unicast6Unassigned,
634 globalUnicast: true,
635 },
636 {
637 name: "multicast v4Addr",
638 ip: multicast4,
639 linkLocalMulticast: true,
640 multicast: true,
641 },
642 {
643 name: "multicast v6Addr",
644 ip: multicast6,
645 linkLocalMulticast: true,
646 multicast: true,
647 },
648 {
649 name: "multicast v6AddrZone",
650 ip: multicastZone6,
651 linkLocalMulticast: true,
652 multicast: true,
653 },
654 {
655 name: "link-local unicast v4Addr",
656 ip: llu4,
657 linkLocalUnicast: true,
658 },
659 {
660 name: "link-local unicast v6Addr",
661 ip: llu6,
662 linkLocalUnicast: true,
663 },
664 {
665 name: "link-local unicast v6Addr upper bound",
666 ip: llu6Last,
667 linkLocalUnicast: true,
668 },
669 {
670 name: "link-local unicast v6AddrZone",
671 ip: lluZone6,
672 linkLocalUnicast: true,
673 },
674 {
675 name: "loopback v4Addr",
676 ip: loopback4,
677 loopback: true,
678 },
679 {
680 name: "loopback v6Addr",
681 ip: IPv6Loopback(),
682 loopback: true,
683 },
684 {
685 name: "interface-local multicast v6Addr",
686 ip: ilm6,
687 interfaceLocalMulticast: true,
688 multicast: true,
689 },
690 {
691 name: "interface-local multicast v6AddrZone",
692 ip: ilmZone6,
693 interfaceLocalMulticast: true,
694 multicast: true,
695 },
696 {
697 name: "private v4Addr 10/8",
698 ip: private4a,
699 globalUnicast: true,
700 private: true,
701 },
702 {
703 name: "private v4Addr 172.16/12",
704 ip: private4b,
705 globalUnicast: true,
706 private: true,
707 },
708 {
709 name: "private v4Addr 192.168/16",
710 ip: private4c,
711 globalUnicast: true,
712 private: true,
713 },
714 {
715 name: "private v6Addr",
716 ip: private6,
717 globalUnicast: true,
718 private: true,
719 },
720 {
721 name: "unspecified v4Addr",
722 ip: IPv4Unspecified(),
723 unspecified: true,
724 },
725 {
726 name: "unspecified v6Addr",
727 ip: IPv6Unspecified(),
728 unspecified: true,
729 },
730 }
731
732 for _, tt := range tests {
733 t.Run(tt.name, func(t *testing.T) {
734 gu := tt.ip.IsGlobalUnicast()
735 if gu != tt.globalUnicast {
736 t.Errorf("IsGlobalUnicast(%v) = %v; want %v", tt.ip, gu, tt.globalUnicast)
737 }
738
739 ilm := tt.ip.IsInterfaceLocalMulticast()
740 if ilm != tt.interfaceLocalMulticast {
741 t.Errorf("IsInterfaceLocalMulticast(%v) = %v; want %v", tt.ip, ilm, tt.interfaceLocalMulticast)
742 }
743
744 llu := tt.ip.IsLinkLocalUnicast()
745 if llu != tt.linkLocalUnicast {
746 t.Errorf("IsLinkLocalUnicast(%v) = %v; want %v", tt.ip, llu, tt.linkLocalUnicast)
747 }
748
749 llm := tt.ip.IsLinkLocalMulticast()
750 if llm != tt.linkLocalMulticast {
751 t.Errorf("IsLinkLocalMulticast(%v) = %v; want %v", tt.ip, llm, tt.linkLocalMulticast)
752 }
753
754 lo := tt.ip.IsLoopback()
755 if lo != tt.loopback {
756 t.Errorf("IsLoopback(%v) = %v; want %v", tt.ip, lo, tt.loopback)
757 }
758
759 multicast := tt.ip.IsMulticast()
760 if multicast != tt.multicast {
761 t.Errorf("IsMulticast(%v) = %v; want %v", tt.ip, multicast, tt.multicast)
762 }
763
764 private := tt.ip.IsPrivate()
765 if private != tt.private {
766 t.Errorf("IsPrivate(%v) = %v; want %v", tt.ip, private, tt.private)
767 }
768
769 unspecified := tt.ip.IsUnspecified()
770 if unspecified != tt.unspecified {
771 t.Errorf("IsUnspecified(%v) = %v; want %v", tt.ip, unspecified, tt.unspecified)
772 }
773 })
774 }
775 }
776
777 func TestAddrWellKnown(t *testing.T) {
778 tests := []struct {
779 name string
780 ip Addr
781 std net.IP
782 }{
783 {
784 name: "IPv6 link-local all nodes",
785 ip: IPv6LinkLocalAllNodes(),
786 std: net.IPv6linklocalallnodes,
787 },
788 {
789 name: "IPv6 link-local all routers",
790 ip: IPv6LinkLocalAllRouters(),
791 std: net.IPv6linklocalallrouters,
792 },
793 {
794 name: "IPv6 loopback",
795 ip: IPv6Loopback(),
796 std: net.IPv6loopback,
797 },
798 {
799 name: "IPv6 unspecified",
800 ip: IPv6Unspecified(),
801 std: net.IPv6unspecified,
802 },
803 }
804
805 for _, tt := range tests {
806 t.Run(tt.name, func(t *testing.T) {
807 want := tt.std.String()
808 got := tt.ip.String()
809
810 if got != want {
811 t.Fatalf("got %s, want %s", got, want)
812 }
813 })
814 }
815 }
816
817 func TestAddrLessCompare(t *testing.T) {
818 tests := []struct {
819 a, b Addr
820 want bool
821 }{
822 {Addr{}, Addr{}, false},
823 {Addr{}, mustIP("1.2.3.4"), true},
824 {mustIP("1.2.3.4"), Addr{}, false},
825
826 {mustIP("1.2.3.4"), mustIP("0102:0304::0"), true},
827 {mustIP("0102:0304::0"), mustIP("1.2.3.4"), false},
828 {mustIP("1.2.3.4"), mustIP("1.2.3.4"), false},
829
830 {mustIP("::1"), mustIP("::2"), true},
831 {mustIP("::1"), mustIP("::1%foo"), true},
832 {mustIP("::1%foo"), mustIP("::2"), true},
833 {mustIP("::2"), mustIP("::3"), true},
834
835 {mustIP("::"), mustIP("0.0.0.0"), false},
836 {mustIP("0.0.0.0"), mustIP("::"), true},
837
838 {mustIP("::1%a"), mustIP("::1%b"), true},
839 {mustIP("::1%a"), mustIP("::1%a"), false},
840 {mustIP("::1%b"), mustIP("::1%a"), false},
841 }
842 for _, tt := range tests {
843 got := tt.a.Less(tt.b)
844 if got != tt.want {
845 t.Errorf("Less(%q, %q) = %v; want %v", tt.a, tt.b, got, tt.want)
846 }
847 cmp := tt.a.Compare(tt.b)
848 if got && cmp != -1 {
849 t.Errorf("Less(%q, %q) = true, but Compare = %v (not -1)", tt.a, tt.b, cmp)
850 }
851 if cmp < -1 || cmp > 1 {
852 t.Errorf("bogus Compare return value %v", cmp)
853 }
854 if cmp == 0 && tt.a != tt.b {
855 t.Errorf("Compare(%q, %q) = 0; but not equal", tt.a, tt.b)
856 }
857 if cmp == 1 && !tt.b.Less(tt.a) {
858 t.Errorf("Compare(%q, %q) = 1; but b.Less(a) isn't true", tt.a, tt.b)
859 }
860
861
862 if got == tt.want && got {
863 got2 := tt.b.Less(tt.a)
864 if got2 {
865 t.Errorf("Less(%q, %q) was correctly %v, but so was Less(%q, %q)", tt.a, tt.b, got, tt.b, tt.a)
866 }
867 }
868 }
869
870
871 values := []Addr{
872 mustIP("::1"),
873 mustIP("::2"),
874 Addr{},
875 mustIP("1.2.3.4"),
876 mustIP("8.8.8.8"),
877 mustIP("::1%foo"),
878 }
879 sort.Slice(values, func(i, j int) bool { return values[i].Less(values[j]) })
880 got := fmt.Sprintf("%s", values)
881 want := `[invalid IP 1.2.3.4 8.8.8.8 ::1 ::1%foo ::2]`
882 if got != want {
883 t.Errorf("unexpected sort\n got: %s\nwant: %s\n", got, want)
884 }
885 }
886
887 func TestAddrPortCompare(t *testing.T) {
888 tests := []struct {
889 a, b AddrPort
890 want int
891 }{
892 {AddrPort{}, AddrPort{}, 0},
893 {AddrPort{}, mustIPPort("1.2.3.4:80"), -1},
894
895 {mustIPPort("1.2.3.4:80"), mustIPPort("1.2.3.4:80"), 0},
896 {mustIPPort("[::1]:80"), mustIPPort("[::1]:80"), 0},
897
898 {mustIPPort("1.2.3.4:80"), mustIPPort("2.3.4.5:22"), -1},
899 {mustIPPort("[::1]:80"), mustIPPort("[::2]:22"), -1},
900
901 {mustIPPort("1.2.3.4:80"), mustIPPort("1.2.3.4:443"), -1},
902 {mustIPPort("[::1]:80"), mustIPPort("[::1]:443"), -1},
903
904 {mustIPPort("1.2.3.4:80"), mustIPPort("[0102:0304::0]:80"), -1},
905 }
906 for _, tt := range tests {
907 got := tt.a.Compare(tt.b)
908 if got != tt.want {
909 t.Errorf("Compare(%q, %q) = %v; want %v", tt.a, tt.b, got, tt.want)
910 }
911
912
913 if got == tt.want {
914 got2 := tt.b.Compare(tt.a)
915 if want2 := -1 * tt.want; got2 != want2 {
916 t.Errorf("Compare(%q, %q) was correctly %v, but Compare(%q, %q) was %v", tt.a, tt.b, got, tt.b, tt.a, got2)
917 }
918 }
919 }
920
921
922 values := []AddrPort{
923 mustIPPort("[::1]:80"),
924 mustIPPort("[::2]:80"),
925 AddrPort{},
926 mustIPPort("1.2.3.4:443"),
927 mustIPPort("8.8.8.8:8080"),
928 mustIPPort("[::1%foo]:1024"),
929 }
930 slices.SortFunc(values, func(a, b AddrPort) int { return a.Compare(b) })
931 got := fmt.Sprintf("%s", values)
932 want := `[invalid AddrPort 1.2.3.4:443 8.8.8.8:8080 [::1]:80 [::1%foo]:1024 [::2]:80]`
933 if got != want {
934 t.Errorf("unexpected sort\n got: %s\nwant: %s\n", got, want)
935 }
936 }
937
938 func TestPrefixCompare(t *testing.T) {
939 tests := []struct {
940 a, b Prefix
941 want int
942 }{
943 {Prefix{}, Prefix{}, 0},
944 {Prefix{}, mustPrefix("1.2.3.0/24"), -1},
945
946 {mustPrefix("1.2.3.0/24"), mustPrefix("1.2.3.0/24"), 0},
947 {mustPrefix("fe80::/64"), mustPrefix("fe80::/64"), 0},
948
949 {mustPrefix("1.2.3.0/24"), mustPrefix("1.2.4.0/24"), -1},
950 {mustPrefix("fe80::/64"), mustPrefix("fe90::/64"), -1},
951
952 {mustPrefix("1.2.0.0/16"), mustPrefix("1.2.0.0/24"), -1},
953 {mustPrefix("fe80::/48"), mustPrefix("fe80::/64"), -1},
954
955 {mustPrefix("1.2.3.0/24"), mustPrefix("fe80::/8"), -1},
956 }
957 for _, tt := range tests {
958 got := tt.a.Compare(tt.b)
959 if got != tt.want {
960 t.Errorf("Compare(%q, %q) = %v; want %v", tt.a, tt.b, got, tt.want)
961 }
962
963
964 if got == tt.want {
965 got2 := tt.b.Compare(tt.a)
966 if want2 := -1 * tt.want; got2 != want2 {
967 t.Errorf("Compare(%q, %q) was correctly %v, but Compare(%q, %q) was %v", tt.a, tt.b, got, tt.b, tt.a, got2)
968 }
969 }
970 }
971
972
973 values := []Prefix{
974 mustPrefix("1.2.3.0/24"),
975 mustPrefix("fe90::/64"),
976 mustPrefix("fe80::/64"),
977 mustPrefix("1.2.0.0/16"),
978 Prefix{},
979 mustPrefix("fe80::/48"),
980 mustPrefix("1.2.0.0/24"),
981 }
982 slices.SortFunc(values, func(a, b Prefix) int { return a.Compare(b) })
983 got := fmt.Sprintf("%s", values)
984 want := `[invalid Prefix 1.2.0.0/16 1.2.0.0/24 1.2.3.0/24 fe80::/48 fe80::/64 fe90::/64]`
985 if got != want {
986 t.Errorf("unexpected sort\n got: %s\nwant: %s\n", got, want)
987 }
988 }
989
990 func TestIPStringExpanded(t *testing.T) {
991 tests := []struct {
992 ip Addr
993 s string
994 }{
995 {
996 ip: Addr{},
997 s: "invalid IP",
998 },
999 {
1000 ip: mustIP("192.0.2.1"),
1001 s: "192.0.2.1",
1002 },
1003 {
1004 ip: mustIP("::ffff:192.0.2.1"),
1005 s: "0000:0000:0000:0000:0000:ffff:c000:0201",
1006 },
1007 {
1008 ip: mustIP("2001:db8::1"),
1009 s: "2001:0db8:0000:0000:0000:0000:0000:0001",
1010 },
1011 {
1012 ip: mustIP("2001:db8::1%eth0"),
1013 s: "2001:0db8:0000:0000:0000:0000:0000:0001%eth0",
1014 },
1015 }
1016
1017 for _, tt := range tests {
1018 t.Run(tt.ip.String(), func(t *testing.T) {
1019 want := tt.s
1020 got := tt.ip.StringExpanded()
1021
1022 if got != want {
1023 t.Fatalf("got %s, want %s", got, want)
1024 }
1025 })
1026 }
1027 }
1028
1029 func TestPrefixMasking(t *testing.T) {
1030 type subtest struct {
1031 ip Addr
1032 bits uint8
1033 p Prefix
1034 ok bool
1035 }
1036
1037
1038 makeIPv6 := func(zone string) []subtest {
1039 if zone != "" {
1040 zone = "%" + zone
1041 }
1042
1043 return []subtest{
1044 {
1045 ip: mustIP(fmt.Sprintf("2001:db8::1%s", zone)),
1046 bits: 255,
1047 },
1048 {
1049 ip: mustIP(fmt.Sprintf("2001:db8::1%s", zone)),
1050 bits: 32,
1051 p: mustPrefix("2001:db8::/32"),
1052 ok: true,
1053 },
1054 {
1055 ip: mustIP(fmt.Sprintf("fe80::dead:beef:dead:beef%s", zone)),
1056 bits: 96,
1057 p: mustPrefix("fe80::dead:beef:0:0/96"),
1058 ok: true,
1059 },
1060 {
1061 ip: mustIP(fmt.Sprintf("aaaa::%s", zone)),
1062 bits: 4,
1063 p: mustPrefix("a000::/4"),
1064 ok: true,
1065 },
1066 {
1067 ip: mustIP(fmt.Sprintf("::%s", zone)),
1068 bits: 63,
1069 p: mustPrefix("::/63"),
1070 ok: true,
1071 },
1072 }
1073 }
1074
1075 tests := []struct {
1076 family string
1077 subtests []subtest
1078 }{
1079 {
1080 family: "nil",
1081 subtests: []subtest{
1082 {
1083 bits: 255,
1084 ok: true,
1085 },
1086 {
1087 bits: 16,
1088 ok: true,
1089 },
1090 },
1091 },
1092 {
1093 family: "IPv4",
1094 subtests: []subtest{
1095 {
1096 ip: mustIP("192.0.2.0"),
1097 bits: 255,
1098 },
1099 {
1100 ip: mustIP("192.0.2.0"),
1101 bits: 16,
1102 p: mustPrefix("192.0.0.0/16"),
1103 ok: true,
1104 },
1105 {
1106 ip: mustIP("255.255.255.255"),
1107 bits: 20,
1108 p: mustPrefix("255.255.240.0/20"),
1109 ok: true,
1110 },
1111 {
1112
1113
1114 ip: mustIP("100.98.156.66"),
1115 bits: 10,
1116 p: mustPrefix("100.64.0.0/10"),
1117 ok: true,
1118 },
1119 },
1120 },
1121 {
1122 family: "IPv6",
1123 subtests: makeIPv6(""),
1124 },
1125 {
1126 family: "IPv6 zone",
1127 subtests: makeIPv6("eth0"),
1128 },
1129 }
1130
1131 for _, tt := range tests {
1132 t.Run(tt.family, func(t *testing.T) {
1133 for _, st := range tt.subtests {
1134 t.Run(st.p.String(), func(t *testing.T) {
1135
1136 orig := st.ip.String()
1137
1138 p, err := st.ip.Prefix(int(st.bits))
1139 if st.ok && err != nil {
1140 t.Fatalf("failed to produce prefix: %v", err)
1141 }
1142 if !st.ok && err == nil {
1143 t.Fatal("expected an error, but none occurred")
1144 }
1145 if err != nil {
1146 t.Logf("err: %v", err)
1147 return
1148 }
1149
1150 if !reflect.DeepEqual(p, st.p) {
1151 t.Errorf("prefix = %q, want %q", p, st.p)
1152 }
1153
1154 if got := st.ip.String(); got != orig {
1155 t.Errorf("IP was mutated: %q, want %q", got, orig)
1156 }
1157 })
1158 }
1159 })
1160 }
1161 }
1162
1163 func TestPrefixMarshalUnmarshal(t *testing.T) {
1164 tests := []string{
1165 "",
1166 "1.2.3.4/32",
1167 "0.0.0.0/0",
1168 "::/0",
1169 "::1/128",
1170 "2001:db8::/32",
1171 }
1172
1173 for _, s := range tests {
1174 t.Run(s, func(t *testing.T) {
1175
1176
1177 orig := `"` + s + `"`
1178
1179 var p Prefix
1180 if err := json.Unmarshal([]byte(orig), &p); err != nil {
1181 t.Fatalf("failed to unmarshal: %v", err)
1182 }
1183
1184 pb, err := json.Marshal(p)
1185 if err != nil {
1186 t.Fatalf("failed to marshal: %v", err)
1187 }
1188
1189 back := string(pb)
1190 if orig != back {
1191 t.Errorf("Marshal = %q; want %q", back, orig)
1192 }
1193 })
1194 }
1195 }
1196
1197 func TestPrefixUnmarshalTextNonZero(t *testing.T) {
1198 ip := mustPrefix("fe80::/64")
1199 if err := ip.UnmarshalText([]byte("xxx")); err == nil {
1200 t.Fatal("unmarshaled into non-empty Prefix")
1201 }
1202 }
1203
1204 func TestIs4AndIs6(t *testing.T) {
1205 tests := []struct {
1206 ip Addr
1207 is4 bool
1208 is6 bool
1209 }{
1210 {Addr{}, false, false},
1211 {mustIP("1.2.3.4"), true, false},
1212 {mustIP("127.0.0.2"), true, false},
1213 {mustIP("::1"), false, true},
1214 {mustIP("::ffff:192.0.2.128"), false, true},
1215 {mustIP("::fffe:c000:0280"), false, true},
1216 {mustIP("::1%eth0"), false, true},
1217 }
1218 for _, tt := range tests {
1219 got4 := tt.ip.Is4()
1220 if got4 != tt.is4 {
1221 t.Errorf("Is4(%q) = %v; want %v", tt.ip, got4, tt.is4)
1222 }
1223
1224 got6 := tt.ip.Is6()
1225 if got6 != tt.is6 {
1226 t.Errorf("Is6(%q) = %v; want %v", tt.ip, got6, tt.is6)
1227 }
1228 }
1229 }
1230
1231 func TestIs4In6(t *testing.T) {
1232 tests := []struct {
1233 ip Addr
1234 want bool
1235 wantUnmap Addr
1236 }{
1237 {Addr{}, false, Addr{}},
1238 {mustIP("::ffff:c000:0280"), true, mustIP("192.0.2.128")},
1239 {mustIP("::ffff:192.0.2.128"), true, mustIP("192.0.2.128")},
1240 {mustIP("::ffff:192.0.2.128%eth0"), true, mustIP("192.0.2.128")},
1241 {mustIP("::fffe:c000:0280"), false, mustIP("::fffe:c000:0280")},
1242 {mustIP("::ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
1243 {mustIP("::ffff:7f01:0203"), true, mustIP("127.1.2.3")},
1244 {mustIP("0:0:0:0:0000:ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
1245 {mustIP("0:0:0:0:000000:ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
1246 {mustIP("0:0:0:0::ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
1247 {mustIP("::1"), false, mustIP("::1")},
1248 {mustIP("1.2.3.4"), false, mustIP("1.2.3.4")},
1249 }
1250 for _, tt := range tests {
1251 got := tt.ip.Is4In6()
1252 if got != tt.want {
1253 t.Errorf("Is4In6(%q) = %v; want %v", tt.ip, got, tt.want)
1254 }
1255 u := tt.ip.Unmap()
1256 if u != tt.wantUnmap {
1257 t.Errorf("Unmap(%q) = %v; want %v", tt.ip, u, tt.wantUnmap)
1258 }
1259 }
1260 }
1261
1262 func TestPrefixMasked(t *testing.T) {
1263 tests := []struct {
1264 prefix Prefix
1265 masked Prefix
1266 }{
1267 {
1268 prefix: mustPrefix("192.168.0.255/24"),
1269 masked: mustPrefix("192.168.0.0/24"),
1270 },
1271 {
1272 prefix: mustPrefix("2100::/3"),
1273 masked: mustPrefix("2000::/3"),
1274 },
1275 {
1276 prefix: PrefixFrom(mustIP("2000::"), 129),
1277 masked: Prefix{},
1278 },
1279 {
1280 prefix: PrefixFrom(mustIP("1.2.3.4"), 33),
1281 masked: Prefix{},
1282 },
1283 }
1284 for _, test := range tests {
1285 t.Run(test.prefix.String(), func(t *testing.T) {
1286 got := test.prefix.Masked()
1287 if got != test.masked {
1288 t.Errorf("Masked=%s, want %s", got, test.masked)
1289 }
1290 })
1291 }
1292 }
1293
1294 func TestPrefix(t *testing.T) {
1295 tests := []struct {
1296 prefix string
1297 ip Addr
1298 bits int
1299 str string
1300 contains []Addr
1301 notContains []Addr
1302 }{
1303 {
1304 prefix: "192.168.0.0/24",
1305 ip: mustIP("192.168.0.0"),
1306 bits: 24,
1307 contains: mustIPs("192.168.0.1", "192.168.0.55"),
1308 notContains: mustIPs("192.168.1.1", "1.1.1.1"),
1309 },
1310 {
1311 prefix: "192.168.1.1/32",
1312 ip: mustIP("192.168.1.1"),
1313 bits: 32,
1314 contains: mustIPs("192.168.1.1"),
1315 notContains: mustIPs("192.168.1.2"),
1316 },
1317 {
1318 prefix: "100.64.0.0/10",
1319 ip: mustIP("100.64.0.0"),
1320 bits: 10,
1321 contains: mustIPs("100.64.0.0", "100.64.0.1", "100.81.251.94", "100.100.100.100", "100.127.255.254", "100.127.255.255"),
1322 notContains: mustIPs("100.63.255.255", "100.128.0.0"),
1323 },
1324 {
1325 prefix: "2001:db8::/96",
1326 ip: mustIP("2001:db8::"),
1327 bits: 96,
1328 contains: mustIPs("2001:db8::aaaa:bbbb", "2001:db8::1"),
1329 notContains: mustIPs("2001:db8::1:aaaa:bbbb", "2001:db9::"),
1330 },
1331 {
1332 prefix: "0.0.0.0/0",
1333 ip: mustIP("0.0.0.0"),
1334 bits: 0,
1335 contains: mustIPs("192.168.0.1", "1.1.1.1"),
1336 notContains: append(mustIPs("2001:db8::1"), Addr{}),
1337 },
1338 {
1339 prefix: "::/0",
1340 ip: mustIP("::"),
1341 bits: 0,
1342 contains: mustIPs("::1", "2001:db8::1"),
1343 notContains: mustIPs("192.0.2.1"),
1344 },
1345 {
1346 prefix: "2000::/3",
1347 ip: mustIP("2000::"),
1348 bits: 3,
1349 contains: mustIPs("2001:db8::1"),
1350 notContains: mustIPs("fe80::1"),
1351 },
1352 }
1353 for _, test := range tests {
1354 t.Run(test.prefix, func(t *testing.T) {
1355 prefix, err := ParsePrefix(test.prefix)
1356 if err != nil {
1357 t.Fatal(err)
1358 }
1359 if prefix.Addr() != test.ip {
1360 t.Errorf("IP=%s, want %s", prefix.Addr(), test.ip)
1361 }
1362 if prefix.Bits() != test.bits {
1363 t.Errorf("bits=%d, want %d", prefix.Bits(), test.bits)
1364 }
1365 for _, ip := range test.contains {
1366 if !prefix.Contains(ip) {
1367 t.Errorf("does not contain %s", ip)
1368 }
1369 }
1370 for _, ip := range test.notContains {
1371 if prefix.Contains(ip) {
1372 t.Errorf("contains %s", ip)
1373 }
1374 }
1375 want := test.str
1376 if want == "" {
1377 want = test.prefix
1378 }
1379 if got := prefix.String(); got != want {
1380 t.Errorf("prefix.String()=%q, want %q", got, want)
1381 }
1382
1383 TestAppendToMarshal(t, prefix)
1384 })
1385 }
1386 }
1387
1388 func TestPrefixFromInvalidBits(t *testing.T) {
1389 v4 := MustParseAddr("1.2.3.4")
1390 v6 := MustParseAddr("66::66")
1391 tests := []struct {
1392 ip Addr
1393 in, want int
1394 }{
1395 {v4, 0, 0},
1396 {v6, 0, 0},
1397 {v4, 1, 1},
1398 {v4, 33, -1},
1399 {v6, 33, 33},
1400 {v6, 127, 127},
1401 {v6, 128, 128},
1402 {v4, 254, -1},
1403 {v4, 255, -1},
1404 {v4, -1, -1},
1405 {v6, -1, -1},
1406 {v4, -5, -1},
1407 {v6, -5, -1},
1408 }
1409 for _, tt := range tests {
1410 p := PrefixFrom(tt.ip, tt.in)
1411 if got := p.Bits(); got != tt.want {
1412 t.Errorf("for (%v, %v), Bits out = %v; want %v", tt.ip, tt.in, got, tt.want)
1413 }
1414 }
1415 }
1416
1417 func TestParsePrefixAllocs(t *testing.T) {
1418 tests := []struct {
1419 ip string
1420 slash string
1421 }{
1422 {"192.168.1.0", "/24"},
1423 {"aaaa:bbbb:cccc::", "/24"},
1424 }
1425 for _, test := range tests {
1426 prefix := test.ip + test.slash
1427 t.Run(prefix, func(t *testing.T) {
1428 ipAllocs := int(testing.AllocsPerRun(5, func() {
1429 ParseAddr(test.ip)
1430 }))
1431 prefixAllocs := int(testing.AllocsPerRun(5, func() {
1432 ParsePrefix(prefix)
1433 }))
1434 if got := prefixAllocs - ipAllocs; got != 0 {
1435 t.Errorf("allocs=%d, want 0", got)
1436 }
1437 })
1438 }
1439 }
1440
1441 func TestParsePrefixError(t *testing.T) {
1442 tests := []struct {
1443 prefix string
1444 errstr string
1445 }{
1446 {
1447 prefix: "192.168.0.0",
1448 errstr: "no '/'",
1449 },
1450 {
1451 prefix: "1.257.1.1/24",
1452 errstr: "value >255",
1453 },
1454 {
1455 prefix: "1.1.1.0/q",
1456 errstr: "bad bits",
1457 },
1458 {
1459 prefix: "1.1.1.0/-1",
1460 errstr: "bad bits",
1461 },
1462 {
1463 prefix: "1.1.1.0/33",
1464 errstr: "out of range",
1465 },
1466 {
1467 prefix: "2001::/129",
1468 errstr: "out of range",
1469 },
1470
1471 {
1472 prefix: "1.1.1.0%a/24",
1473 errstr: "unexpected character",
1474 },
1475 {
1476 prefix: "2001:db8::%a/32",
1477 errstr: "zones cannot be present",
1478 },
1479 {
1480 prefix: "1.1.1.0/+32",
1481 errstr: "bad bits",
1482 },
1483 {
1484 prefix: "1.1.1.0/-32",
1485 errstr: "bad bits",
1486 },
1487 {
1488 prefix: "1.1.1.0/032",
1489 errstr: "bad bits",
1490 },
1491 {
1492 prefix: "1.1.1.0/0032",
1493 errstr: "bad bits",
1494 },
1495 }
1496 for _, test := range tests {
1497 t.Run(test.prefix, func(t *testing.T) {
1498 _, err := ParsePrefix(test.prefix)
1499 if err == nil {
1500 t.Fatal("no error")
1501 }
1502 if got := err.Error(); !strings.Contains(got, test.errstr) {
1503 t.Errorf("error is missing substring %q: %s", test.errstr, got)
1504 }
1505 })
1506 }
1507 }
1508
1509 func TestPrefixIsSingleIP(t *testing.T) {
1510 tests := []struct {
1511 ipp Prefix
1512 want bool
1513 }{
1514 {ipp: mustPrefix("127.0.0.1/32"), want: true},
1515 {ipp: mustPrefix("127.0.0.1/31"), want: false},
1516 {ipp: mustPrefix("127.0.0.1/0"), want: false},
1517 {ipp: mustPrefix("::1/128"), want: true},
1518 {ipp: mustPrefix("::1/127"), want: false},
1519 {ipp: mustPrefix("::1/0"), want: false},
1520 {ipp: Prefix{}, want: false},
1521 }
1522 for _, tt := range tests {
1523 got := tt.ipp.IsSingleIP()
1524 if got != tt.want {
1525 t.Errorf("IsSingleIP(%v) = %v want %v", tt.ipp, got, tt.want)
1526 }
1527 }
1528 }
1529
1530 func mustIPs(strs ...string) []Addr {
1531 var res []Addr
1532 for _, s := range strs {
1533 res = append(res, mustIP(s))
1534 }
1535 return res
1536 }
1537
1538 func BenchmarkBinaryMarshalRoundTrip(b *testing.B) {
1539 b.ReportAllocs()
1540 tests := []struct {
1541 name string
1542 ip string
1543 }{
1544 {"ipv4", "1.2.3.4"},
1545 {"ipv6", "2001:db8::1"},
1546 {"ipv6+zone", "2001:db8::1%eth0"},
1547 }
1548 for _, tc := range tests {
1549 b.Run(tc.name, func(b *testing.B) {
1550 ip := mustIP(tc.ip)
1551 for i := 0; i < b.N; i++ {
1552 bt, err := ip.MarshalBinary()
1553 if err != nil {
1554 b.Fatal(err)
1555 }
1556 var ip2 Addr
1557 if err := ip2.UnmarshalBinary(bt); err != nil {
1558 b.Fatal(err)
1559 }
1560 }
1561 })
1562 }
1563 }
1564
1565 func BenchmarkStdIPv4(b *testing.B) {
1566 b.ReportAllocs()
1567 ips := []net.IP{}
1568 for i := 0; i < b.N; i++ {
1569 ip := net.IPv4(8, 8, 8, 8)
1570 ips = ips[:0]
1571 for i := 0; i < 100; i++ {
1572 ips = append(ips, ip)
1573 }
1574 }
1575 }
1576
1577 func BenchmarkIPv4(b *testing.B) {
1578 b.ReportAllocs()
1579 ips := []Addr{}
1580 for i := 0; i < b.N; i++ {
1581 ip := IPv4(8, 8, 8, 8)
1582 ips = ips[:0]
1583 for i := 0; i < 100; i++ {
1584 ips = append(ips, ip)
1585 }
1586 }
1587 }
1588
1589
1590
1591
1592 type ip4i struct {
1593 ip4 [4]byte
1594 flags1 byte
1595 flags2 byte
1596 flags3 byte
1597 flags4 byte
1598 ipv6 any
1599 }
1600
1601 func newip4i_v4(a, b, c, d byte) ip4i {
1602 return ip4i{ip4: [4]byte{a, b, c, d}}
1603 }
1604
1605
1606 func BenchmarkIPv4_inline(b *testing.B) {
1607 b.ReportAllocs()
1608 ips := []ip4i{}
1609 for i := 0; i < b.N; i++ {
1610 ip := newip4i_v4(8, 8, 8, 8)
1611 ips = ips[:0]
1612 for i := 0; i < 100; i++ {
1613 ips = append(ips, ip)
1614 }
1615 }
1616 }
1617
1618 func BenchmarkStdIPv6(b *testing.B) {
1619 b.ReportAllocs()
1620 ips := []net.IP{}
1621 for i := 0; i < b.N; i++ {
1622 ip := net.ParseIP("2001:db8::1")
1623 ips = ips[:0]
1624 for i := 0; i < 100; i++ {
1625 ips = append(ips, ip)
1626 }
1627 }
1628 }
1629
1630 func BenchmarkIPv6(b *testing.B) {
1631 b.ReportAllocs()
1632 ips := []Addr{}
1633 for i := 0; i < b.N; i++ {
1634 ip := mustIP("2001:db8::1")
1635 ips = ips[:0]
1636 for i := 0; i < 100; i++ {
1637 ips = append(ips, ip)
1638 }
1639 }
1640 }
1641
1642 func BenchmarkIPv4Contains(b *testing.B) {
1643 b.ReportAllocs()
1644 prefix := PrefixFrom(IPv4(192, 168, 1, 0), 24)
1645 ip := IPv4(192, 168, 1, 1)
1646 for i := 0; i < b.N; i++ {
1647 prefix.Contains(ip)
1648 }
1649 }
1650
1651 func BenchmarkIPv6Contains(b *testing.B) {
1652 b.ReportAllocs()
1653 prefix := MustParsePrefix("::1/128")
1654 ip := MustParseAddr("::1")
1655 for i := 0; i < b.N; i++ {
1656 prefix.Contains(ip)
1657 }
1658 }
1659
1660 var parseBenchInputs = []struct {
1661 name string
1662 ip string
1663 }{
1664 {"v4", "192.168.1.1"},
1665 {"v6", "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b"},
1666 {"v6_ellipsis", "fd7a:115c::626b:430b"},
1667 {"v6_v4", "::ffff:192.168.140.255"},
1668 {"v6_zone", "1:2::ffff:192.168.140.255%eth1"},
1669 }
1670
1671 func BenchmarkParseAddr(b *testing.B) {
1672 sinkInternValue = intern.Get("eth1")
1673 for _, test := range parseBenchInputs {
1674 b.Run(test.name, func(b *testing.B) {
1675 b.ReportAllocs()
1676 for i := 0; i < b.N; i++ {
1677 sinkIP, _ = ParseAddr(test.ip)
1678 }
1679 })
1680 }
1681 }
1682
1683 func BenchmarkStdParseIP(b *testing.B) {
1684 for _, test := range parseBenchInputs {
1685 b.Run(test.name, func(b *testing.B) {
1686 b.ReportAllocs()
1687 for i := 0; i < b.N; i++ {
1688 sinkStdIP = net.ParseIP(test.ip)
1689 }
1690 })
1691 }
1692 }
1693
1694 func BenchmarkIPString(b *testing.B) {
1695 for _, test := range parseBenchInputs {
1696 ip := MustParseAddr(test.ip)
1697 b.Run(test.name, func(b *testing.B) {
1698 b.ReportAllocs()
1699 for i := 0; i < b.N; i++ {
1700 sinkString = ip.String()
1701 }
1702 })
1703 }
1704 }
1705
1706 func BenchmarkIPStringExpanded(b *testing.B) {
1707 for _, test := range parseBenchInputs {
1708 ip := MustParseAddr(test.ip)
1709 b.Run(test.name, func(b *testing.B) {
1710 b.ReportAllocs()
1711 for i := 0; i < b.N; i++ {
1712 sinkString = ip.StringExpanded()
1713 }
1714 })
1715 }
1716 }
1717
1718 func BenchmarkIPMarshalText(b *testing.B) {
1719 b.ReportAllocs()
1720 ip := MustParseAddr("66.55.44.33")
1721 for i := 0; i < b.N; i++ {
1722 sinkBytes, _ = ip.MarshalText()
1723 }
1724 }
1725
1726 func BenchmarkAddrPortString(b *testing.B) {
1727 for _, test := range parseBenchInputs {
1728 ip := MustParseAddr(test.ip)
1729 ipp := AddrPortFrom(ip, 60000)
1730 b.Run(test.name, func(b *testing.B) {
1731 b.ReportAllocs()
1732 for i := 0; i < b.N; i++ {
1733 sinkString = ipp.String()
1734 }
1735 })
1736 }
1737 }
1738
1739 func BenchmarkAddrPortMarshalText(b *testing.B) {
1740 for _, test := range parseBenchInputs {
1741 ip := MustParseAddr(test.ip)
1742 ipp := AddrPortFrom(ip, 60000)
1743 b.Run(test.name, func(b *testing.B) {
1744 b.ReportAllocs()
1745 for i := 0; i < b.N; i++ {
1746 sinkBytes, _ = ipp.MarshalText()
1747 }
1748 })
1749 }
1750 }
1751
1752 func BenchmarkPrefixMasking(b *testing.B) {
1753 tests := []struct {
1754 name string
1755 ip Addr
1756 bits int
1757 }{
1758 {
1759 name: "IPv4 /32",
1760 ip: IPv4(192, 0, 2, 0),
1761 bits: 32,
1762 },
1763 {
1764 name: "IPv4 /17",
1765 ip: IPv4(192, 0, 2, 0),
1766 bits: 17,
1767 },
1768 {
1769 name: "IPv4 /0",
1770 ip: IPv4(192, 0, 2, 0),
1771 bits: 0,
1772 },
1773 {
1774 name: "IPv6 /128",
1775 ip: mustIP("2001:db8::1"),
1776 bits: 128,
1777 },
1778 {
1779 name: "IPv6 /65",
1780 ip: mustIP("2001:db8::1"),
1781 bits: 65,
1782 },
1783 {
1784 name: "IPv6 /0",
1785 ip: mustIP("2001:db8::1"),
1786 bits: 0,
1787 },
1788 {
1789 name: "IPv6 zone /128",
1790 ip: mustIP("2001:db8::1%eth0"),
1791 bits: 128,
1792 },
1793 {
1794 name: "IPv6 zone /65",
1795 ip: mustIP("2001:db8::1%eth0"),
1796 bits: 65,
1797 },
1798 {
1799 name: "IPv6 zone /0",
1800 ip: mustIP("2001:db8::1%eth0"),
1801 bits: 0,
1802 },
1803 }
1804
1805 for _, tt := range tests {
1806 b.Run(tt.name, func(b *testing.B) {
1807 b.ReportAllocs()
1808
1809 for i := 0; i < b.N; i++ {
1810 sinkPrefix, _ = tt.ip.Prefix(tt.bits)
1811 }
1812 })
1813 }
1814 }
1815
1816 func BenchmarkPrefixMarshalText(b *testing.B) {
1817 b.ReportAllocs()
1818 ipp := MustParsePrefix("66.55.44.33/22")
1819 for i := 0; i < b.N; i++ {
1820 sinkBytes, _ = ipp.MarshalText()
1821 }
1822 }
1823
1824 func BenchmarkParseAddrPort(b *testing.B) {
1825 for _, test := range parseBenchInputs {
1826 var ipp string
1827 if strings.HasPrefix(test.name, "v6") {
1828 ipp = fmt.Sprintf("[%s]:1234", test.ip)
1829 } else {
1830 ipp = fmt.Sprintf("%s:1234", test.ip)
1831 }
1832 b.Run(test.name, func(b *testing.B) {
1833 b.ReportAllocs()
1834
1835 for i := 0; i < b.N; i++ {
1836 sinkAddrPort, _ = ParseAddrPort(ipp)
1837 }
1838 })
1839 }
1840 }
1841
1842 func TestAs4(t *testing.T) {
1843 tests := []struct {
1844 ip Addr
1845 want [4]byte
1846 wantPanic bool
1847 }{
1848 {
1849 ip: mustIP("1.2.3.4"),
1850 want: [4]byte{1, 2, 3, 4},
1851 },
1852 {
1853 ip: AddrFrom16(mustIP("1.2.3.4").As16()),
1854 want: [4]byte{1, 2, 3, 4},
1855 },
1856 {
1857 ip: mustIP("0.0.0.0"),
1858 want: [4]byte{0, 0, 0, 0},
1859 },
1860 {
1861 ip: Addr{},
1862 wantPanic: true,
1863 },
1864 {
1865 ip: mustIP("::1"),
1866 wantPanic: true,
1867 },
1868 }
1869 as4 := func(ip Addr) (v [4]byte, gotPanic bool) {
1870 defer func() {
1871 if recover() != nil {
1872 gotPanic = true
1873 return
1874 }
1875 }()
1876 v = ip.As4()
1877 return
1878 }
1879 for i, tt := range tests {
1880 got, gotPanic := as4(tt.ip)
1881 if gotPanic != tt.wantPanic {
1882 t.Errorf("%d. panic on %v = %v; want %v", i, tt.ip, gotPanic, tt.wantPanic)
1883 continue
1884 }
1885 if got != tt.want {
1886 t.Errorf("%d. %v = %v; want %v", i, tt.ip, got, tt.want)
1887 }
1888 }
1889 }
1890
1891 func TestPrefixOverlaps(t *testing.T) {
1892 pfx := mustPrefix
1893 tests := []struct {
1894 a, b Prefix
1895 want bool
1896 }{
1897 {Prefix{}, pfx("1.2.0.0/16"), false},
1898 {pfx("1.2.0.0/16"), Prefix{}, false},
1899 {pfx("::0/3"), pfx("0.0.0.0/3"), false},
1900
1901 {pfx("1.2.0.0/16"), pfx("1.2.0.0/16"), true},
1902
1903 {pfx("1.2.0.0/16"), pfx("1.2.3.0/24"), true},
1904 {pfx("1.2.3.0/24"), pfx("1.2.0.0/16"), true},
1905
1906 {pfx("1.2.0.0/16"), pfx("1.2.3.0/32"), true},
1907 {pfx("1.2.3.0/32"), pfx("1.2.0.0/16"), true},
1908
1909
1910 {pfx("1.2.3.0/32"), pfx("0.0.0.0/0"), true},
1911 {pfx("0.0.0.0/0"), pfx("1.2.3.0/32"), true},
1912
1913 {pfx("1.2.3.0/32"), pfx("5.5.5.5/0"), true},
1914
1915
1916 {pfx("5::1/128"), pfx("5::0/8"), true},
1917 {pfx("5::0/8"), pfx("5::1/128"), true},
1918
1919
1920 {pfx("1::1/128"), pfx("2::2/128"), false},
1921 {pfx("0100::0/8"), pfx("::1/128"), false},
1922
1923
1924 {PrefixFrom(AddrFrom16(mustIP("1.2.0.0").As16()), 16), pfx("1.2.3.0/24"), false},
1925
1926
1927 {PrefixFrom(mustIP("1.2.3.4"), 33), pfx("1.2.3.0/24"), false},
1928 {PrefixFrom(mustIP("2000::"), 129), pfx("2000::/64"), false},
1929 }
1930 for i, tt := range tests {
1931 if got := tt.a.Overlaps(tt.b); got != tt.want {
1932 t.Errorf("%d. (%v).Overlaps(%v) = %v; want %v", i, tt.a, tt.b, got, tt.want)
1933 }
1934
1935 if got := tt.b.Overlaps(tt.a); got != tt.want {
1936 t.Errorf("%d. (%v).Overlaps(%v) = %v; want %v", i, tt.b, tt.a, got, tt.want)
1937 }
1938 }
1939 }
1940
1941
1942
1943
1944
1945
1946
1947 var (
1948 sinkIP Addr
1949 sinkStdIP net.IP
1950 sinkAddrPort AddrPort
1951 sinkPrefix Prefix
1952 sinkPrefixSlice []Prefix
1953 sinkInternValue *intern.Value
1954 sinkIP16 [16]byte
1955 sinkIP4 [4]byte
1956 sinkBool bool
1957 sinkString string
1958 sinkBytes []byte
1959 sinkUDPAddr = &net.UDPAddr{IP: make(net.IP, 0, 16)}
1960 )
1961
1962 func TestNoAllocs(t *testing.T) {
1963
1964
1965 panicIP := func(ip Addr, err error) Addr {
1966 if err != nil {
1967 panic(err)
1968 }
1969 return ip
1970 }
1971 panicPfx := func(pfx Prefix, err error) Prefix {
1972 if err != nil {
1973 panic(err)
1974 }
1975 return pfx
1976 }
1977 panicIPP := func(ipp AddrPort, err error) AddrPort {
1978 if err != nil {
1979 panic(err)
1980 }
1981 return ipp
1982 }
1983 test := func(name string, f func()) {
1984 t.Run(name, func(t *testing.T) {
1985 n := testing.AllocsPerRun(1000, f)
1986 if n != 0 {
1987 t.Fatalf("allocs = %d; want 0", int(n))
1988 }
1989 })
1990 }
1991
1992
1993 test("IPv4", func() { sinkIP = IPv4(1, 2, 3, 4) })
1994 test("AddrFrom4", func() { sinkIP = AddrFrom4([4]byte{1, 2, 3, 4}) })
1995 test("AddrFrom16", func() { sinkIP = AddrFrom16([16]byte{}) })
1996 test("ParseAddr/4", func() { sinkIP = panicIP(ParseAddr("1.2.3.4")) })
1997 test("ParseAddr/6", func() { sinkIP = panicIP(ParseAddr("::1")) })
1998 test("MustParseAddr", func() { sinkIP = MustParseAddr("1.2.3.4") })
1999 test("IPv6LinkLocalAllNodes", func() { sinkIP = IPv6LinkLocalAllNodes() })
2000 test("IPv6LinkLocalAllRouters", func() { sinkIP = IPv6LinkLocalAllRouters() })
2001 test("IPv6Loopback", func() { sinkIP = IPv6Loopback() })
2002 test("IPv6Unspecified", func() { sinkIP = IPv6Unspecified() })
2003
2004
2005 test("Addr.IsZero", func() { sinkBool = MustParseAddr("1.2.3.4").IsZero() })
2006 test("Addr.BitLen", func() { sinkBool = MustParseAddr("1.2.3.4").BitLen() == 8 })
2007 test("Addr.Zone/4", func() { sinkBool = MustParseAddr("1.2.3.4").Zone() == "" })
2008 test("Addr.Zone/6", func() { sinkBool = MustParseAddr("fe80::1").Zone() == "" })
2009 test("Addr.Zone/6zone", func() { sinkBool = MustParseAddr("fe80::1%zone").Zone() == "" })
2010 test("Addr.Compare", func() {
2011 a := MustParseAddr("1.2.3.4")
2012 b := MustParseAddr("2.3.4.5")
2013 sinkBool = a.Compare(b) == 0
2014 })
2015 test("Addr.Less", func() {
2016 a := MustParseAddr("1.2.3.4")
2017 b := MustParseAddr("2.3.4.5")
2018 sinkBool = a.Less(b)
2019 })
2020 test("Addr.Is4", func() { sinkBool = MustParseAddr("1.2.3.4").Is4() })
2021 test("Addr.Is6", func() { sinkBool = MustParseAddr("fe80::1").Is6() })
2022 test("Addr.Is4In6", func() { sinkBool = MustParseAddr("fe80::1").Is4In6() })
2023 test("Addr.Unmap", func() { sinkIP = MustParseAddr("ffff::2.3.4.5").Unmap() })
2024 test("Addr.WithZone", func() { sinkIP = MustParseAddr("fe80::1").WithZone("") })
2025 test("Addr.IsGlobalUnicast", func() { sinkBool = MustParseAddr("2001:db8::1").IsGlobalUnicast() })
2026 test("Addr.IsInterfaceLocalMulticast", func() { sinkBool = MustParseAddr("fe80::1").IsInterfaceLocalMulticast() })
2027 test("Addr.IsLinkLocalMulticast", func() { sinkBool = MustParseAddr("fe80::1").IsLinkLocalMulticast() })
2028 test("Addr.IsLinkLocalUnicast", func() { sinkBool = MustParseAddr("fe80::1").IsLinkLocalUnicast() })
2029 test("Addr.IsLoopback", func() { sinkBool = MustParseAddr("fe80::1").IsLoopback() })
2030 test("Addr.IsMulticast", func() { sinkBool = MustParseAddr("fe80::1").IsMulticast() })
2031 test("Addr.IsPrivate", func() { sinkBool = MustParseAddr("fd00::1").IsPrivate() })
2032 test("Addr.IsUnspecified", func() { sinkBool = IPv6Unspecified().IsUnspecified() })
2033 test("Addr.Prefix/4", func() { sinkPrefix = panicPfx(MustParseAddr("1.2.3.4").Prefix(20)) })
2034 test("Addr.Prefix/6", func() { sinkPrefix = panicPfx(MustParseAddr("fe80::1").Prefix(64)) })
2035 test("Addr.As16", func() { sinkIP16 = MustParseAddr("1.2.3.4").As16() })
2036 test("Addr.As4", func() { sinkIP4 = MustParseAddr("1.2.3.4").As4() })
2037 test("Addr.Next", func() { sinkIP = MustParseAddr("1.2.3.4").Next() })
2038 test("Addr.Prev", func() { sinkIP = MustParseAddr("1.2.3.4").Prev() })
2039
2040
2041 test("AddrPortFrom", func() { sinkAddrPort = AddrPortFrom(IPv4(1, 2, 3, 4), 22) })
2042 test("ParseAddrPort", func() { sinkAddrPort = panicIPP(ParseAddrPort("[::1]:1234")) })
2043 test("MustParseAddrPort", func() { sinkAddrPort = MustParseAddrPort("[::1]:1234") })
2044
2045
2046 test("PrefixFrom", func() { sinkPrefix = PrefixFrom(IPv4(1, 2, 3, 4), 32) })
2047 test("ParsePrefix/4", func() { sinkPrefix = panicPfx(ParsePrefix("1.2.3.4/20")) })
2048 test("ParsePrefix/6", func() { sinkPrefix = panicPfx(ParsePrefix("fe80::1/64")) })
2049 test("MustParsePrefix", func() { sinkPrefix = MustParsePrefix("1.2.3.4/20") })
2050
2051
2052 test("Prefix.Contains", func() { sinkBool = MustParsePrefix("1.2.3.0/24").Contains(MustParseAddr("1.2.3.4")) })
2053 test("Prefix.Overlaps", func() {
2054 a, b := MustParsePrefix("1.2.3.0/24"), MustParsePrefix("1.2.0.0/16")
2055 sinkBool = a.Overlaps(b)
2056 })
2057 test("Prefix.IsZero", func() { sinkBool = MustParsePrefix("1.2.0.0/16").IsZero() })
2058 test("Prefix.IsSingleIP", func() { sinkBool = MustParsePrefix("1.2.3.4/32").IsSingleIP() })
2059 test("Prefix.Masked", func() { sinkPrefix = MustParsePrefix("1.2.3.4/16").Masked() })
2060 }
2061
2062 func TestAddrStringAllocs(t *testing.T) {
2063 tests := []struct {
2064 name string
2065 ip Addr
2066 wantAllocs int
2067 }{
2068 {"zero", Addr{}, 0},
2069 {"ipv4", MustParseAddr("192.168.1.1"), 1},
2070 {"ipv6", MustParseAddr("2001:db8::1"), 1},
2071 {"ipv6+zone", MustParseAddr("2001:db8::1%eth0"), 1},
2072 {"ipv4-in-ipv6", MustParseAddr("::ffff:192.168.1.1"), 1},
2073 {"ipv4-in-ipv6+zone", MustParseAddr("::ffff:192.168.1.1%eth0"), 1},
2074 }
2075 optimizationOff := testenv.OptimizationOff()
2076 for _, tc := range tests {
2077 t.Run(tc.name, func(t *testing.T) {
2078 if optimizationOff && strings.HasPrefix(tc.name, "ipv4-in-ipv6") {
2079
2080 t.Skipf("skipping on %v", testenv.Builder())
2081 }
2082 allocs := int(testing.AllocsPerRun(1000, func() {
2083 sinkString = tc.ip.String()
2084 }))
2085 if allocs != tc.wantAllocs {
2086 t.Errorf("allocs=%d, want %d", allocs, tc.wantAllocs)
2087 }
2088 })
2089 }
2090 }
2091
2092 func TestPrefixString(t *testing.T) {
2093 tests := []struct {
2094 ipp Prefix
2095 want string
2096 }{
2097 {Prefix{}, "invalid Prefix"},
2098 {PrefixFrom(Addr{}, 8), "invalid Prefix"},
2099 {PrefixFrom(MustParseAddr("1.2.3.4"), 88), "invalid Prefix"},
2100 }
2101
2102 for _, tt := range tests {
2103 if got := tt.ipp.String(); got != tt.want {
2104 t.Errorf("(%#v).String() = %q want %q", tt.ipp, got, tt.want)
2105 }
2106 }
2107 }
2108
2109 func TestInvalidAddrPortString(t *testing.T) {
2110 tests := []struct {
2111 ipp AddrPort
2112 want string
2113 }{
2114 {AddrPort{}, "invalid AddrPort"},
2115 {AddrPortFrom(Addr{}, 80), "invalid AddrPort"},
2116 }
2117
2118 for _, tt := range tests {
2119 if got := tt.ipp.String(); got != tt.want {
2120 t.Errorf("(%#v).String() = %q want %q", tt.ipp, got, tt.want)
2121 }
2122 }
2123 }
2124
2125 func TestAsSlice(t *testing.T) {
2126 tests := []struct {
2127 in Addr
2128 want []byte
2129 }{
2130 {in: Addr{}, want: nil},
2131 {in: mustIP("1.2.3.4"), want: []byte{1, 2, 3, 4}},
2132 {in: mustIP("ffff::1"), want: []byte{0xff, 0xff, 15: 1}},
2133 }
2134
2135 for _, test := range tests {
2136 got := test.in.AsSlice()
2137 if !bytes.Equal(got, test.want) {
2138 t.Errorf("%v.AsSlice() = %v want %v", test.in, got, test.want)
2139 }
2140 }
2141 }
2142
2143 var sink16 [16]byte
2144
2145 func BenchmarkAs16(b *testing.B) {
2146 addr := MustParseAddr("1::10")
2147 for i := 0; i < b.N; i++ {
2148 sink16 = addr.As16()
2149 }
2150 }
2151
View as plain text