google / google/go-cmp

Convenient FilterPath functions

Open
#75 9 comments 1 reaction 0 assignees View on GitHub
enhancement
Dominant language
Go
Stars
4.7k
Forks
243
PR merge metrics
No merged PRs in 30d

Description

Hello, I've been[ using `go-cmp`](https://godoc.org/github.com/gotestyourself/gotestyourself/assert#DeepEqual) for a bit now and I've found that the two most common cases for needing an `Option` are:
1. `AllowUnexported`/`IgnoreUnexported` - which is already easy to use
2. A `FilterPath` for fields that have values set from `time.Now()` (`time.Time`, or `time.Duration`)

It wasn't immediately obvious to me how to create a correct `FilterPath` filter function. After a quick scan of the godoc my first approach was something like this:

```go
func(path gocmp.Path) bool {
return path.Last().String() == ".Elapsed"
}
```
This worked, but it seems to me like it could potentially match fields that I don't want it to match if I used it with a large nested structure where multiple types had an `Elapsed` field.

Digging into the godoc further I noticed that a bunch of the types embedded `PathStep`, which made me realize that a more correct way of using `Path` would probably be to iterate over the steps, type assert to the expected type, and compare to `Name()` or `Key()`.

My next iteration (https://github.com/gotestyourself/gotestyourself/pull/62) looks something like this:

```go
func fieldPathWithTypes(pathspec string) func(gocmp.Path) bool {
return func(path gocmp.Path) bool {
spec := strings.Split(pathspec, ".")
index := 0

for _, step := range path {
fieldStep, ok := step.(gocmp.StructField)
if !ok {
continue
}
if index >= len(spec) || spec[index] != fieldStep.Name() {
return false
}
index++
}
return index == len(spec)
}
}
```

Which could be made a lot simpler if it's expected that `PathStep.String()` is stable and wont change between minor versions:

```go
func fieldPathSimple(pathspec string) func(gocmp.Path) bool {
return func(path gocmp.Path) bool {
return path.String() == pathspec
}
}
```

The same idea could be applied using `GoString()` if that is considered stable. The idea behind both of these functions is that it's much easier for a reader to understand a dotted path string, than it is to read a long function with a bunch of type assertions.

Questions:
1. What is the expected/"best practice" way of using `PathStep`? Is it similar to `fieldPathWithTypes` ?
2. Would you be interested in a PR that adds a convenience function for building the `PathFilter` filter function from a simple string? This could be something like `fieldPathWithTypes` or it could be more verbose (to match against something like `GoString()`. I believe the only type that can't be easily translated from a string representation would be `Transform`.
3. Would you be interested in a PR that adds one or more examples for using `FilterPath` (based on feedback from these other questions) ?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.