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