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

View as plain text