package clog import ( "encoding/json" "testing" ) // Logging this should result in the MarshalLog() value. type Tmarshaler struct{ val string } func (t Tmarshaler) MarshalLog() any { return struct{ Inner string }{"I am a logr.Marshaler"} } func (t Tmarshaler) String() string { return "String(): you should not see this" } func (t Tmarshaler) Error() string { return "Error(): you should not see this" } // Logging this should result in a panic. type Tmarshalerpanic struct{ val string } func (t Tmarshalerpanic) MarshalLog() any { panic("Tmarshalerpanic") } // Logging this should result in the String() value. type Tstringer struct{ val string } func (t Tstringer) String() string { return "I am a fmt.Stringer" } func (t Tstringer) Error() string { return "Error(): you should not see this" } // Logging this should result in a panic. type Tstringerpanic struct{ val string } func (t Tstringerpanic) String() string { panic("Tstringerpanic") } // Logging this should result in the Error() value. type Terror struct{ val string } func (t Terror) Error() string { return "I am an error" } // Logging this should result in a panic. type Terrorpanic struct{ val string } func (t Terrorpanic) Error() string { panic("Terrorpanic") } func TestPretty(t *testing.T) { cases := []struct { val any exp string // used in cases where JSON can't handle it }{ { val: "strval", exp: "strval", }, { val: "strval\nwith\t\"escapes\"", }, { val: true, }, { val: false, }, { val: int(93), }, { val: int8(93), }, { val: int16(93), }, { val: int32(93), }, { val: int64(93), }, { val: int(-93), }, { val: int8(-93), }, { val: int16(-93), }, { val: int32(-93), }, { val: int64(-93), }, { val: uint(93), }, { val: uint8(93), }, { val: uint16(93), }, { val: uint32(93), }, { val: uint64(93), }, { val: uintptr(93), }, { val: float32(93.76), }, { val: float64(93.76), }, { val: complex64(93i), exp: `"(0+93i)"`, }, { val: complex128(93i), exp: `"(0+93i)"`, }, { val: Tmarshaler{"foobar"}, exp: "{Inner:I am a logr.Marshaler}", }, { val: &Tmarshaler{"foobar"}, exp: "{Inner:I am a logr.Marshaler}", }, { val: (*Tmarshaler)(nil), exp: "", }, { val: Tmarshalerpanic{"foobar"}, exp: "", }, { val: Tstringer{"foobar"}, exp: "I am a fmt.Stringer", }, { val: &Tstringer{"foobar"}, exp: "I am a fmt.Stringer", }, { val: (*Tstringer)(nil), exp: "", }, { val: Tstringerpanic{"foobar"}, exp: "", }, { val: Terror{"foobar"}, exp: "I am an error", }, { val: &Terror{"foobar"}, exp: "I am an error", }, { val: (*Terror)(nil), exp: "", }, { val: Terrorpanic{"foobar"}, exp: "", }, { val: []string{"foo", "bar"}, exp: "\n foo\n bar", }, { val: map[string]string{ "foo": "bar", "yes": "no", }, exp: "\n foo bar\n yes no", }, { val: map[string]string{ "yes": "", "foo": "bar", }, exp: "\n foo bar", }, { val: map[string]string{ "foo": "bar", "yes": "", }, exp: "\n foo bar", }, { val: map[string]string{ "no": "", "foo": "bar", "yes": "", "op": "delete", }, exp: "\n foo bar\n op delete", }, // TODO: non-string slices, non-string values in map (TextMarshaler & !TextMarshaler), slice in map, etc } for i, tc := range cases { l := &clog{tabWidth: 2} ours := l.pretty(tc.val) want := "" if tc.exp != "" { want = tc.exp } else { jb, err := json.Marshal(tc.val) if err != nil { t.Fatalf("[%d]: unexpected error: %v\ngot: %q", i, err, ours) } want = string(jb) } if ours != want { t.Errorf("[%d]:\n\texpected %q\n\tgot %q", i, want, ours) } } }