github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/net/netip/netip_test.go (about)

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