Skip to content

Commit

Permalink
record both old and new value of modified fields
Browse files Browse the repository at this point in the history
This is to support alternative output formats than the
one implemented by PrettyDiff.

Most notably, with this change it would be trivial to
implement a pretty-printed with output similar to that
of the `diff` tool, which can display a modified field
as follows:

    -path: old_value
    +path: new_value

Prior to this commit, only the new value was recorded,
so producing output such as the one examplified above
would require traversing the `a` parameter passed to
DeepDiff, and such traversal would require an extensive
use of reflect, essentially re-implementing the core of
messagediff.

Therefore, to allow for broader use-cases of messagediff,
the API is adjusted to include both the old and the new
value for modified fields.

This may be considered a backwards incompatible change
to the API, in particular the type of the Modified
field of the Diff struct has been updated. Users of
PrettyPrint still have the same functionality, and
all test cases pass without any modifications, so it
may be possible to argue that this API change is more
considered an internal detail, than something facing
the average user.

In either case, the added functionalty may warrant
the update to the API.
  • Loading branch information
mewmew authored and d4l3k committed Aug 29, 2019
1 parent afddc8b commit 7e0a312
Showing 1 changed file with 17 additions and 10 deletions.
27 changes: 17 additions & 10 deletions messagediff.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func PrettyDiff(a, b interface{}, options ...Option) (string, bool) {
dstr = append(dstr, fmt.Sprintf("removed: %s = %#v\n", path.String(), removed))
}
for path, modified := range d.Modified {
dstr = append(dstr, fmt.Sprintf("modified: %s = %#v\n", path.String(), modified))
dstr = append(dstr, fmt.Sprintf("modified: %s = %#v\n", path.String(), modified.New))
}
natsort.Strings(dstr)
return strings.Join(dstr, ""), equal
Expand All @@ -43,11 +43,17 @@ func newDiff() *Diff {
return &Diff{
Added: make(map[*Path]interface{}),
Removed: make(map[*Path]interface{}),
Modified: make(map[*Path]interface{}),
Modified: make(map[*Path]Update),
visited: make(map[visit]bool),
}
}

// Update records the old and new value of a modified field.
type Update struct {
Old interface{}
New interface{}
}

func (d *Diff) diff(aVal, bVal reflect.Value, path Path, opts *opts) bool {
// The array underlying `path` could be modified in subsequent
// calls. Make sure we have a local copy.
Expand All @@ -59,15 +65,15 @@ func (d *Diff) diff(aVal, bVal reflect.Value, path Path, opts *opts) bool {
return true
}
if !bVal.IsValid() {
d.Modified[&localPath] = nil
d.Modified[&localPath] = Update{Old: aVal.Interface(), New: nil}
return false
} else if !aVal.IsValid() {
d.Modified[&localPath] = bVal.Interface()
d.Modified[&localPath] = Update{Old: nil, New: bVal.Interface()}
return false
}

if aVal.Type() != bVal.Type() {
d.Modified[&localPath] = bVal.Interface()
d.Modified[&localPath] = Update{Old: aVal.Interface(), New: bVal.Interface()}
return false
}
kind := aVal.Kind()
Expand Down Expand Up @@ -109,7 +115,7 @@ func (d *Diff) diff(aVal, bVal reflect.Value, path Path, opts *opts) bool {
return true
}
if aVal.IsNil() || bVal.IsNil() {
d.Modified[&localPath] = bVal.Interface()
d.Modified[&localPath] = Update{Old: aVal.Interface(), New: bVal.Interface()}
return false
}
}
Expand Down Expand Up @@ -165,7 +171,7 @@ func (d *Diff) diff(aVal, bVal reflect.Value, path Path, opts *opts) bool {
aTime := aVal.Interface().(time.Time)
bTime := bVal.Interface().(time.Time)
if !aTime.Equal(bTime) {
d.Modified[&localPath] = bVal.Interface().(time.Time).String()
d.Modified[&localPath] = Update{Old: aTime.String(), New: bTime.String()}
equal = false
}
} else {
Expand All @@ -192,7 +198,7 @@ func (d *Diff) diff(aVal, bVal reflect.Value, path Path, opts *opts) bool {
if reflect.DeepEqual(aVal.Interface(), bVal.Interface()) {
equal = true
} else {
d.Modified[&localPath] = bVal.Interface()
d.Modified[&localPath] = Update{Old: aVal.Interface(), New: bVal.Interface()}
equal = false
}
}
Expand All @@ -219,8 +225,9 @@ type visit struct {

// Diff represents a change in a struct.
type Diff struct {
Added, Removed, Modified map[*Path]interface{}
visited map[visit]bool
Added, Removed map[*Path]interface{}
Modified map[*Path]Update
visited map[visit]bool
}

// Path represents a path to a changed datum.
Expand Down

1 comment on commit 7e0a312

@marcelometal
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi @d4l3k,

Please, release na new version with this patch =)

Please sign in to comment.