From 101cf8f0cfe3ebbf045502105a71f800cadbad61 Mon Sep 17 00:00:00 2001 From: bashayer alsalman Date: Wed, 7 Oct 2020 12:36:24 +0300 Subject: [PATCH 1/5] add new function DiffAsMap to return the differences as map. The key is the name of the attribute or the element kind, and the value is the old and new value in this format data{from, to} --- diff.go | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/diff.go b/diff.go index 40a09dc..12eda54 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 } @@ -37,6 +57,12 @@ type Printfer interface { Printf(format string, a ...interface{}) } +//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. @@ -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,6 +95,10 @@ func (p *logprintfer) Printf(format string, a ...interface{}) { p.l.Logf(format, a...) } +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. @@ -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.printf("%s[%d] != %s[%d]", av.Type(), lenA, bv.Type(), lenB) todo + 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 { From 60de53f165d96876203a714e1adf13791810ecb8 Mon Sep 17 00:00:00 2001 From: bashayer alsalman Date: Wed, 7 Oct 2020 12:56:15 +0300 Subject: [PATCH 2/5] change module name --- go.mod | 2 +- go.sum | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 579209a..cdf8c65 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/kr/pretty +module github.com/bashayerAlsalma/pretty go 1.12 diff --git a/go.sum b/go.sum index a0e55fc..81431f5 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +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= From 2a4ef07b0ab838f8bacedb3953908d0e7711605a Mon Sep 17 00:00:00 2001 From: bashayer alsalman Date: Mon, 2 Nov 2020 09:37:14 +0300 Subject: [PATCH 3/5] export attributes --- diff.go | 74 ++++++++++++++++++++++++++++----------------------------- go.mod | 1 + 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/diff.go b/diff.go index 12eda54..eeacf38 100644 --- a/diff.go +++ b/diff.go @@ -7,16 +7,16 @@ import ( ) type sbuf []string -type mbuf map[string]data +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) +//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 } @@ -35,7 +35,7 @@ func Diff(a, b interface{}) (desc []string) { // DiffAsMap returns a map fo where each element describes // a difference between a and b. -func DiffAsMap(a, b interface{}) (desc map[string]data) { +func DiffAsMap(a, b interface{}) (desc map[string]Data) { Mdiff((*mbuf)(&desc), a, b) return desc } @@ -48,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) } @@ -57,13 +57,13 @@ type Printfer interface { Printf(format string, a ...interface{}) } -//Comparator interface for comparing between a,b then calling +//ComparaTor interface for comparing between a,b then calling //the subsequent element -type Comparator interface { - Comparem(label string, d ...data) +type ComparaTor interface { + Comparem(label string, d ...Data) } -// Pdiff prints to p a description of the differences between a and b. +// 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{}) { @@ -76,8 +76,8 @@ func Pdiff(p Printfer, a, b interface{}) { } //Mdiff func -func Mdiff(p Comparator, a, b interface{}) { - d := diffcompator{ +func Mdiff(p ComparaTor, a, b interface{}) { + d := diffcompaTor{ w: p, } d.diff(reflect.ValueOf(a), reflect.ValueOf(b)) @@ -99,7 +99,7 @@ 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. +// 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{}) { @@ -114,15 +114,15 @@ type diffPrinter struct { bVisited map[visit]visit } -type diffcompator struct { - w Comparator +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{} +//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{}) { @@ -133,7 +133,7 @@ func (w diffPrinter) printf(f string, a ...interface{}) { w.w.Printf(l+f, a...) } -func (w diffcompator) comparem(f string, d ...data) { +func (w diffcompaTor) comparem(f string, d ...Data) { var l string if w.l != "" { l = w.l @@ -143,13 +143,13 @@ func (w diffcompator) comparem(f string, d ...data) { w.w.Comparem(l, d...) } -func (w diffcompator) diff(av, bv reflect.Value) { +func (w diffcompaTor) diff(av, bv reflect.Value) { if !av.IsValid() && bv.IsValid() { - w.comparem("", data{from: "nill", to: bv}) + w.comparem("", Data{From: "nill", To: bv}) return } if av.IsValid() && !bv.IsValid() { - w.comparem("", data{from: av, to: "nill"}) + w.comparem("", Data{From: av, To: "nill"}) return } if !av.IsValid() && !bv.IsValid() { @@ -159,30 +159,30 @@ func (w diffcompator) diff(av, bv reflect.Value) { at := av.Type() bt := bv.Type() if at != bt { - w.comparem(fmt.Sprintf("%s", at.Kind()), data{from: av, to: bv}) + 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}) + 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}) + 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)}) + 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}) + 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}) + w.comparem(fmt.Sprintf("%s", at.Kind()), Data{From: av, To: bv}) } case reflect.Array: n := av.Len() @@ -191,7 +191,7 @@ func (w diffcompator) diff(av, bv reflect.Value) { } 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}) + w.comparem(fmt.Sprintf("%s", at.Kind()), Data{From: av, To: bv}) } case reflect.Interface: w.diff(av.Elem(), bv.Elem()) @@ -199,7 +199,7 @@ func (w diffcompator) diff(av, bv reflect.Value) { 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"}) + 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)) @@ -207,14 +207,14 @@ func (w diffcompator) diff(av, bv reflect.Value) { } for _, k := range bk { w.relabel(fmt.Sprintf("[%#v]", k)) - w.comparem(fmt.Sprintf("%s", bt.Kind()), data{from: "missing", to: av.MapIndex(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}) + w.comparem("", Data{From: "nil", To: bv}) case !av.IsNil() && bv.IsNil(): - w.comparem("", data{from: av, to: "nil"}) + w.comparem("", Data{From: av, To: "nil"}) case !av.IsNil() && !bv.IsNil(): w.diff(av.Elem(), bv.Elem()) } @@ -222,7 +222,7 @@ func (w diffcompator) diff(av, bv reflect.Value) { lenA := av.Len() lenB := bv.Len() if lenA != lenB { - // w.printf("%s[%d] != %s[%d]", av.Type(), lenA, bv.Type(), lenB) todo + // w.printf("%s[%d] != %s[%d]", av.Type(), lenA, bv.Type(), lenB) Todo break } for i := 0; i < lenA; i++ { @@ -230,7 +230,7 @@ func (w diffcompator) diff(av, bv reflect.Value) { } case reflect.String: if a, b := av.String(), bv.String(); a != b { - w.comparem(fmt.Sprintf("%s", at.Kind()), data{from: a, to: b}) + w.comparem(fmt.Sprintf("%s", at.Kind()), Data{From: a, To: b}) } case reflect.Struct: for i := 0; i < av.NumField(); i++ { @@ -370,7 +370,7 @@ func (d diffPrinter) relabel(name string) (d1 diffPrinter) { return d1 } -func (d diffcompator) relabel(name string) (d1 diffcompator) { +func (d diffcompaTor) relabel(name string) (d1 diffcompaTor) { d1 = d if d.l != "" && name[0] != '[' { d1.l += "." diff --git a/go.mod b/go.mod index cdf8c65..41b4d16 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/bashayerAlsalma/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 ) From cd04d92e761e93c19fdb74ebe531d09f5c74c296 Mon Sep 17 00:00:00 2001 From: bashayer alsalman Date: Mon, 2 Nov 2020 09:44:44 +0300 Subject: [PATCH 4/5] compare item in slice --- diff.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diff.go b/diff.go index eeacf38..33d47ee 100644 --- a/diff.go +++ b/diff.go @@ -222,7 +222,7 @@ func (w diffcompaTor) diff(av, bv reflect.Value) { lenA := av.Len() lenB := bv.Len() if lenA != lenB { - // w.printf("%s[%d] != %s[%d]", av.Type(), lenA, bv.Type(), lenB) Todo + w.comparem("", Data{From: fmt.Sprintf("[%d]", lenA), To: fmt.Sprintf("[%d]", lenB)}) break } for i := 0; i < lenA; i++ { From 49c2baf0ccffeeb42f1fbfe89f4bff982dd4cddd Mon Sep 17 00:00:00 2001 From: bashayer alsalman Date: Thu, 19 Nov 2020 09:59:39 +0300 Subject: [PATCH 5/5] package name --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 41b4d16..936aabf 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/bashayerAlsalma/pretty +module github.com/bashayerAlsalman/pretty go 1.12 diff --git a/go.sum b/go.sum index 81431f5..695f1a1 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +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=