Diff may omit difference of map in struct in slice
- Dominant language
- Go
- Stars
- 4.7k
- Forks
- 243
- PR merge metrics
- No merged PRs in 30d
Description
I've run into a case where the relevant difference is omitted from the cmp.Diff output. I have differences within a large (≥18 entries) map that is nested inside a slice of structs, with some other fields preceding it:
```Go
func TestMapDiff(t *testing.T) {
const (
// Diff only outputs the first 8 map entries, so if they're identical, the diff is useless
numSame = 8
// only 10 differing entries or more trigger the issue
numDiff = 10
)
type Wrapper struct {
// we need a couple of unrelated fields above the map to trigger the issue,
// slices or other maps seem to work well (strings don't)
UnrelatedField1 []string
UnrelatedField2 []string
UnrelatedField3 []string
UnrelatedField4 []string
UnrelatedField5 []string
UnrelatedField6 []string
// this is where the difference is
DifferingMap map[string]any
}
want := map[string]any{}
got := map[string]any{}
for i := 0; i < numSame+numDiff; i++ {
key := fmt.Sprintf("key-%02d", i)
if i < numSame {
want[key] = "same"
got[key] = "same"
} else {
// note that the missing entries must come after the present ones, alphabetically
want[key] = "missing"
}
}
if diff := cmp.Diff(
// we must use a slice to trigger the issue, comparing plain Wrappers doesn't trigger it
[]*Wrapper{
{
// To reproduce the issue, these must not be nil
UnrelatedField1: []string{},
UnrelatedField2: []string{},
UnrelatedField3: []string{},
UnrelatedField4: []string{},
UnrelatedField5: []string{},
UnrelatedField6: []string{},
DifferingMap: want,
},
},
[]*Wrapper{
{
UnrelatedField1: []string{},
UnrelatedField2: []string{},
UnrelatedField3: []string{},
UnrelatedField4: []string{},
UnrelatedField5: []string{},
UnrelatedField6: []string{},
DifferingMap: got,
},
}); diff != "" {
t.Errorf("mismatch (-want +got):\n%s", diff)
}
}
```
This leads to the following output:
```
[]*main.Wrapper{
- &{
- UnrelatedField1: []string{},
- UnrelatedField2: []string{},
- UnrelatedField3: []string{},
- UnrelatedField4: []string{},
- UnrelatedField5: []string{},
- UnrelatedField6: []string{},
- DifferingMap: map[string]any{
- "key-00": string("same"),
- "key-01": string("same"),
- "key-02": string("same"),
- "key-03": string("same"),
- "key-04": string("same"),
- "key-05": string("same"),
- "key-06": string("same"),
- "key-07": string("same"),
- ...
- },
- },
+ &{
+ UnrelatedField1: []string{},
+ UnrelatedField2: []string{},
+ UnrelatedField3: []string{},
+ UnrelatedField4: []string{},
+ UnrelatedField5: []string{},
+ UnrelatedField6: []string{},
+ DifferingMap: map[string]any{
+ "key-00": string("same"),
+ "key-01": string("same"),
+ "key-02": string("same"),
+ "key-03": string("same"),
+ "key-04": string("same"),
+ "key-05": string("same"),
+ "key-06": string("same"),
+ "key-07": string("same"),
+ },
+ },
}
```
Note how the whole Wrapper is marked as differing, instead of just the map inside, and the interesting differing part of the map is omitted, likely as a direct result.
Reducing the number of differences inside the nested map to 9 yields this much more useful output:
```
[]*main.Wrapper{
&{
... // 4 identical fields
UnrelatedField5: {},
UnrelatedField6: {},
DifferingMap: map[string]any{
... // 6 identical entries
"key-06": string("same"),
"key-07": string("same"),
- "key-08": string("missing"),
- "key-09": string("missing"),
- "key-10": string("missing"),
- "key-11": string("missing"),
- "key-12": string("missing"),
- "key-13": string("missing"),
- "key-14": string("missing"),
- "key-15": string("missing"),
- "key-16": string("missing"),
},
},
}
```
Contributor guide
Assessment
This issue has not been assessed yet.