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