From f999a77ff9bd0e3ce3453009a744ccf8ba80baa4 Mon Sep 17 00:00:00 2001 From: Arpad Ryszka Date: Mon, 23 Nov 2020 00:46:14 +0100 Subject: [PATCH] Print variants --- debug_test.go | 2 +- notation.go | 73 +++++++++++++++++++--- notation_test.go | 153 +++++++++++++++++++++++++++++++++++++++++++++++ reflect.go | 10 +++- sprint_test.go | 9 +++ 5 files changed, 236 insertions(+), 11 deletions(-) create mode 100644 notation_test.go diff --git a/debug_test.go b/debug_test.go index 5f6ccb4..502a409 100644 --- a/debug_test.go +++ b/debug_test.go @@ -9,7 +9,7 @@ import ( func TestDebugNode(t *testing.T) { const expect = `"foobarbaz"` o := "foobarbaz" - n := reflectValue(none, &pending{values: make(map[valueKey]nodeRef)}, reflect.ValueOf(o)) + n := reflectValue(none, &pending{values: make(map[uintptr]nodeRef)}, reflect.ValueOf(o)) s := fmt.Sprint(n) if s != expect { t.Fatalf( diff --git a/notation.go b/notation.go index 8d96fd6..fdba41e 100644 --- a/notation.go +++ b/notation.go @@ -26,17 +26,12 @@ type wrapLen struct { first, max, last int } -type valueKey struct { - typ reflect.Type - ptr uintptr -} - type nodeRef struct { id, refCount int } type pending struct { - values map[valueKey]nodeRef + values map[uintptr]nodeRef idCounter int } @@ -75,6 +70,8 @@ type writer struct { err error } +var stderr io.Writer = os.Stderr + func (n node) String() string { var b bytes.Buffer w := &writer{w: &b} @@ -167,7 +164,7 @@ func fprintValues(w io.Writer, o opts, v []interface{}) (int, error) { n := reflectValue( o, - &pending{values: make(map[valueKey]nodeRef)}, + &pending{values: make(map[uintptr]nodeRef)}, reflect.ValueOf(vi), ) @@ -182,6 +179,20 @@ func fprintValues(w io.Writer, o opts, v []interface{}) (int, error) { return wr.n, wr.err } +func printValues(o opts, v []interface{}) (int, error) { + return fprintValues(stderr, o, v) +} + +func printlnValues(o opts, v []interface{}) (int, error) { + n, err := fprintValues(stderr, o, v) + if err != nil { + return n, err + } + + nn, err := stderr.Write([]byte("\n")) + return n + nn, err +} + func sprintValues(o opts, v []interface{}) string { var b bytes.Buffer fprintValues(&b, o, v) @@ -212,6 +223,54 @@ func Fprintwv(w io.Writer, v ...interface{}) (int, error) { return fprintValues(w, wrap|allTypes, v) } +func Print(v ...interface{}) (int, error) { + return printValues(none, v) +} + +func Printw(v ...interface{}) (int, error) { + return printValues(wrap, v) +} + +func Printt(v ...interface{}) (int, error) { + return printValues(types, v) +} + +func Printwt(v ...interface{}) (int, error) { + return printValues(wrap|types, v) +} + +func Printv(v ...interface{}) (int, error) { + return printValues(allTypes, v) +} + +func Printwv(v ...interface{}) (int, error) { + return printValues(wrap|allTypes, v) +} + +func Println(v ...interface{}) (int, error) { + return printlnValues(none, v) +} + +func Printlnw(v ...interface{}) (int, error) { + return printlnValues(wrap, v) +} + +func Printlnt(v ...interface{}) (int, error) { + return printlnValues(types, v) +} + +func Printlnwt(v ...interface{}) (int, error) { + return printlnValues(wrap|types, v) +} + +func Printlnv(v ...interface{}) (int, error) { + return printlnValues(allTypes, v) +} + +func Printlnwv(v ...interface{}) (int, error) { + return printlnValues(wrap|allTypes, v) +} + func Sprint(v ...interface{}) string { return sprintValues(none, v) } diff --git a/notation_test.go b/notation_test.go new file mode 100644 index 0000000..8adc1c2 --- /dev/null +++ b/notation_test.go @@ -0,0 +1,153 @@ +package notation + +import ( + "bytes" + "testing" +) + +func TestPrint(t *testing.T) { + for _, test := range []struct { + p func(...interface{}) (int, error) + o interface{} + e string + }{{ + p: Print, + o: struct{foo int}{42}, + e: `{foo: 42}`, + }, { + p: Printw, + o: struct{foo int}{42}, + e: `{ + foo: 42, +}`, + }, { + p: Printt, + o: struct{foo int}{42}, + e: `struct{foo int}{foo: 42}`, + }, { + p: Printwt, + o: struct{foo int}{42}, + e: `struct{ + foo int +}{ + foo: 42, +}`, + }, { + p: Printv, + o: struct{foo int}{42}, + e: `struct{foo int}{foo: int(42)}`, + }, { + p: Printwv, + o: struct{foo int}{42}, + e: `struct{ + foo int +}{ + foo: int(42), +}`, + }} { + defer withEnv(t, "TABWIDTH=0", "LINEWIDTH=0", "LINEWIDTH1=0")() + t.Run("", func(t *testing.T) { + var b bytes.Buffer + orig := stderr + stderr = &b + defer func() { stderr = orig }() + n, err := test.p(test.o) + if err != nil { + t.Fatal(err) + } + + if n != len(test.e) { + t.Fatalf("expected length: %d, got: %d", len(test.e), n) + } + + s := b.String() + if s != test.e { + t.Fatalf("expected: %s, got: %s", test.e, s) + } + }) + } +} + +func TestPrintln(t *testing.T) { + for _, test := range []struct { + p func(...interface{}) (int, error) + f bool + o interface{} + e string + }{{ + p: Println, + o: struct{foo int}{42}, + e: "{foo: 42}\n", + }, { + p: Printlnw, + o: struct{foo int}{42}, + e: `{ + foo: 42, +} +`, + }, { + p: Printlnt, + o: struct{foo int}{42}, + e: "struct{foo int}{foo: 42}\n", + }, { + p: Printlnwt, + o: struct{foo int}{42}, + e: `struct{ + foo int +}{ + foo: 42, +} +`, + }, { + p: Printlnv, + o: struct{foo int}{42}, + e: "struct{foo int}{foo: int(42)}\n", + }, { + p: Printlnwv, + o: struct{foo int}{42}, + e: `struct{ + foo int +}{ + foo: int(42), +} +`, + }, { + p: Println, + o: struct{foo int}{42}, + f: true, + }} { + defer withEnv(t, "TABWIDTH=0", "LINEWIDTH=0", "LINEWIDTH1=0")() + t.Run("", func(t *testing.T) { + var b bytes.Buffer + orig := stderr + stderr = &b + if test.f { + var w failingWriter + stderr = &w + } + + defer func() { stderr = orig }() + n, err := test.p(test.o) + if test.f && err == nil { + t.Fatal("failed to fail") + } + + if test.f { + return + } + + if err != nil { + t.Fatal(err) + } + + if n != len(test.e) { + t.Fatalf("expected length: %d, got: %d", len(test.e), n) + } + + s := b.String() + if s != test.e { + t.Fatalf("expected: %s, got: %s", test.e, s) + } + }) + } +} diff --git a/reflect.go b/reflect.go index e3241d2..548d609 100644 --- a/reflect.go +++ b/reflect.go @@ -118,7 +118,7 @@ func reflectInterface(o opts, p *pending, r reflect.Value) node { return reflectNil(o, false, r) } - e := reflectValue(o, p, r.Elem()) + e := reflectValue(o&^skipTypes, p, r.Elem()) if _, t, _ := withType(o); !t { return e } @@ -169,7 +169,11 @@ func reflectMap(o opts, p *pending, r reflect.Value) node { nodeOf( sn[skey], ": ", - reflectValue(itemOpts, p, r.MapIndex(sv[skey])), + reflectValue( + itemOpts, + p, + r.MapIndex(sv[skey]), + ), ), ) } @@ -301,7 +305,7 @@ func checkPending(p *pending, r reflect.Value) (applyRef func(node) node, ref no } var nr nodeRef - key := valueKey{typ: r.Type(), ptr: r.Pointer()} + key := r.Pointer() nr, isPending = p.values[key] if isPending { nr.refCount++ diff --git a/sprint_test.go b/sprint_test.go index 924715a..b3be827 100644 --- a/sprint_test.go +++ b/sprint_test.go @@ -1076,3 +1076,12 @@ func TestCyclicReferences(t *testing.T) { } }) } + +func TestInterfaceType(t *testing.T) { + const expect = `struct{foo interface{}}{foo: *struct{bar int}{bar: 42}}` + o := struct{ foo interface{} }{foo: &struct{ bar int }{42}} + s := Sprintt(o) + if s != expect { + t.Fatalf("expected: %s, got: %s", expect, s) + } +}