github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/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  		loopback6 = mustIP("::1")
   589  
   590  		ilm6     = mustIP("ff01::1")
   591  		ilmZone6 = mustIP("ff01::1%eth0")
   592  
   593  		private4a = mustIP("10.0.0.1")
   594  		private4b = mustIP("172.16.0.1")
   595  		private4c = mustIP("192.168.1.1")
   596  		private6  = mustIP("fd00::1")
   597  	)
   598  
   599  	tests := []struct {
   600  		name                    string
   601  		ip                      Addr
   602  		globalUnicast           bool
   603  		interfaceLocalMulticast bool
   604  		linkLocalMulticast      bool
   605  		linkLocalUnicast        bool
   606  		loopback                bool
   607  		multicast               bool
   608  		private                 bool
   609  		unspecified             bool
   610  	}{
   611  		{
   612  			name: "nil",
   613  			ip:   nilIP,
   614  		},
   615  		{
   616  			name:          "unicast v4Addr",
   617  			ip:            unicast4,
   618  			globalUnicast: true,
   619  		},
   620  		{
   621  			name:          "unicast v6Addr",
   622  			ip:            unicast6,
   623  			globalUnicast: true,
   624  		},
   625  		{
   626  			name:          "unicast v6AddrZone",
   627  			ip:            unicastZone6,
   628  			globalUnicast: true,
   629  		},
   630  		{
   631  			name:          "unicast v6Addr unassigned",
   632  			ip:            unicast6Unassigned,
   633  			globalUnicast: true,
   634  		},
   635  		{
   636  			name:               "multicast v4Addr",
   637  			ip:                 multicast4,
   638  			linkLocalMulticast: true,
   639  			multicast:          true,
   640  		},
   641  		{
   642  			name:               "multicast v6Addr",
   643  			ip:                 multicast6,
   644  			linkLocalMulticast: true,
   645  			multicast:          true,
   646  		},
   647  		{
   648  			name:               "multicast v6AddrZone",
   649  			ip:                 multicastZone6,
   650  			linkLocalMulticast: true,
   651  			multicast:          true,
   652  		},
   653  		{
   654  			name:             "link-local unicast v4Addr",
   655  			ip:               llu4,
   656  			linkLocalUnicast: true,
   657  		},
   658  		{
   659  			name:             "link-local unicast v6Addr",
   660  			ip:               llu6,
   661  			linkLocalUnicast: true,
   662  		},
   663  		{
   664  			name:             "link-local unicast v6Addr upper bound",
   665  			ip:               llu6Last,
   666  			linkLocalUnicast: true,
   667  		},
   668  		{
   669  			name:             "link-local unicast v6AddrZone",
   670  			ip:               lluZone6,
   671  			linkLocalUnicast: true,
   672  		},
   673  		{
   674  			name:     "loopback v4Addr",
   675  			ip:       loopback4,
   676  			loopback: true,
   677  		},
   678  		{
   679  			name:     "loopback v6Addr",
   680  			ip:       loopback6,
   681  			loopback: true,
   682  		},
   683  		{
   684  			name:                    "interface-local multicast v6Addr",
   685  			ip:                      ilm6,
   686  			interfaceLocalMulticast: true,
   687  			multicast:               true,
   688  		},
   689  		{
   690  			name:                    "interface-local multicast v6AddrZone",
   691  			ip:                      ilmZone6,
   692  			interfaceLocalMulticast: true,
   693  			multicast:               true,
   694  		},
   695  		{
   696  			name:          "private v4Addr 10/8",
   697  			ip:            private4a,
   698  			globalUnicast: true,
   699  			private:       true,
   700  		},
   701  		{
   702  			name:          "private v4Addr 172.16/12",
   703  			ip:            private4b,
   704  			globalUnicast: true,
   705  			private:       true,
   706  		},
   707  		{
   708  			name:          "private v4Addr 192.168/16",
   709  			ip:            private4c,
   710  			globalUnicast: true,
   711  			private:       true,
   712  		},
   713  		{
   714  			name:          "private v6Addr",
   715  			ip:            private6,
   716  			globalUnicast: true,
   717  			private:       true,
   718  		},
   719  		{
   720  			name:        "unspecified v4Addr",
   721  			ip:          IPv4Unspecified(),
   722  			unspecified: true,
   723  		},
   724  		{
   725  			name:        "unspecified v6Addr",
   726  			ip:          IPv6Unspecified(),
   727  			unspecified: true,
   728  		},
   729  	}
   730  
   731  	for _, tt := range tests {
   732  		t.Run(tt.name, func(t *testing.T) {
   733  			gu := tt.ip.IsGlobalUnicast()
   734  			if gu != tt.globalUnicast {
   735  				t.Errorf("IsGlobalUnicast(%v) = %v; want %v", tt.ip, gu, tt.globalUnicast)
   736  			}
   737  
   738  			ilm := tt.ip.IsInterfaceLocalMulticast()
   739  			if ilm != tt.interfaceLocalMulticast {
   740  				t.Errorf("IsInterfaceLocalMulticast(%v) = %v; want %v", tt.ip, ilm, tt.interfaceLocalMulticast)
   741  			}
   742  
   743  			llu := tt.ip.IsLinkLocalUnicast()
   744  			if llu != tt.linkLocalUnicast {
   745  				t.Errorf("IsLinkLocalUnicast(%v) = %v; want %v", tt.ip, llu, tt.linkLocalUnicast)
   746  			}
   747  
   748  			llm := tt.ip.IsLinkLocalMulticast()
   749  			if llm != tt.linkLocalMulticast {
   750  				t.Errorf("IsLinkLocalMulticast(%v) = %v; want %v", tt.ip, llm, tt.linkLocalMulticast)
   751  			}
   752  
   753  			lo := tt.ip.IsLoopback()
   754  			if lo != tt.loopback {
   755  				t.Errorf("IsLoopback(%v) = %v; want %v", tt.ip, lo, tt.loopback)
   756  			}
   757  
   758  			multicast := tt.ip.IsMulticast()
   759  			if multicast != tt.multicast {
   760  				t.Errorf("IsMulticast(%v) = %v; want %v", tt.ip, multicast, tt.multicast)
   761  			}
   762  
   763  			private := tt.ip.IsPrivate()
   764  			if private != tt.private {
   765  				t.Errorf("IsPrivate(%v) = %v; want %v", tt.ip, private, tt.private)
   766  			}
   767  
   768  			unspecified := tt.ip.IsUnspecified()
   769  			if unspecified != tt.unspecified {
   770  				t.Errorf("IsUnspecified(%v) = %v; want %v", tt.ip, unspecified, tt.unspecified)
   771  			}
   772  		})
   773  	}
   774  }
   775  
   776  func TestAddrWellKnown(t *testing.T) {
   777  	tests := []struct {
   778  		name string
   779  		ip   Addr
   780  		std  net.IP
   781  	}{
   782  		{
   783  			name: "IPv6 link-local all nodes",
   784  			ip:   IPv6LinkLocalAllNodes(),
   785  			std:  net.IPv6linklocalallnodes,
   786  		},
   787  		{
   788  			name: "IPv6 unspecified",
   789  			ip:   IPv6Unspecified(),
   790  			std:  net.IPv6unspecified,
   791  		},
   792  	}
   793  
   794  	for _, tt := range tests {
   795  		t.Run(tt.name, func(t *testing.T) {
   796  			want := tt.std.String()
   797  			got := tt.ip.String()
   798  
   799  			if got != want {
   800  				t.Fatalf("got %s, want %s", got, want)
   801  			}
   802  		})
   803  	}
   804  }
   805  
   806  func TestLessCompare(t *testing.T) {
   807  	tests := []struct {
   808  		a, b Addr
   809  		want bool
   810  	}{
   811  		{Addr{}, Addr{}, false},
   812  		{Addr{}, mustIP("1.2.3.4"), true},
   813  		{mustIP("1.2.3.4"), Addr{}, false},
   814  
   815  		{mustIP("1.2.3.4"), mustIP("0102:0304::0"), true},
   816  		{mustIP("0102:0304::0"), mustIP("1.2.3.4"), false},
   817  		{mustIP("1.2.3.4"), mustIP("1.2.3.4"), false},
   818  
   819  		{mustIP("::1"), mustIP("::2"), true},
   820  		{mustIP("::1"), mustIP("::1%foo"), true},
   821  		{mustIP("::1%foo"), mustIP("::2"), true},
   822  		{mustIP("::2"), mustIP("::3"), true},
   823  
   824  		{mustIP("::"), mustIP("0.0.0.0"), false},
   825  		{mustIP("0.0.0.0"), mustIP("::"), true},
   826  
   827  		{mustIP("::1%a"), mustIP("::1%b"), true},
   828  		{mustIP("::1%a"), mustIP("::1%a"), false},
   829  		{mustIP("::1%b"), mustIP("::1%a"), false},
   830  	}
   831  	for _, tt := range tests {
   832  		got := tt.a.Less(tt.b)
   833  		if got != tt.want {
   834  			t.Errorf("Less(%q, %q) = %v; want %v", tt.a, tt.b, got, tt.want)
   835  		}
   836  		cmp := tt.a.Compare(tt.b)
   837  		if got && cmp != -1 {
   838  			t.Errorf("Less(%q, %q) = true, but Compare = %v (not -1)", tt.a, tt.b, cmp)
   839  		}
   840  		if cmp < -1 || cmp > 1 {
   841  			t.Errorf("bogus Compare return value %v", cmp)
   842  		}
   843  		if cmp == 0 && tt.a != tt.b {
   844  			t.Errorf("Compare(%q, %q) = 0; but not equal", tt.a, tt.b)
   845  		}
   846  		if cmp == 1 && !tt.b.Less(tt.a) {
   847  			t.Errorf("Compare(%q, %q) = 1; but b.Less(a) isn't true", tt.a, tt.b)
   848  		}
   849  
   850  		// Also check inverse.
   851  		if got == tt.want && got {
   852  			got2 := tt.b.Less(tt.a)
   853  			if got2 {
   854  				t.Errorf("Less(%q, %q) was correctly %v, but so was Less(%q, %q)", tt.a, tt.b, got, tt.b, tt.a)
   855  			}
   856  		}
   857  	}
   858  
   859  	// And just sort.
   860  	values := []Addr{
   861  		mustIP("::1"),
   862  		mustIP("::2"),
   863  		Addr{},
   864  		mustIP("1.2.3.4"),
   865  		mustIP("8.8.8.8"),
   866  		mustIP("::1%foo"),
   867  	}
   868  	sort.Slice(values, func(i, j int) bool { return values[i].Less(values[j]) })
   869  	got := fmt.Sprintf("%s", values)
   870  	want := `[invalid IP 1.2.3.4 8.8.8.8 ::1 ::1%foo ::2]`
   871  	if got != want {
   872  		t.Errorf("unexpected sort\n got: %s\nwant: %s\n", got, want)
   873  	}
   874  }
   875  
   876  func TestIPStringExpanded(t *testing.T) {
   877  	tests := []struct {
   878  		ip Addr
   879  		s  string
   880  	}{
   881  		{
   882  			ip: Addr{},
   883  			s:  "invalid IP",
   884  		},
   885  		{
   886  			ip: mustIP("192.0.2.1"),
   887  			s:  "192.0.2.1",
   888  		},
   889  		{
   890  			ip: mustIP("::ffff:192.0.2.1"),
   891  			s:  "0000:0000:0000:0000:0000:ffff:c000:0201",
   892  		},
   893  		{
   894  			ip: mustIP("2001:db8::1"),
   895  			s:  "2001:0db8:0000:0000:0000:0000:0000:0001",
   896  		},
   897  		{
   898  			ip: mustIP("2001:db8::1%eth0"),
   899  			s:  "2001:0db8:0000:0000:0000:0000:0000:0001%eth0",
   900  		},
   901  	}
   902  
   903  	for _, tt := range tests {
   904  		t.Run(tt.ip.String(), func(t *testing.T) {
   905  			want := tt.s
   906  			got := tt.ip.StringExpanded()
   907  
   908  			if got != want {
   909  				t.Fatalf("got %s, want %s", got, want)
   910  			}
   911  		})
   912  	}
   913  }
   914  
   915  func TestPrefixMasking(t *testing.T) {
   916  	type subtest struct {
   917  		ip   Addr
   918  		bits uint8
   919  		p    Prefix
   920  		ok   bool
   921  	}
   922  
   923  	// makeIPv6 produces a set of IPv6 subtests with an optional zone identifier.
   924  	makeIPv6 := func(zone string) []subtest {
   925  		if zone != "" {
   926  			zone = "%" + zone
   927  		}
   928  
   929  		return []subtest{
   930  			{
   931  				ip:   mustIP(fmt.Sprintf("2001:db8::1%s", zone)),
   932  				bits: 255,
   933  			},
   934  			{
   935  				ip:   mustIP(fmt.Sprintf("2001:db8::1%s", zone)),
   936  				bits: 32,
   937  				p:    mustPrefix("2001:db8::/32"),
   938  				ok:   true,
   939  			},
   940  			{
   941  				ip:   mustIP(fmt.Sprintf("fe80::dead:beef:dead:beef%s", zone)),
   942  				bits: 96,
   943  				p:    mustPrefix("fe80::dead:beef:0:0/96"),
   944  				ok:   true,
   945  			},
   946  			{
   947  				ip:   mustIP(fmt.Sprintf("aaaa::%s", zone)),
   948  				bits: 4,
   949  				p:    mustPrefix("a000::/4"),
   950  				ok:   true,
   951  			},
   952  			{
   953  				ip:   mustIP(fmt.Sprintf("::%s", zone)),
   954  				bits: 63,
   955  				p:    mustPrefix("::/63"),
   956  				ok:   true,
   957  			},
   958  		}
   959  	}
   960  
   961  	tests := []struct {
   962  		family   string
   963  		subtests []subtest
   964  	}{
   965  		{
   966  			family: "nil",
   967  			subtests: []subtest{
   968  				{
   969  					bits: 255,
   970  					ok:   true,
   971  				},
   972  				{
   973  					bits: 16,
   974  					ok:   true,
   975  				},
   976  			},
   977  		},
   978  		{
   979  			family: "IPv4",
   980  			subtests: []subtest{
   981  				{
   982  					ip:   mustIP("192.0.2.0"),
   983  					bits: 255,
   984  				},
   985  				{
   986  					ip:   mustIP("192.0.2.0"),
   987  					bits: 16,
   988  					p:    mustPrefix("192.0.0.0/16"),
   989  					ok:   true,
   990  				},
   991  				{
   992  					ip:   mustIP("255.255.255.255"),
   993  					bits: 20,
   994  					p:    mustPrefix("255.255.240.0/20"),
   995  					ok:   true,
   996  				},
   997  				{
   998  					// Partially masking one byte that contains both
   999  					// 1s and 0s on either side of the mask limit.
  1000  					ip:   mustIP("100.98.156.66"),
  1001  					bits: 10,
  1002  					p:    mustPrefix("100.64.0.0/10"),
  1003  					ok:   true,
  1004  				},
  1005  			},
  1006  		},
  1007  		{
  1008  			family:   "IPv6",
  1009  			subtests: makeIPv6(""),
  1010  		},
  1011  		{
  1012  			family:   "IPv6 zone",
  1013  			subtests: makeIPv6("eth0"),
  1014  		},
  1015  	}
  1016  
  1017  	for _, tt := range tests {
  1018  		t.Run(tt.family, func(t *testing.T) {
  1019  			for _, st := range tt.subtests {
  1020  				t.Run(st.p.String(), func(t *testing.T) {
  1021  					// Ensure st.ip is not mutated.
  1022  					orig := st.ip.String()
  1023  
  1024  					p, err := st.ip.Prefix(int(st.bits))
  1025  					if st.ok && err != nil {
  1026  						t.Fatalf("failed to produce prefix: %v", err)
  1027  					}
  1028  					if !st.ok && err == nil {
  1029  						t.Fatal("expected an error, but none occurred")
  1030  					}
  1031  					if err != nil {
  1032  						t.Logf("err: %v", err)
  1033  						return
  1034  					}
  1035  
  1036  					if !reflect.DeepEqual(p, st.p) {
  1037  						t.Errorf("prefix = %q, want %q", p, st.p)
  1038  					}
  1039  
  1040  					if got := st.ip.String(); got != orig {
  1041  						t.Errorf("IP was mutated: %q, want %q", got, orig)
  1042  					}
  1043  				})
  1044  			}
  1045  		})
  1046  	}
  1047  }
  1048  
  1049  func TestPrefixMarshalUnmarshal(t *testing.T) {
  1050  	tests := []string{
  1051  		"",
  1052  		"1.2.3.4/32",
  1053  		"0.0.0.0/0",
  1054  		"::/0",
  1055  		"::1/128",
  1056  		"2001:db8::/32",
  1057  	}
  1058  
  1059  	for _, s := range tests {
  1060  		t.Run(s, func(t *testing.T) {
  1061  			// Ensure that JSON  (and by extension, text) marshaling is
  1062  			// sane by entering quoted input.
  1063  			orig := `"` + s + `"`
  1064  
  1065  			var p Prefix
  1066  			if err := json.Unmarshal([]byte(orig), &p); err != nil {
  1067  				t.Fatalf("failed to unmarshal: %v", err)
  1068  			}
  1069  
  1070  			pb, err := json.Marshal(p)
  1071  			if err != nil {
  1072  				t.Fatalf("failed to marshal: %v", err)
  1073  			}
  1074  
  1075  			back := string(pb)
  1076  			if orig != back {
  1077  				t.Errorf("Marshal = %q; want %q", back, orig)
  1078  			}
  1079  		})
  1080  	}
  1081  }
  1082  
  1083  func TestPrefixUnmarshalTextNonZero(t *testing.T) {
  1084  	ip := mustPrefix("fe80::/64")
  1085  	if err := ip.UnmarshalText([]byte("xxx")); err == nil {
  1086  		t.Fatal("unmarshaled into non-empty Prefix")
  1087  	}
  1088  }
  1089  
  1090  func TestIs4AndIs6(t *testing.T) {
  1091  	tests := []struct {
  1092  		ip  Addr
  1093  		is4 bool
  1094  		is6 bool
  1095  	}{
  1096  		{Addr{}, false, false},
  1097  		{mustIP("1.2.3.4"), true, false},
  1098  		{mustIP("127.0.0.2"), true, false},
  1099  		{mustIP("::1"), false, true},
  1100  		{mustIP("::ffff:192.0.2.128"), false, true},
  1101  		{mustIP("::fffe:c000:0280"), false, true},
  1102  		{mustIP("::1%eth0"), false, true},
  1103  	}
  1104  	for _, tt := range tests {
  1105  		got4 := tt.ip.Is4()
  1106  		if got4 != tt.is4 {
  1107  			t.Errorf("Is4(%q) = %v; want %v", tt.ip, got4, tt.is4)
  1108  		}
  1109  
  1110  		got6 := tt.ip.Is6()
  1111  		if got6 != tt.is6 {
  1112  			t.Errorf("Is6(%q) = %v; want %v", tt.ip, got6, tt.is6)
  1113  		}
  1114  	}
  1115  }
  1116  
  1117  func TestIs4In6(t *testing.T) {
  1118  	tests := []struct {
  1119  		ip        Addr
  1120  		want      bool
  1121  		wantUnmap Addr
  1122  	}{
  1123  		{Addr{}, false, Addr{}},
  1124  		{mustIP("::ffff:c000:0280"), true, mustIP("192.0.2.128")},
  1125  		{mustIP("::ffff:192.0.2.128"), true, mustIP("192.0.2.128")},
  1126  		{mustIP("::ffff:192.0.2.128%eth0"), true, mustIP("192.0.2.128")},
  1127  		{mustIP("::fffe:c000:0280"), false, mustIP("::fffe:c000:0280")},
  1128  		{mustIP("::ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
  1129  		{mustIP("::ffff:7f01:0203"), true, mustIP("127.1.2.3")},
  1130  		{mustIP("0:0:0:0:0000:ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
  1131  		{mustIP("0:0:0:0:000000:ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
  1132  		{mustIP("0:0:0:0::ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
  1133  		{mustIP("::1"), false, mustIP("::1")},
  1134  		{mustIP("1.2.3.4"), false, mustIP("1.2.3.4")},
  1135  	}
  1136  	for _, tt := range tests {
  1137  		got := tt.ip.Is4In6()
  1138  		if got != tt.want {
  1139  			t.Errorf("Is4In6(%q) = %v; want %v", tt.ip, got, tt.want)
  1140  		}
  1141  		u := tt.ip.Unmap()
  1142  		if u != tt.wantUnmap {
  1143  			t.Errorf("Unmap(%q) = %v; want %v", tt.ip, u, tt.wantUnmap)
  1144  		}
  1145  	}
  1146  }
  1147  
  1148  func TestPrefixMasked(t *testing.T) {
  1149  	tests := []struct {
  1150  		prefix Prefix
  1151  		masked Prefix
  1152  	}{
  1153  		{
  1154  			prefix: mustPrefix("192.168.0.255/24"),
  1155  			masked: mustPrefix("192.168.0.0/24"),
  1156  		},
  1157  		{
  1158  			prefix: mustPrefix("2100::/3"),
  1159  			masked: mustPrefix("2000::/3"),
  1160  		},
  1161  		{
  1162  			prefix: PrefixFrom(mustIP("2000::"), 129),
  1163  			masked: Prefix{},
  1164  		},
  1165  		{
  1166  			prefix: PrefixFrom(mustIP("1.2.3.4"), 33),
  1167  			masked: Prefix{},
  1168  		},
  1169  	}
  1170  	for _, test := range tests {
  1171  		t.Run(test.prefix.String(), func(t *testing.T) {
  1172  			got := test.prefix.Masked()
  1173  			if got != test.masked {
  1174  				t.Errorf("Masked=%s, want %s", got, test.masked)
  1175  			}
  1176  		})
  1177  	}
  1178  }
  1179  
  1180  func TestPrefix(t *testing.T) {
  1181  	tests := []struct {
  1182  		prefix      string
  1183  		ip          Addr
  1184  		bits        int
  1185  		str         string
  1186  		contains    []Addr
  1187  		notContains []Addr
  1188  	}{
  1189  		{
  1190  			prefix:      "192.168.0.0/24",
  1191  			ip:          mustIP("192.168.0.0"),
  1192  			bits:        24,
  1193  			contains:    mustIPs("192.168.0.1", "192.168.0.55"),
  1194  			notContains: mustIPs("192.168.1.1", "1.1.1.1"),
  1195  		},
  1196  		{
  1197  			prefix:      "192.168.1.1/32",
  1198  			ip:          mustIP("192.168.1.1"),
  1199  			bits:        32,
  1200  			contains:    mustIPs("192.168.1.1"),
  1201  			notContains: mustIPs("192.168.1.2"),
  1202  		},
  1203  		{
  1204  			prefix:      "100.64.0.0/10", // CGNAT range; prefix not multiple of 8
  1205  			ip:          mustIP("100.64.0.0"),
  1206  			bits:        10,
  1207  			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"),
  1208  			notContains: mustIPs("100.63.255.255", "100.128.0.0"),
  1209  		},
  1210  		{
  1211  			prefix:      "2001:db8::/96",
  1212  			ip:          mustIP("2001:db8::"),
  1213  			bits:        96,
  1214  			contains:    mustIPs("2001:db8::aaaa:bbbb", "2001:db8::1"),
  1215  			notContains: mustIPs("2001:db8::1:aaaa:bbbb", "2001:db9::"),
  1216  		},
  1217  		{
  1218  			prefix:      "0.0.0.0/0",
  1219  			ip:          mustIP("0.0.0.0"),
  1220  			bits:        0,
  1221  			contains:    mustIPs("192.168.0.1", "1.1.1.1"),
  1222  			notContains: append(mustIPs("2001:db8::1"), Addr{}),
  1223  		},
  1224  		{
  1225  			prefix:      "::/0",
  1226  			ip:          mustIP("::"),
  1227  			bits:        0,
  1228  			contains:    mustIPs("::1", "2001:db8::1"),
  1229  			notContains: mustIPs("192.0.2.1"),
  1230  		},
  1231  		{
  1232  			prefix:      "2000::/3",
  1233  			ip:          mustIP("2000::"),
  1234  			bits:        3,
  1235  			contains:    mustIPs("2001:db8::1"),
  1236  			notContains: mustIPs("fe80::1"),
  1237  		},
  1238  	}
  1239  	for _, test := range tests {
  1240  		t.Run(test.prefix, func(t *testing.T) {
  1241  			prefix, err := ParsePrefix(test.prefix)
  1242  			if err != nil {
  1243  				t.Fatal(err)
  1244  			}
  1245  			if prefix.Addr() != test.ip {
  1246  				t.Errorf("IP=%s, want %s", prefix.Addr(), test.ip)
  1247  			}
  1248  			if prefix.Bits() != test.bits {
  1249  				t.Errorf("bits=%d, want %d", prefix.Bits(), test.bits)
  1250  			}
  1251  			for _, ip := range test.contains {
  1252  				if !prefix.Contains(ip) {
  1253  					t.Errorf("does not contain %s", ip)
  1254  				}
  1255  			}
  1256  			for _, ip := range test.notContains {
  1257  				if prefix.Contains(ip) {
  1258  					t.Errorf("contains %s", ip)
  1259  				}
  1260  			}
  1261  			want := test.str
  1262  			if want == "" {
  1263  				want = test.prefix
  1264  			}
  1265  			if got := prefix.String(); got != want {
  1266  				t.Errorf("prefix.String()=%q, want %q", got, want)
  1267  			}
  1268  
  1269  			TestAppendToMarshal(t, prefix)
  1270  		})
  1271  	}
  1272  }
  1273  
  1274  func TestPrefixFromInvalidBits(t *testing.T) {
  1275  	v4 := MustParseAddr("1.2.3.4")
  1276  	v6 := MustParseAddr("66::66")
  1277  	tests := []struct {
  1278  		ip       Addr
  1279  		in, want int
  1280  	}{
  1281  		{v4, 0, 0},
  1282  		{v6, 0, 0},
  1283  		{v4, 1, 1},
  1284  		{v4, 33, -1},
  1285  		{v6, 33, 33},
  1286  		{v6, 127, 127},
  1287  		{v6, 128, 128},
  1288  		{v4, 254, -1},
  1289  		{v4, 255, -1},
  1290  		{v4, -1, -1},
  1291  		{v6, -1, -1},
  1292  		{v4, -5, -1},
  1293  		{v6, -5, -1},
  1294  	}
  1295  	for _, tt := range tests {
  1296  		p := PrefixFrom(tt.ip, tt.in)
  1297  		if got := p.Bits(); got != tt.want {
  1298  			t.Errorf("for (%v, %v), Bits out = %v; want %v", tt.ip, tt.in, got, tt.want)
  1299  		}
  1300  	}
  1301  }
  1302  
  1303  func TestParsePrefixAllocs(t *testing.T) {
  1304  	tests := []struct {
  1305  		ip    string
  1306  		slash string
  1307  	}{
  1308  		{"192.168.1.0", "/24"},
  1309  		{"aaaa:bbbb:cccc::", "/24"},
  1310  	}
  1311  	for _, test := range tests {
  1312  		prefix := test.ip + test.slash
  1313  		t.Run(prefix, func(t *testing.T) {
  1314  			ipAllocs := int(testing.AllocsPerRun(5, func() {
  1315  				ParseAddr(test.ip)
  1316  			}))
  1317  			prefixAllocs := int(testing.AllocsPerRun(5, func() {
  1318  				ParsePrefix(prefix)
  1319  			}))
  1320  			if got := prefixAllocs - ipAllocs; got != 0 {
  1321  				t.Errorf("allocs=%d, want 0", got)
  1322  			}
  1323  		})
  1324  	}
  1325  }
  1326  
  1327  func TestParsePrefixError(t *testing.T) {
  1328  	tests := []struct {
  1329  		prefix string
  1330  		errstr string
  1331  	}{
  1332  		{
  1333  			prefix: "192.168.0.0",
  1334  			errstr: "no '/'",
  1335  		},
  1336  		{
  1337  			prefix: "1.257.1.1/24",
  1338  			errstr: "value >255",
  1339  		},
  1340  		{
  1341  			prefix: "1.1.1.0/q",
  1342  			errstr: "bad bits",
  1343  		},
  1344  		{
  1345  			prefix: "1.1.1.0/-1",
  1346  			errstr: "out of range",
  1347  		},
  1348  		{
  1349  			prefix: "1.1.1.0/33",
  1350  			errstr: "out of range",
  1351  		},
  1352  		{
  1353  			prefix: "2001::/129",
  1354  			errstr: "out of range",
  1355  		},
  1356  		// Zones are not allowed: https://go.dev/issue/51899
  1357  		{
  1358  			prefix: "1.1.1.0%a/24",
  1359  			errstr: "unexpected character",
  1360  		},
  1361  		{
  1362  			prefix: "2001:db8::%a/32",
  1363  			errstr: "zones cannot be present",
  1364  		},
  1365  	}
  1366  	for _, test := range tests {
  1367  		t.Run(test.prefix, func(t *testing.T) {
  1368  			_, err := ParsePrefix(test.prefix)
  1369  			if err == nil {
  1370  				t.Fatal("no error")
  1371  			}
  1372  			if got := err.Error(); !strings.Contains(got, test.errstr) {
  1373  				t.Errorf("error is missing substring %q: %s", test.errstr, got)
  1374  			}
  1375  		})
  1376  	}
  1377  }
  1378  
  1379  func TestPrefixIsSingleIP(t *testing.T) {
  1380  	tests := []struct {
  1381  		ipp  Prefix
  1382  		want bool
  1383  	}{
  1384  		{ipp: mustPrefix("127.0.0.1/32"), want: true},
  1385  		{ipp: mustPrefix("127.0.0.1/31"), want: false},
  1386  		{ipp: mustPrefix("127.0.0.1/0"), want: false},
  1387  		{ipp: mustPrefix("::1/128"), want: true},
  1388  		{ipp: mustPrefix("::1/127"), want: false},
  1389  		{ipp: mustPrefix("::1/0"), want: false},
  1390  		{ipp: Prefix{}, want: false},
  1391  	}
  1392  	for _, tt := range tests {
  1393  		got := tt.ipp.IsSingleIP()
  1394  		if got != tt.want {
  1395  			t.Errorf("IsSingleIP(%v) = %v want %v", tt.ipp, got, tt.want)
  1396  		}
  1397  	}
  1398  }
  1399  
  1400  func mustIPs(strs ...string) []Addr {
  1401  	var res []Addr
  1402  	for _, s := range strs {
  1403  		res = append(res, mustIP(s))
  1404  	}
  1405  	return res
  1406  }
  1407  
  1408  func BenchmarkBinaryMarshalRoundTrip(b *testing.B) {
  1409  	b.ReportAllocs()
  1410  	tests := []struct {
  1411  		name string
  1412  		ip   string
  1413  	}{
  1414  		{"ipv4", "1.2.3.4"},
  1415  		{"ipv6", "2001:db8::1"},
  1416  		{"ipv6+zone", "2001:db8::1%eth0"},
  1417  	}
  1418  	for _, tc := range tests {
  1419  		b.Run(tc.name, func(b *testing.B) {
  1420  			ip := mustIP(tc.ip)
  1421  			for i := 0; i < b.N; i++ {
  1422  				bt, err := ip.MarshalBinary()
  1423  				if err != nil {
  1424  					b.Fatal(err)
  1425  				}
  1426  				var ip2 Addr
  1427  				if err := ip2.UnmarshalBinary(bt); err != nil {
  1428  					b.Fatal(err)
  1429  				}
  1430  			}
  1431  		})
  1432  	}
  1433  }
  1434  
  1435  func BenchmarkStdIPv4(b *testing.B) {
  1436  	b.ReportAllocs()
  1437  	ips := []net.IP{}
  1438  	for i := 0; i < b.N; i++ {
  1439  		ip := net.IPv4(8, 8, 8, 8)
  1440  		ips = ips[:0]
  1441  		for i := 0; i < 100; i++ {
  1442  			ips = append(ips, ip)
  1443  		}
  1444  	}
  1445  }
  1446  
  1447  func BenchmarkIPv4(b *testing.B) {
  1448  	b.ReportAllocs()
  1449  	ips := []Addr{}
  1450  	for i := 0; i < b.N; i++ {
  1451  		ip := IPv4(8, 8, 8, 8)
  1452  		ips = ips[:0]
  1453  		for i := 0; i < 100; i++ {
  1454  			ips = append(ips, ip)
  1455  		}
  1456  	}
  1457  }
  1458  
  1459  // ip4i was one of the possible representations of IP that came up in
  1460  // discussions, inlining IPv4 addresses, but having an "overflow"
  1461  // interface for IPv6 or IPv6 + zone. This is here for benchmarking.
  1462  type ip4i struct {
  1463  	ip4    [4]byte
  1464  	flags1 byte
  1465  	flags2 byte
  1466  	flags3 byte
  1467  	flags4 byte
  1468  	ipv6   any
  1469  }
  1470  
  1471  func newip4i_v4(a, b, c, d byte) ip4i {
  1472  	return ip4i{ip4: [4]byte{a, b, c, d}}
  1473  }
  1474  
  1475  // BenchmarkIPv4_inline benchmarks the candidate representation, ip4i.
  1476  func BenchmarkIPv4_inline(b *testing.B) {
  1477  	b.ReportAllocs()
  1478  	ips := []ip4i{}
  1479  	for i := 0; i < b.N; i++ {
  1480  		ip := newip4i_v4(8, 8, 8, 8)
  1481  		ips = ips[:0]
  1482  		for i := 0; i < 100; i++ {
  1483  			ips = append(ips, ip)
  1484  		}
  1485  	}
  1486  }
  1487  
  1488  func BenchmarkStdIPv6(b *testing.B) {
  1489  	b.ReportAllocs()
  1490  	ips := []net.IP{}
  1491  	for i := 0; i < b.N; i++ {
  1492  		ip := net.ParseIP("2001:db8::1")
  1493  		ips = ips[:0]
  1494  		for i := 0; i < 100; i++ {
  1495  			ips = append(ips, ip)
  1496  		}
  1497  	}
  1498  }
  1499  
  1500  func BenchmarkIPv6(b *testing.B) {
  1501  	b.ReportAllocs()
  1502  	ips := []Addr{}
  1503  	for i := 0; i < b.N; i++ {
  1504  		ip := mustIP("2001:db8::1")
  1505  		ips = ips[:0]
  1506  		for i := 0; i < 100; i++ {
  1507  			ips = append(ips, ip)
  1508  		}
  1509  	}
  1510  }
  1511  
  1512  func BenchmarkIPv4Contains(b *testing.B) {
  1513  	b.ReportAllocs()
  1514  	prefix := PrefixFrom(IPv4(192, 168, 1, 0), 24)
  1515  	ip := IPv4(192, 168, 1, 1)
  1516  	for i := 0; i < b.N; i++ {
  1517  		prefix.Contains(ip)
  1518  	}
  1519  }
  1520  
  1521  func BenchmarkIPv6Contains(b *testing.B) {
  1522  	b.ReportAllocs()
  1523  	prefix := MustParsePrefix("::1/128")
  1524  	ip := MustParseAddr("::1")
  1525  	for i := 0; i < b.N; i++ {
  1526  		prefix.Contains(ip)
  1527  	}
  1528  }
  1529  
  1530  var parseBenchInputs = []struct {
  1531  	name string
  1532  	ip   string
  1533  }{
  1534  	{"v4", "192.168.1.1"},
  1535  	{"v6", "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b"},
  1536  	{"v6_ellipsis", "fd7a:115c::626b:430b"},
  1537  	{"v6_v4", "::ffff:192.168.140.255"},
  1538  	{"v6_zone", "1:2::ffff:192.168.140.255%eth1"},
  1539  }
  1540  
  1541  func BenchmarkParseAddr(b *testing.B) {
  1542  	sinkInternValue = intern.Get("eth1") // Pin to not benchmark the intern package
  1543  	for _, test := range parseBenchInputs {
  1544  		b.Run(test.name, func(b *testing.B) {
  1545  			b.ReportAllocs()
  1546  			for i := 0; i < b.N; i++ {
  1547  				sinkIP, _ = ParseAddr(test.ip)
  1548  			}
  1549  		})
  1550  	}
  1551  }
  1552  
  1553  func BenchmarkStdParseIP(b *testing.B) {
  1554  	for _, test := range parseBenchInputs {
  1555  		b.Run(test.name, func(b *testing.B) {
  1556  			b.ReportAllocs()
  1557  			for i := 0; i < b.N; i++ {
  1558  				sinkStdIP = net.ParseIP(test.ip)
  1559  			}
  1560  		})
  1561  	}
  1562  }
  1563  
  1564  func BenchmarkIPString(b *testing.B) {
  1565  	for _, test := range parseBenchInputs {
  1566  		ip := MustParseAddr(test.ip)
  1567  		b.Run(test.name, func(b *testing.B) {
  1568  			b.ReportAllocs()
  1569  			for i := 0; i < b.N; i++ {
  1570  				sinkString = ip.String()
  1571  			}
  1572  		})
  1573  	}
  1574  }
  1575  
  1576  func BenchmarkIPStringExpanded(b *testing.B) {
  1577  	for _, test := range parseBenchInputs {
  1578  		ip := MustParseAddr(test.ip)
  1579  		b.Run(test.name, func(b *testing.B) {
  1580  			b.ReportAllocs()
  1581  			for i := 0; i < b.N; i++ {
  1582  				sinkString = ip.StringExpanded()
  1583  			}
  1584  		})
  1585  	}
  1586  }
  1587  
  1588  func BenchmarkIPMarshalText(b *testing.B) {
  1589  	b.ReportAllocs()
  1590  	ip := MustParseAddr("66.55.44.33")
  1591  	for i := 0; i < b.N; i++ {
  1592  		sinkBytes, _ = ip.MarshalText()
  1593  	}
  1594  }
  1595  
  1596  func BenchmarkAddrPortString(b *testing.B) {
  1597  	for _, test := range parseBenchInputs {
  1598  		ip := MustParseAddr(test.ip)
  1599  		ipp := AddrPortFrom(ip, 60000)
  1600  		b.Run(test.name, func(b *testing.B) {
  1601  			b.ReportAllocs()
  1602  			for i := 0; i < b.N; i++ {
  1603  				sinkString = ipp.String()
  1604  			}
  1605  		})
  1606  	}
  1607  }
  1608  
  1609  func BenchmarkAddrPortMarshalText(b *testing.B) {
  1610  	for _, test := range parseBenchInputs {
  1611  		ip := MustParseAddr(test.ip)
  1612  		ipp := AddrPortFrom(ip, 60000)
  1613  		b.Run(test.name, func(b *testing.B) {
  1614  			b.ReportAllocs()
  1615  			for i := 0; i < b.N; i++ {
  1616  				sinkBytes, _ = ipp.MarshalText()
  1617  			}
  1618  		})
  1619  	}
  1620  }
  1621  
  1622  func BenchmarkPrefixMasking(b *testing.B) {
  1623  	tests := []struct {
  1624  		name string
  1625  		ip   Addr
  1626  		bits int
  1627  	}{
  1628  		{
  1629  			name: "IPv4 /32",
  1630  			ip:   IPv4(192, 0, 2, 0),
  1631  			bits: 32,
  1632  		},
  1633  		{
  1634  			name: "IPv4 /17",
  1635  			ip:   IPv4(192, 0, 2, 0),
  1636  			bits: 17,
  1637  		},
  1638  		{
  1639  			name: "IPv4 /0",
  1640  			ip:   IPv4(192, 0, 2, 0),
  1641  			bits: 0,
  1642  		},
  1643  		{
  1644  			name: "IPv6 /128",
  1645  			ip:   mustIP("2001:db8::1"),
  1646  			bits: 128,
  1647  		},
  1648  		{
  1649  			name: "IPv6 /65",
  1650  			ip:   mustIP("2001:db8::1"),
  1651  			bits: 65,
  1652  		},
  1653  		{
  1654  			name: "IPv6 /0",
  1655  			ip:   mustIP("2001:db8::1"),
  1656  			bits: 0,
  1657  		},
  1658  		{
  1659  			name: "IPv6 zone /128",
  1660  			ip:   mustIP("2001:db8::1%eth0"),
  1661  			bits: 128,
  1662  		},
  1663  		{
  1664  			name: "IPv6 zone /65",
  1665  			ip:   mustIP("2001:db8::1%eth0"),
  1666  			bits: 65,
  1667  		},
  1668  		{
  1669  			name: "IPv6 zone /0",
  1670  			ip:   mustIP("2001:db8::1%eth0"),
  1671  			bits: 0,
  1672  		},
  1673  	}
  1674  
  1675  	for _, tt := range tests {
  1676  		b.Run(tt.name, func(b *testing.B) {
  1677  			b.ReportAllocs()
  1678  
  1679  			for i := 0; i < b.N; i++ {
  1680  				sinkPrefix, _ = tt.ip.Prefix(tt.bits)
  1681  			}
  1682  		})
  1683  	}
  1684  }
  1685  
  1686  func BenchmarkPrefixMarshalText(b *testing.B) {
  1687  	b.ReportAllocs()
  1688  	ipp := MustParsePrefix("66.55.44.33/22")
  1689  	for i := 0; i < b.N; i++ {
  1690  		sinkBytes, _ = ipp.MarshalText()
  1691  	}
  1692  }
  1693  
  1694  func BenchmarkParseAddrPort(b *testing.B) {
  1695  	for _, test := range parseBenchInputs {
  1696  		var ipp string
  1697  		if strings.HasPrefix(test.name, "v6") {
  1698  			ipp = fmt.Sprintf("[%s]:1234", test.ip)
  1699  		} else {
  1700  			ipp = fmt.Sprintf("%s:1234", test.ip)
  1701  		}
  1702  		b.Run(test.name, func(b *testing.B) {
  1703  			b.ReportAllocs()
  1704  
  1705  			for i := 0; i < b.N; i++ {
  1706  				sinkAddrPort, _ = ParseAddrPort(ipp)
  1707  			}
  1708  		})
  1709  	}
  1710  }
  1711  
  1712  func TestAs4(t *testing.T) {
  1713  	tests := []struct {
  1714  		ip        Addr
  1715  		want      [4]byte
  1716  		wantPanic bool
  1717  	}{
  1718  		{
  1719  			ip:   mustIP("1.2.3.4"),
  1720  			want: [4]byte{1, 2, 3, 4},
  1721  		},
  1722  		{
  1723  			ip:   AddrFrom16(mustIP("1.2.3.4").As16()), // IPv4-in-IPv6
  1724  			want: [4]byte{1, 2, 3, 4},
  1725  		},
  1726  		{
  1727  			ip:   mustIP("0.0.0.0"),
  1728  			want: [4]byte{0, 0, 0, 0},
  1729  		},
  1730  		{
  1731  			ip:        Addr{},
  1732  			wantPanic: true,
  1733  		},
  1734  		{
  1735  			ip:        mustIP("::1"),
  1736  			wantPanic: true,
  1737  		},
  1738  	}
  1739  	as4 := func(ip Addr) (v [4]byte, gotPanic bool) {
  1740  		defer func() {
  1741  			if recover() != nil {
  1742  				gotPanic = true
  1743  				return
  1744  			}
  1745  		}()
  1746  		v = ip.As4()
  1747  		return
  1748  	}
  1749  	for i, tt := range tests {
  1750  		got, gotPanic := as4(tt.ip)
  1751  		if gotPanic != tt.wantPanic {
  1752  			t.Errorf("%d. panic on %v = %v; want %v", i, tt.ip, gotPanic, tt.wantPanic)
  1753  			continue
  1754  		}
  1755  		if got != tt.want {
  1756  			t.Errorf("%d. %v = %v; want %v", i, tt.ip, got, tt.want)
  1757  		}
  1758  	}
  1759  }
  1760  
  1761  func TestPrefixOverlaps(t *testing.T) {
  1762  	pfx := mustPrefix
  1763  	tests := []struct {
  1764  		a, b Prefix
  1765  		want bool
  1766  	}{
  1767  		{Prefix{}, pfx("1.2.0.0/16"), false},    // first zero
  1768  		{pfx("1.2.0.0/16"), Prefix{}, false},    // second zero
  1769  		{pfx("::0/3"), pfx("0.0.0.0/3"), false}, // different families
  1770  
  1771  		{pfx("1.2.0.0/16"), pfx("1.2.0.0/16"), true}, // equal
  1772  
  1773  		{pfx("1.2.0.0/16"), pfx("1.2.3.0/24"), true},
  1774  		{pfx("1.2.3.0/24"), pfx("1.2.0.0/16"), true},
  1775  
  1776  		{pfx("1.2.0.0/16"), pfx("1.2.3.0/32"), true},
  1777  		{pfx("1.2.3.0/32"), pfx("1.2.0.0/16"), true},
  1778  
  1779  		// Match /0 either order
  1780  		{pfx("1.2.3.0/32"), pfx("0.0.0.0/0"), true},
  1781  		{pfx("0.0.0.0/0"), pfx("1.2.3.0/32"), true},
  1782  
  1783  		{pfx("1.2.3.0/32"), pfx("5.5.5.5/0"), true}, // normalization not required; /0 means true
  1784  
  1785  		// IPv6 overlapping
  1786  		{pfx("5::1/128"), pfx("5::0/8"), true},
  1787  		{pfx("5::0/8"), pfx("5::1/128"), true},
  1788  
  1789  		// IPv6 not overlapping
  1790  		{pfx("1::1/128"), pfx("2::2/128"), false},
  1791  		{pfx("0100::0/8"), pfx("::1/128"), false},
  1792  
  1793  		// IPv4-mapped IPv6 addresses should not overlap with IPv4.
  1794  		{PrefixFrom(AddrFrom16(mustIP("1.2.0.0").As16()), 16), pfx("1.2.3.0/24"), false},
  1795  
  1796  		// Invalid prefixes
  1797  		{PrefixFrom(mustIP("1.2.3.4"), 33), pfx("1.2.3.0/24"), false},
  1798  		{PrefixFrom(mustIP("2000::"), 129), pfx("2000::/64"), false},
  1799  	}
  1800  	for i, tt := range tests {
  1801  		if got := tt.a.Overlaps(tt.b); got != tt.want {
  1802  			t.Errorf("%d. (%v).Overlaps(%v) = %v; want %v", i, tt.a, tt.b, got, tt.want)
  1803  		}
  1804  		// Overlaps is commutative
  1805  		if got := tt.b.Overlaps(tt.a); got != tt.want {
  1806  			t.Errorf("%d. (%v).Overlaps(%v) = %v; want %v", i, tt.b, tt.a, got, tt.want)
  1807  		}
  1808  	}
  1809  }
  1810  
  1811  // Sink variables are here to force the compiler to not elide
  1812  // seemingly useless work in benchmarks and allocation tests. If you
  1813  // were to just `_ = foo()` within a test function, the compiler could
  1814  // correctly deduce that foo() does nothing and doesn't need to be
  1815  // called. By writing results to a global variable, we hide that fact
  1816  // from the compiler and force it to keep the code under test.
  1817  var (
  1818  	sinkIP          Addr
  1819  	sinkStdIP       net.IP
  1820  	sinkAddrPort    AddrPort
  1821  	sinkPrefix      Prefix
  1822  	sinkPrefixSlice []Prefix
  1823  	sinkInternValue *intern.Value
  1824  	sinkIP16        [16]byte
  1825  	sinkIP4         [4]byte
  1826  	sinkBool        bool
  1827  	sinkString      string
  1828  	sinkBytes       []byte
  1829  	sinkUDPAddr     = &net.UDPAddr{IP: make(net.IP, 0, 16)}
  1830  )
  1831  
  1832  func TestNoAllocs(t *testing.T) {
  1833  	// Wrappers that panic on error, to prove that our alloc-free
  1834  	// methods are returning successfully.
  1835  	panicIP := func(ip Addr, err error) Addr {
  1836  		if err != nil {
  1837  			panic(err)
  1838  		}
  1839  		return ip
  1840  	}
  1841  	panicPfx := func(pfx Prefix, err error) Prefix {
  1842  		if err != nil {
  1843  			panic(err)
  1844  		}
  1845  		return pfx
  1846  	}
  1847  	panicIPP := func(ipp AddrPort, err error) AddrPort {
  1848  		if err != nil {
  1849  			panic(err)
  1850  		}
  1851  		return ipp
  1852  	}
  1853  	test := func(name string, f func()) {
  1854  		t.Run(name, func(t *testing.T) {
  1855  			n := testing.AllocsPerRun(1000, f)
  1856  			if n != 0 {
  1857  				t.Fatalf("allocs = %d; want 0", int(n))
  1858  			}
  1859  		})
  1860  	}
  1861  
  1862  	// IP constructors
  1863  	test("IPv4", func() { sinkIP = IPv4(1, 2, 3, 4) })
  1864  	test("AddrFrom4", func() { sinkIP = AddrFrom4([4]byte{1, 2, 3, 4}) })
  1865  	test("AddrFrom16", func() { sinkIP = AddrFrom16([16]byte{}) })
  1866  	test("ParseAddr/4", func() { sinkIP = panicIP(ParseAddr("1.2.3.4")) })
  1867  	test("ParseAddr/6", func() { sinkIP = panicIP(ParseAddr("::1")) })
  1868  	test("MustParseAddr", func() { sinkIP = MustParseAddr("1.2.3.4") })
  1869  	test("IPv6LinkLocalAllNodes", func() { sinkIP = IPv6LinkLocalAllNodes() })
  1870  	test("IPv6Unspecified", func() { sinkIP = IPv6Unspecified() })
  1871  
  1872  	// IP methods
  1873  	test("IP.IsZero", func() { sinkBool = MustParseAddr("1.2.3.4").IsZero() })
  1874  	test("IP.BitLen", func() { sinkBool = MustParseAddr("1.2.3.4").BitLen() == 8 })
  1875  	test("IP.Zone/4", func() { sinkBool = MustParseAddr("1.2.3.4").Zone() == "" })
  1876  	test("IP.Zone/6", func() { sinkBool = MustParseAddr("fe80::1").Zone() == "" })
  1877  	test("IP.Zone/6zone", func() { sinkBool = MustParseAddr("fe80::1%zone").Zone() == "" })
  1878  	test("IP.Compare", func() {
  1879  		a := MustParseAddr("1.2.3.4")
  1880  		b := MustParseAddr("2.3.4.5")
  1881  		sinkBool = a.Compare(b) == 0
  1882  	})
  1883  	test("IP.Less", func() {
  1884  		a := MustParseAddr("1.2.3.4")
  1885  		b := MustParseAddr("2.3.4.5")
  1886  		sinkBool = a.Less(b)
  1887  	})
  1888  	test("IP.Is4", func() { sinkBool = MustParseAddr("1.2.3.4").Is4() })
  1889  	test("IP.Is6", func() { sinkBool = MustParseAddr("fe80::1").Is6() })
  1890  	test("IP.Is4In6", func() { sinkBool = MustParseAddr("fe80::1").Is4In6() })
  1891  	test("IP.Unmap", func() { sinkIP = MustParseAddr("ffff::2.3.4.5").Unmap() })
  1892  	test("IP.WithZone", func() { sinkIP = MustParseAddr("fe80::1").WithZone("") })
  1893  	test("IP.IsGlobalUnicast", func() { sinkBool = MustParseAddr("2001:db8::1").IsGlobalUnicast() })
  1894  	test("IP.IsInterfaceLocalMulticast", func() { sinkBool = MustParseAddr("fe80::1").IsInterfaceLocalMulticast() })
  1895  	test("IP.IsLinkLocalMulticast", func() { sinkBool = MustParseAddr("fe80::1").IsLinkLocalMulticast() })
  1896  	test("IP.IsLinkLocalUnicast", func() { sinkBool = MustParseAddr("fe80::1").IsLinkLocalUnicast() })
  1897  	test("IP.IsLoopback", func() { sinkBool = MustParseAddr("fe80::1").IsLoopback() })
  1898  	test("IP.IsMulticast", func() { sinkBool = MustParseAddr("fe80::1").IsMulticast() })
  1899  	test("IP.IsPrivate", func() { sinkBool = MustParseAddr("fd00::1").IsPrivate() })
  1900  	test("IP.IsUnspecified", func() { sinkBool = IPv6Unspecified().IsUnspecified() })
  1901  	test("IP.Prefix/4", func() { sinkPrefix = panicPfx(MustParseAddr("1.2.3.4").Prefix(20)) })
  1902  	test("IP.Prefix/6", func() { sinkPrefix = panicPfx(MustParseAddr("fe80::1").Prefix(64)) })
  1903  	test("IP.As16", func() { sinkIP16 = MustParseAddr("1.2.3.4").As16() })
  1904  	test("IP.As4", func() { sinkIP4 = MustParseAddr("1.2.3.4").As4() })
  1905  	test("IP.Next", func() { sinkIP = MustParseAddr("1.2.3.4").Next() })
  1906  	test("IP.Prev", func() { sinkIP = MustParseAddr("1.2.3.4").Prev() })
  1907  
  1908  	// AddrPort constructors
  1909  	test("AddrPortFrom", func() { sinkAddrPort = AddrPortFrom(IPv4(1, 2, 3, 4), 22) })
  1910  	test("ParseAddrPort", func() { sinkAddrPort = panicIPP(ParseAddrPort("[::1]:1234")) })
  1911  	test("MustParseAddrPort", func() { sinkAddrPort = MustParseAddrPort("[::1]:1234") })
  1912  
  1913  	// Prefix constructors
  1914  	test("PrefixFrom", func() { sinkPrefix = PrefixFrom(IPv4(1, 2, 3, 4), 32) })
  1915  	test("ParsePrefix/4", func() { sinkPrefix = panicPfx(ParsePrefix("1.2.3.4/20")) })
  1916  	test("ParsePrefix/6", func() { sinkPrefix = panicPfx(ParsePrefix("fe80::1/64")) })
  1917  	test("MustParsePrefix", func() { sinkPrefix = MustParsePrefix("1.2.3.4/20") })
  1918  
  1919  	// Prefix methods
  1920  	test("Prefix.Contains", func() { sinkBool = MustParsePrefix("1.2.3.0/24").Contains(MustParseAddr("1.2.3.4")) })
  1921  	test("Prefix.Overlaps", func() {
  1922  		a, b := MustParsePrefix("1.2.3.0/24"), MustParsePrefix("1.2.0.0/16")
  1923  		sinkBool = a.Overlaps(b)
  1924  	})
  1925  	test("Prefix.IsZero", func() { sinkBool = MustParsePrefix("1.2.0.0/16").IsZero() })
  1926  	test("Prefix.IsSingleIP", func() { sinkBool = MustParsePrefix("1.2.3.4/32").IsSingleIP() })
  1927  	test("IPPRefix.Masked", func() { sinkPrefix = MustParsePrefix("1.2.3.4/16").Masked() })
  1928  }
  1929  
  1930  func TestAddrStringAllocs(t *testing.T) {
  1931  	tests := []struct {
  1932  		name       string
  1933  		ip         Addr
  1934  		wantAllocs int
  1935  	}{
  1936  		{"zero", Addr{}, 0},
  1937  		{"ipv4", MustParseAddr("192.168.1.1"), 1},
  1938  		{"ipv6", MustParseAddr("2001:db8::1"), 1},
  1939  		{"ipv6+zone", MustParseAddr("2001:db8::1%eth0"), 1},
  1940  		{"ipv4-in-ipv6", MustParseAddr("::ffff:192.168.1.1"), 1},
  1941  		{"ipv4-in-ipv6+zone", MustParseAddr("::ffff:192.168.1.1%eth0"), 1},
  1942  	}
  1943  	optimizationOff := testenv.OptimizationOff()
  1944  	for _, tc := range tests {
  1945  		t.Run(tc.name, func(t *testing.T) {
  1946  			if optimizationOff && strings.HasPrefix(tc.name, "ipv4-in-ipv6") {
  1947  				// Optimizations are required to remove some allocs.
  1948  				t.Skipf("skipping on %v", testenv.Builder())
  1949  			}
  1950  			allocs := int(testing.AllocsPerRun(1000, func() {
  1951  				sinkString = tc.ip.String()
  1952  			}))
  1953  			if allocs != tc.wantAllocs {
  1954  				t.Errorf("allocs=%d, want %d", allocs, tc.wantAllocs)
  1955  			}
  1956  		})
  1957  	}
  1958  }
  1959  
  1960  func TestPrefixString(t *testing.T) {
  1961  	tests := []struct {
  1962  		ipp  Prefix
  1963  		want string
  1964  	}{
  1965  		{Prefix{}, "invalid Prefix"},
  1966  		{PrefixFrom(Addr{}, 8), "invalid Prefix"},
  1967  		{PrefixFrom(MustParseAddr("1.2.3.4"), 88), "invalid Prefix"},
  1968  	}
  1969  
  1970  	for _, tt := range tests {
  1971  		if got := tt.ipp.String(); got != tt.want {
  1972  			t.Errorf("(%#v).String() = %q want %q", tt.ipp, got, tt.want)
  1973  		}
  1974  	}
  1975  }
  1976  
  1977  func TestInvalidAddrPortString(t *testing.T) {
  1978  	tests := []struct {
  1979  		ipp  AddrPort
  1980  		want string
  1981  	}{
  1982  		{AddrPort{}, "invalid AddrPort"},
  1983  		{AddrPortFrom(Addr{}, 80), "invalid AddrPort"},
  1984  	}
  1985  
  1986  	for _, tt := range tests {
  1987  		if got := tt.ipp.String(); got != tt.want {
  1988  			t.Errorf("(%#v).String() = %q want %q", tt.ipp, got, tt.want)
  1989  		}
  1990  	}
  1991  }
  1992  
  1993  func TestAsSlice(t *testing.T) {
  1994  	tests := []struct {
  1995  		in   Addr
  1996  		want []byte
  1997  	}{
  1998  		{in: Addr{}, want: nil},
  1999  		{in: mustIP("1.2.3.4"), want: []byte{1, 2, 3, 4}},
  2000  		{in: mustIP("ffff::1"), want: []byte{0xff, 0xff, 15: 1}},
  2001  	}
  2002  
  2003  	for _, test := range tests {
  2004  		got := test.in.AsSlice()
  2005  		if !bytes.Equal(got, test.want) {
  2006  			t.Errorf("%v.AsSlice() = %v want %v", test.in, got, test.want)
  2007  		}
  2008  	}
  2009  }
  2010  
  2011  var sink16 [16]byte
  2012  
  2013  func BenchmarkAs16(b *testing.B) {
  2014  	addr := MustParseAddr("1::10")
  2015  	for i := 0; i < b.N; i++ {
  2016  		sink16 = addr.As16()
  2017  	}
  2018  }