Coder Social home page Coder Social logo

messagediff's Introduction

messagediff Build Status Coverage Status GoDoc

A library for doing diffs of arbitrary Golang structs.

If the unsafe package is available messagediff will diff unexported fields in addition to exported fields. This is primarily used for testing purposes as it allows for providing informative error messages.

Optionally, fields in structs can be tagged as testdiff:"ignore" to make messagediff skip it when doing the comparison.

Example Usage

In a normal file:

package main

import "gopkg.in/d4l3k/messagediff.v1"

type someStruct struct {
    A, b int
    C []int
}

func main() {
    a := someStruct{1, 2, []int{1}}
    b := someStruct{1, 3, []int{1, 2}}
    diff, equal := messagediff.PrettyDiff(a, b)
    /*
        diff =
        `added: .C[1] = 2
        modified: .b = 3`

        equal = false
    */
}

In a test:

import "gopkg.in/d4l3k/messagediff.v1"

...

type someStruct struct {
    A, b int
    C []int
}

func TestSomething(t *testing.T) {
    want := someStruct{1, 2, []int{1}}
    got := someStruct{1, 3, []int{1, 2}}
    if diff, equal := messagediff.PrettyDiff(want, got); !equal {
        t.Errorf("Something() = %#v\n%s", got, diff)
    }
}

To ignore a field in a struct, just annotate it with testdiff:"ignore" like this:

package main

import "gopkg.in/d4l3k/messagediff.v1"

type someStruct struct {
    A int
    B int `testdiff:"ignore"`
}

func main() {
    a := someStruct{1, 2}
    b := someStruct{1, 3}
    diff, equal := messagediff.PrettyDiff(a, b)
    /*
        equal = true
        diff = ""
    */
}

See the DeepDiff function for using the diff results programmatically.

License

Copyright (c) 2015 Tristan Rice [email protected]

messagediff is licensed under the MIT license. See the LICENSE file for more information.

bypass.go and bypasssafe.go are borrowed from go-spew and have a seperate copyright notice.

messagediff's People

Contributors

d4l3k avatar dthadi3 avatar ifraixedes avatar kibra avatar mewmew avatar mikijov avatar rdwilliamson avatar sadayuki-matsuno avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

messagediff's Issues

Please tag and version this repository

Hello,

Can you please tag and version this project?

I am the Debian Maintainer for messagediff and versioning would help Debian keep up with development.

Different representation of a diff?

I came across this project while looking for a simple way to compare two instances of the same struct. I currently define type Delta struct{ old, new interface{} } and then use a map of that where the member name is the key. Obviously can't do deep compares with that, but it works well from a programmatic standpoint.

I'm wondering if you considered any other methods for handling the paths? Would you be interested in having any alternative representations in this project?

Stack overflow on recursive data structures.

package main_test

import (
    "reflect"
    "testing"

    "golang.org/x/net/html"
    "golang.org/x/net/html/atom"
    "gopkg.in/d4l3k/messagediff.v1"
)

func Test(t *testing.T) {
    if got, want := data2(), data1(); !reflect.DeepEqual(got, want) {
        diff, _ := messagediff.PrettyDiff(want, got)
        t.Errorf("diff %v", diff)
    }
}

func data1() []*html.Node {
    n := &html.Node{
        Type: html.ElementNode, Data: atom.Span.String(),
        Attr: []html.Attribute{
            {Key: atom.Class.String(), Val: "foo"},
        },
    }
    n.AppendChild(
        &html.Node{
            Type: html.ElementNode, Data: atom.Span.String(),
            Attr: []html.Attribute{
                {Key: atom.Class.String(), Val: "bar"},
            },
        },
    )
    n.AppendChild(&html.Node{
        Type: html.TextNode, Data: "baz",
    })
    return []*html.Node{n}
}

func data2() []*html.Node {
    n := &html.Node{
        Type: html.ElementNode, Data: atom.Span.String(),
        Attr: []html.Attribute{
            {Key: atom.Class.String(), Val: "foo"},
        },
    }
    n.AppendChild(
        &html.Node{
            Type: html.ElementNode, Data: atom.Span.String(),
            Attr: []html.Attribute{
                {Key: atom.Class.String(), Val: "bar"},
            },
        },
    )
    n.AppendChild(&html.Node{
        Type: html.TextNode, Data: " baz",
    })
    return []*html.Node{n}
}

Running go test -v results in:

=== RUN   Test
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

runtime stack:
runtime.throw(0x471120, 0xe)
    /usr/local/go/src/runtime/panic.go:547 +0x90
runtime.newstack()
    /usr/local/go/src/runtime/stack.go:940 +0xb11
runtime.morestack()
    /usr/local/go/src/runtime/asm_amd64.s:359 +0x7f

goroutine 20 [stack growth]:
gopkg.in/d4l3k/messagediff%2ev1.diff(0x42a200, 0xc825cf9110, 0x42a200, 0xc825cf9180, 0xc824834000, 0x3759e, 0x38c00, 0xc8200da7e0, 0x0)
...

TrackBy for arrays

it would be interesting if we could define a field by which we track objects inside array(similar as angular.js or vue.js does it)
This way we could precisely tell which objects were deleted/added to an array when doing a diff

testdiff: ignore doesn't work

Hello,

I've copied exactly the example exposed in README and ran it. The output I get is that they are different in the field I told it to ignore.
I am using golang 1.10

Thanks,

gopkg.in/...v1 is pulling in old code

The readme says use "gopkg.in/d4l3k/messagediff.v1"

I did that and I got old code. Took me about 1/2 hour before I realized why things weren't working correctly.

I needed what was in master, the testdiff:"ignore" but gopkg.in doesn't have that code.

tests fail with go 1.9

When running "go test" with go 1.9, the following failure occurs:

go test -compiler gc -ldflags '' github.com/d4l3k/messagediff
--- FAIL: TestPrettyDiff (0.00s)
	messagediff_test.go:41: 12. PrettyDiff(time.Time{wall:0x0, ext:62135596800, loc:(*time.Location)(nil)}, time.Time{wall:0x0, ext:0, loc:(*time.Location)(nil)}) diff = "modified: .ext = 0\n"; not "modified: .sec = 0\n"
FAIL
FAIL	github.com/d4l3k/messagediff	0.002s

Natural sorting of indices in PrettyDiff output

Hi @d4l3k,

First off. Thanks for sharing this library! It's exactly what I needed and really does the job well. I think it makes sense to fork a deep pretty-printed, and base the diff on that as you've done with go-spew.

After running messagediff.PrettyDiff on a few data sets, I noticed one aspect that could be improved with regards to the readability of the output. Currently array and slice indices are printed in lexicographic order, whereas natural sorting would make the output more intuitive.

For instance, the current output of messagediff.PrettyDiff is as follows:

modified: [0].Foo = 0x2
modified: [0].Bar = "asdf"
modified: [100].Foo = 0x2
modified: [100].Bar = "asdf"
modified: [101].Foo = 0x2
modified: [101].Bar = "asdf"
modified: [102].Foo = 0x2
modified: [102].Bar = "asdf"
modified: [103].Foo = 0x2
modified: [103].Bar = "asdf"
modified: [104].Foo = 0x2
modified: [104].Bar = "asdf"
modified: [105].Foo = 0x2
modified: [105].Bar = "asdf"
modified: [106].Foo = 0x2
modified: [106].Bar = "asdf"
modified: [107].Foo = 0x2
modified: [107].Bar = "asdf"
modified: [108].Foo = 0x2
modified: [108].Bar = "asdf"
modified: [109].Foo = 0x2
modified: [109].Bar = "asdf"
modified: [10].Foo = 0x2
modified: [10].Bar = "asdf"
modified: [110].Foo = 0x2
modified: [110].Bar = "asdf"

And with natural sorting applied, it would look as follows:

modified: [0].Bar = "asdf"
modified: [0].Foo = 0x2
modified: [10].Bar = "asdf"
modified: [10].Foo = 0x2
modified: [100].Bar = "asdf"
modified: [100].Foo = 0x2
modified: [101].Bar = "asdf"
modified: [101].Foo = 0x2
modified: [102].Bar = "asdf"
modified: [102].Foo = 0x2
modified: [103].Bar = "asdf"
modified: [103].Foo = 0x2
modified: [104].Bar = "asdf"
modified: [104].Foo = 0x2
modified: [105].Bar = "asdf"
modified: [105].Foo = 0x2
modified: [106].Bar = "asdf"
modified: [106].Foo = 0x2
modified: [107].Bar = "asdf"
modified: [107].Foo = 0x2
modified: [108].Bar = "asdf"
modified: [108].Foo = 0x2
modified: [109].Bar = "asdf"
modified: [109].Foo = 0x2
modified: [110].Bar = "asdf"
modified: [110].Foo = 0x2

For natural sorting, feel free to use any library you see fit, or for that matter copy over the implementation from https://github.com/llir/llvm/tree/master/internal/natsort which is based on @fvbommel's natural sorting package. The code is MIT licensed. (any code changes I did are released into the public domain).

Wish you all the best and happy times ahead!

Cheers,
Robin

Provide access to both old and new value of modified fields

This is a feature request to record both the old and the new value of modified fields, as returned by the DeepDiff function.

The motivation for this would be to enable further use-cases, where users may want to print the diff in other formats that that provided by PrettyDiff. In particular, a common use-case may be to want to print both the value before the change of a field, and the value after the change; as to provide further context, what has changed, and from what to what.

This style of diff output is used in tools such as diff (and git), where users are given context of how lines change.

-old source line
+new source line

I would like to implement similar pretty-printing functionality of values using messagediff. In particular, I would like to output the following:

-path: old value
+path: new value

e.g.

- [0].Name = "John Doe"
+ [0].Name = "Jane Rue"

With the current API, I can reach the new value as stored in Diff.Modified, but access is not provided to the old value. It would be possible to reach the old value by deep traversal of the a parameter, using the path of Diff.Modified, but doing so would require heavy use of reflection, and it would be redundant effort to implement, seeing that this is already implemented by messagediff.

As such, I would wish to update the API of the Diff.Modified field to include both old and new data.

I'll have a preliminary PR submitted shortly, upon which we can discuss if this is the right approach to take.

Cheers,
Robin

Request diff as map[string]interface{}

This is awesome! It would be interesting to get the diff as a map[string]interface{} to be able to operate on those differences beyond the string output. Thoughts?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.