Add tests for Dashboard protobuf & misc renaming

There were previously no tests around Dashboard serialization to
protobuf, so this patch adds coverage for that. Also, the `go-cmp`
package has been introduced to replace our usage of `reflect.DeepEqual`
going forward because it has better comparison features that make it
more stable across Go versions and produces nice diffs in tests when
they fail, reducing the need for debug lines and manual inspection.
pull/1740/head
Tim Raymond 2017-07-21 11:08:52 -04:00
parent bab3c7fa6a
commit d94911f1b3
18 changed files with 4267 additions and 83 deletions

7
Gopkg.lock generated
View File

@ -47,6 +47,11 @@
packages = ["proto"]
revision = "8ee79997227bf9b34611aee7946ae64735e6fd93"
[[projects]]
name = "github.com/google/go-cmp"
packages = ["cmp"]
revision = "79b2d888f100ec053545168aa94bcfb322e8bfc8"
[[projects]]
name = "github.com/google/go-github"
packages = ["github"]
@ -135,6 +140,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "bac138180cd86a0ae604cd3aa7b6ba300673478c880882bd58a4bd7f8bff518d"
inputs-digest = "f34fb88755292baba8b52c14bf5b9a028daff96a763368a7cf1de90004d33695"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -181,15 +181,15 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) {
}
}
axes := make(map[string]*DashboardRange, len(c.Axes))
axes := make(map[string]*Axis, len(c.Axes))
for a, r := range c.Axes {
// need to explicitly allocate a new array because r.Bounds is
// over-written and the resulting slices from previous iterations will
// point to later iteration's data. It is _not_ enough to simply re-slice
// r.Bounds
axis := [2]int32{}
axis := [2]int64{}
copy(axis[:], r.Bounds[:2])
axes[a] = &DashboardRange{
axes[a] = &Axis{
Bounds: axis[:],
}
}

View File

@ -12,7 +12,7 @@ It has these top-level messages:
Source
Dashboard
DashboardCell
DashboardRange
Axis
Template
TemplateValue
TemplateQuery
@ -87,15 +87,15 @@ func (m *Dashboard) GetTemplates() []*Template {
}
type DashboardCell struct {
X int32 `protobuf:"varint,1,opt,name=x,proto3" json:"x,omitempty"`
Y int32 `protobuf:"varint,2,opt,name=y,proto3" json:"y,omitempty"`
W int32 `protobuf:"varint,3,opt,name=w,proto3" json:"w,omitempty"`
H int32 `protobuf:"varint,4,opt,name=h,proto3" json:"h,omitempty"`
Queries []*Query `protobuf:"bytes,5,rep,name=queries" json:"queries,omitempty"`
Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"`
Type string `protobuf:"bytes,7,opt,name=type,proto3" json:"type,omitempty"`
ID string `protobuf:"bytes,8,opt,name=ID,proto3" json:"ID,omitempty"`
Axes map[string]*DashboardRange `protobuf:"bytes,9,rep,name=axes" json:"axes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"`
X int32 `protobuf:"varint,1,opt,name=x,proto3" json:"x,omitempty"`
Y int32 `protobuf:"varint,2,opt,name=y,proto3" json:"y,omitempty"`
W int32 `protobuf:"varint,3,opt,name=w,proto3" json:"w,omitempty"`
H int32 `protobuf:"varint,4,opt,name=h,proto3" json:"h,omitempty"`
Queries []*Query `protobuf:"bytes,5,rep,name=queries" json:"queries,omitempty"`
Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"`
Type string `protobuf:"bytes,7,opt,name=type,proto3" json:"type,omitempty"`
ID string `protobuf:"bytes,8,opt,name=ID,proto3" json:"ID,omitempty"`
Axes map[string]*Axis `protobuf:"bytes,9,rep,name=axes" json:"axes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"`
}
func (m *DashboardCell) Reset() { *m = DashboardCell{} }
@ -110,21 +110,21 @@ func (m *DashboardCell) GetQueries() []*Query {
return nil
}
func (m *DashboardCell) GetAxes() map[string]*DashboardRange {
func (m *DashboardCell) GetAxes() map[string]*Axis {
if m != nil {
return m.Axes
}
return nil
}
type DashboardRange struct {
Bounds []int32 `protobuf:"varint,1,rep,name=bounds" json:"bounds,omitempty"`
type Axis struct {
Bounds []int64 `protobuf:"varint,1,rep,name=bounds" json:"bounds,omitempty"`
}
func (m *DashboardRange) Reset() { *m = DashboardRange{} }
func (m *DashboardRange) String() string { return proto.CompactTextString(m) }
func (*DashboardRange) ProtoMessage() {}
func (*DashboardRange) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{3} }
func (m *Axis) Reset() { *m = Axis{} }
func (m *Axis) String() string { return proto.CompactTextString(m) }
func (*Axis) ProtoMessage() {}
func (*Axis) Descriptor() ([]byte, []int) { return fileDescriptorInternal, []int{3} }
type Template struct {
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
@ -297,7 +297,7 @@ func init() {
proto.RegisterType((*Source)(nil), "internal.Source")
proto.RegisterType((*Dashboard)(nil), "internal.Dashboard")
proto.RegisterType((*DashboardCell)(nil), "internal.DashboardCell")
proto.RegisterType((*DashboardRange)(nil), "internal.DashboardRange")
proto.RegisterType((*Axis)(nil), "internal.Axis")
proto.RegisterType((*Template)(nil), "internal.Template")
proto.RegisterType((*TemplateValue)(nil), "internal.TemplateValue")
proto.RegisterType((*TemplateQuery)(nil), "internal.TemplateQuery")
@ -313,65 +313,65 @@ func init() {
func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) }
var fileDescriptorInternal = []byte{
// 953 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x56, 0x51, 0x6f, 0xe3, 0x44,
0x10, 0xd6, 0xc6, 0x76, 0x12, 0x4f, 0x7b, 0x05, 0xad, 0x4e, 0xdc, 0x72, 0xbc, 0x04, 0x0b, 0xa4,
0x80, 0x44, 0x41, 0x77, 0x42, 0x42, 0xbc, 0xb5, 0x0d, 0x42, 0xa1, 0xbd, 0xa3, 0xb7, 0x69, 0xcb,
0x13, 0x3a, 0x6d, 0x92, 0x49, 0x63, 0x9d, 0x13, 0x9b, 0xb5, 0xdd, 0xd4, 0xff, 0x82, 0x5f, 0x80,
0x84, 0xc4, 0x33, 0x0f, 0x88, 0x77, 0x7e, 0x04, 0x7f, 0x08, 0xcd, 0xee, 0xda, 0x4e, 0xb8, 0x1c,
0xba, 0x27, 0x9e, 0xba, 0xdf, 0xcc, 0x66, 0xc6, 0xfb, 0xcd, 0x37, 0x9f, 0x0a, 0x47, 0xf1, 0xba,
0x40, 0xbd, 0x56, 0xc9, 0x71, 0xa6, 0xd3, 0x22, 0xe5, 0xfd, 0x1a, 0x47, 0xbf, 0x77, 0xa0, 0x3b,
0x49, 0x4b, 0x3d, 0x43, 0x7e, 0x04, 0x9d, 0xf1, 0x48, 0xb0, 0x01, 0x1b, 0x7a, 0xb2, 0x33, 0x1e,
0x71, 0x0e, 0xfe, 0x73, 0xb5, 0x42, 0xd1, 0x19, 0xb0, 0x61, 0x28, 0xcd, 0x99, 0x62, 0x57, 0x55,
0x86, 0xc2, 0xb3, 0x31, 0x3a, 0xf3, 0xc7, 0xd0, 0xbf, 0xce, 0xa9, 0xda, 0x0a, 0x85, 0x6f, 0xe2,
0x0d, 0xa6, 0xdc, 0xa5, 0xca, 0xf3, 0x4d, 0xaa, 0xe7, 0x22, 0xb0, 0xb9, 0x1a, 0xf3, 0x77, 0xc1,
0xbb, 0x96, 0x17, 0xa2, 0x6b, 0xc2, 0x74, 0xe4, 0x02, 0x7a, 0x23, 0x5c, 0xa8, 0x32, 0x29, 0x44,
0x6f, 0xc0, 0x86, 0x7d, 0x59, 0x43, 0xaa, 0x73, 0x85, 0x09, 0xde, 0x6a, 0xb5, 0x10, 0x7d, 0x5b,
0xa7, 0xc6, 0xfc, 0x18, 0xf8, 0x78, 0x9d, 0xe3, 0xac, 0xd4, 0x38, 0x79, 0x15, 0x67, 0x37, 0xa8,
0xe3, 0x45, 0x25, 0x42, 0x53, 0x60, 0x4f, 0x86, 0xba, 0x3c, 0xc3, 0x42, 0x51, 0x6f, 0x30, 0xa5,
0x6a, 0xc8, 0x23, 0x38, 0x9c, 0x2c, 0x95, 0xc6, 0xf9, 0x04, 0x67, 0x1a, 0x0b, 0x71, 0x60, 0xd2,
0x3b, 0xb1, 0xe8, 0x67, 0x06, 0xe1, 0x48, 0xe5, 0xcb, 0x69, 0xaa, 0xf4, 0xfc, 0xad, 0x38, 0xfb,
0x0c, 0x82, 0x19, 0x26, 0x49, 0x2e, 0xbc, 0x81, 0x37, 0x3c, 0x78, 0xf2, 0xe8, 0xb8, 0x19, 0x46,
0x53, 0xe7, 0x0c, 0x93, 0x44, 0xda, 0x5b, 0xfc, 0x0b, 0x08, 0x0b, 0x5c, 0x65, 0x89, 0x2a, 0x30,
0x17, 0xbe, 0xf9, 0x09, 0x6f, 0x7f, 0x72, 0xe5, 0x52, 0xb2, 0xbd, 0x14, 0xfd, 0xd9, 0x81, 0x07,
0x3b, 0xa5, 0xf8, 0x21, 0xb0, 0x7b, 0xf3, 0x55, 0x81, 0x64, 0xf7, 0x84, 0x2a, 0xf3, 0x45, 0x81,
0x64, 0x15, 0xa1, 0x8d, 0x99, 0x5f, 0x20, 0xd9, 0x86, 0xd0, 0xd2, 0x4c, 0x2d, 0x90, 0x6c, 0xc9,
0x3f, 0x81, 0xde, 0x4f, 0x25, 0xea, 0x18, 0x73, 0x11, 0x98, 0xce, 0xef, 0xb4, 0x9d, 0x5f, 0x94,
0xa8, 0x2b, 0x59, 0xe7, 0xe9, 0xa5, 0x66, 0xe2, 0x76, 0x7c, 0xe6, 0x4c, 0xb1, 0x82, 0xd4, 0xd1,
0xb3, 0x31, 0x3a, 0x3b, 0x86, 0xec, 0xcc, 0x88, 0xa1, 0x2f, 0xc1, 0x57, 0xf7, 0x98, 0x8b, 0xd0,
0xd4, 0xff, 0xf0, 0x0d, 0x64, 0x1c, 0x9f, 0xdc, 0x63, 0xfe, 0xcd, 0xba, 0xd0, 0x95, 0x34, 0xd7,
0x1f, 0xbf, 0x80, 0xb0, 0x09, 0x91, 0x72, 0x5e, 0x61, 0x65, 0x1e, 0x18, 0x4a, 0x3a, 0xf2, 0x63,
0x08, 0xee, 0x54, 0x52, 0x5a, 0xe2, 0x0f, 0x9e, 0x88, 0x3d, 0x65, 0xa5, 0x5a, 0xdf, 0xa2, 0xb4,
0xd7, 0xbe, 0xee, 0x7c, 0xc5, 0xa2, 0x21, 0x1c, 0xed, 0x26, 0xf9, 0x7b, 0xd0, 0x9d, 0xa6, 0xe5,
0x7a, 0x9e, 0x0b, 0x36, 0xf0, 0x86, 0x81, 0x74, 0x28, 0xfa, 0x8b, 0x91, 0xfc, 0x2c, 0xdd, 0x5b,
0x23, 0xb7, 0x0f, 0x7a, 0x1f, 0xfa, 0x34, 0x8a, 0x97, 0x77, 0x4a, 0xbb, 0xb1, 0xf7, 0x08, 0xdf,
0x28, 0xcd, 0x3f, 0x87, 0xae, 0x69, 0xb7, 0x67, 0xf4, 0x75, 0xb9, 0x1b, 0xca, 0x4b, 0x77, 0xad,
0x21, 0xd0, 0xdf, 0x22, 0xf0, 0x21, 0x04, 0x89, 0x9a, 0x62, 0xe2, 0xf6, 0xc7, 0x02, 0x12, 0x15,
0x4d, 0xa2, 0x32, 0xfc, 0xef, 0xad, 0x6c, 0xe7, 0x65, 0x6f, 0x45, 0xd7, 0xf0, 0x60, 0xa7, 0x63,
0xd3, 0x89, 0xed, 0x76, 0x6a, 0x49, 0x0c, 0x1d, 0x55, 0xb4, 0x7a, 0x39, 0x26, 0x38, 0x2b, 0x70,
0x6e, 0x64, 0xd3, 0x97, 0x0d, 0x8e, 0x7e, 0x65, 0x6d, 0x5d, 0xd3, 0x8f, 0x96, 0x6b, 0x96, 0xae,
0x56, 0x6a, 0x3d, 0x77, 0xa5, 0x6b, 0x48, 0xbc, 0xcd, 0xa7, 0xae, 0x74, 0x67, 0x3e, 0x25, 0xac,
0x33, 0x67, 0x24, 0x1d, 0x9d, 0xf1, 0x01, 0x1c, 0xac, 0x50, 0xe5, 0xa5, 0xc6, 0x15, 0xae, 0x0b,
0x47, 0xc1, 0x76, 0x88, 0x3f, 0x82, 0x5e, 0xa1, 0x6e, 0x5f, 0xd2, 0xe8, 0x2d, 0x17, 0xdd, 0x42,
0xdd, 0x9e, 0x63, 0xc5, 0x3f, 0x80, 0x70, 0x11, 0x63, 0x32, 0x37, 0x29, 0x2b, 0xc8, 0xbe, 0x09,
0x9c, 0x63, 0x15, 0xfd, 0xc6, 0xa0, 0x3b, 0x41, 0x7d, 0x87, 0xfa, 0xad, 0xb6, 0x75, 0xdb, 0xcd,
0xbc, 0xff, 0x70, 0x33, 0x7f, 0xbf, 0x9b, 0x05, 0xad, 0x9b, 0x3d, 0x84, 0x60, 0xa2, 0x67, 0xe3,
0x91, 0xf9, 0x22, 0x4f, 0x5a, 0x40, 0x1a, 0x3b, 0x99, 0x15, 0xf1, 0x1d, 0x3a, 0x8b, 0x73, 0x28,
0xfa, 0x85, 0x41, 0xf7, 0x42, 0x55, 0x69, 0x59, 0xbc, 0xa6, 0xb0, 0x01, 0x1c, 0x9c, 0x64, 0x59,
0x12, 0xcf, 0x54, 0x11, 0xa7, 0x6b, 0xf7, 0xb5, 0xdb, 0x21, 0xba, 0xf1, 0x6c, 0x8b, 0x3b, 0xfb,
0xdd, 0xdb, 0x21, 0xfe, 0x11, 0x04, 0x67, 0xc6, 0x84, 0xac, 0xa3, 0x1c, 0xb5, 0x7a, 0xb1, 0xde,
0x63, 0x92, 0xf4, 0xc0, 0x93, 0xb2, 0x48, 0x17, 0x49, 0xba, 0x31, 0x2f, 0xe9, 0xcb, 0x06, 0x47,
0x7f, 0x33, 0xf0, 0xff, 0x2f, 0x73, 0x39, 0x04, 0x16, 0xbb, 0x41, 0xb2, 0xb8, 0xb1, 0x9a, 0xde,
0x96, 0xd5, 0x08, 0xe8, 0x55, 0x9a, 0x96, 0x36, 0x17, 0xfd, 0x81, 0x37, 0xf4, 0x64, 0x0d, 0x4d,
0xc6, 0xec, 0x88, 0xf5, 0x98, 0x50, 0xd6, 0xb0, 0xd1, 0x3c, 0xb4, 0x9a, 0x8f, 0xfe, 0x60, 0x10,
0x34, 0xca, 0x3d, 0xdb, 0x55, 0xee, 0x59, 0xab, 0xdc, 0xd1, 0x69, 0xad, 0xdc, 0xd1, 0x29, 0x61,
0x79, 0x59, 0x2b, 0x57, 0x5e, 0x12, 0x6b, 0xdf, 0xea, 0xb4, 0xcc, 0x4e, 0x2b, 0x4b, 0x6f, 0x28,
0x1b, 0x4c, 0xe3, 0xfe, 0x61, 0x89, 0xda, 0xbd, 0x39, 0x94, 0x0e, 0x91, 0x38, 0x2e, 0xcc, 0x56,
0xdb, 0x57, 0x5a, 0xc0, 0x3f, 0x86, 0xc0, 0x38, 0x91, 0x79, 0xea, 0x0e, 0x41, 0xce, 0xbd, 0xcc,
0x9f, 0xe8, 0xa9, 0xbb, 0x46, 0x55, 0xae, 0xb3, 0x0c, 0xb5, 0xd3, 0xb4, 0x05, 0xa6, 0x76, 0xba,
0x41, 0x6b, 0x47, 0x9e, 0xb4, 0x20, 0xfa, 0x11, 0xc2, 0x93, 0x04, 0x75, 0x21, 0xcb, 0xe4, 0x75,
0x13, 0xe3, 0xe0, 0x7f, 0x37, 0xf9, 0xfe, 0x79, 0xbd, 0x09, 0x74, 0x6e, 0xf5, 0xeb, 0xfd, 0x4b,
0xbf, 0xe7, 0x2a, 0x53, 0xe3, 0x91, 0x19, 0xac, 0x27, 0x1d, 0x8a, 0x3e, 0x05, 0x9f, 0xf6, 0x64,
0xab, 0xb2, 0xff, 0xa6, 0x1d, 0x9b, 0x76, 0xcd, 0x7f, 0x21, 0x4f, 0xff, 0x09, 0x00, 0x00, 0xff,
0xff, 0xa3, 0x1c, 0x73, 0xcc, 0x97, 0x08, 0x00, 0x00,
// 952 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x56, 0xcf, 0x8e, 0xe3, 0xc4,
0x13, 0x56, 0xc7, 0x76, 0x12, 0x57, 0x66, 0xe7, 0xf7, 0x53, 0x6b, 0xc5, 0x9a, 0x45, 0x42, 0xc1,
0x02, 0x29, 0x20, 0x31, 0xa0, 0x5d, 0x21, 0x21, 0x6e, 0x99, 0x09, 0x5a, 0x85, 0x99, 0x5d, 0x86,
0xce, 0xcc, 0x70, 0x42, 0xab, 0x4e, 0x52, 0x99, 0x58, 0xeb, 0xc4, 0xa6, 0x6d, 0x4f, 0xe2, 0xb7,
0xe0, 0x09, 0x90, 0x90, 0x38, 0x71, 0xe0, 0xc0, 0x0b, 0xf0, 0x10, 0xbc, 0x10, 0xaa, 0xee, 0xf6,
0x9f, 0xb0, 0xb3, 0x68, 0x4f, 0xdc, 0xfa, 0xab, 0xea, 0x7c, 0xe5, 0xfe, 0xea, 0xab, 0x52, 0xe0,
0x38, 0xda, 0xe6, 0xa8, 0xb6, 0x32, 0x3e, 0x49, 0x55, 0x92, 0x27, 0xbc, 0x5f, 0xe1, 0xf0, 0xf7,
0x0e, 0x74, 0x67, 0x49, 0xa1, 0x16, 0xc8, 0x8f, 0xa1, 0x33, 0x9d, 0x04, 0x6c, 0xc8, 0x46, 0x8e,
0xe8, 0x4c, 0x27, 0x9c, 0x83, 0xfb, 0x42, 0x6e, 0x30, 0xe8, 0x0c, 0xd9, 0xc8, 0x17, 0xfa, 0x4c,
0xb1, 0xab, 0x32, 0xc5, 0xc0, 0x31, 0x31, 0x3a, 0xf3, 0xc7, 0xd0, 0xbf, 0xce, 0x88, 0x6d, 0x83,
0x81, 0xab, 0xe3, 0x35, 0xa6, 0xdc, 0xa5, 0xcc, 0xb2, 0x5d, 0xa2, 0x96, 0x81, 0x67, 0x72, 0x15,
0xe6, 0xff, 0x07, 0xe7, 0x5a, 0x5c, 0x04, 0x5d, 0x1d, 0xa6, 0x23, 0x0f, 0xa0, 0x37, 0xc1, 0x95,
0x2c, 0xe2, 0x3c, 0xe8, 0x0d, 0xd9, 0xa8, 0x2f, 0x2a, 0x48, 0x3c, 0x57, 0x18, 0xe3, 0xad, 0x92,
0xab, 0xa0, 0x6f, 0x78, 0x2a, 0xcc, 0x4f, 0x80, 0x4f, 0xb7, 0x19, 0x2e, 0x0a, 0x85, 0xb3, 0x57,
0x51, 0x7a, 0x83, 0x2a, 0x5a, 0x95, 0x81, 0xaf, 0x09, 0xee, 0xc9, 0x50, 0x95, 0xe7, 0x98, 0x4b,
0xaa, 0x0d, 0x9a, 0xaa, 0x82, 0x3c, 0x84, 0xa3, 0xd9, 0x5a, 0x2a, 0x5c, 0xce, 0x70, 0xa1, 0x30,
0x0f, 0x06, 0x3a, 0x7d, 0x10, 0x0b, 0x7f, 0x62, 0xe0, 0x4f, 0x64, 0xb6, 0x9e, 0x27, 0x52, 0x2d,
0xdf, 0x4a, 0xb3, 0x4f, 0xc1, 0x5b, 0x60, 0x1c, 0x67, 0x81, 0x33, 0x74, 0x46, 0x83, 0x27, 0x8f,
0x4e, 0xea, 0x66, 0xd4, 0x3c, 0x67, 0x18, 0xc7, 0xc2, 0xdc, 0xe2, 0x9f, 0x83, 0x9f, 0xe3, 0x26,
0x8d, 0x65, 0x8e, 0x59, 0xe0, 0xea, 0x9f, 0xf0, 0xe6, 0x27, 0x57, 0x36, 0x25, 0x9a, 0x4b, 0xe1,
0x6f, 0x1d, 0x78, 0x70, 0x40, 0xc5, 0x8f, 0x80, 0xed, 0xf5, 0x57, 0x79, 0x82, 0xed, 0x09, 0x95,
0xfa, 0x8b, 0x3c, 0xc1, 0x4a, 0x42, 0x3b, 0xdd, 0x3f, 0x4f, 0xb0, 0x1d, 0xa1, 0xb5, 0xee, 0x9a,
0x27, 0xd8, 0x9a, 0x7f, 0x0c, 0xbd, 0x1f, 0x0b, 0x54, 0x11, 0x66, 0x81, 0xa7, 0x2b, 0xff, 0xaf,
0xa9, 0xfc, 0x5d, 0x81, 0xaa, 0x14, 0x55, 0x9e, 0x5e, 0xaa, 0x3b, 0x6e, 0xda, 0xa7, 0xcf, 0x14,
0xcb, 0xc9, 0x1d, 0x3d, 0x13, 0xa3, 0xb3, 0x55, 0xc8, 0xf4, 0x8c, 0x14, 0xfa, 0x02, 0x5c, 0xb9,
0xc7, 0x2c, 0xf0, 0x35, 0xff, 0x07, 0x6f, 0x10, 0xe3, 0x64, 0xbc, 0xc7, 0xec, 0xeb, 0x6d, 0xae,
0x4a, 0xa1, 0xaf, 0x3f, 0x7e, 0x06, 0x7e, 0x1d, 0x22, 0xe7, 0xbc, 0xc2, 0x52, 0x3f, 0xd0, 0x17,
0x74, 0xe4, 0x1f, 0x82, 0x77, 0x27, 0xe3, 0xc2, 0x08, 0x3f, 0x78, 0x72, 0xdc, 0xd0, 0x8e, 0xf7,
0x51, 0x26, 0x4c, 0xf2, 0xab, 0xce, 0x97, 0x2c, 0x7c, 0x1f, 0x5c, 0x0a, 0xf1, 0x77, 0xa0, 0x3b,
0x4f, 0x8a, 0xed, 0x32, 0x0b, 0xd8, 0xd0, 0x19, 0x39, 0xc2, 0xa2, 0xf0, 0x4f, 0x46, 0x56, 0x33,
0xd2, 0xb6, 0xda, 0x6b, 0x3e, 0xfe, 0x5d, 0xe8, 0x93, 0xec, 0x2f, 0xef, 0xa4, 0xb2, 0x2d, 0xee,
0x11, 0xbe, 0x91, 0x8a, 0x7f, 0x06, 0x5d, 0x5d, 0xe4, 0x9e, 0x36, 0x57, 0x74, 0x37, 0x94, 0x17,
0xf6, 0x5a, 0x2d, 0x96, 0xdb, 0x12, 0xeb, 0x21, 0x78, 0xb1, 0x9c, 0x63, 0x6c, 0x67, 0xc5, 0x00,
0x32, 0x10, 0xa9, 0x5e, 0x6a, 0xad, 0xef, 0x65, 0x36, 0xbd, 0x31, 0xb7, 0xc2, 0x6b, 0x78, 0x70,
0x50, 0xb1, 0xae, 0xc4, 0x0e, 0x2b, 0x35, 0x82, 0xf9, 0x56, 0x20, 0x1a, 0xb3, 0x0c, 0x63, 0x5c,
0xe4, 0xb8, 0xd4, 0x16, 0xe9, 0x8b, 0x1a, 0x87, 0xbf, 0xb0, 0x86, 0x57, 0xd7, 0xa3, 0x41, 0x5a,
0x24, 0x9b, 0x8d, 0xdc, 0x2e, 0x2d, 0x75, 0x05, 0x49, 0xb7, 0xe5, 0xdc, 0x52, 0x77, 0x96, 0x73,
0xc2, 0x2a, 0xb5, 0x4b, 0xa3, 0xa3, 0x52, 0x3e, 0x84, 0xc1, 0x06, 0x65, 0x56, 0x28, 0xdc, 0xe0,
0x36, 0xb7, 0x12, 0xb4, 0x43, 0xfc, 0x11, 0xf4, 0x72, 0x79, 0xfb, 0x92, 0xda, 0x6c, 0xb4, 0xe8,
0xe6, 0xf2, 0xf6, 0x1c, 0x4b, 0xfe, 0x1e, 0xf8, 0xab, 0x08, 0xe3, 0xa5, 0x4e, 0x19, 0xf3, 0xf5,
0x75, 0xe0, 0x1c, 0xcb, 0xf0, 0x57, 0x06, 0xdd, 0x19, 0xaa, 0x3b, 0x54, 0x6f, 0x35, 0x99, 0xed,
0xcd, 0xe5, 0xfc, 0xcb, 0xe6, 0x72, 0xef, 0xdf, 0x5c, 0x5e, 0xb3, 0xb9, 0x1e, 0x82, 0x37, 0x53,
0x8b, 0xe9, 0x44, 0x7f, 0x91, 0x23, 0x0c, 0x20, 0x8f, 0x8d, 0x17, 0x79, 0x74, 0x87, 0x76, 0x9d,
0x59, 0x14, 0xfe, 0xcc, 0xa0, 0x7b, 0x21, 0xcb, 0xa4, 0xc8, 0x5f, 0x73, 0xd8, 0x10, 0x06, 0xe3,
0x34, 0x8d, 0xa3, 0x85, 0xcc, 0xa3, 0x64, 0x6b, 0xbf, 0xb6, 0x1d, 0xa2, 0x1b, 0xcf, 0x5b, 0xda,
0x99, 0xef, 0x6e, 0x87, 0x68, 0x18, 0xce, 0xf4, 0xc2, 0x31, 0xdb, 0xa3, 0x35, 0x0c, 0x66, 0xcf,
0xe8, 0x24, 0x3d, 0x70, 0x5c, 0xe4, 0xc9, 0x2a, 0x4e, 0x76, 0xfa, 0x25, 0x7d, 0x51, 0xe3, 0xf0,
0x2f, 0x06, 0xee, 0x7f, 0xb5, 0x48, 0x8e, 0x80, 0x45, 0xb6, 0x91, 0x2c, 0xaa, 0xd7, 0x4a, 0xaf,
0xb5, 0x56, 0x02, 0xe8, 0x95, 0x4a, 0x6e, 0x6f, 0x31, 0x0b, 0xfa, 0x7a, 0x56, 0x2b, 0xa8, 0x33,
0x7a, 0x46, 0xcc, 0x3e, 0xf1, 0x45, 0x05, 0x6b, 0xcf, 0x43, 0xe3, 0xf9, 0xf0, 0x0f, 0x06, 0x5e,
0xed, 0xdc, 0xb3, 0x43, 0xe7, 0x9e, 0x35, 0xce, 0x9d, 0x9c, 0x56, 0xce, 0x9d, 0x9c, 0x12, 0x16,
0x97, 0x95, 0x73, 0xc5, 0x25, 0xa9, 0xf6, 0x4c, 0x25, 0x45, 0x7a, 0x5a, 0x1a, 0x79, 0x7d, 0x51,
0x63, 0x6a, 0xf7, 0xf7, 0x6b, 0x54, 0xf6, 0xcd, 0xbe, 0xb0, 0x88, 0xcc, 0x71, 0xa1, 0xa7, 0xda,
0xbc, 0xd2, 0x00, 0xfe, 0x11, 0x78, 0x82, 0x5e, 0xa1, 0x9f, 0x7a, 0x20, 0x90, 0x0e, 0x0b, 0x93,
0x0d, 0x9f, 0xda, 0x6b, 0xc4, 0x72, 0x9d, 0xa6, 0xa8, 0xac, 0xa7, 0x0d, 0xd0, 0xdc, 0xc9, 0x0e,
0xcd, 0x3a, 0x72, 0x84, 0x01, 0xe1, 0x0f, 0xe0, 0x8f, 0x63, 0x54, 0xb9, 0x28, 0xe2, 0xd7, 0x97,
0x18, 0x07, 0xf7, 0x9b, 0xd9, 0xb7, 0x2f, 0xaa, 0x49, 0xa0, 0x73, 0xe3, 0x5f, 0xe7, 0x1f, 0xfe,
0x3d, 0x97, 0xa9, 0x9c, 0x4e, 0x74, 0x63, 0x1d, 0x61, 0x51, 0xf8, 0x09, 0xb8, 0x34, 0x27, 0x2d,
0x66, 0xf7, 0x4d, 0x33, 0x36, 0xef, 0xea, 0x7f, 0x1c, 0x4f, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff,
0x94, 0xd8, 0xce, 0x85, 0x83, 0x08, 0x00, 0x00,
}

View File

@ -4,6 +4,7 @@ import (
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/influxdata/chronograf"
"github.com/influxdata/chronograf/bolt/internal"
)
@ -136,3 +137,45 @@ func TestMarshalLayout(t *testing.T) {
t.Fatalf("source protobuf copy error: got %#v, expected %#v", vv, layout)
}
}
func Test_MarshalDashboard(t *testing.T) {
dashboard := chronograf.Dashboard{
ID: 1,
Cells: []chronograf.DashboardCell{
{
ID: "9b5367de-c552-4322-a9e8-7f384cbd235c",
X: 0,
Y: 0,
W: 4,
H: 4,
Name: "Super awesome query",
Queries: []chronograf.DashboardQuery{
{
Command: "select * from cpu",
Label: "CPU Utilization",
Range: &chronograf.Range{
Upper: int64(100),
},
},
},
Axes: map[string]chronograf.Axis{
"y": chronograf.Axis{
Bounds: [2]int64{0, 100},
},
},
Type: "line",
},
},
Templates: []chronograf.Template{},
Name: "Dashboard",
}
var actual chronograf.Dashboard
if buf, err := internal.MarshalDashboard(dashboard); err != nil {
t.Fatal("Error marshaling dashboard: err", err)
} else if err := internal.UnmarshalDashboard(buf, &actual); err != nil {
t.Fatal("Error unmarshaling dashboard: err:", err)
} else if !cmp.Equal(dashboard, actual) {
t.Fatalf("Dashboard protobuf copy error: diff follows:\n%s", cmp.Diff(dashboard, actual))
}
}

18
vendor/github.com/google/go-cmp/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,18 @@
sudo: false
language: go
go:
- 1.x
- master
matrix:
include:
- go: 1.6.x
script: go test -v -race ./...
allow_failures:
- go: master
fast_finish: true
install:
- # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (it is intended for this package to have no dependencies other than the standard library).
script:
- diff -u <(echo -n) <(gofmt -d -s .)
- go tool vet .
- go test -v -race ./...

23
vendor/github.com/google/go-cmp/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,23 @@
# How to Contribute
We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.
## Contributor License Agreement
Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution,
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.
You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.
## Code reviews
All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.

27
vendor/github.com/google/go-cmp/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2017 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

41
vendor/github.com/google/go-cmp/README.md generated vendored Normal file
View File

@ -0,0 +1,41 @@
# Package for equality of Go values
[![GoDoc](https://godoc.org/github.com/google/go-cmp/cmp?status.svg)][godoc]
[![Build Status](https://travis-ci.org/google/go-cmp.svg?branch=master)][travis]
This package is intended to be a more powerful and safer alternative to
`reflect.DeepEqual` for comparing whether two values are semantically equal.
The primary features of cmp are:
* When the default behavior of equality does not suit the needs of the test,
custom equality functions can override the equality operation.
For example, an equality function may report floats as equal so long as they
are within some tolerance of each other.
* Types that have an `Equal` method may use that method to determine equality.
This allows package authors to determine the equality operation for the types
that they define.
* If no custom equality functions are used and no `Equal` method is defined,
equality is determined by recursively comparing the primitive kinds on both
values, much like `reflect.DeepEqual`. Unlike `reflect.DeepEqual`, unexported
fields are not compared; they result in panics unless suppressed by using
an `Ignore` option.
This is not an official Google product.
[godoc]: https://godoc.org/github.com/google/go-cmp/cmp
[travis]: https://travis-ci.org/google/go-cmp
## Install
```
go get -u github.com/google/go-cmp/cmp
```
## License
BSD - See [LICENSE][license] file
[license]: https://github.com/google/go-cmp/blob/master/LICENSE

519
vendor/github.com/google/go-cmp/cmp/compare.go generated vendored Normal file
View File

@ -0,0 +1,519 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.
// Package cmp determines equality of values.
//
// This package is intended to be a more powerful and safer alternative to
// reflect.DeepEqual for comparing whether two values are semantically equal.
//
// The primary features of cmp are:
//
// • When the default behavior of equality does not suit the needs of the test,
// custom equality functions can override the equality operation.
// For example, an equality function may report floats as equal so long as they
// are within some tolerance of each other.
//
// • Types that have an Equal method may use that method to determine equality.
// This allows package authors to determine the equality operation for the types
// that they define.
//
// • If no custom equality functions are used and no Equal method is defined,
// equality is determined by recursively comparing the primitive kinds on both
// values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported
// fields are not compared by default; they result in panics unless suppressed
// by using an Ignore option (see cmpopts.IgnoreUnexported) or explictly compared
// using the AllowUnexported option.
package cmp
import (
"fmt"
"reflect"
)
// BUG: Maps with keys containing NaN values cannot be properly compared due to
// the reflection package's inability to retrieve such entries. Equal will panic
// anytime it comes across a NaN key, but this behavior may change.
//
// See https://golang.org/issue/11104 for more details.
// Equal reports whether x and y are equal by recursively applying the
// following rules in the given order to x and y and all of their sub-values:
//
// • If two values are not of the same type, then they are never equal
// and the overall result is false.
//
// • Let S be the set of all Ignore, Transformer, and Comparer options that
// remain after applying all path filters, value filters, and type filters.
// If at least one Ignore exists in S, then the comparison is ignored.
// If the number of Transformer and Comparer options in S is greater than one,
// then Equal panics because it is ambiguous which option to use.
// If S contains a single Transformer, then apply that transformer on the
// current values and recursively call Equal on the transformed output values.
// If S contains a single Comparer, then use that Comparer to determine whether
// the current values are equal or not.
// Otherwise, S is empty and evaluation proceeds to the next rule.
//
// • If the values have an Equal method of the form "(T) Equal(T) bool" or
// "(T) Equal(I) bool" where T is assignable to I, then use the result of
// x.Equal(y). Otherwise, no such method exists and evaluation proceeds to
// the next rule.
//
// • Lastly, try to compare x and y based on their basic kinds.
// Simple kinds like booleans, integers, floats, complex numbers, strings, and
// channels are compared using the equivalent of the == operator in Go.
// Functions are only equal if they are both nil, otherwise they are unequal.
// Pointers are equal if the underlying values they point to are also equal.
// Interfaces are equal if their underlying concrete values are also equal.
//
// Structs are equal if all of their fields are equal. If a struct contains
// unexported fields, Equal panics unless the AllowUnexported option is used or
// an Ignore option (e.g., cmpopts.IgnoreUnexported) ignores that field.
//
// Arrays, slices, and maps are equal if they are both nil or both non-nil
// with the same length and the elements at each index or key are equal.
// Note that a non-nil empty slice and a nil slice are not equal.
// To equate empty slices and maps, consider using cmpopts.EquateEmpty.
// Map keys are equal according to the == operator.
// To use custom comparisons for map keys, consider using cmpopts.SortMaps.
func Equal(x, y interface{}, opts ...Option) bool {
s := newState(opts)
s.compareAny(reflect.ValueOf(x), reflect.ValueOf(y))
return s.eq
}
// Diff returns a human-readable report of the differences between two values.
// It returns an empty string if and only if Equal returns true for the same
// input values and options. The output string will use the "-" symbol to
// indicate elements removed from x, and the "+" symbol to indicate elements
// added to y.
//
// Do not depend on this output being stable.
func Diff(x, y interface{}, opts ...Option) string {
r := new(defaultReporter)
opts = append(opts[:len(opts):len(opts)], r) // Force copy when appending
eq := Equal(x, y, opts...)
d := r.String()
if (d == "") != eq {
panic("inconsistent difference and equality results")
}
return d
}
type state struct {
eq bool // Current result of comparison
curPath Path // The current path in the value tree
// dsCheck tracks the state needed to periodically perform checks that
// user provided func(T, T) bool functions are symmetric and deterministic.
//
// Checks occur every Nth function call, where N is a triangular number:
// 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 ...
// See https://en.wikipedia.org/wiki/Triangular_number
//
// This sequence ensures that the cost of checks drops significantly as
// the number of functions calls grows larger.
dsCheck struct{ curr, next int }
// These fields, once set by processOption, will not change.
exporters map[reflect.Type]bool // Set of structs with unexported field visibility
optsIgn []option // List of all ignore options without value filters
opts []option // List of all other options
reporter reporter // Optional reporter used for difference formatting
}
func newState(opts []Option) *state {
s := &state{eq: true}
for _, opt := range opts {
s.processOption(opt)
}
// Move Ignore options to the front so that they are evaluated first.
for i, j := 0, 0; i < len(s.opts); i++ {
if s.opts[i].op == nil {
s.opts[i], s.opts[j] = s.opts[j], s.opts[i]
j++
}
}
return s
}
func (s *state) processOption(opt Option) {
switch opt := opt.(type) {
case Options:
for _, o := range opt {
s.processOption(o)
}
case visibleStructs:
if s.exporters == nil {
s.exporters = make(map[reflect.Type]bool)
}
for t := range opt {
s.exporters[t] = true
}
case option:
if opt.typeFilter == nil && len(opt.pathFilters)+len(opt.valueFilters) == 0 {
panic(fmt.Sprintf("cannot use an unfiltered option: %v", opt))
}
if opt.op == nil && len(opt.valueFilters) == 0 {
s.optsIgn = append(s.optsIgn, opt)
} else {
s.opts = append(s.opts, opt)
}
case reporter:
if s.reporter != nil {
panic("difference reporter already registered")
}
s.reporter = opt
default:
panic(fmt.Sprintf("unknown option %T", opt))
}
}
func (s *state) compareAny(vx, vy reflect.Value) {
// TODO: Support cyclic data structures.
// Rule 0: Differing types are never equal.
if !vx.IsValid() || !vy.IsValid() {
s.report(vx.IsValid() == vy.IsValid(), vx, vy)
return
}
if vx.Type() != vy.Type() {
s.report(false, vx, vy) // Possible for path to be empty
return
}
t := vx.Type()
if len(s.curPath) == 0 {
s.curPath.push(&pathStep{typ: t})
}
// Rule 1: Check whether an option applies on this node in the value tree.
if s.tryOptions(&vx, &vy, t) {
return
}
// Rule 2: Check whether the type has a valid Equal method.
if s.tryMethod(vx, vy, t) {
return
}
// Rule 3: Recursively descend into each value's underlying kind.
switch t.Kind() {
case reflect.Bool:
s.report(vx.Bool() == vy.Bool(), vx, vy)
return
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
s.report(vx.Int() == vy.Int(), vx, vy)
return
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
s.report(vx.Uint() == vy.Uint(), vx, vy)
return
case reflect.Float32, reflect.Float64:
s.report(vx.Float() == vy.Float(), vx, vy)
return
case reflect.Complex64, reflect.Complex128:
s.report(vx.Complex() == vy.Complex(), vx, vy)
return
case reflect.String:
s.report(vx.String() == vy.String(), vx, vy)
return
case reflect.Chan, reflect.UnsafePointer:
s.report(vx.Pointer() == vy.Pointer(), vx, vy)
return
case reflect.Func:
s.report(vx.IsNil() && vy.IsNil(), vx, vy)
return
case reflect.Ptr:
if vx.IsNil() || vy.IsNil() {
s.report(vx.IsNil() && vy.IsNil(), vx, vy)
return
}
s.curPath.push(&indirect{pathStep{t.Elem()}})
defer s.curPath.pop()
s.compareAny(vx.Elem(), vy.Elem())
return
case reflect.Interface:
if vx.IsNil() || vy.IsNil() {
s.report(vx.IsNil() && vy.IsNil(), vx, vy)
return
}
if vx.Elem().Type() != vy.Elem().Type() {
s.report(false, vx.Elem(), vy.Elem())
return
}
s.curPath.push(&typeAssertion{pathStep{vx.Elem().Type()}})
defer s.curPath.pop()
s.compareAny(vx.Elem(), vy.Elem())
return
case reflect.Slice:
if vx.IsNil() || vy.IsNil() {
s.report(vx.IsNil() && vy.IsNil(), vx, vy)
return
}
fallthrough
case reflect.Array:
s.compareArray(vx, vy, t)
return
case reflect.Map:
s.compareMap(vx, vy, t)
return
case reflect.Struct:
s.compareStruct(vx, vy, t)
return
default:
panic(fmt.Sprintf("%v kind not handled", t.Kind()))
}
}
// tryOptions iterates through all of the options and evaluates whether any
// of them can be applied. This may modify the underlying values vx and vy
// if an unexported field is being forcibly exported.
func (s *state) tryOptions(vx, vy *reflect.Value, t reflect.Type) bool {
// Try all ignore options that do not depend on the value first.
// This avoids possible panics when processing unexported fields.
for _, opt := range s.optsIgn {
var v reflect.Value // Dummy value; should never be used
if s.applyFilters(v, v, t, opt) {
return true // Ignore option applied
}
}
// Since the values must be used after this point, verify that the values
// are either exported or can be forcibly exported.
if sf, ok := s.curPath[len(s.curPath)-1].(*structField); ok && sf.unexported {
if !sf.force {
const help = "consider using AllowUnexported or cmpopts.IgnoreUnexported"
panic(fmt.Sprintf("cannot handle unexported field: %#v\n%s", s.curPath, help))
}
// Use unsafe pointer arithmetic to get read-write access to an
// unexported field in the struct.
*vx = unsafeRetrieveField(sf.pvx, sf.field)
*vy = unsafeRetrieveField(sf.pvy, sf.field)
}
// Try all other options now.
optIdx := -1 // Index of Option to apply
for i, opt := range s.opts {
if !s.applyFilters(*vx, *vy, t, opt) {
continue
}
if opt.op == nil {
return true // Ignored comparison
}
if optIdx >= 0 {
panic(fmt.Sprintf("ambiguous set of options at %#v\n\n%v\n\n%v\n", s.curPath, s.opts[optIdx], opt))
}
optIdx = i
}
if optIdx >= 0 {
s.applyOption(*vx, *vy, t, s.opts[optIdx])
return true
}
return false
}
func (s *state) applyFilters(vx, vy reflect.Value, t reflect.Type, opt option) bool {
if opt.typeFilter != nil {
if !t.AssignableTo(opt.typeFilter) {
return false
}
}
for _, f := range opt.pathFilters {
if !f(s.curPath) {
return false
}
}
for _, f := range opt.valueFilters {
if !t.AssignableTo(f.in) || !s.callFunc(f.fnc, vx, vy) {
return false
}
}
return true
}
func (s *state) applyOption(vx, vy reflect.Value, t reflect.Type, opt option) {
switch op := opt.op.(type) {
case *transformer:
vx = op.fnc.Call([]reflect.Value{vx})[0]
vy = op.fnc.Call([]reflect.Value{vy})[0]
s.curPath.push(&transform{pathStep{op.fnc.Type().Out(0)}, op})
defer s.curPath.pop()
s.compareAny(vx, vy)
return
case *comparer:
eq := s.callFunc(op.fnc, vx, vy)
s.report(eq, vx, vy)
return
}
}
func (s *state) tryMethod(vx, vy reflect.Value, t reflect.Type) bool {
// Check if this type even has an Equal method.
m, ok := t.MethodByName("Equal")
ft := functionType(m.Type)
if !ok || (ft != equalFunc && ft != equalIfaceFunc) {
return false
}
eq := s.callFunc(m.Func, vx, vy)
s.report(eq, vx, vy)
return true
}
func (s *state) callFunc(f, x, y reflect.Value) bool {
got := f.Call([]reflect.Value{x, y})[0].Bool()
if s.dsCheck.curr == s.dsCheck.next {
// Swapping the input arguments is sufficient to check that
// f is symmetric and deterministic.
want := f.Call([]reflect.Value{y, x})[0].Bool()
if got != want {
fn := getFuncName(f.Pointer())
panic(fmt.Sprintf("non-deterministic or non-symmetric function detected: %s", fn))
}
s.dsCheck.curr = 0
s.dsCheck.next++
}
s.dsCheck.curr++
return got
}
func (s *state) compareArray(vx, vy reflect.Value, t reflect.Type) {
step := &sliceIndex{pathStep{t.Elem()}, 0}
s.curPath.push(step)
defer s.curPath.pop()
// Regardless of the lengths, we always try to compare the elements.
// If one slice is longer, we will report the elements of the longer
// slice as different (relative to an invalid reflect.Value).
nmin := vx.Len()
if nmin > vy.Len() {
nmin = vy.Len()
}
for i := 0; i < nmin; i++ {
step.key = i
s.compareAny(vx.Index(i), vy.Index(i))
}
for i := nmin; i < vx.Len(); i++ {
step.key = i
s.report(false, vx.Index(i), reflect.Value{})
}
for i := nmin; i < vy.Len(); i++ {
step.key = i
s.report(false, reflect.Value{}, vy.Index(i))
}
}
func (s *state) compareMap(vx, vy reflect.Value, t reflect.Type) {
if vx.IsNil() || vy.IsNil() {
s.report(vx.IsNil() && vy.IsNil(), vx, vy)
return
}
// We combine and sort the two map keys so that we can perform the
// comparisons in a deterministic order.
step := &mapIndex{pathStep: pathStep{t.Elem()}}
s.curPath.push(step)
defer s.curPath.pop()
for _, k := range sortKeys(append(vx.MapKeys(), vy.MapKeys()...)) {
step.key = k
vvx := vx.MapIndex(k)
vvy := vy.MapIndex(k)
switch {
case vvx.IsValid() && vvy.IsValid():
s.compareAny(vvx, vvy)
case vvx.IsValid() && !vvy.IsValid():
s.report(false, vvx, reflect.Value{})
case !vvx.IsValid() && vvy.IsValid():
s.report(false, reflect.Value{}, vvy)
default:
// It is possible for both vvx and vvy to be invalid if the
// key contained a NaN value in it. There is no way in
// reflection to be able to retrieve these values.
// See https://golang.org/issue/11104
panic(fmt.Sprintf("%#v has map key with NaNs", s.curPath))
}
}
}
func (s *state) compareStruct(vx, vy reflect.Value, t reflect.Type) {
var vax, vay reflect.Value // Addressable versions of vx and vy
step := &structField{}
s.curPath.push(step)
defer s.curPath.pop()
for i := 0; i < t.NumField(); i++ {
vvx := vx.Field(i)
vvy := vy.Field(i)
step.typ = t.Field(i).Type
step.name = t.Field(i).Name
step.idx = i
step.unexported = !isExported(step.name)
if step.unexported {
// Defer checking of unexported fields until later to give an
// Ignore a chance to ignore the field.
if !vax.IsValid() || !vay.IsValid() {
// For unsafeRetrieveField to work, the parent struct must
// be addressable. Create a new copy of the values if
// necessary to make them addressable.
vax = makeAddressable(vx)
vay = makeAddressable(vy)
}
step.force = s.exporters[t]
step.pvx = vax
step.pvy = vay
step.field = t.Field(i)
}
s.compareAny(vvx, vvy)
}
}
// report records the result of a single comparison.
// It also calls Report if any reporter is registered.
func (s *state) report(eq bool, vx, vy reflect.Value) {
s.eq = s.eq && eq
if s.reporter != nil {
s.reporter.Report(vx, vy, eq, s.curPath)
}
}
// makeAddressable returns a value that is always addressable.
// It returns the input verbatim if it is already addressable,
// otherwise it creates a new value and returns an addressable copy.
func makeAddressable(v reflect.Value) reflect.Value {
if v.CanAddr() {
return v
}
vc := reflect.New(v.Type()).Elem()
vc.Set(v)
return vc
}
type funcType int
const (
invalidFunc funcType = iota
equalFunc // func(T, T) bool
equalIfaceFunc // func(T, I) bool
transformFunc // func(T) R
valueFilterFunc = equalFunc // func(T, T) bool
)
var boolType = reflect.TypeOf(true)
// functionType identifies which type of function signature this is.
func functionType(t reflect.Type) funcType {
if t == nil || t.Kind() != reflect.Func || t.IsVariadic() {
return invalidFunc
}
ni, no := t.NumIn(), t.NumOut()
switch {
case ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType:
return equalFunc // or valueFilterFunc
case ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType:
return equalIfaceFunc
case ni == 1 && no == 1:
return transformFunc
default:
return invalidFunc
}
}

1775
vendor/github.com/google/go-cmp/cmp/compare_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

266
vendor/github.com/google/go-cmp/cmp/example_test.go generated vendored Normal file
View File

@ -0,0 +1,266 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.
package cmp_test
import (
"fmt"
"math"
"reflect"
"sort"
"strings"
"github.com/google/go-cmp/cmp"
)
// TODO: Re-write these examples in terms of how you actually use the
// fundamental options and filters and not in terms of what cool things you can
// do with them since that overlaps with cmp/cmpopts.
// Approximate equality for floats can be handled by defining a custom
// comparer on floats that determines two values to be equal if they are within
// some range of each other.
//
// This example is for demonstrative purposes; use cmpopts.EquateApprox instead.
func ExampleOption_approximateFloats() {
// This Comparer only operates on float64.
// To handle float32s, either define a similar function for that type
// or use a Transformer to convert float32s into float64s.
opt := cmp.Comparer(func(x, y float64) bool {
delta := math.Abs(x - y)
mean := math.Abs(x+y) / 2.0
return delta/mean < 0.00001
})
x := []float64{1.0, 1.1, 1.2, math.Pi}
y := []float64{1.0, 1.1, 1.2, 3.14159265359} // Accurate enough to Pi
z := []float64{1.0, 1.1, 1.2, 3.1415} // Diverges too far from Pi
fmt.Println(cmp.Equal(x, y, opt))
fmt.Println(cmp.Equal(y, z, opt))
fmt.Println(cmp.Equal(z, x, opt))
// Output:
// true
// false
// false
}
// Normal floating-point arithmetic defines == to be false when comparing
// NaN with itself. In certain cases, this is not the desired property.
//
// This example is for demonstrative purposes; use cmpopts.EquateNaNs instead.
func ExampleOption_equalNaNs() {
// This Comparer only operates on float64.
// To handle float32s, either define a similar function for that type
// or use a Transformer to convert float32s into float64s.
opt := cmp.Comparer(func(x, y float64) bool {
return (math.IsNaN(x) && math.IsNaN(y)) || x == y
})
x := []float64{1.0, math.NaN(), math.E, -0.0, +0.0}
y := []float64{1.0, math.NaN(), math.E, -0.0, +0.0}
z := []float64{1.0, math.NaN(), math.Pi, -0.0, +0.0} // Pi constant instead of E
fmt.Println(cmp.Equal(x, y, opt))
fmt.Println(cmp.Equal(y, z, opt))
fmt.Println(cmp.Equal(z, x, opt))
// Output:
// true
// false
// false
}
// To have floating-point comparisons combine both properties of NaN being
// equal to itself and also approximate equality of values, filters are needed
// to restrict the scope of the comparison so that they are composable.
//
// This example is for demonstrative purposes;
// use cmpopts.EquateNaNs and cmpopts.EquateApprox instead.
func ExampleOption_equalNaNsAndApproximateFloats() {
alwaysEqual := cmp.Comparer(func(_, _ interface{}) bool { return true })
opts := cmp.Options{
// This option declares that a float64 comparison is equal only if
// both inputs are NaN.
cmp.FilterValues(func(x, y float64) bool {
return math.IsNaN(x) && math.IsNaN(y)
}, alwaysEqual),
// This option declares approximate equality on float64s only if
// both inputs are not NaN.
cmp.FilterValues(func(x, y float64) bool {
return !math.IsNaN(x) && !math.IsNaN(y)
}, cmp.Comparer(func(x, y float64) bool {
delta := math.Abs(x - y)
mean := math.Abs(x+y) / 2.0
return delta/mean < 0.00001
})),
}
x := []float64{math.NaN(), 1.0, 1.1, 1.2, math.Pi}
y := []float64{math.NaN(), 1.0, 1.1, 1.2, 3.14159265359} // Accurate enough to Pi
z := []float64{math.NaN(), 1.0, 1.1, 1.2, 3.1415} // Diverges too far from Pi
fmt.Println(cmp.Equal(x, y, opts))
fmt.Println(cmp.Equal(y, z, opts))
fmt.Println(cmp.Equal(z, x, opts))
// Output:
// true
// false
// false
}
// Sometimes, an empty map or slice is considered equal to an allocated one
// of zero length.
//
// This example is for demonstrative purposes; use cmpopts.EquateEmpty instead.
func ExampleOption_equalEmpty() {
alwaysEqual := cmp.Comparer(func(_, _ interface{}) bool { return true })
// This option handles slices and maps of any type.
opt := cmp.FilterValues(func(x, y interface{}) bool {
vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
return (vx.IsValid() && vy.IsValid() && vx.Type() == vy.Type()) &&
(vx.Kind() == reflect.Slice || vx.Kind() == reflect.Map) &&
(vx.Len() == 0 && vy.Len() == 0)
}, alwaysEqual)
type S struct {
A []int
B map[string]bool
}
x := S{nil, make(map[string]bool, 100)}
y := S{make([]int, 0, 200), nil}
z := S{[]int{0}, nil} // []int has a single element (i.e., not empty)
fmt.Println(cmp.Equal(x, y, opt))
fmt.Println(cmp.Equal(y, z, opt))
fmt.Println(cmp.Equal(z, x, opt))
// Output:
// true
// false
// false
}
// Two slices may be considered equal if they have the same elements,
// regardless of the order that they appear in. Transformations can be used
// to sort the slice.
//
// This example is for demonstrative purposes; use cmpopts.SortSlices instead.
func ExampleOption_sortedSlice() {
// This Transformer sorts a []int.
// Since the transformer transforms []int into []int, there is problem where
// this is recursively applied forever. To prevent this, use a FilterValues
// to first check for the condition upon which the transformer ought to apply.
trans := cmp.FilterValues(func(x, y []int) bool {
return !sort.IntsAreSorted(x) || !sort.IntsAreSorted(y)
}, cmp.Transformer("Sort", func(in []int) []int {
out := append([]int(nil), in...) // Copy input to avoid mutating it
sort.Ints(out)
return out
}))
x := struct{ Ints []int }{[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}
y := struct{ Ints []int }{[]int{2, 8, 0, 9, 6, 1, 4, 7, 3, 5}}
z := struct{ Ints []int }{[]int{0, 0, 1, 2, 3, 4, 5, 6, 7, 8}}
fmt.Println(cmp.Equal(x, y, trans))
fmt.Println(cmp.Equal(y, z, trans))
fmt.Println(cmp.Equal(z, x, trans))
// Output:
// true
// false
// false
}
type otherString string
func (x otherString) Equal(y otherString) bool {
return strings.ToLower(string(x)) == strings.ToLower(string(y))
}
// If the Equal method defined on a type is not suitable, the type can be be
// dynamically transformed to be stripped of the Equal method (or any method
// for that matter).
func ExampleOption_avoidEqualMethod() {
// Suppose otherString.Equal performs a case-insensitive equality,
// which is too loose for our needs.
// We can avoid the methods of otherString by declaring a new type.
type myString otherString
// This transformer converts otherString to myString, allowing Equal to use
// other Options to determine equality.
trans := cmp.Transformer("", func(in otherString) myString {
return myString(in)
})
x := []otherString{"foo", "bar", "baz"}
y := []otherString{"fOO", "bAr", "Baz"} // Same as before, but with different case
fmt.Println(cmp.Equal(x, y)) // Equal because of case-insensitivity
fmt.Println(cmp.Equal(x, y, trans)) // Not equal because of more exact equality
// Output:
// true
// false
}
func roundF64(z float64) float64 {
if z < 0 {
return math.Ceil(z - 0.5)
}
return math.Floor(z + 0.5)
}
// The complex numbers complex64 and complex128 can really just be decomposed
// into a pair of float32 or float64 values. It would be convenient to be able
// define only a single comparator on float64 and have float32, complex64, and
// complex128 all be able to use that comparator. Transformations can be used
// to handle this.
func ExampleOption_transformComplex() {
opts := []cmp.Option{
// This transformer decomposes complex128 into a pair of float64s.
cmp.Transformer("T1", func(in complex128) (out struct{ Real, Imag float64 }) {
out.Real, out.Imag = real(in), imag(in)
return out
}),
// This transformer converts complex64 to complex128 to allow the
// above transform to take effect.
cmp.Transformer("T2", func(in complex64) complex128 {
return complex128(in)
}),
// This transformer converts float32 to float64.
cmp.Transformer("T3", func(in float32) float64 {
return float64(in)
}),
// This equality function compares float64s as rounded integers.
cmp.Comparer(func(x, y float64) bool {
return roundF64(x) == roundF64(y)
}),
}
x := []interface{}{
complex128(3.0), complex64(5.1 + 2.9i), float32(-1.2), float64(12.3),
}
y := []interface{}{
complex128(3.1), complex64(4.9 + 3.1i), float32(-1.3), float64(11.7),
}
z := []interface{}{
complex128(3.8), complex64(4.9 + 3.1i), float32(-1.3), float64(11.7),
}
fmt.Println(cmp.Equal(x, y, opts...))
fmt.Println(cmp.Equal(y, z, opts...))
fmt.Println(cmp.Equal(z, x, opts...))
// Output:
// true
// false
// false
}

304
vendor/github.com/google/go-cmp/cmp/options.go generated vendored Normal file
View File

@ -0,0 +1,304 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.
package cmp
import (
"fmt"
"reflect"
"runtime"
"strings"
)
// Option configures for specific behavior of Equal and Diff. In particular,
// the fundamental Option functions (Ignore, Transformer, and Comparer),
// configure how equality is determined.
//
// The fundamental options may be composed with filters (FilterPath and
// FilterValues) to control the scope over which they are applied.
//
// The cmp/cmpopts package provides helper functions for creating options that
// may be used with Equal and Diff.
type Option interface {
// Prevent Option from being equivalent to interface{}, which provides
// a small type checking benefit by preventing Equal(opt, x, y).
option()
}
// Options is a list of Option values that also satisfies the Option interface.
// Helper comparison packages may return an Options value when packing multiple
// Option values into a single Option. When this package processes an Options,
// it will be implicitly expanded into a flat list.
//
// Applying a filter on an Options is equivalent to applying that same filter
// on all individual options held within.
type Options []Option
func (Options) option() {}
type (
pathFilter func(Path) bool
valueFilter struct {
in reflect.Type // T
fnc reflect.Value // func(T, T) bool
}
)
type option struct {
typeFilter reflect.Type
pathFilters []pathFilter
valueFilters []valueFilter
// op is the operation to perform. If nil, then this acts as an ignore.
op interface{} // nil | *transformer | *comparer
}
func (option) option() {}
func (o option) String() string {
// TODO: Add information about the caller?
// TODO: Maintain the order that filters were added?
var ss []string
switch op := o.op.(type) {
case *transformer:
fn := getFuncName(op.fnc.Pointer())
ss = append(ss, fmt.Sprintf("Transformer(%s, %s)", op.name, fn))
case *comparer:
fn := getFuncName(op.fnc.Pointer())
ss = append(ss, fmt.Sprintf("Comparer(%s)", fn))
default:
ss = append(ss, "Ignore()")
}
for _, f := range o.pathFilters {
fn := getFuncName(reflect.ValueOf(f).Pointer())
ss = append(ss, fmt.Sprintf("FilterPath(%s)", fn))
}
for _, f := range o.valueFilters {
fn := getFuncName(f.fnc.Pointer())
ss = append(ss, fmt.Sprintf("FilterValues(%s)", fn))
}
return strings.Join(ss, "\n\t")
}
// getFuncName returns a short function name from the pointer.
// The string parsing logic works up until Go1.9.
func getFuncName(p uintptr) string {
fnc := runtime.FuncForPC(p)
if fnc == nil {
return "<unknown>"
}
name := fnc.Name() // E.g., "long/path/name/mypkg.(mytype).(long/path/name/mypkg.myfunc)-fm"
if strings.HasSuffix(name, ")-fm") || strings.HasSuffix(name, ")·fm") {
// Strip the package name from method name.
name = strings.TrimSuffix(name, ")-fm")
name = strings.TrimSuffix(name, ")·fm")
if i := strings.LastIndexByte(name, '('); i >= 0 {
methodName := name[i+1:] // E.g., "long/path/name/mypkg.myfunc"
if j := strings.LastIndexByte(methodName, '.'); j >= 0 {
methodName = methodName[j+1:] // E.g., "myfunc"
}
name = name[:i] + methodName // E.g., "long/path/name/mypkg.(mytype)." + "myfunc"
}
}
if i := strings.LastIndexByte(name, '/'); i >= 0 {
// Strip the package name.
name = name[i+1:] // E.g., "mypkg.(mytype).myfunc"
}
return name
}
// FilterPath returns a new Option where opt is only evaluated if filter f
// returns true for the current Path in the value tree.
//
// The option passed in may be an Ignore, Transformer, Comparer, Options, or
// a previously filtered Option.
func FilterPath(f func(Path) bool, opt Option) Option {
if f == nil {
panic("invalid path filter function")
}
switch opt := opt.(type) {
case Options:
var opts []Option
for _, o := range opt {
opts = append(opts, FilterPath(f, o)) // Append to slice copy
}
return Options(opts)
case option:
n := len(opt.pathFilters)
opt.pathFilters = append(opt.pathFilters[:n:n], f) // Append to copy
return opt
default:
panic(fmt.Sprintf("unknown option type: %T", opt))
}
}
// FilterValues returns a new Option where opt is only evaluated if filter f,
// which is a function of the form "func(T, T) bool", returns true for the
// current pair of values being compared. If the type of the values is not
// assignable to T, then this filter implicitly returns false.
//
// The filter function must be
// symmetric (i.e., agnostic to the order of the inputs) and
// deterministic (i.e., produces the same result when given the same inputs).
// If T is an interface, it is possible that f is called with two values with
// different concrete types that both implement T.
//
// The option passed in may be an Ignore, Transformer, Comparer, Options, or
// a previously filtered Option.
func FilterValues(f interface{}, opt Option) Option {
v := reflect.ValueOf(f)
if functionType(v.Type()) != valueFilterFunc || v.IsNil() {
panic(fmt.Sprintf("invalid values filter function: %T", f))
}
switch opt := opt.(type) {
case Options:
var opts []Option
for _, o := range opt {
opts = append(opts, FilterValues(f, o)) // Append to slice copy
}
return Options(opts)
case option:
n := len(opt.valueFilters)
vf := valueFilter{v.Type().In(0), v}
opt.valueFilters = append(opt.valueFilters[:n:n], vf) // Append to copy
return opt
default:
panic(fmt.Sprintf("unknown option type: %T", opt))
}
}
// Ignore is an Option that causes all comparisons to be ignored.
// This value is intended to be combined with FilterPath or FilterValues.
// It is an error to pass an unfiltered Ignore option to Equal.
func Ignore() Option {
return option{}
}
// Transformer returns an Option that applies a transformation function that
// converts values of a certain type into that of another.
//
// The transformer f must be a function "func(T) R" that converts values of
// type T to those of type R and is implicitly filtered to input values
// assignable to T. The transformer must not mutate T in any way.
// If T and R are the same type, an additional filter must be applied to
// act as the base case to prevent an infinite recursion applying the same
// transform to itself (see the SortedSlice example).
//
// The name is a user provided label that is used as the Transform.Name in the
// transformation PathStep. If empty, an arbitrary name is used.
func Transformer(name string, f interface{}) Option {
v := reflect.ValueOf(f)
if functionType(v.Type()) != transformFunc || v.IsNil() {
panic(fmt.Sprintf("invalid transformer function: %T", f))
}
if name == "" {
name = "λ" // Lambda-symbol as place-holder for anonymous transformer
}
if !isValid(name) {
panic(fmt.Sprintf("invalid name: %q", name))
}
opt := option{op: &transformer{name, reflect.ValueOf(f)}}
if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 {
opt.typeFilter = ti
}
return opt
}
type transformer struct {
name string
fnc reflect.Value // func(T) R
}
// Comparer returns an Option that determines whether two values are equal
// to each other.
//
// The comparer f must be a function "func(T, T) bool" and is implicitly
// filtered to input values assignable to T. If T is an interface, it is
// possible that f is called with two values of different concrete types that
// both implement T.
//
// The equality function must be:
// • Symmetric: equal(x, y) == equal(y, x)
// • Deterministic: equal(x, y) == equal(x, y)
// • Pure: equal(x, y) does not modify x or y
func Comparer(f interface{}) Option {
v := reflect.ValueOf(f)
if functionType(v.Type()) != equalFunc || v.IsNil() {
panic(fmt.Sprintf("invalid comparer function: %T", f))
}
opt := option{op: &comparer{v}}
if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 {
opt.typeFilter = ti
}
return opt
}
type comparer struct {
fnc reflect.Value // func(T, T) bool
}
// AllowUnexported returns an Option that forcibly allows operations on
// unexported fields in certain structs, which are specified by passing in a
// value of each struct type.
//
// Users of this option must understand that comparing on unexported fields
// from external packages is not safe since changes in the internal
// implementation of some external package may cause the result of Equal
// to unexpectedly change. However, it may be valid to use this option on types
// defined in an internal package where the semantic meaning of an unexported
// field is in the control of the user.
//
// For some cases, a custom Comparer should be used instead that defines
// equality as a function of the public API of a type rather than the underlying
// unexported implementation.
//
// For example, the reflect.Type documentation defines equality to be determined
// by the == operator on the interface (essentially performing a shallow pointer
// comparison) and most attempts to compare *regexp.Regexp types are interested
// in only checking that the regular expression strings are equal.
// Both of these are accomplished using Comparers:
//
// Comparer(func(x, y reflect.Type) bool { return x == y })
// Comparer(func(x, y *regexp.Regexp) bool { return x.String() == y.String() })
//
// In other cases, the cmpopts.IgnoreUnexported option can be used to ignore
// all unexported fields on specified struct types.
func AllowUnexported(types ...interface{}) Option {
if !supportAllowUnexported {
panic("AllowUnexported is not supported on App Engine Classic or GopherJS")
}
m := make(map[reflect.Type]bool)
for _, typ := range types {
t := reflect.TypeOf(typ)
if t.Kind() != reflect.Struct {
panic(fmt.Sprintf("invalid struct type: %T", typ))
}
m[t] = true
}
return visibleStructs(m)
}
type visibleStructs map[reflect.Type]bool
func (visibleStructs) option() {}
// reporter is an Option that configures how differences are reported.
//
// TODO: Not exported yet, see concerns in defaultReporter.Report.
type reporter interface {
Option
// Report is called for every comparison made and will be provided with
// the two values being compared, the equality result, and the
// current path in the value tree. It is possible for x or y to be an
// invalid reflect.Value if one of the values is non-existent;
// which is possible with maps and slices.
Report(x, y reflect.Value, eq bool, p Path)
// TODO: Perhaps add PushStep and PopStep and change Report to only accept
// a PathStep instead of the full-path? This change allows us to provide
// better output closer to what pretty.Compare is able to achieve.
}

231
vendor/github.com/google/go-cmp/cmp/options_test.go generated vendored Normal file
View File

@ -0,0 +1,231 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.
package cmp
import (
"io"
"reflect"
"strings"
"testing"
ts "github.com/google/go-cmp/cmp/internal/teststructs"
)
// Test that the creation of Option values with non-sensible inputs produces
// a run-time panic with a decent error message
func TestOptionPanic(t *testing.T) {
type myBool bool
tests := []struct {
label string // Test description
fnc interface{} // Option function to call
args []interface{} // Arguments to pass in
wantPanic string // Expected panic message
}{{
label: "AllowUnexported",
fnc: AllowUnexported,
args: []interface{}{},
}, {
label: "AllowUnexported",
fnc: AllowUnexported,
args: []interface{}{1},
wantPanic: "invalid struct type",
}, {
label: "AllowUnexported",
fnc: AllowUnexported,
args: []interface{}{ts.StructA{}},
}, {
label: "AllowUnexported",
fnc: AllowUnexported,
args: []interface{}{ts.StructA{}, ts.StructB{}, ts.StructA{}},
}, {
label: "AllowUnexported",
fnc: AllowUnexported,
args: []interface{}{ts.StructA{}, &ts.StructB{}, ts.StructA{}},
wantPanic: "invalid struct type",
}, {
label: "Comparer",
fnc: Comparer,
args: []interface{}{5},
wantPanic: "invalid comparer function",
}, {
label: "Comparer",
fnc: Comparer,
args: []interface{}{func(x, y interface{}) bool { return true }},
}, {
label: "Comparer",
fnc: Comparer,
args: []interface{}{func(x, y io.Reader) bool { return true }},
}, {
label: "Comparer",
fnc: Comparer,
args: []interface{}{func(x, y io.Reader) myBool { return true }},
wantPanic: "invalid comparer function",
}, {
label: "Comparer",
fnc: Comparer,
args: []interface{}{func(x string, y interface{}) bool { return true }},
wantPanic: "invalid comparer function",
}, {
label: "Comparer",
fnc: Comparer,
args: []interface{}{(func(int, int) bool)(nil)},
wantPanic: "invalid comparer function",
}, {
label: "Transformer",
fnc: Transformer,
args: []interface{}{"", 0},
wantPanic: "invalid transformer function",
}, {
label: "Transformer",
fnc: Transformer,
args: []interface{}{"", func(int) int { return 0 }},
}, {
label: "Transformer",
fnc: Transformer,
args: []interface{}{"", func(bool) bool { return true }},
}, {
label: "Transformer",
fnc: Transformer,
args: []interface{}{"", func(int) bool { return true }},
}, {
label: "Transformer",
fnc: Transformer,
args: []interface{}{"", func(int, int) bool { return true }},
wantPanic: "invalid transformer function",
}, {
label: "Transformer",
fnc: Transformer,
args: []interface{}{"", (func(int) uint)(nil)},
wantPanic: "invalid transformer function",
}, {
label: "Transformer",
fnc: Transformer,
args: []interface{}{"Func", func(Path) Path { return nil }},
}, {
label: "Transformer",
fnc: Transformer,
args: []interface{}{"世界", func(int) bool { return true }},
}, {
label: "Transformer",
fnc: Transformer,
args: []interface{}{"/*", func(int) bool { return true }},
wantPanic: "invalid name",
}, {
label: "Transformer",
fnc: Transformer,
args: []interface{}{"_", func(int) bool { return true }},
wantPanic: "invalid name",
}, {
label: "FilterPath",
fnc: FilterPath,
args: []interface{}{(func(Path) bool)(nil), Ignore()},
wantPanic: "invalid path filter function",
}, {
label: "FilterPath",
fnc: FilterPath,
args: []interface{}{func(Path) bool { return true }, Ignore()},
}, {
label: "FilterPath",
fnc: FilterPath,
args: []interface{}{func(Path) bool { return true }, &defaultReporter{}},
wantPanic: "unknown option type",
}, {
label: "FilterPath",
fnc: FilterPath,
args: []interface{}{func(Path) bool { return true }, Options{Ignore(), Ignore()}},
}, {
label: "FilterPath",
fnc: FilterPath,
args: []interface{}{func(Path) bool { return true }, Options{Ignore(), &defaultReporter{}}},
wantPanic: "unknown option type",
}, {
label: "FilterValues",
fnc: FilterValues,
args: []interface{}{0, Ignore()},
wantPanic: "invalid values filter function",
}, {
label: "FilterValues",
fnc: FilterValues,
args: []interface{}{func(x, y int) bool { return true }, Ignore()},
}, {
label: "FilterValues",
fnc: FilterValues,
args: []interface{}{func(x, y interface{}) bool { return true }, Ignore()},
}, {
label: "FilterValues",
fnc: FilterValues,
args: []interface{}{func(x, y interface{}) myBool { return true }, Ignore()},
wantPanic: "invalid values filter function",
}, {
label: "FilterValues",
fnc: FilterValues,
args: []interface{}{func(x io.Reader, y interface{}) bool { return true }, Ignore()},
wantPanic: "invalid values filter function",
}, {
label: "FilterValues",
fnc: FilterValues,
args: []interface{}{(func(int, int) bool)(nil), Ignore()},
wantPanic: "invalid values filter function",
}, {
label: "FilterValues",
fnc: FilterValues,
args: []interface{}{func(int, int) bool { return true }, &defaultReporter{}},
wantPanic: "unknown option type",
}, {
label: "FilterValues",
fnc: FilterValues,
args: []interface{}{func(int, int) bool { return true }, Options{Ignore(), Ignore()}},
}, {
label: "FilterValues",
fnc: FilterValues,
args: []interface{}{func(int, int) bool { return true }, Options{Ignore(), &defaultReporter{}}},
wantPanic: "unknown option type",
}}
for _, tt := range tests {
tRun(t, tt.label, func(t *testing.T) {
var gotPanic string
func() {
defer func() {
if ex := recover(); ex != nil {
if s, ok := ex.(string); ok {
gotPanic = s
} else {
panic(ex)
}
}
}()
var vargs []reflect.Value
for _, arg := range tt.args {
vargs = append(vargs, reflect.ValueOf(arg))
}
reflect.ValueOf(tt.fnc).Call(vargs)
}()
if tt.wantPanic == "" {
if gotPanic != "" {
t.Fatalf("unexpected panic message: %s", gotPanic)
}
} else {
if !strings.Contains(gotPanic, tt.wantPanic) {
t.Fatalf("panic message:\ngot: %s\nwant: %s", gotPanic, tt.wantPanic)
}
}
})
}
}
// TODO: Delete this hack when we drop Go1.6 support.
func tRun(t *testing.T, name string, f func(t *testing.T)) {
type runner interface {
Run(string, func(t *testing.T)) bool
}
var ti interface{} = t
if r, ok := ti.(runner); ok {
r.Run(name, f)
} else {
t.Logf("Test: %s", name)
f(t)
}
}

261
vendor/github.com/google/go-cmp/cmp/path.go generated vendored Normal file
View File

@ -0,0 +1,261 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.
package cmp
import (
"fmt"
"reflect"
"strings"
"unicode"
"unicode/utf8"
)
type (
// Path is a list of PathSteps describing the sequence of operations to get
// from some root type to the current position in the value tree.
// The first Path element is always an operation-less PathStep that exists
// simply to identify the initial type.
//
// When traversing structs with embedded structs, the embedded struct will
// always be accessed as a field before traversing the fields of the
// embedded struct themselves. That is, an exported field from the
// embedded struct will never be accessed directly from the parent struct.
Path []PathStep
// PathStep is a union-type for specific operations to traverse
// a value's tree structure. Users of this package never need to implement
// these types as values of this type will be returned by this package.
PathStep interface {
String() string
Type() reflect.Type // Resulting type after performing the path step
isPathStep()
}
// SliceIndex is an index operation on a slice or array at some index Key.
SliceIndex interface {
PathStep
Key() int
isSliceIndex()
}
// MapIndex is an index operation on a map at some index Key.
MapIndex interface {
PathStep
Key() reflect.Value
isMapIndex()
}
// TypeAssertion represents a type assertion on an interface.
TypeAssertion interface {
PathStep
isTypeAssertion()
}
// StructField represents a struct field access on a field called Name.
StructField interface {
PathStep
Name() string
Index() int
isStructField()
}
// Indirect represents pointer indirection on the parent type.
Indirect interface {
PathStep
isIndirect()
}
// Transform is a transformation from the parent type to the current type.
Transform interface {
PathStep
Name() string
Func() reflect.Value
isTransform()
}
)
func (pa *Path) push(s PathStep) {
*pa = append(*pa, s)
}
func (pa *Path) pop() {
*pa = (*pa)[:len(*pa)-1]
}
// Last returns the last PathStep in the Path.
// If the path is empty, this returns a non-nil PathStep that reports a nil Type.
func (pa Path) Last() PathStep {
if len(pa) > 0 {
return pa[len(pa)-1]
}
return pathStep{}
}
// String returns the simplified path to a node.
// The simplified path only contains struct field accesses.
//
// For example:
// MyMap.MySlices.MyField
func (pa Path) String() string {
var ss []string
for _, s := range pa {
if _, ok := s.(*structField); ok {
ss = append(ss, s.String())
}
}
return strings.TrimPrefix(strings.Join(ss, ""), ".")
}
// GoString returns the path to a specific node using Go syntax.
//
// For example:
// (*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField
func (pa Path) GoString() string {
var ssPre, ssPost []string
var numIndirect int
for i, s := range pa {
var nextStep PathStep
if i+1 < len(pa) {
nextStep = pa[i+1]
}
switch s := s.(type) {
case *indirect:
numIndirect++
pPre, pPost := "(", ")"
switch nextStep.(type) {
case *indirect:
continue // Next step is indirection, so let them batch up
case *structField:
numIndirect-- // Automatic indirection on struct fields
case nil:
pPre, pPost = "", "" // Last step; no need for parenthesis
}
if numIndirect > 0 {
ssPre = append(ssPre, pPre+strings.Repeat("*", numIndirect))
ssPost = append(ssPost, pPost)
}
numIndirect = 0
continue
case *transform:
ssPre = append(ssPre, s.trans.name+"(")
ssPost = append(ssPost, ")")
continue
case *typeAssertion:
// Elide type assertions immediately following a transform to
// prevent overly verbose path printouts.
// Some transforms return interface{} because of Go's lack of
// generics, but typically take in and return the exact same
// concrete type. Other times, the transform creates an anonymous
// struct, which will be very verbose to print.
if _, ok := nextStep.(*transform); ok {
continue
}
}
ssPost = append(ssPost, s.String())
}
for i, j := 0, len(ssPre)-1; i < j; i, j = i+1, j-1 {
ssPre[i], ssPre[j] = ssPre[j], ssPre[i]
}
return strings.Join(ssPre, "") + strings.Join(ssPost, "")
}
type (
pathStep struct {
typ reflect.Type
}
sliceIndex struct {
pathStep
key int
}
mapIndex struct {
pathStep
key reflect.Value
}
typeAssertion struct {
pathStep
}
structField struct {
pathStep
name string
idx int
// These fields are used for forcibly accessing an unexported field.
// pvx, pvy, and field are only valid if unexported is true.
unexported bool
force bool // Forcibly allow visibility
pvx, pvy reflect.Value // Parent values
field reflect.StructField // Field information
}
indirect struct {
pathStep
}
transform struct {
pathStep
trans *transformer
}
)
func (ps pathStep) Type() reflect.Type { return ps.typ }
func (ps pathStep) String() string {
if ps.typ == nil {
return "<nil>"
}
s := ps.typ.String()
if s == "" || strings.ContainsAny(s, "{}\n") {
return "root" // Type too simple or complex to print
}
return fmt.Sprintf("{%s}", s)
}
func (si sliceIndex) String() string { return fmt.Sprintf("[%d]", si.key) }
func (mi mapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) }
func (ta typeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) }
func (sf structField) String() string { return fmt.Sprintf(".%s", sf.name) }
func (in indirect) String() string { return "*" }
func (tf transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) }
func (si sliceIndex) Key() int { return si.key }
func (mi mapIndex) Key() reflect.Value { return mi.key }
func (sf structField) Name() string { return sf.name }
func (sf structField) Index() int { return sf.idx }
func (tf transform) Name() string { return tf.trans.name }
func (tf transform) Func() reflect.Value { return tf.trans.fnc }
func (pathStep) isPathStep() {}
func (sliceIndex) isSliceIndex() {}
func (mapIndex) isMapIndex() {}
func (typeAssertion) isTypeAssertion() {}
func (structField) isStructField() {}
func (indirect) isIndirect() {}
func (transform) isTransform() {}
var (
_ SliceIndex = sliceIndex{}
_ MapIndex = mapIndex{}
_ TypeAssertion = typeAssertion{}
_ StructField = structField{}
_ Indirect = indirect{}
_ Transform = transform{}
_ PathStep = sliceIndex{}
_ PathStep = mapIndex{}
_ PathStep = typeAssertion{}
_ PathStep = structField{}
_ PathStep = indirect{}
_ PathStep = transform{}
)
// isExported reports whether the identifier is exported.
func isExported(id string) bool {
r, _ := utf8.DecodeRuneInString(id)
return unicode.IsUpper(r)
}
// isValid reports whether the identifier is valid.
// Empty and underscore-only strings are not valid.
func isValid(id string) bool {
ok := id != "" && id != "_"
for j, c := range id {
ok = ok && (j > 0 || !unicode.IsDigit(c))
ok = ok && (c == '_' || unicode.IsLetter(c) || unicode.IsDigit(c))
}
return ok
}

406
vendor/github.com/google/go-cmp/cmp/reporter.go generated vendored Normal file
View File

@ -0,0 +1,406 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.
package cmp
import (
"fmt"
"math"
"reflect"
"sort"
"strings"
)
// TODO: Can we leave the interface for a reporter here in the cmp package
// and somehow extract the implementation of defaultReporter into cmp/report?
type defaultReporter struct {
Option
diffs []string // List of differences, possibly truncated
ndiffs int // Total number of differences
nbytes int // Number of bytes in diffs
nlines int // Number of lines in diffs
}
var _ reporter = (*defaultReporter)(nil)
func (r *defaultReporter) Report(x, y reflect.Value, eq bool, p Path) {
// TODO: Is there a way to nicely print added/modified/removed elements
// from a slice? This will most certainly require support from the
// equality logic, but what would be the right API for this?
//
// The current API is equivalent to a Hamming distance for measuring the
// difference between two sequences of symbols. That is, the only operation
// we can represent is substitution. The new API would need to handle a
// Levenshtein distance, such that insertions, deletions, and substitutions
// are permitted. Furthermore, this will require an algorithm for computing
// the edit distance. Unfortunately, the time complexity for a minimal
// edit distance algorithm is not much better than O(n^2).
// There are approximations for the algorithm that can run much faster.
// See literature on computing Levenshtein distance.
//
// Passing in a pair of x and y is actually good for representing insertion
// and deletion by the fact that x or y may be an invalid value. However,
// we may need to pass in two paths px and py, to indicate the paths
// relative to x and y. Alternative, since we only perform the Levenshtein
// distance on slices, maybe we alter the SliceIndex type to record
// two different indexes.
// TODO: Perhaps we should coalesce differences on primitive kinds
// together if the number of differences exceeds some ratio.
// For example, comparing two SHA256s leads to many byte differences.
if eq {
// TODO: Maybe print some equal results for context?
return // Ignore equal results
}
const maxBytes = 4096
const maxLines = 256
r.ndiffs++
if r.nbytes < maxBytes && r.nlines < maxLines {
sx := prettyPrint(x, true)
sy := prettyPrint(y, true)
if sx == sy {
// Use of Stringer is not helpful, so rely on more exact formatting.
sx = prettyPrint(x, false)
sy = prettyPrint(y, false)
}
s := fmt.Sprintf("%#v:\n\t-: %s\n\t+: %s\n", p, sx, sy)
r.diffs = append(r.diffs, s)
r.nbytes += len(s)
r.nlines += strings.Count(s, "\n")
}
}
func (r *defaultReporter) String() string {
s := strings.Join(r.diffs, "")
if r.ndiffs == len(r.diffs) {
return s
}
return fmt.Sprintf("%s... %d more differences ...", s, len(r.diffs)-r.ndiffs)
}
var stringerIface = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
func prettyPrint(v reflect.Value, useStringer bool) string {
return formatAny(v, formatConfig{useStringer, true, true, true}, nil)
}
type formatConfig struct {
useStringer bool // Should the String method be used if available?
printType bool // Should we print the type before the value?
followPointers bool // Should we recursively follow pointers?
realPointers bool // Should we print the real address of pointers?
}
// formatAny prints the value v in a pretty formatted manner.
// This is similar to fmt.Sprintf("%+v", v) except this:
// * Prints the type unless it can be elided.
// * Avoids printing struct fields that are zero.
// * Prints a nil-slice as being nil, not empty.
// * Prints map entries in deterministic order.
func formatAny(v reflect.Value, conf formatConfig, visited map[uintptr]bool) string {
// TODO: Should this be a multi-line printout in certain situations?
if !v.IsValid() {
return "<non-existent>"
}
if conf.useStringer && v.Type().Implements(stringerIface) {
if v.Kind() == reflect.Ptr && v.IsNil() {
return "<nil>"
}
return fmt.Sprintf("%q", v.Interface().(fmt.Stringer).String())
}
switch v.Kind() {
case reflect.Bool:
return fmt.Sprint(v.Bool())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return fmt.Sprint(v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
if v.Type().PkgPath() == "" || v.Kind() == reflect.Uintptr {
return formatHex(v.Uint()) // Unnamed uints are usually bytes or words
}
return fmt.Sprint(v.Uint()) // Named uints are usually enumerations
case reflect.Float32, reflect.Float64:
return fmt.Sprint(v.Float())
case reflect.Complex64, reflect.Complex128:
return fmt.Sprint(v.Complex())
case reflect.String:
return fmt.Sprintf("%q", v)
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
return formatPointer(v, conf)
case reflect.Ptr:
if v.IsNil() {
if conf.printType {
return fmt.Sprintf("(%v)(nil)", v.Type())
}
return "<nil>"
}
if visited[v.Pointer()] || !conf.followPointers {
return formatPointer(v, conf)
}
visited = insertPointer(visited, v.Pointer())
return "&" + formatAny(v.Elem(), conf, visited)
case reflect.Interface:
if v.IsNil() {
if conf.printType {
return fmt.Sprintf("%v(nil)", v.Type())
}
return "<nil>"
}
return formatAny(v.Elem(), conf, visited)
case reflect.Slice:
if v.IsNil() {
if conf.printType {
return fmt.Sprintf("%v(nil)", v.Type())
}
return "<nil>"
}
if visited[v.Pointer()] {
return formatPointer(v, conf)
}
visited = insertPointer(visited, v.Pointer())
fallthrough
case reflect.Array:
var ss []string
subConf := conf
subConf.printType = v.Type().Elem().Kind() == reflect.Interface
for i := 0; i < v.Len(); i++ {
s := formatAny(v.Index(i), subConf, visited)
ss = append(ss, s)
}
s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
if conf.printType {
return v.Type().String() + s
}
return s
case reflect.Map:
if v.IsNil() {
if conf.printType {
return fmt.Sprintf("%v(nil)", v.Type())
}
return "<nil>"
}
if visited[v.Pointer()] {
return formatPointer(v, conf)
}
visited = insertPointer(visited, v.Pointer())
var ss []string
subConf := conf
subConf.printType = v.Type().Elem().Kind() == reflect.Interface
for _, k := range sortKeys(v.MapKeys()) {
sk := formatAny(k, formatConfig{realPointers: conf.realPointers}, visited)
sv := formatAny(v.MapIndex(k), subConf, visited)
ss = append(ss, fmt.Sprintf("%s: %s", sk, sv))
}
s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
if conf.printType {
return v.Type().String() + s
}
return s
case reflect.Struct:
var ss []string
subConf := conf
subConf.printType = true
for i := 0; i < v.NumField(); i++ {
vv := v.Field(i)
if isZero(vv) {
continue // Elide zero value fields
}
name := v.Type().Field(i).Name
subConf.useStringer = conf.useStringer && isExported(name)
s := formatAny(vv, subConf, visited)
ss = append(ss, fmt.Sprintf("%s: %s", name, s))
}
s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
if conf.printType {
return v.Type().String() + s
}
return s
default:
panic(fmt.Sprintf("%v kind not handled", v.Kind()))
}
}
func formatPointer(v reflect.Value, conf formatConfig) string {
p := v.Pointer()
if !conf.realPointers {
p = 0 // For deterministic printing purposes
}
s := formatHex(uint64(p))
if conf.printType {
return fmt.Sprintf("(%v)(%s)", v.Type(), s)
}
return s
}
func formatHex(u uint64) string {
var f string
switch {
case u <= 0xff:
f = "0x%02x"
case u <= 0xffff:
f = "0x%04x"
case u <= 0xffffff:
f = "0x%06x"
case u <= 0xffffffff:
f = "0x%08x"
case u <= 0xffffffffff:
f = "0x%010x"
case u <= 0xffffffffffff:
f = "0x%012x"
case u <= 0xffffffffffffff:
f = "0x%014x"
case u <= 0xffffffffffffffff:
f = "0x%016x"
}
return fmt.Sprintf(f, u)
}
// insertPointer insert p into m, allocating m if necessary.
func insertPointer(m map[uintptr]bool, p uintptr) map[uintptr]bool {
if m == nil {
m = make(map[uintptr]bool)
}
m[p] = true
return m
}
// isZero reports whether v is the zero value.
// This does not rely on Interface and so can be used on unexported fields.
func isZero(v reflect.Value) bool {
switch v.Kind() {
case reflect.Bool:
return v.Bool() == false
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Complex64, reflect.Complex128:
return v.Complex() == 0
case reflect.String:
return v.String() == ""
case reflect.UnsafePointer:
return v.Pointer() == 0
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
return v.IsNil()
case reflect.Array:
for i := 0; i < v.Len(); i++ {
if !isZero(v.Index(i)) {
return false
}
}
return true
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
if !isZero(v.Field(i)) {
return false
}
}
return true
}
return false
}
// isLess is a generic function for sorting arbitrary map keys.
// The inputs must be of the same type and must be comparable.
func isLess(x, y reflect.Value) bool {
switch x.Type().Kind() {
case reflect.Bool:
return !x.Bool() && y.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return x.Int() < y.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return x.Uint() < y.Uint()
case reflect.Float32, reflect.Float64:
fx, fy := x.Float(), y.Float()
return fx < fy || math.IsNaN(fx) && !math.IsNaN(fy)
case reflect.Complex64, reflect.Complex128:
cx, cy := x.Complex(), y.Complex()
rx, ix, ry, iy := real(cx), imag(cx), real(cy), imag(cy)
if rx == ry || (math.IsNaN(rx) && math.IsNaN(ry)) {
return ix < iy || math.IsNaN(ix) && !math.IsNaN(iy)
}
return rx < ry || math.IsNaN(rx) && !math.IsNaN(ry)
case reflect.Ptr, reflect.UnsafePointer, reflect.Chan:
return x.Pointer() < y.Pointer()
case reflect.String:
return x.String() < y.String()
case reflect.Array:
for i := 0; i < x.Len(); i++ {
if isLess(x.Index(i), y.Index(i)) {
return true
}
if isLess(y.Index(i), x.Index(i)) {
return false
}
}
return false
case reflect.Struct:
for i := 0; i < x.NumField(); i++ {
if isLess(x.Field(i), y.Field(i)) {
return true
}
if isLess(y.Field(i), x.Field(i)) {
return false
}
}
return false
case reflect.Interface:
vx, vy := x.Elem(), y.Elem()
if !vx.IsValid() || !vy.IsValid() {
return !vx.IsValid() && vy.IsValid()
}
tx, ty := vx.Type(), vy.Type()
if tx == ty {
return isLess(x.Elem(), y.Elem())
}
if tx.Kind() != ty.Kind() {
return vx.Kind() < vy.Kind()
}
if tx.String() != ty.String() {
return tx.String() < ty.String()
}
if tx.PkgPath() != ty.PkgPath() {
return tx.PkgPath() < ty.PkgPath()
}
// This can happen in rare situations, so we fallback to just comparing
// the unique pointer for a reflect.Type. This guarantees deterministic
// ordering within a program, but it is obviously not stable.
return reflect.ValueOf(vx.Type()).Pointer() < reflect.ValueOf(vy.Type()).Pointer()
default:
// Must be Func, Map, or Slice; which are not comparable.
panic(fmt.Sprintf("%T is not comparable", x.Type()))
}
}
// sortKey sorts a list of map keys, deduplicating keys if necessary.
func sortKeys(vs []reflect.Value) []reflect.Value {
if len(vs) == 0 {
return vs
}
// Sort the map keys.
sort.Sort(valueSorter(vs))
// Deduplicate keys (fails for NaNs).
vs2 := vs[:1]
for _, v := range vs[1:] {
if v.Interface() != vs2[len(vs2)-1].Interface() {
vs2 = append(vs2, v)
}
}
return vs2
}
// TODO: Use sort.Slice once Google AppEngine is on Go1.8 or above.
type valueSorter []reflect.Value
func (vs valueSorter) Len() int { return len(vs) }
func (vs valueSorter) Less(i, j int) bool { return isLess(vs[i], vs[j]) }
func (vs valueSorter) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] }

227
vendor/github.com/google/go-cmp/cmp/reporter_test.go generated vendored Normal file
View File

@ -0,0 +1,227 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.
package cmp
import (
"bytes"
"io"
"math"
"reflect"
"testing"
)
func TestFormatAny(t *testing.T) {
type key struct {
a int
b string
c chan bool
}
tests := []struct {
in interface{}
want string
}{{
in: []int{},
want: "[]int{}",
}, {
in: []int(nil),
want: "[]int(nil)",
}, {
in: []int{1, 2, 3, 4, 5},
want: "[]int{1, 2, 3, 4, 5}",
}, {
in: []interface{}{1, true, "hello", struct{ A, B int }{1, 2}},
want: "[]interface {}{1, true, \"hello\", struct { A int; B int }{A: 1, B: 2}}",
}, {
in: []struct{ A, B int }{{1, 2}, {0, 4}, {}},
want: "[]struct { A int; B int }{{A: 1, B: 2}, {B: 4}, {}}",
}, {
in: map[*int]string{new(int): "hello"},
want: "map[*int]string{0x00: \"hello\"}",
}, {
in: map[key]string{{}: "hello"},
want: "map[cmp.key]string{{}: \"hello\"}",
}, {
in: map[key]string{{a: 5, b: "key", c: make(chan bool)}: "hello"},
want: "map[cmp.key]string{{a: 5, b: \"key\", c: (chan bool)(0x00)}: \"hello\"}",
}, {
in: map[io.Reader]string{new(bytes.Reader): "hello"},
want: "map[io.Reader]string{0x00: \"hello\"}",
}, {
in: func() interface{} {
var a = []interface{}{nil}
a[0] = a
return a
}(),
want: "[]interface {}{([]interface {})(0x00)}",
}, {
in: func() interface{} {
type A *A
var a A
a = &a
return a
}(),
want: "&(cmp.A)(0x00)",
}, {
in: func() interface{} {
type A map[*A]A
a := make(A)
a[&a] = a
return a
}(),
want: "cmp.A{0x00: 0x00}",
}, {
in: func() interface{} {
var a [2]interface{}
a[0] = &a
return a
}(),
want: "[2]interface {}{&[2]interface {}{(*[2]interface {})(0x00), interface {}(nil)}, interface {}(nil)}",
}}
for i, tt := range tests {
got := formatAny(reflect.ValueOf(tt.in), formatConfig{true, true, true, false}, nil)
if got != tt.want {
t.Errorf("test %d, pretty print:\ngot %q\nwant %q", i, got, tt.want)
}
}
}
func TestSortKeys(t *testing.T) {
type (
MyString string
MyArray [2]int
MyStruct struct {
A MyString
B MyArray
C chan float64
}
EmptyStruct struct{}
)
opts := []Option{
Comparer(func(x, y float64) bool {
if math.IsNaN(x) && math.IsNaN(y) {
return true
}
return x == y
}),
Comparer(func(x, y complex128) bool {
rx, ix, ry, iy := real(x), imag(x), real(y), imag(y)
if math.IsNaN(rx) && math.IsNaN(ry) {
rx, ry = 0, 0
}
if math.IsNaN(ix) && math.IsNaN(iy) {
ix, iy = 0, 0
}
return rx == ry && ix == iy
}),
Comparer(func(x, y chan bool) bool { return true }),
Comparer(func(x, y chan int) bool { return true }),
Comparer(func(x, y chan float64) bool { return true }),
Comparer(func(x, y chan interface{}) bool { return true }),
Comparer(func(x, y *int) bool { return true }),
}
tests := []struct {
in map[interface{}]bool // Set of keys to sort
want []interface{}
}{{
in: map[interface{}]bool{1: true, 2: true, 3: true},
want: []interface{}{1, 2, 3},
}, {
in: map[interface{}]bool{
nil: true,
true: true,
false: true,
-5: true,
-55: true,
-555: true,
uint(1): true,
uint(11): true,
uint(111): true,
"abc": true,
"abcd": true,
"abcde": true,
"foo": true,
"bar": true,
MyString("abc"): true,
MyString("abcd"): true,
MyString("abcde"): true,
new(int): true,
new(int): true,
make(chan bool): true,
make(chan bool): true,
make(chan int): true,
make(chan interface{}): true,
math.Inf(+1): true,
math.Inf(-1): true,
1.2345: true,
12.345: true,
123.45: true,
1234.5: true,
0 + 0i: true,
1 + 0i: true,
2 + 0i: true,
0 + 1i: true,
0 + 2i: true,
0 + 3i: true,
[2]int{2, 3}: true,
[2]int{4, 0}: true,
[2]int{2, 4}: true,
MyArray([2]int{2, 4}): true,
EmptyStruct{}: true,
MyStruct{
"bravo", [2]int{2, 3}, make(chan float64),
}: true,
MyStruct{
"alpha", [2]int{3, 3}, make(chan float64),
}: true,
},
want: []interface{}{
nil, false, true,
-555, -55, -5, uint(1), uint(11), uint(111),
math.Inf(-1), 1.2345, 12.345, 123.45, 1234.5, math.Inf(+1),
(0 + 0i), (0 + 1i), (0 + 2i), (0 + 3i), (1 + 0i), (2 + 0i),
[2]int{2, 3}, [2]int{2, 4}, [2]int{4, 0}, MyArray([2]int{2, 4}),
make(chan bool), make(chan bool), make(chan int), make(chan interface{}),
new(int), new(int),
MyString("abc"), MyString("abcd"), MyString("abcde"), "abc", "abcd", "abcde", "bar", "foo",
EmptyStruct{},
MyStruct{"alpha", [2]int{3, 3}, make(chan float64)},
MyStruct{"bravo", [2]int{2, 3}, make(chan float64)},
},
}, {
// NaN values cannot be properly deduplicated.
// This is okay since map entries with NaN in the keys cannot be
// retrieved anyways.
in: map[interface{}]bool{
math.NaN(): true,
math.NaN(): true,
complex(0, math.NaN()): true,
complex(0, math.NaN()): true,
complex(math.NaN(), 0): true,
complex(math.NaN(), 0): true,
complex(math.NaN(), math.NaN()): true,
},
want: []interface{}{
math.NaN(), math.NaN(), math.NaN(), math.NaN(),
complex(math.NaN(), math.NaN()), complex(math.NaN(), math.NaN()),
complex(math.NaN(), 0), complex(math.NaN(), 0), complex(math.NaN(), 0), complex(math.NaN(), 0),
complex(0, math.NaN()), complex(0, math.NaN()), complex(0, math.NaN()), complex(0, math.NaN()),
},
}}
for i, tt := range tests {
keys := append(reflect.ValueOf(tt.in).MapKeys(), reflect.ValueOf(tt.in).MapKeys()...)
var got []interface{}
for _, k := range sortKeys(keys) {
got = append(got, k.Interface())
}
if !Equal(got, tt.want, opts...) {
t.Errorf("test %d, output mismatch:\ngot %#v\nwant %#v", i, got, tt.want)
}
}
}

15
vendor/github.com/google/go-cmp/cmp/unsafe_panic.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.
// +build appengine js
package cmp
import "reflect"
const supportAllowUnexported = false
func unsafeRetrieveField(reflect.Value, reflect.StructField) reflect.Value {
panic("unsafeRetrieveField is not implemented")
}

23
vendor/github.com/google/go-cmp/cmp/unsafe_reflect.go generated vendored Normal file
View File

@ -0,0 +1,23 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.
// +build !appengine,!js
package cmp
import (
"reflect"
"unsafe"
)
const supportAllowUnexported = true
// unsafeRetrieveField uses unsafe to forcibly retrieve any field from a struct
// such that the value has read-write permissions.
//
// The parent struct, v, must be addressable, while f must be a StructField
// describing the field to retrieve.
func unsafeRetrieveField(v reflect.Value, f reflect.StructField) reflect.Value {
return reflect.NewAt(f.Type, unsafe.Pointer(v.UnsafeAddr()+f.Offset)).Elem()
}