net: make IP.{String,MarshalText} return helpful information on address error
This change makes String and MarshalText methods of IP return a
hexadecial form of IP with no punctuation as part of error
notification. It doesn't affect the existing behavior of ParseIP.
Also fixes bad shadowing in ipToSockaddr and makes use of reserved
IP address blocks for documnetation.
Fixes #15052.
Updates #15228.
Change-Id: I9e9ecce308952ed5683066c3d1bb6a7b36458c65
Reviewed-on: https://go-review.googlesource.com/21642
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/net/ip_test.go b/src/net/ip_test.go
index 2006085..87c1213 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -5,6 +5,7 @@
package net
import (
+ "bytes"
"reflect"
"runtime"
"testing"
@@ -124,30 +125,119 @@
}
var ipStringTests = []struct {
- in IP
- out string // see RFC 5952
+ in IP // see RFC 791 and RFC 4291
+ str string // see RFC 791, RFC 4291 and RFC 5952
+ byt []byte
+ error
}{
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, "2001:db8::123:12:1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1}, "2001:db8::1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1}, "2001:db8:0:1:0:1:0:1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0}, "2001:db8:1:0:1:0:1:0"},
- {IP{0x20, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1}, "2001::1:0:0:1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0}, "2001:db8:0:0:1::"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1}, "2001:db8::1:0:0:1"},
- {IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0, 0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD}, "2001:db8::a:b:c:d"},
- {IPv4(192, 168, 0, 1), "192.168.0.1"},
- {nil, ""},
+ // IPv4 address
+ {
+ IP{192, 0, 2, 1},
+ "192.0.2.1",
+ []byte("192.0.2.1"),
+ nil,
+ },
+ {
+ IP{0, 0, 0, 0},
+ "0.0.0.0",
+ []byte("0.0.0.0"),
+ nil,
+ },
+
+ // IPv4-mapped IPv6 address
+ {
+ IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 0, 2, 1},
+ "192.0.2.1",
+ []byte("192.0.2.1"),
+ nil,
+ },
+ {
+ IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0},
+ "0.0.0.0",
+ []byte("0.0.0.0"),
+ nil,
+ },
+
+ // IPv6 address
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
+ "2001:db8::123:12:1",
+ []byte("2001:db8::123:12:1"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1},
+ "2001:db8::1",
+ []byte("2001:db8::1"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1},
+ "2001:db8:0:1:0:1:0:1",
+ []byte("2001:db8:0:1:0:1:0:1"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0},
+ "2001:db8:1:0:1:0:1:0",
+ []byte("2001:db8:1:0:1:0:1:0"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+ "2001::1:0:0:1",
+ []byte("2001::1:0:0:1"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0},
+ "2001:db8:0:0:1::",
+ []byte("2001:db8:0:0:1::"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+ "2001:db8::1:0:0:1",
+ []byte("2001:db8::1:0:0:1"),
+ nil,
+ },
+ {
+ IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0xa, 0, 0xb, 0, 0xc, 0, 0xd},
+ "2001:db8::a:b:c:d",
+ []byte("2001:db8::a:b:c:d"),
+ nil,
+ },
+ {
+ IPv6unspecified,
+ "::",
+ []byte("::"),
+ nil,
+ },
+
+ // IP wildcard equivalent address in Dial/Listen API
+ {
+ nil,
+ "<nil>",
+ nil,
+ nil,
+ },
+
+ // Opaque byte sequence
+ {
+ IP{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ "0123456789abcdef",
+ nil,
+ &AddrError{Err: "invalid IP address", Addr: "0123456789abcdef"},
+ },
}
func TestIPString(t *testing.T) {
for _, tt := range ipStringTests {
- if tt.in != nil {
- if out := tt.in.String(); out != tt.out {
- t.Errorf("IP.String(%v) = %q, want %q", tt.in, out, tt.out)
- }
+ if out := tt.in.String(); out != tt.str {
+ t.Errorf("IP.String(%v) = %q, want %q", tt.in, out, tt.str)
}
- if out, err := tt.in.MarshalText(); string(out) != tt.out || err != nil {
- t.Errorf("IP.MarshalText(%v) = %q, %v, want %q, nil", tt.in, out, err, tt.out)
+ if out, err := tt.in.MarshalText(); !bytes.Equal(out, tt.byt) || !reflect.DeepEqual(err, tt.error) {
+ t.Errorf("IP.MarshalText(%v) = %v, %v, want %v, %v", tt.in, out, err, tt.byt, tt.error)
}
}
}