diff --git a/diff.go b/diff.go index 40a09dc..33d47ee 100644 --- a/diff.go +++ b/diff.go @@ -7,12 +7,25 @@ import ( ) type sbuf []string +type mbuf map[string]Data func (p *sbuf) Printf(format string, a ...interface{}) { s := fmt.Sprintf(format, a...) *p = append(*p, s) } +//Comparem func To append the latest compared values To previous result `p` +func (p *mbuf) Comparem(label string, d ...Data) { + var m mbuf = make(map[string]Data) + for _, dd := range d { + m[label] = dd + } + for k, v := range *p { + m[k] = v + } + *p = m +} + // Diff returns a slice where each element describes // a difference between a and b. func Diff(a, b interface{}) (desc []string) { @@ -20,6 +33,13 @@ func Diff(a, b interface{}) (desc []string) { return desc } +// DiffAsMap returns a map fo where each element describes +// a difference between a and b. +func DiffAsMap(a, b interface{}) (desc map[string]Data) { + Mdiff((*mbuf)(&desc), a, b) + return desc +} + // wprintfer calls Fprintf on w for each Printf call // with a trailing newline. type wprintfer struct{ w io.Writer } @@ -28,7 +48,7 @@ func (p *wprintfer) Printf(format string, a ...interface{}) { fmt.Fprintf(p.w, format+"\n", a...) } -// Fdiff writes to w a description of the differences between a and b. +// Fdiff writes To w a description of the differences between a and b. func Fdiff(w io.Writer, a, b interface{}) { Pdiff(&wprintfer{w}, a, b) } @@ -37,7 +57,13 @@ type Printfer interface { Printf(format string, a ...interface{}) } -// Pdiff prints to p a description of the differences between a and b. +//ComparaTor interface for comparing between a,b then calling +//the subsequent element +type ComparaTor interface { + Comparem(label string, d ...Data) +} + +// Pdiff prints To p a description of the differences between a and b. // It calls Printf once for each difference, with no trailing newline. // The standard library log.Logger is a Printfer. func Pdiff(p Printfer, a, b interface{}) { @@ -49,6 +75,14 @@ func Pdiff(p Printfer, a, b interface{}) { d.diff(reflect.ValueOf(a), reflect.ValueOf(b)) } +//Mdiff func +func Mdiff(p ComparaTor, a, b interface{}) { + d := diffcompaTor{ + w: p, + } + d.diff(reflect.ValueOf(a), reflect.ValueOf(b)) +} + type Logfer interface { Logf(format string, a ...interface{}) } @@ -61,7 +95,11 @@ func (p *logprintfer) Printf(format string, a ...interface{}) { p.l.Logf(format, a...) } -// Ldiff prints to l a description of the differences between a and b. +func (p *logprintfer) Comparem(format string, a ...interface{}) { + p.l.Logf(format, a...) +} + +// Ldiff prints To l a description of the differences between a and b. // It calls Logf once for each difference, with no trailing newline. // The standard library testing.T and testing.B are Logfers. func Ldiff(l Logfer, a, b interface{}) { @@ -76,6 +114,17 @@ type diffPrinter struct { bVisited map[visit]visit } +type diffcompaTor struct { + w ComparaTor + l string // label +} + +//Data sctruct To write the compare result as From: `old Data`, To: `new Data` for each entry +type Data struct { + From interface{} + To interface{} +} + func (w diffPrinter) printf(f string, a ...interface{}) { var l string if w.l != "" { @@ -84,6 +133,114 @@ func (w diffPrinter) printf(f string, a ...interface{}) { w.w.Printf(l+f, a...) } +func (w diffcompaTor) comparem(f string, d ...Data) { + var l string + if w.l != "" { + l = w.l + } else { + l = f + } + w.w.Comparem(l, d...) +} + +func (w diffcompaTor) diff(av, bv reflect.Value) { + if !av.IsValid() && bv.IsValid() { + w.comparem("", Data{From: "nill", To: bv}) + return + } + if av.IsValid() && !bv.IsValid() { + w.comparem("", Data{From: av, To: "nill"}) + return + } + if !av.IsValid() && !bv.IsValid() { + return + } + + at := av.Type() + bt := bv.Type() + if at != bt { + w.comparem(fmt.Sprintf("%s", at.Kind()), Data{From: av, To: bv}) + return + } + + switch kind := at.Kind(); kind { + case reflect.Bool: + if a, b := av.Bool(), bv.Bool(); a != b { + w.comparem(fmt.Sprintf("%s", at.Kind()), Data{From: av, To: bv}) + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if a, b := av.Int(), bv.Int(); a != b { + w.comparem(fmt.Sprintf("%s", at.Kind()), Data{From: av, To: bv}) + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + if a, b := av.Uint(), bv.Uint(); a != b { + w.comparem(fmt.Sprintf("%s", at.Kind()), Data{From: fmt.Sprintf("%#v", av), To: fmt.Sprintf("%#v", bv)}) + } + case reflect.Float32, reflect.Float64: + if a, b := av.Float(), bv.Float(); a != b { + w.comparem(fmt.Sprintf("%s", at.Kind()), Data{From: av, To: bv}) + } + case reflect.Complex64, reflect.Complex128: + if a, b := av.Complex(), bv.Complex(); a != b { + w.comparem(fmt.Sprintf("%s", at.Kind()), Data{From: av, To: bv}) + } + case reflect.Array: + n := av.Len() + for i := 0; i < n; i++ { + w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i)) + } + case reflect.Chan, reflect.Func, reflect.UnsafePointer: + if a, b := av.Pointer(), bv.Pointer(); a != b { + w.comparem(fmt.Sprintf("%s", at.Kind()), Data{From: av, To: bv}) + } + case reflect.Interface: + w.diff(av.Elem(), bv.Elem()) + case reflect.Map: + ak, both, bk := keyDiff(av.MapKeys(), bv.MapKeys()) + for _, k := range ak { + w.relabel(fmt.Sprintf("[%#v]", k)) + w.comparem(fmt.Sprintf("%s", at.Kind()), Data{From: av.MapIndex(k), To: "missing"}) + } + for _, k := range both { + w := w.relabel(fmt.Sprintf("[%#v]", k)) + w.diff(av.MapIndex(k), bv.MapIndex(k)) + } + for _, k := range bk { + w.relabel(fmt.Sprintf("[%#v]", k)) + w.comparem(fmt.Sprintf("%s", bt.Kind()), Data{From: "missing", To: av.MapIndex(k)}) + } + case reflect.Ptr: + switch { + case av.IsNil() && !bv.IsNil(): + w.comparem("", Data{From: "nil", To: bv}) + case !av.IsNil() && bv.IsNil(): + w.comparem("", Data{From: av, To: "nil"}) + case !av.IsNil() && !bv.IsNil(): + w.diff(av.Elem(), bv.Elem()) + } + case reflect.Slice: + lenA := av.Len() + lenB := bv.Len() + if lenA != lenB { + w.comparem("", Data{From: fmt.Sprintf("[%d]", lenA), To: fmt.Sprintf("[%d]", lenB)}) + break + } + for i := 0; i < lenA; i++ { + w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i)) + } + case reflect.String: + if a, b := av.String(), bv.String(); a != b { + w.comparem(fmt.Sprintf("%s", at.Kind()), Data{From: a, To: b}) + } + case reflect.Struct: + for i := 0; i < av.NumField(); i++ { + w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i)) + } + default: + panic("unknown reflect Kind: " + kind.String()) + } +} + func (w diffPrinter) diff(av, bv reflect.Value) { if !av.IsValid() && bv.IsValid() { w.printf("nil != %# v", formatter{v: bv, quote: true}) @@ -213,6 +370,15 @@ func (d diffPrinter) relabel(name string) (d1 diffPrinter) { return d1 } +func (d diffcompaTor) relabel(name string) (d1 diffcompaTor) { + d1 = d + if d.l != "" && name[0] != '[' { + d1.l += "." + } + d1.l += name + return d1 +} + // keyEqual compares a and b for equality. // Both a and b must be valid map keys. func keyEqual(av, bv reflect.Value) bool { diff --git a/go.mod b/go.mod index 579209a..936aabf 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,9 @@ -module github.com/kr/pretty +module github.com/bashayerAlsalman/pretty go 1.12 require ( + github.com/kr/pretty v0.1.0 github.com/kr/text v0.1.0 github.com/rogpeppe/go-internal v1.6.1 ) diff --git a/go.sum b/go.sum index a0e55fc..695f1a1 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,6 @@ +github.com/bashayerAlsalman/pretty v0.2.2 h1:EWU7r2gPvqk+TvfVbEaOk4Ywi4sajUiD77SJhe5tZ5A= +github.com/bashayerAlsalman/pretty v0.2.2/go.mod h1:cQNADiuuYMIElf6FFQOh2mrd7+lAYZavDujxgJaDDKc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=