Skip to content

Commit 0d296f9

Browse files
authored
Limit number of printed differences for variable-length composites (#213)
For large slices, arrays, and maps, the reporter can be unreadable if there are many differences. Limit the number of results to some reasonable maximum.
1 parent 7c9a834 commit 0d296f9

File tree

5 files changed

+173
-3
lines changed

5 files changed

+173
-3
lines changed

cmp/compare_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,34 @@ func reporterTests() []test {
974974
y: "aaa\nbbb\nccc \nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nrrr\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n",
975975
wantEqual: false,
976976
reason: "avoid triple-quote syntax due to visual equivalence of differences",
977+
}, {
978+
label: label + "/LimitMaximumBytesDiffs",
979+
x: []byte("\xcd====\x06\x1f\xc2\xcc\xc2-S=====\x1d\xdfa\xae\x98\x9fH======ǰ\xb7=======\xef====:\\\x94\xe6J\xc7=====\xb4======\n\n\xf7\x94===========\xf2\x9c\xc0f=====4\xf6\xf1\xc3\x17\x82======n\x16`\x91D\xc6\x06=======\x1cE====.===========\xc4\x18=======\x8a\x8d\x0e====\x87\xb1\xa5\x8e\xc3=====z\x0f1\xaeU======G,=======5\xe75\xee\x82\xf4\xce====\x11r===========\xaf]=======z\x05\xb3\x91\x88%\xd2====\n1\x89=====i\xb7\x055\xe6\x81\xd2=============\x883=@̾====\x14\x05\x96%^t\x04=====\xe7Ȉ\x90\x1d============="),
980+
y: []byte("\\====|\x96\xe7SB\xa0\xab=====\xf0\xbd\xa5q\xab\x17;======\xabP\x00=======\xeb====\xa5\x14\xe6O(\xe4=====(======/c@?===========\xd9x\xed\x13=====J\xfc\x918B\x8d======a8A\xebs\x04\xae=======\aC====\x1c===========\x91\"=======uؾ====s\xec\x845\a=====;\xabS9t======\x1f\x1b=======\x80\xab/\xed+:;====\xeaI===========\xabl=======\xb9\xe9\xfdH\x93\x8e\u007f====ח\xe5=====Ig\x88m\xf5\x01V=============\xf7+4\xb0\x92E====\x9fj\xf8&\xd0h\xf9=====\xeeΨ\r\xbf============="),
981+
wantEqual: false,
982+
reason: "total bytes difference output is truncated due to excessive number of differences",
983+
}, {
984+
label: label + "/LimitMaximumStringDiffs",
985+
x: "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\nA\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nU\nV\nW\nX\nY\nZ\n",
986+
y: "aa\nb\ncc\nd\nee\nf\ngg\nh\nii\nj\nkk\nl\nmm\nn\noo\np\nqq\nr\nss\nt\nuu\nv\nww\nx\nyy\nz\nAA\nB\nCC\nD\nEE\nF\nGG\nH\nII\nJ\nKK\nL\nMM\nN\nOO\nP\nQQ\nR\nSS\nT\nUU\nV\nWW\nX\nYY\nZ\n",
987+
wantEqual: false,
988+
reason: "total string difference output is truncated due to excessive number of differences",
989+
}, {
990+
label: label + "/LimitMaximumSliceDiffs",
991+
x: func() (out []struct{ S string }) {
992+
for _, s := range strings.Split("a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\nA\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nU\nV\nW\nX\nY\nZ\n", "\n") {
993+
out = append(out, struct{ S string }{s})
994+
}
995+
return out
996+
}(),
997+
y: func() (out []struct{ S string }) {
998+
for _, s := range strings.Split("aa\nb\ncc\nd\nee\nf\ngg\nh\nii\nj\nkk\nl\nmm\nn\noo\np\nqq\nr\nss\nt\nuu\nv\nww\nx\nyy\nz\nAA\nB\nCC\nD\nEE\nF\nGG\nH\nII\nJ\nKK\nL\nMM\nN\nOO\nP\nQQ\nR\nSS\nT\nUU\nV\nWW\nX\nYY\nZ\n", "\n") {
999+
out = append(out, struct{ S string }{s})
1000+
}
1001+
return out
1002+
}(),
1003+
wantEqual: false,
1004+
reason: "total slice difference output is truncated due to excessive number of differences",
9771005
}, {
9781006
label: label,
9791007
x: MyComposite{

cmp/report_compare.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,13 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te
207207
// Handle differencing.
208208
var list textList
209209
groups := coalesceAdjacentRecords(name, recs)
210+
maxGroup := diffStats{Name: name}
210211
for i, ds := range groups {
212+
if len(list) >= maxDiffElements {
213+
maxGroup = maxGroup.Append(ds)
214+
continue
215+
}
216+
211217
// Handle equal records.
212218
if ds.NumDiff() == 0 {
213219
// Compute the number of leading and trailing records to print.
@@ -268,7 +274,11 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te
268274
}
269275
recs = recs[ds.NumDiff():]
270276
}
271-
assert(len(recs) == 0)
277+
if maxGroup.IsZero() {
278+
assert(len(recs) == 0)
279+
} else {
280+
list.AppendEllipsis(maxGroup)
281+
}
272282
return textWrap{"{", list, "}"}
273283
}
274284

cmp/report_slices.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ import (
1616
"github.com/google/go-cmp/cmp/internal/diff"
1717
)
1818

19+
// maxDiffElements is the maximum number of difference elements to format
20+
// before the remaining differences are coalesced together.
21+
const maxDiffElements = 32
22+
1923
// CanFormatDiffSlice reports whether we support custom formatting for nodes
2024
// that are slices of primitive kinds or strings.
2125
func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool {
@@ -335,7 +339,13 @@ func (opts formatOptions) formatDiffSlice(
335339

336340
groups := coalesceAdjacentEdits(name, es)
337341
groups = coalesceInterveningIdentical(groups, chunkSize/4)
342+
maxGroup := diffStats{Name: name}
338343
for i, ds := range groups {
344+
if len(list) >= maxDiffElements {
345+
maxGroup = maxGroup.Append(ds)
346+
continue
347+
}
348+
339349
// Print equal.
340350
if ds.NumDiff() == 0 {
341351
// Compute the number of leading and trailing equal bytes to print.
@@ -369,7 +379,11 @@ func (opts formatOptions) formatDiffSlice(
369379
ny := appendChunks(vy.Slice(0, ds.NumIdentical+ds.NumInserted+ds.NumModified), diffInserted)
370380
vy = vy.Slice(ny, vy.Len())
371381
}
372-
assert(vx.Len() == 0 && vy.Len() == 0)
382+
if maxGroup.IsZero() {
383+
assert(vx.Len() == 0 && vy.Len() == 0)
384+
} else {
385+
list.AppendEllipsis(maxGroup)
386+
}
373387
return list
374388
}
375389

cmp/report_text.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ type textRecord struct {
149149
// exists at the end. If cs is non-zero it coalesces the statistics with the
150150
// previous diffStats.
151151
func (s *textList) AppendEllipsis(ds diffStats) {
152-
hasStats := ds != diffStats{}
152+
hasStats := !ds.IsZero()
153153
if len(*s) == 0 || !(*s)[len(*s)-1].Value.Equal(textEllipsis) {
154154
if hasStats {
155155
*s = append(*s, textRecord{Value: textEllipsis, ElideComma: true, Comment: ds})
@@ -369,6 +369,11 @@ type diffStats struct {
369369
NumModified int
370370
}
371371

372+
func (s diffStats) IsZero() bool {
373+
s.Name = ""
374+
return s == diffStats{}
375+
}
376+
372377
func (s diffStats) NumDiff() int {
373378
return s.NumRemoved + s.NumInserted + s.NumModified
374379
}

cmp/testdata/diffs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,119 @@
659659
... // 7 identical lines
660660
}, "\n")
661661
>>> TestDiff/Reporter/AvoidTripleQuoteIdenticalWhitespace
662+
<<< TestDiff/Reporter/LimitMaximumBytesDiffs
663+
[]uint8{
664+
- 0xcd, 0x3d, 0x3d, 0x3d, 0x3d, 0x06, 0x1f, 0xc2, 0xcc, 0xc2, 0x2d, 0x53, // -|.====.....-S|
665+
+ 0x5c, 0x3d, 0x3d, 0x3d, 0x3d, 0x7c, 0x96, 0xe7, 0x53, 0x42, 0xa0, 0xab, // +|\====|..SB..|
666+
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, // |=====|
667+
- 0x1d, 0xdf, 0x61, 0xae, 0x98, 0x9f, 0x48, // -|..a...H|
668+
+ 0xf0, 0xbd, 0xa5, 0x71, 0xab, 0x17, 0x3b, // +|...q..;|
669+
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, // |======|
670+
- 0xc7, 0xb0, 0xb7, // -|...|
671+
+ 0xab, 0x50, 0x00, // +|.P.|
672+
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, // |=======|
673+
- 0xef, 0x3d, 0x3d, 0x3d, 0x3d, 0x3a, 0x5c, 0x94, 0xe6, 0x4a, 0xc7, // -|.====:\..J.|
674+
+ 0xeb, 0x3d, 0x3d, 0x3d, 0x3d, 0xa5, 0x14, 0xe6, 0x4f, 0x28, 0xe4, // +|.====...O(.|
675+
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, // |=====|
676+
- 0xb4, // -|.|
677+
+ 0x28, // +|(|
678+
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, // |======|
679+
- 0x0a, 0x0a, 0xf7, 0x94, // -|....|
680+
+ 0x2f, 0x63, 0x40, 0x3f, // +|/c@?|
681+
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, // |===========|
682+
- 0xf2, 0x9c, 0xc0, 0x66, // -|...f|
683+
+ 0xd9, 0x78, 0xed, 0x13, // +|.x..|
684+
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, // |=====|
685+
- 0x34, 0xf6, 0xf1, 0xc3, 0x17, 0x82, // -|4.....|
686+
+ 0x4a, 0xfc, 0x91, 0x38, 0x42, 0x8d, // +|J..8B.|
687+
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, // |======|
688+
- 0x6e, 0x16, 0x60, 0x91, 0x44, 0xc6, 0x06, // -|n.`.D..|
689+
+ 0x61, 0x38, 0x41, 0xeb, 0x73, 0x04, 0xae, // +|a8A.s..|
690+
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, // |=======|
691+
- 0x1c, 0x45, 0x3d, 0x3d, 0x3d, 0x3d, 0x2e, // -|.E====.|
692+
+ 0x07, 0x43, 0x3d, 0x3d, 0x3d, 0x3d, 0x1c, // +|.C====.|
693+
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, // |===========|
694+
- 0xc4, 0x18, // -|..|
695+
+ 0x91, 0x22, // +|."|
696+
... // 95 identical, 61 removed, and 61 inserted bytes
697+
}
698+
>>> TestDiff/Reporter/LimitMaximumBytesDiffs
699+
<<< TestDiff/Reporter/LimitMaximumStringDiffs
700+
(
701+
"""
702+
- a
703+
+ aa
704+
b
705+
- c
706+
+ cc
707+
d
708+
- e
709+
+ ee
710+
f
711+
- g
712+
+ gg
713+
h
714+
- i
715+
+ ii
716+
j
717+
- k
718+
+ kk
719+
l
720+
- m
721+
+ mm
722+
n
723+
- o
724+
+ oo
725+
p
726+
- q
727+
+ qq
728+
r
729+
- s
730+
+ ss
731+
t
732+
- u
733+
+ uu
734+
... // 17 identical, 15 removed, and 15 inserted lines
735+
"""
736+
)
737+
>>> TestDiff/Reporter/LimitMaximumStringDiffs
738+
<<< TestDiff/Reporter/LimitMaximumSliceDiffs
739+
[]struct{ S string }{
740+
- {S: "a"},
741+
+ {S: "aa"},
742+
{S: "b"},
743+
- {S: "c"},
744+
+ {S: "cc"},
745+
{S: "d"},
746+
- {S: "e"},
747+
+ {S: "ee"},
748+
{S: "f"},
749+
- {S: "g"},
750+
+ {S: "gg"},
751+
{S: "h"},
752+
- {S: "i"},
753+
+ {S: "ii"},
754+
{S: "j"},
755+
- {S: "k"},
756+
+ {S: "kk"},
757+
{S: "l"},
758+
- {S: "m"},
759+
+ {S: "mm"},
760+
{S: "n"},
761+
- {S: "o"},
762+
+ {S: "oo"},
763+
{S: "p"},
764+
- {S: "q"},
765+
+ {S: "qq"},
766+
{S: "r"},
767+
- {S: "s"},
768+
+ {S: "ss"},
769+
{S: "t"},
770+
- {S: "u"},
771+
+ {S: "uu"},
772+
... // 17 identical and 15 modified elements
773+
}
774+
>>> TestDiff/Reporter/LimitMaximumSliceDiffs
662775
<<< TestDiff/Reporter#06
663776
cmp_test.MyComposite{
664777
StringA: strings.Join({

0 commit comments

Comments
 (0)