Source file src/net/netip/netip_test.go

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

View as plain text