Path.String() only returns a path in a Struct
Josemaralves opened this issue · 2 comments
There is any reason why Path.String() only checks for a StructField while building the path?
This check is documented in the docs but it limits its utilization in maps of interface{} and can be improved with a little effort.
Right now it looks like this:
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, ""), ".")
}
the fix looks like:
func (pa Path) String() string {
var ss []string
for _, s := range pa {
if _, ok := s.(StructField); ok {
ss = append(ss, s.String())
} else if index, ok := s.(MapIndex); ok {
ss = append(ss, "."+index.Key().String())
}
}
return strings.TrimPrefix(strings.Join(ss, ""), ".")
}
and a test case:
func Test(t *testing.T) {
a := map[string]interface{}{
"a": map[string]interface{}{
"b": "bvalue",
"c": "cvalue",
},
"d": "dvalue",
}
b := map[string]interface{}{
"a": map[string]interface{}{
"b": "evalue",
"c": "cvalue",
},
"d": "dvalue",
}
diff := Diff(a, b, FilterPath(func(path Path) bool {
return path.String() == "a.b"
}, Ignore()))
fmt.Println(diff)
}
It was possibly a mistake to have Path.String
only print the struct field accesses, but that behavior can't be changed since some tests already depend on that as a way to implement filters. For example, they'll do something like strings.Contains(p.String(), "Foo.Bar")
to deliberately ignore any slice or map accesses between Foo
and Bar
.
If you want a complete print of the path, then use Path.GoString
, which was added later.
Closing as working as intended. The output of Path.String
isn't going to change and Path.GoString
has what is requested.