Update dependencies, enable pruning for vendor/

So, `dep` got an nice new feature to remove tests and non-go files from
`vendor/`, and this brings the size of the vendor directory from ~300MiB
down to ~20MiB. We don that now.
This commit is contained in:
Alexander Neumann 2018-08-01 19:43:44 +02:00
parent 3422c1ca83
commit bff635bc5f
6741 changed files with 26942 additions and 4902033 deletions

View file

@ -50,7 +50,7 @@ import (
//
// The series of '.', 'X', 'Y', and 'M' characters at the bottom represents
// the currently established path from the forward and reverse searches,
// seperated by a '|' character.
// separated by a '|' character.
const (
updateDelay = 100 * time.Millisecond

View file

@ -106,9 +106,9 @@ func (r Result) Similar() bool {
// Difference reports whether two lists of lengths nx and ny are equal
// given the definition of equality provided as f.
//
// This function may return a edit-script, which is a sequence of operations
// needed to convert one list into the other. If non-nil, the following
// invariants for the edit-script are maintained:
// This function returns an edit-script, which is a sequence of operations
// needed to convert one list into the other. The following invariants for
// the edit-script are maintained:
// • eq == (es.Dist()==0)
// • nx == es.LenX()
// • ny == es.LenY()
@ -117,17 +117,7 @@ func (r Result) Similar() bool {
// produces an edit-script with a minimal Levenshtein distance). This algorithm
// favors performance over optimality. The exact output is not guaranteed to
// be stable and may change over time.
func Difference(nx, ny int, f EqualFunc) (eq bool, es EditScript) {
es = searchGraph(nx, ny, f)
st := es.stats()
eq = len(es) == st.NI
if !eq && st.NI < (nx+ny)/4 {
return eq, nil // Edit-script more distracting than helpful
}
return eq, es
}
func searchGraph(nx, ny int, f EqualFunc) EditScript {
func Difference(nx, ny int, f EqualFunc) (es EditScript) {
// This algorithm is based on traversing what is known as an "edit-graph".
// See Figure 1 from "An O(ND) Difference Algorithm and Its Variations"
// by Eugene W. Myers. Since D can be as large as N itself, this is

View file

@ -1,467 +0,0 @@
// 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 diff
import (
"fmt"
"math/rand"
"strings"
"testing"
"unicode"
)
func TestDifference(t *testing.T) {
tests := []struct {
// Before passing x and y to Difference, we strip all spaces so that
// they can be used by the test author to indicate a missing symbol
// in one of the lists.
x, y string
want string
}{{
x: "",
y: "",
want: "",
}, {
x: "#",
y: "#",
want: ".",
}, {
x: "##",
y: "# ",
want: ".X",
}, {
x: "a#",
y: "A ",
want: "MX",
}, {
x: "#a",
y: " A",
want: "XM",
}, {
x: "# ",
y: "##",
want: ".Y",
}, {
x: " #",
y: "@#",
want: "Y.",
}, {
x: "@#",
y: " #",
want: "X.",
}, {
x: "##########0123456789",
y: " 0123456789",
want: "XXXXXXXXXX..........",
}, {
x: " 0123456789",
y: "##########0123456789",
want: "YYYYYYYYYY..........",
}, {
x: "#####0123456789#####",
y: " 0123456789 ",
want: "XXXXX..........XXXXX",
}, {
x: " 0123456789 ",
y: "#####0123456789#####",
want: "YYYYY..........YYYYY",
}, {
x: "01234##########56789",
y: "01234 56789",
want: ".....XXXXXXXXXX.....",
}, {
x: "01234 56789",
y: "01234##########56789",
want: ".....YYYYYYYYYY.....",
}, {
x: "0123456789##########",
y: "0123456789 ",
want: "..........XXXXXXXXXX",
}, {
x: "0123456789 ",
y: "0123456789##########",
want: "..........YYYYYYYYYY",
}, {
x: "abcdefghij0123456789",
y: "ABCDEFGHIJ0123456789",
want: "MMMMMMMMMM..........",
}, {
x: "ABCDEFGHIJ0123456789",
y: "abcdefghij0123456789",
want: "MMMMMMMMMM..........",
}, {
x: "01234abcdefghij56789",
y: "01234ABCDEFGHIJ56789",
want: ".....MMMMMMMMMM.....",
}, {
x: "01234ABCDEFGHIJ56789",
y: "01234abcdefghij56789",
want: ".....MMMMMMMMMM.....",
}, {
x: "0123456789abcdefghij",
y: "0123456789ABCDEFGHIJ",
want: "..........MMMMMMMMMM",
}, {
x: "0123456789ABCDEFGHIJ",
y: "0123456789abcdefghij",
want: "..........MMMMMMMMMM",
}, {
x: "ABCDEFGHIJ0123456789 ",
y: " 0123456789abcdefghij",
want: "XXXXXXXXXX..........YYYYYYYYYY",
}, {
x: " 0123456789abcdefghij",
y: "ABCDEFGHIJ0123456789 ",
want: "YYYYYYYYYY..........XXXXXXXXXX",
}, {
x: "ABCDE0123456789 FGHIJ",
y: " 0123456789abcdefghij",
want: "XXXXX..........YYYYYMMMMM",
}, {
x: " 0123456789abcdefghij",
y: "ABCDE0123456789 FGHIJ",
want: "YYYYY..........XXXXXMMMMM",
}, {
x: "ABCDE01234F G H I J 56789 ",
y: " 01234 a b c d e56789fghij",
want: "XXXXX.....XYXYXYXYXY.....YYYYY",
}, {
x: " 01234a b c d e 56789fghij",
y: "ABCDE01234 F G H I J56789 ",
want: "YYYYY.....XYXYXYXYXY.....XXXXX",
}, {
x: "FGHIJ01234ABCDE56789 ",
y: " 01234abcde56789fghij",
want: "XXXXX.....MMMMM.....YYYYY",
}, {
x: " 01234abcde56789fghij",
y: "FGHIJ01234ABCDE56789 ",
want: "YYYYY.....MMMMM.....XXXXX",
}, {
x: "ABCAB BA ",
y: " C BABAC",
want: "XX.X.Y..Y",
}, {
x: "# #### ###",
y: "#y####yy###",
want: ".Y....YY...",
}, {
x: "# #### # ##x#x",
y: "#y####y y## # ",
want: ".Y....YXY..X.X",
}, {
x: "###z#z###### x #",
y: "#y##Z#Z###### yy#",
want: ".Y..M.M......XYY.",
}, {
x: "0 12z3x 456789 x x 0",
y: "0y12Z3 y456789y y y0",
want: ".Y..M.XY......YXYXY.",
}, {
x: "0 2 4 6 8 ..................abXXcdEXF.ghXi",
y: " 1 3 5 7 9..................AB CDE F.GH I",
want: "XYXYXYXYXY..................MMXXMM.X..MMXM",
}, {
x: "I HG.F EDC BA..................9 7 5 3 1 ",
y: "iXhg.FXEdcXXba.................. 8 6 4 2 0",
want: "MYMM..Y.MMYYMM..................XYXYXYXYXY",
}, {
x: "x1234",
y: " 1234",
want: "X....",
}, {
x: "x123x4",
y: " 123 4",
want: "X...X.",
}, {
x: "x1234x56",
y: " 1234 ",
want: "X....XXX",
}, {
x: "x1234xxx56",
y: " 1234 56",
want: "X....XXX..",
}, {
x: ".1234...ab",
y: " 1234 AB",
want: "X....XXXMM",
}, {
x: "x1234xxab.",
y: " 1234 AB ",
want: "X....XXMMX",
}, {
x: " 0123456789",
y: "9012345678 ",
want: "Y.........X",
}, {
x: " 0123456789",
y: "8901234567 ",
want: "YY........XX",
}, {
x: " 0123456789",
y: "7890123456 ",
want: "YYY.......XXX",
}, {
x: " 0123456789",
y: "6789012345 ",
want: "YYYY......XXXX",
}, {
x: "0123456789 ",
y: " 5678901234",
want: "XXXXX.....YYYYY",
}, {
x: "0123456789 ",
y: " 4567890123",
want: "XXXX......YYYY",
}, {
x: "0123456789 ",
y: " 3456789012",
want: "XXX.......YYY",
}, {
x: "0123456789 ",
y: " 2345678901",
want: "XX........YY",
}, {
x: "0123456789 ",
y: " 1234567890",
want: "X.........Y",
}, {
x: "0123456789",
y: "9876543210",
}, {
x: "0123456789",
y: "6725819034",
}, {
x: "FBQMOIGTLN72X90E4SP651HKRJUDA83CVZW",
y: "5WHXO10R9IVKZLCTAJ8P3NSEQM472G6UBDF",
}}
for _, tt := range tests {
tRun(t, "", func(t *testing.T) {
x := strings.Replace(tt.x, " ", "", -1)
y := strings.Replace(tt.y, " ", "", -1)
es := testStrings(t, x, y)
if got := es.String(); got != tt.want {
t.Errorf("Difference(%s, %s):\ngot %s\nwant %s", x, y, got, tt.want)
}
})
}
}
func TestDifferenceFuzz(t *testing.T) {
tests := []struct{ px, py, pm float32 }{
{px: 0.0, py: 0.0, pm: 0.1},
{px: 0.0, py: 0.1, pm: 0.0},
{px: 0.1, py: 0.0, pm: 0.0},
{px: 0.0, py: 0.1, pm: 0.1},
{px: 0.1, py: 0.0, pm: 0.1},
{px: 0.2, py: 0.2, pm: 0.2},
{px: 0.3, py: 0.1, pm: 0.2},
{px: 0.1, py: 0.3, pm: 0.2},
{px: 0.2, py: 0.2, pm: 0.2},
{px: 0.3, py: 0.3, pm: 0.3},
{px: 0.1, py: 0.1, pm: 0.5},
{px: 0.4, py: 0.1, pm: 0.5},
{px: 0.3, py: 0.2, pm: 0.5},
{px: 0.2, py: 0.3, pm: 0.5},
{px: 0.1, py: 0.4, pm: 0.5},
}
for i, tt := range tests {
tRun(t, fmt.Sprintf("P%d", i), func(t *testing.T) {
// Sweep from 1B to 1KiB.
for n := 1; n <= 1024; n <<= 1 {
tRun(t, fmt.Sprintf("N%d", n), func(t *testing.T) {
for j := 0; j < 10; j++ {
x, y := generateStrings(n, tt.px, tt.py, tt.pm, int64(j))
testStrings(t, x, y)
}
})
}
})
}
}
func benchmarkDifference(b *testing.B, n int) {
// TODO: Use testing.B.Run when we drop Go1.6 support.
x, y := generateStrings(n, 0.05, 0.05, 0.10, 0)
b.ReportAllocs()
b.SetBytes(int64(len(x) + len(y)))
for i := 0; i < b.N; i++ {
Difference(len(x), len(y), func(ix, iy int) Result {
return compareByte(x[ix], y[iy])
})
}
}
func BenchmarkDifference1K(b *testing.B) { benchmarkDifference(b, 1<<10) }
func BenchmarkDifference4K(b *testing.B) { benchmarkDifference(b, 1<<12) }
func BenchmarkDifference16K(b *testing.B) { benchmarkDifference(b, 1<<14) }
func BenchmarkDifference64K(b *testing.B) { benchmarkDifference(b, 1<<16) }
func BenchmarkDifference256K(b *testing.B) { benchmarkDifference(b, 1<<18) }
func BenchmarkDifference1M(b *testing.B) { benchmarkDifference(b, 1<<20) }
func generateStrings(n int, px, py, pm float32, seed int64) (string, string) {
if px+py+pm > 1.0 {
panic("invalid probabilities")
}
py += px
pm += py
b := make([]byte, n)
r := rand.New(rand.NewSource(seed))
r.Read(b)
var x, y []byte
for len(b) > 0 {
switch p := r.Float32(); {
case p < px: // UniqueX
x = append(x, b[0])
case p < py: // UniqueY
y = append(y, b[0])
case p < pm: // Modified
x = append(x, 'A'+(b[0]%26))
y = append(y, 'a'+(b[0]%26))
default: // Identity
x = append(x, b[0])
y = append(y, b[0])
}
b = b[1:]
}
return string(x), string(y)
}
func testStrings(t *testing.T, x, y string) EditScript {
wantEq := x == y
eq, es := Difference(len(x), len(y), func(ix, iy int) Result {
return compareByte(x[ix], y[iy])
})
if eq != wantEq {
t.Errorf("equality mismatch: got %v, want %v", eq, wantEq)
}
if es != nil {
if es.LenX() != len(x) {
t.Errorf("es.LenX = %d, want %d", es.LenX(), len(x))
}
if es.LenY() != len(y) {
t.Errorf("es.LenY = %d, want %d", es.LenY(), len(y))
}
if got := (es.Dist() == 0); got != wantEq {
t.Errorf("violation of equality invariant: got %v, want %v", got, wantEq)
}
if !validateScript(x, y, es) {
t.Errorf("invalid edit script: %v", es)
}
}
return es
}
func validateScript(x, y string, es EditScript) bool {
var bx, by []byte
for _, e := range es {
switch e {
case Identity:
if !compareByte(x[len(bx)], y[len(by)]).Equal() {
return false
}
bx = append(bx, x[len(bx)])
by = append(by, y[len(by)])
case UniqueX:
bx = append(bx, x[len(bx)])
case UniqueY:
by = append(by, y[len(by)])
case Modified:
if !compareByte(x[len(bx)], y[len(by)]).Similar() {
return false
}
bx = append(bx, x[len(bx)])
by = append(by, y[len(by)])
}
}
return string(bx) == x && string(by) == y
}
// compareByte returns a Result where the result is Equal if x == y,
// similar if x and y differ only in casing, and different otherwise.
func compareByte(x, y byte) (r Result) {
switch {
case x == y:
return equalResult // Identity
case unicode.ToUpper(rune(x)) == unicode.ToUpper(rune(y)):
return similarResult // Modified
default:
return differentResult // UniqueX or UniqueY
}
}
var (
equalResult = Result{NDiff: 0}
similarResult = Result{NDiff: 1}
differentResult = Result{NDiff: 2}
)
func TestResult(t *testing.T) {
tests := []struct {
result Result
wantEqual bool
wantSimilar bool
}{
// equalResult is equal since NDiff == 0, by definition of Equal method.
{equalResult, true, true},
// similarResult is similar since it is a binary result where only one
// element was compared (i.e., Either NSame==1 or NDiff==1).
{similarResult, false, true},
// differentResult is different since there are enough differences that
// it isn't even considered similar.
{differentResult, false, false},
// Zero value is always equal.
{Result{NSame: 0, NDiff: 0}, true, true},
// Binary comparisons (where NSame+NDiff == 1) are always similar.
{Result{NSame: 1, NDiff: 0}, true, true},
{Result{NSame: 0, NDiff: 1}, false, true},
// More complex ratios. The exact ratio for similarity may change,
// and may require updates to these test cases.
{Result{NSame: 1, NDiff: 1}, false, true},
{Result{NSame: 1, NDiff: 2}, false, true},
{Result{NSame: 1, NDiff: 3}, false, false},
{Result{NSame: 2, NDiff: 1}, false, true},
{Result{NSame: 2, NDiff: 2}, false, true},
{Result{NSame: 2, NDiff: 3}, false, true},
{Result{NSame: 3, NDiff: 1}, false, true},
{Result{NSame: 3, NDiff: 2}, false, true},
{Result{NSame: 3, NDiff: 3}, false, true},
{Result{NSame: 1000, NDiff: 0}, true, true},
{Result{NSame: 1000, NDiff: 1}, false, true},
{Result{NSame: 1000, NDiff: 2}, false, true},
{Result{NSame: 0, NDiff: 1000}, false, false},
{Result{NSame: 1, NDiff: 1000}, false, false},
{Result{NSame: 2, NDiff: 1000}, false, false},
}
for _, tt := range tests {
if got := tt.result.Equal(); got != tt.wantEqual {
t.Errorf("%#v.Equal() = %v, want %v", tt.result, got, tt.wantEqual)
}
if got := tt.result.Similar(); got != tt.wantSimilar {
t.Errorf("%#v.Similar() = %v, want %v", tt.result, got, tt.wantSimilar)
}
}
}
// 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)
}
}

View file

@ -1,116 +0,0 @@
// 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 testprotos
func Equal(x, y Message) bool {
if x == nil || y == nil {
return x == nil && y == nil
}
return x.String() == y.String()
}
type Message interface {
Proto()
String() string
}
type proto interface {
Proto()
}
type notComparable struct {
unexportedField func()
}
type Stringer struct{ X string }
func (s *Stringer) String() string { return s.X }
// Project1 protocol buffers
type (
Eagle_States int
Eagle_MissingCalls int
Dreamer_States int
Dreamer_MissingCalls int
Slap_States int
Goat_States int
Donkey_States int
SummerType int
Eagle struct {
proto
notComparable
Stringer
}
Dreamer struct {
proto
notComparable
Stringer
}
Slap struct {
proto
notComparable
Stringer
}
Goat struct {
proto
notComparable
Stringer
}
Donkey struct {
proto
notComparable
Stringer
}
)
// Project2 protocol buffers
type (
Germ struct {
proto
notComparable
Stringer
}
Dish struct {
proto
notComparable
Stringer
}
)
// Project3 protocol buffers
type (
Dirt struct {
proto
notComparable
Stringer
}
Wizard struct {
proto
notComparable
Stringer
}
Sadistic struct {
proto
notComparable
Stringer
}
)
// Project4 protocol buffers
type (
HoneyStatus int
PoisonType int
MetaData struct {
proto
notComparable
Stringer
}
Restrictions struct {
proto
notComparable
Stringer
}
)

View file

@ -1,267 +0,0 @@
// 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 teststructs
import (
"time"
pb "github.com/google/go-cmp/cmp/internal/testprotos"
)
// This is an sanitized example of equality from a real use-case.
// The original equality function was as follows:
/*
func equalEagle(x, y Eagle) bool {
if x.Name != y.Name &&
!reflect.DeepEqual(x.Hounds, y.Hounds) &&
x.Desc != y.Desc &&
x.DescLong != y.DescLong &&
x.Prong != y.Prong &&
x.StateGoverner != y.StateGoverner &&
x.PrankRating != y.PrankRating &&
x.FunnyPrank != y.FunnyPrank &&
!pb.Equal(x.Immutable.Proto(), y.Immutable.Proto()) {
return false
}
if len(x.Dreamers) != len(y.Dreamers) {
return false
}
for i := range x.Dreamers {
if !equalDreamer(x.Dreamers[i], y.Dreamers[i]) {
return false
}
}
if len(x.Slaps) != len(y.Slaps) {
return false
}
for i := range x.Slaps {
if !equalSlap(x.Slaps[i], y.Slaps[i]) {
return false
}
}
return true
}
func equalDreamer(x, y Dreamer) bool {
if x.Name != y.Name ||
x.Desc != y.Desc ||
x.DescLong != y.DescLong ||
x.ContSlapsInterval != y.ContSlapsInterval ||
x.Ornamental != y.Ornamental ||
x.Amoeba != y.Amoeba ||
x.Heroes != y.Heroes ||
x.FloppyDisk != y.FloppyDisk ||
x.MightiestDuck != y.MightiestDuck ||
x.FunnyPrank != y.FunnyPrank ||
!pb.Equal(x.Immutable.Proto(), y.Immutable.Proto()) {
return false
}
if len(x.Animal) != len(y.Animal) {
return false
}
for i := range x.Animal {
vx := x.Animal[i]
vy := y.Animal[i]
if reflect.TypeOf(x.Animal) != reflect.TypeOf(y.Animal) {
return false
}
switch vx.(type) {
case Goat:
if !equalGoat(vx.(Goat), vy.(Goat)) {
return false
}
case Donkey:
if !equalDonkey(vx.(Donkey), vy.(Donkey)) {
return false
}
default:
panic(fmt.Sprintf("unknown type: %T", vx))
}
}
if len(x.PreSlaps) != len(y.PreSlaps) {
return false
}
for i := range x.PreSlaps {
if !equalSlap(x.PreSlaps[i], y.PreSlaps[i]) {
return false
}
}
if len(x.ContSlaps) != len(y.ContSlaps) {
return false
}
for i := range x.ContSlaps {
if !equalSlap(x.ContSlaps[i], y.ContSlaps[i]) {
return false
}
}
return true
}
func equalSlap(x, y Slap) bool {
return x.Name == y.Name &&
x.Desc == y.Desc &&
x.DescLong == y.DescLong &&
pb.Equal(x.Args, y.Args) &&
x.Tense == y.Tense &&
x.Interval == y.Interval &&
x.Homeland == y.Homeland &&
x.FunnyPrank == y.FunnyPrank &&
pb.Equal(x.Immutable.Proto(), y.Immutable.Proto())
}
func equalGoat(x, y Goat) bool {
if x.Target != y.Target ||
x.FunnyPrank != y.FunnyPrank ||
!pb.Equal(x.Immutable.Proto(), y.Immutable.Proto()) {
return false
}
if len(x.Slaps) != len(y.Slaps) {
return false
}
for i := range x.Slaps {
if !equalSlap(x.Slaps[i], y.Slaps[i]) {
return false
}
}
return true
}
func equalDonkey(x, y Donkey) bool {
return x.Pause == y.Pause &&
x.Sleep == y.Sleep &&
x.FunnyPrank == y.FunnyPrank &&
pb.Equal(x.Immutable.Proto(), y.Immutable.Proto())
}
*/
type Eagle struct {
Name string
Hounds []string
Desc string
DescLong string
Dreamers []Dreamer
Prong int64
Slaps []Slap
StateGoverner string
PrankRating string
FunnyPrank string
Immutable *EagleImmutable
}
type EagleImmutable struct {
ID string
State *pb.Eagle_States
MissingCall *pb.Eagle_MissingCalls
Birthday time.Time
Death time.Time
Started time.Time
LastUpdate time.Time
Creator string
empty bool
}
type Dreamer struct {
Name string
Desc string
DescLong string
PreSlaps []Slap
ContSlaps []Slap
ContSlapsInterval int32
Animal []interface{} // Could be either Goat or Donkey
Ornamental bool
Amoeba int64
Heroes int32
FloppyDisk int32
MightiestDuck bool
FunnyPrank string
Immutable *DreamerImmutable
}
type DreamerImmutable struct {
ID string
State *pb.Dreamer_States
MissingCall *pb.Dreamer_MissingCalls
Calls int32
Started time.Time
Stopped time.Time
LastUpdate time.Time
empty bool
}
type Slap struct {
Name string
Desc string
DescLong string
Args pb.Message
Tense int32
Interval int32
Homeland uint32
FunnyPrank string
Immutable *SlapImmutable
}
type SlapImmutable struct {
ID string
Out pb.Message
MildSlap bool
PrettyPrint string
State *pb.Slap_States
Started time.Time
Stopped time.Time
LastUpdate time.Time
LoveRadius *LoveRadius
empty bool
}
type Goat struct {
Target string
Slaps []Slap
FunnyPrank string
Immutable *GoatImmutable
}
type GoatImmutable struct {
ID string
State *pb.Goat_States
Started time.Time
Stopped time.Time
LastUpdate time.Time
empty bool
}
type Donkey struct {
Pause bool
Sleep int32
FunnyPrank string
Immutable *DonkeyImmutable
}
type DonkeyImmutable struct {
ID string
State *pb.Donkey_States
Started time.Time
Stopped time.Time
LastUpdate time.Time
empty bool
}
type LoveRadius struct {
Summer *SummerLove
empty bool
}
type SummerLove struct {
Summary *SummerLoveSummary
empty bool
}
type SummerLoveSummary struct {
Devices []string
ChangeType []pb.SummerType
empty bool
}
func (EagleImmutable) Proto() *pb.Eagle { return nil }
func (DreamerImmutable) Proto() *pb.Dreamer { return nil }
func (SlapImmutable) Proto() *pb.Slap { return nil }
func (GoatImmutable) Proto() *pb.Goat { return nil }
func (DonkeyImmutable) Proto() *pb.Donkey { return nil }

View file

@ -1,74 +0,0 @@
// 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 teststructs
import (
"time"
pb "github.com/google/go-cmp/cmp/internal/testprotos"
)
// This is an sanitized example of equality from a real use-case.
// The original equality function was as follows:
/*
func equalBatch(b1, b2 *GermBatch) bool {
for _, b := range []*GermBatch{b1, b2} {
for _, l := range b.DirtyGerms {
sort.Slice(l, func(i, j int) bool { return l[i].String() < l[j].String() })
}
for _, l := range b.CleanGerms {
sort.Slice(l, func(i, j int) bool { return l[i].String() < l[j].String() })
}
}
if !pb.DeepEqual(b1.DirtyGerms, b2.DirtyGerms) ||
!pb.DeepEqual(b1.CleanGerms, b2.CleanGerms) ||
!pb.DeepEqual(b1.GermMap, b2.GermMap) {
return false
}
if len(b1.DishMap) != len(b2.DishMap) {
return false
}
for id := range b1.DishMap {
kpb1, err1 := b1.DishMap[id].Proto()
kpb2, err2 := b2.DishMap[id].Proto()
if !pb.Equal(kpb1, kpb2) || !reflect.DeepEqual(err1, err2) {
return false
}
}
return b1.HasPreviousResult == b2.HasPreviousResult &&
b1.DirtyID == b2.DirtyID &&
b1.CleanID == b2.CleanID &&
b1.GermStrain == b2.GermStrain &&
b1.TotalDirtyGerms == b2.TotalDirtyGerms &&
b1.InfectedAt.Equal(b2.InfectedAt)
}
*/
type GermBatch struct {
DirtyGerms, CleanGerms map[int32][]*pb.Germ
GermMap map[int32]*pb.Germ
DishMap map[int32]*Dish
HasPreviousResult bool
DirtyID, CleanID int32
GermStrain int32
TotalDirtyGerms int
InfectedAt time.Time
}
type Dish struct {
pb *pb.Dish
err error
}
func CreateDish(m *pb.Dish, err error) *Dish {
return &Dish{pb: m, err: err}
}
func (d *Dish) Proto() (*pb.Dish, error) {
if d.err != nil {
return nil, d.err
}
return d.pb, nil
}

View file

@ -1,77 +0,0 @@
// 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 teststructs
import (
"sync"
pb "github.com/google/go-cmp/cmp/internal/testprotos"
)
// This is an sanitized example of equality from a real use-case.
// The original equality function was as follows:
/*
func equalDirt(x, y *Dirt) bool {
if !reflect.DeepEqual(x.table, y.table) ||
!reflect.DeepEqual(x.ts, y.ts) ||
x.Discord != y.Discord ||
!pb.Equal(&x.Proto, &y.Proto) ||
len(x.wizard) != len(y.wizard) ||
len(x.sadistic) != len(y.sadistic) ||
x.lastTime != y.lastTime {
return false
}
for k, vx := range x.wizard {
vy, ok := y.wizard[k]
if !ok || !pb.Equal(vx, vy) {
return false
}
}
for k, vx := range x.sadistic {
vy, ok := y.sadistic[k]
if !ok || !pb.Equal(vx, vy) {
return false
}
}
return true
}
*/
type Dirt struct {
table Table // Always concrete type of MockTable
ts Timestamp
Discord DiscordState
Proto pb.Dirt
wizard map[string]*pb.Wizard
sadistic map[string]*pb.Sadistic
lastTime int64
mu sync.Mutex
}
type DiscordState int
type Timestamp int64
func (d *Dirt) SetTable(t Table) { d.table = t }
func (d *Dirt) SetTimestamp(t Timestamp) { d.ts = t }
func (d *Dirt) SetWizard(m map[string]*pb.Wizard) { d.wizard = m }
func (d *Dirt) SetSadistic(m map[string]*pb.Sadistic) { d.sadistic = m }
func (d *Dirt) SetLastTime(t int64) { d.lastTime = t }
type Table interface {
Operation1() error
Operation2() error
Operation3() error
}
type MockTable struct {
state []string
}
func CreateMockTable(s []string) *MockTable { return &MockTable{s} }
func (mt *MockTable) Operation1() error { return nil }
func (mt *MockTable) Operation2() error { return nil }
func (mt *MockTable) Operation3() error { return nil }
func (mt *MockTable) State() []string { return mt.state }

View file

@ -1,142 +0,0 @@
// 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 teststructs
import (
"time"
pb "github.com/google/go-cmp/cmp/internal/testprotos"
)
// This is an sanitized example of equality from a real use-case.
// The original equality function was as follows:
/*
func equalCartel(x, y Cartel) bool {
if !(equalHeadquarter(x.Headquarter, y.Headquarter) &&
x.Source() == y.Source() &&
x.CreationDate().Equal(y.CreationDate()) &&
x.Boss() == y.Boss() &&
x.LastCrimeDate().Equal(y.LastCrimeDate())) {
return false
}
if len(x.Poisons()) != len(y.Poisons()) {
return false
}
for i := range x.Poisons() {
if !equalPoison(*x.Poisons()[i], *y.Poisons()[i]) {
return false
}
}
return true
}
func equalHeadquarter(x, y Headquarter) bool {
xr, yr := x.Restrictions(), y.Restrictions()
return x.ID() == y.ID() &&
x.Location() == y.Location() &&
reflect.DeepEqual(x.SubDivisions(), y.SubDivisions()) &&
x.IncorporatedDate().Equal(y.IncorporatedDate()) &&
pb.Equal(x.MetaData(), y.MetaData()) &&
bytes.Equal(x.PrivateMessage(), y.PrivateMessage()) &&
bytes.Equal(x.PublicMessage(), y.PublicMessage()) &&
x.HorseBack() == y.HorseBack() &&
x.Rattle() == y.Rattle() &&
x.Convulsion() == y.Convulsion() &&
x.Expansion() == y.Expansion() &&
x.Status() == y.Status() &&
pb.Equal(&xr, &yr) &&
x.CreationTime().Equal(y.CreationTime())
}
func equalPoison(x, y Poison) bool {
return x.PoisonType() == y.PoisonType() &&
x.Expiration().Equal(y.Expiration()) &&
x.Manufactuer() == y.Manufactuer() &&
x.Potency() == y.Potency()
}
*/
type Cartel struct {
Headquarter
source string
creationDate time.Time
boss string
lastCrimeDate time.Time
poisons []*Poison
}
func (p Cartel) Source() string { return p.source }
func (p Cartel) CreationDate() time.Time { return p.creationDate }
func (p Cartel) Boss() string { return p.boss }
func (p Cartel) LastCrimeDate() time.Time { return p.lastCrimeDate }
func (p Cartel) Poisons() []*Poison { return p.poisons }
func (p *Cartel) SetSource(x string) { p.source = x }
func (p *Cartel) SetCreationDate(x time.Time) { p.creationDate = x }
func (p *Cartel) SetBoss(x string) { p.boss = x }
func (p *Cartel) SetLastCrimeDate(x time.Time) { p.lastCrimeDate = x }
func (p *Cartel) SetPoisons(x []*Poison) { p.poisons = x }
type Headquarter struct {
id uint64
location string
subDivisions []string
incorporatedDate time.Time
metaData *pb.MetaData
privateMessage []byte
publicMessage []byte
horseBack string
rattle string
convulsion bool
expansion uint64
status pb.HoneyStatus
restrictions pb.Restrictions
creationTime time.Time
}
func (hq Headquarter) ID() uint64 { return hq.id }
func (hq Headquarter) Location() string { return hq.location }
func (hq Headquarter) SubDivisions() []string { return hq.subDivisions }
func (hq Headquarter) IncorporatedDate() time.Time { return hq.incorporatedDate }
func (hq Headquarter) MetaData() *pb.MetaData { return hq.metaData }
func (hq Headquarter) PrivateMessage() []byte { return hq.privateMessage }
func (hq Headquarter) PublicMessage() []byte { return hq.publicMessage }
func (hq Headquarter) HorseBack() string { return hq.horseBack }
func (hq Headquarter) Rattle() string { return hq.rattle }
func (hq Headquarter) Convulsion() bool { return hq.convulsion }
func (hq Headquarter) Expansion() uint64 { return hq.expansion }
func (hq Headquarter) Status() pb.HoneyStatus { return hq.status }
func (hq Headquarter) Restrictions() pb.Restrictions { return hq.restrictions }
func (hq Headquarter) CreationTime() time.Time { return hq.creationTime }
func (hq *Headquarter) SetID(x uint64) { hq.id = x }
func (hq *Headquarter) SetLocation(x string) { hq.location = x }
func (hq *Headquarter) SetSubDivisions(x []string) { hq.subDivisions = x }
func (hq *Headquarter) SetIncorporatedDate(x time.Time) { hq.incorporatedDate = x }
func (hq *Headquarter) SetMetaData(x *pb.MetaData) { hq.metaData = x }
func (hq *Headquarter) SetPrivateMessage(x []byte) { hq.privateMessage = x }
func (hq *Headquarter) SetPublicMessage(x []byte) { hq.publicMessage = x }
func (hq *Headquarter) SetHorseBack(x string) { hq.horseBack = x }
func (hq *Headquarter) SetRattle(x string) { hq.rattle = x }
func (hq *Headquarter) SetConvulsion(x bool) { hq.convulsion = x }
func (hq *Headquarter) SetExpansion(x uint64) { hq.expansion = x }
func (hq *Headquarter) SetStatus(x pb.HoneyStatus) { hq.status = x }
func (hq *Headquarter) SetRestrictions(x pb.Restrictions) { hq.restrictions = x }
func (hq *Headquarter) SetCreationTime(x time.Time) { hq.creationTime = x }
type Poison struct {
poisonType pb.PoisonType
expiration time.Time
manufactuer string
potency int
}
func (p Poison) PoisonType() pb.PoisonType { return p.poisonType }
func (p Poison) Expiration() time.Time { return p.expiration }
func (p Poison) Manufactuer() string { return p.manufactuer }
func (p Poison) Potency() int { return p.potency }
func (p *Poison) SetPoisonType(x pb.PoisonType) { p.poisonType = x }
func (p *Poison) SetExpiration(x time.Time) { p.expiration = x }
func (p *Poison) SetManufactuer(x string) { p.manufactuer = x }
func (p *Poison) SetPotency(x int) { p.potency = x }

View file

@ -1,197 +0,0 @@
// 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 teststructs
type InterfaceA interface {
InterfaceA()
}
type (
StructA struct{ X string } // Equal method on value receiver
StructB struct{ X string } // Equal method on pointer receiver
StructC struct{ X string } // Equal method (with interface argument) on value receiver
StructD struct{ X string } // Equal method (with interface argument) on pointer receiver
StructE struct{ X string } // Equal method (with interface argument on value receiver) on pointer receiver
StructF struct{ X string } // Equal method (with interface argument on pointer receiver) on value receiver
// These embed the above types as a value.
StructA1 struct {
StructA
X string
}
StructB1 struct {
StructB
X string
}
StructC1 struct {
StructC
X string
}
StructD1 struct {
StructD
X string
}
StructE1 struct {
StructE
X string
}
StructF1 struct {
StructF
X string
}
// These embed the above types as a pointer.
StructA2 struct {
*StructA
X string
}
StructB2 struct {
*StructB
X string
}
StructC2 struct {
*StructC
X string
}
StructD2 struct {
*StructD
X string
}
StructE2 struct {
*StructE
X string
}
StructF2 struct {
*StructF
X string
}
StructNo struct{ X string } // Equal method (with interface argument) on non-satisfying receiver
AssignA func() int
AssignB struct{ A int }
AssignC chan bool
AssignD <-chan bool
)
func (x StructA) Equal(y StructA) bool { return true }
func (x *StructB) Equal(y *StructB) bool { return true }
func (x StructC) Equal(y InterfaceA) bool { return true }
func (x StructC) InterfaceA() {}
func (x *StructD) Equal(y InterfaceA) bool { return true }
func (x *StructD) InterfaceA() {}
func (x *StructE) Equal(y InterfaceA) bool { return true }
func (x StructE) InterfaceA() {}
func (x StructF) Equal(y InterfaceA) bool { return true }
func (x *StructF) InterfaceA() {}
func (x StructNo) Equal(y InterfaceA) bool { return true }
func (x AssignA) Equal(y func() int) bool { return true }
func (x AssignB) Equal(y struct{ A int }) bool { return true }
func (x AssignC) Equal(y chan bool) bool { return true }
func (x AssignD) Equal(y <-chan bool) bool { return true }
var _ = func(
a StructA, b StructB, c StructC, d StructD, e StructE, f StructF,
ap *StructA, bp *StructB, cp *StructC, dp *StructD, ep *StructE, fp *StructF,
a1 StructA1, b1 StructB1, c1 StructC1, d1 StructD1, e1 StructE1, f1 StructF1,
a2 StructA2, b2 StructB2, c2 StructC2, d2 StructD2, e2 StructE2, f2 StructF1,
) {
a.Equal(a)
b.Equal(&b)
c.Equal(c)
d.Equal(&d)
e.Equal(e)
f.Equal(&f)
ap.Equal(*ap)
bp.Equal(bp)
cp.Equal(*cp)
dp.Equal(dp)
ep.Equal(*ep)
fp.Equal(fp)
a1.Equal(a1.StructA)
b1.Equal(&b1.StructB)
c1.Equal(c1)
d1.Equal(&d1)
e1.Equal(e1)
f1.Equal(&f1)
a2.Equal(*a2.StructA)
b2.Equal(b2.StructB)
c2.Equal(c2)
d2.Equal(&d2)
e2.Equal(e2)
f2.Equal(&f2)
}
type (
privateStruct struct{ Public, private int }
PublicStruct struct{ Public, private int }
ParentStructA struct{ privateStruct }
ParentStructB struct{ PublicStruct }
ParentStructC struct {
privateStruct
Public, private int
}
ParentStructD struct {
PublicStruct
Public, private int
}
ParentStructE struct {
privateStruct
PublicStruct
}
ParentStructF struct {
privateStruct
PublicStruct
Public, private int
}
ParentStructG struct {
*privateStruct
}
ParentStructH struct {
*PublicStruct
}
ParentStructI struct {
*privateStruct
*PublicStruct
}
ParentStructJ struct {
*privateStruct
*PublicStruct
Public PublicStruct
private privateStruct
}
)
func NewParentStructG() *ParentStructG {
return &ParentStructG{new(privateStruct)}
}
func NewParentStructH() *ParentStructH {
return &ParentStructH{new(PublicStruct)}
}
func NewParentStructI() *ParentStructI {
return &ParentStructI{new(privateStruct), new(PublicStruct)}
}
func NewParentStructJ() *ParentStructJ {
return &ParentStructJ{
privateStruct: new(privateStruct), PublicStruct: new(PublicStruct),
}
}
func (s *privateStruct) SetPrivate(i int) { s.private = i }
func (s *PublicStruct) SetPrivate(i int) { s.private = i }
func (s *ParentStructC) SetPrivate(i int) { s.private = i }
func (s *ParentStructD) SetPrivate(i int) { s.private = i }
func (s *ParentStructF) SetPrivate(i int) { s.private = i }
func (s *ParentStructA) PrivateStruct() *privateStruct { return &s.privateStruct }
func (s *ParentStructC) PrivateStruct() *privateStruct { return &s.privateStruct }
func (s *ParentStructE) PrivateStruct() *privateStruct { return &s.privateStruct }
func (s *ParentStructF) PrivateStruct() *privateStruct { return &s.privateStruct }
func (s *ParentStructG) PrivateStruct() *privateStruct { return s.privateStruct }
func (s *ParentStructI) PrivateStruct() *privateStruct { return s.privateStruct }
func (s *ParentStructJ) PrivateStruct() *privateStruct { return s.privateStruct }
func (s *ParentStructJ) Private() *privateStruct { return &s.private }

View file

@ -8,15 +8,11 @@ package value
import (
"fmt"
"reflect"
"strconv"
"strings"
"unicode"
"unicode/utf8"
)
// formatFakePointers controls whether to substitute pointer addresses with nil.
// This is used for deterministic testing.
var formatFakePointers = false
var stringerIface = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
// Format formats the value v as a string.
@ -26,28 +22,35 @@ var stringerIface = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
// * Avoids printing struct fields that are zero
// * Prints a nil-slice as being nil, not empty
// * Prints map entries in deterministic order
func Format(v reflect.Value, useStringer bool) string {
return formatAny(v, formatConfig{useStringer, true, true, !formatFakePointers}, nil)
func Format(v reflect.Value, conf FormatConfig) string {
conf.printType = true
conf.followPointers = true
conf.realPointers = true
return formatAny(v, conf, 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?
type FormatConfig struct {
UseStringer bool // Should the String method be used if available?
printType bool // Should we print the type before the value?
PrintPrimitiveType bool // Should we print the type of primitives?
followPointers bool // Should we recursively follow pointers?
realPointers bool // Should we print the real address of pointers?
}
func formatAny(v reflect.Value, conf formatConfig, visited map[uintptr]bool) string {
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) && v.CanInterface() {
if conf.UseStringer && v.Type().Implements(stringerIface) && v.CanInterface() {
if (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) && v.IsNil() {
return "<nil>"
}
return fmt.Sprintf("%q", v.Interface().(fmt.Stringer).String())
const stringerPrefix = "s" // Indicates that the String method was used
s := v.Interface().(fmt.Stringer).String()
return stringerPrefix + formatString(s)
}
switch v.Kind() {
@ -66,7 +69,7 @@ func formatAny(v reflect.Value, conf formatConfig, visited map[uintptr]bool) str
case reflect.Complex64, reflect.Complex128:
return formatPrimitive(v.Type(), v.Complex(), conf)
case reflect.String:
return formatPrimitive(v.Type(), fmt.Sprintf("%q", v), conf)
return formatPrimitive(v.Type(), formatString(v.String()), conf)
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
return formatPointer(v, conf)
case reflect.Ptr:
@ -127,11 +130,13 @@ func formatAny(v reflect.Value, conf formatConfig, visited map[uintptr]bool) str
visited = insertPointer(visited, v.Pointer())
var ss []string
subConf := conf
subConf.printType = v.Type().Elem().Kind() == reflect.Interface
keyConf, valConf := conf, conf
keyConf.printType = v.Type().Key().Kind() == reflect.Interface
keyConf.followPointers = false
valConf.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)
sk := formatAny(k, keyConf, visited)
sv := formatAny(v.MapIndex(k), valConf, visited)
ss = append(ss, fmt.Sprintf("%s: %s", sk, sv))
}
s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
@ -149,7 +154,7 @@ func formatAny(v reflect.Value, conf formatConfig, visited map[uintptr]bool) str
continue // Elide zero value fields
}
name := v.Type().Field(i).Name
subConf.useStringer = conf.useStringer && isExported(name)
subConf.UseStringer = conf.UseStringer
s := formatAny(vv, subConf, visited)
ss = append(ss, fmt.Sprintf("%s: %s", name, s))
}
@ -163,14 +168,33 @@ func formatAny(v reflect.Value, conf formatConfig, visited map[uintptr]bool) str
}
}
func formatPrimitive(t reflect.Type, v interface{}, conf formatConfig) string {
if conf.printType && t.PkgPath() != "" {
func formatString(s string) string {
// Use quoted string if it the same length as a raw string literal.
// Otherwise, attempt to use the raw string form.
qs := strconv.Quote(s)
if len(qs) == 1+len(s)+1 {
return qs
}
// Disallow newlines to ensure output is a single line.
// Only allow printable runes for readability purposes.
rawInvalid := func(r rune) bool {
return r == '`' || r == '\n' || !unicode.IsPrint(r)
}
if strings.IndexFunc(s, rawInvalid) < 0 {
return "`" + s + "`"
}
return qs
}
func formatPrimitive(t reflect.Type, v interface{}, conf FormatConfig) string {
if conf.printType && (conf.PrintPrimitiveType || t.PkgPath() != "") {
return fmt.Sprintf("%v(%v)", t, v)
}
return fmt.Sprintf("%v", v)
}
func formatPointer(v reflect.Value, conf formatConfig) string {
func formatPointer(v reflect.Value, conf FormatConfig) string {
p := v.Pointer()
if !conf.realPointers {
p = 0 // For deterministic printing purposes
@ -251,9 +275,3 @@ func isZero(v reflect.Value) bool {
}
return false
}
// isExported reports whether the identifier is exported.
func isExported(id string) bool {
r, _ := utf8.DecodeRuneInString(id)
return unicode.IsUpper(r)
}

View file

@ -1,91 +0,0 @@
// 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 value
import (
"bytes"
"io"
"reflect"
"testing"
)
func TestFormat(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[value.key]string{{}: \"hello\"}",
}, {
in: map[key]string{{a: 5, b: "key", c: make(chan bool)}: "hello"},
want: "map[value.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: "&(value.A)(0x00)",
}, {
in: func() interface{} {
type A map[*A]A
a := make(A)
a[&a] = a
return a
}(),
want: "value.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)}",
}}
formatFakePointers = true
defer func() { formatFakePointers = false }()
for i, tt := range tests {
got := Format(reflect.ValueOf(tt.in), true)
if got != tt.want {
t.Errorf("test %d, Format():\ngot %q\nwant %q", i, got, tt.want)
}
}
}

View file

@ -24,7 +24,7 @@ func SortKeys(vs []reflect.Value) []reflect.Value {
// Deduplicate keys (fails for NaNs).
vs2 := vs[:1]
for _, v := range vs[1:] {
if v.Interface() != vs2[len(vs2)-1].Interface() {
if isLess(vs2[len(vs2)-1], v) {
vs2 = append(vs2, v)
}
}

View file

@ -1,152 +0,0 @@
// 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 value_test
import (
"math"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/internal/value"
)
func TestSortKeys(t *testing.T) {
type (
MyString string
MyArray [2]int
MyStruct struct {
A MyString
B MyArray
C chan float64
}
EmptyStruct struct{}
)
opts := []cmp.Option{
cmp.Comparer(func(x, y float64) bool {
if math.IsNaN(x) && math.IsNaN(y) {
return true
}
return x == y
}),
cmp.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
}),
cmp.Comparer(func(x, y chan bool) bool { return true }),
cmp.Comparer(func(x, y chan int) bool { return true }),
cmp.Comparer(func(x, y chan float64) bool { return true }),
cmp.Comparer(func(x, y chan interface{}) bool { return true }),
cmp.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),
"abc", "abcd", "abcde", "bar", "foo",
MyString("abc"), MyString("abcd"), MyString("abcde"),
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 value.SortKeys(keys) {
got = append(got, k.Interface())
}
if d := cmp.Diff(got, tt.want, opts...); d != "" {
t.Errorf("test %d, Sort() mismatch (-got +want):\n%s", i, d)
}
}
}