@@ -27,6 +27,7 @@ import (
2727 "github.com/go-logr/logr"
2828)
2929
30+ // Will be handled via reflection instead of type assertions.
3031type substr string
3132
3233func ptrint (i int ) * int {
@@ -36,6 +37,20 @@ func ptrstr(s string) *string {
3637 return & s
3738}
3839
40+ // point implements encoding.TextMarshaler and can be used as a map key.
41+ type point struct { x , y int }
42+
43+ func (p point ) MarshalText () ([]byte , error ) {
44+ return []byte (fmt .Sprintf ("(%d, %d)" , p .x , p .y )), nil
45+ }
46+
47+ // pointErr implements encoding.TextMarshaler but returns an error.
48+ type pointErr struct { x , y int }
49+
50+ func (p pointErr ) MarshalText () ([]byte , error ) {
51+ return nil , fmt .Errorf ("uh oh: %d, %d" , p .x , p .y )
52+ }
53+
3954// Logging this should result in the MarshalLog() value.
4055type Tmarshaler string
4156
@@ -198,7 +213,9 @@ func TestPretty(t *testing.T) {
198213 exp string // used in cases where JSON can't handle it
199214 }{
200215 {val : "strval" },
216+ {val : "strval\n with\t \" escapes\" " },
201217 {val : substr ("substrval" )},
218+ {val : substr ("substrval\n with\t \" escapes\" " )},
202219 {val : true },
203220 {val : false },
204221 {val : int (93 )},
@@ -235,7 +252,11 @@ func TestPretty(t *testing.T) {
235252 exp : `[]` ,
236253 },
237254 {val : []int {9 , 3 , 7 , 6 }},
255+ {val : []string {"str" , "with\t escape" }},
256+ {val : []substr {"substr" , "with\t escape" }},
238257 {val : [4 ]int {9 , 3 , 7 , 6 }},
258+ {val : [2 ]string {"str" , "with\t escape" }},
259+ {val : [2 ]substr {"substr" , "with\t escape" }},
239260 {
240261 val : struct {
241262 Int int
@@ -255,11 +276,43 @@ func TestPretty(t *testing.T) {
255276 "nine" : 3 ,
256277 },
257278 },
279+ {
280+ val : map [string ]int {
281+ "with\t escape" : 76 ,
282+ },
283+ },
258284 {
259285 val : map [substr ]int {
260286 "nine" : 3 ,
261287 },
262288 },
289+ {
290+ val : map [substr ]int {
291+ "with\t escape" : 76 ,
292+ },
293+ },
294+ {
295+ val : map [int ]int {
296+ 9 : 3 ,
297+ },
298+ },
299+ {
300+ val : map [float64 ]int {
301+ 9.5 : 3 ,
302+ },
303+ exp : `{"9.5":3}` ,
304+ },
305+ {
306+ val : map [point ]int {
307+ {x : 1 , y : 2 }: 3 ,
308+ },
309+ },
310+ {
311+ val : map [pointErr ]int {
312+ {x : 1 , y : 2 }: 3 ,
313+ },
314+ exp : `{"<error-MarshalText: uh oh: 1, 2>":3}` ,
315+ },
263316 {
264317 val : struct {
265318 X int `json:"x"`
@@ -283,6 +336,7 @@ func TestPretty(t *testing.T) {
283336 val : []struct { X , Y string }{
284337 {"nine" , "three" },
285338 {"seven" , "six" },
339+ {"with\t " , "\t escapes" },
286340 },
287341 },
288342 {
@@ -438,6 +492,24 @@ func TestPretty(t *testing.T) {
438492 val : PseudoStruct (makeKV ("f1" , 1 , "f2" , true , "f3" , []int {})),
439493 exp : `{"f1":1,"f2":true,"f3":[]}` ,
440494 },
495+ {
496+ val : map [TjsontagsString ]int {
497+ {String1 : `"quoted"` , String4 : `unquoted` }: 1 ,
498+ },
499+ exp : `{"{\"string1\":\"\\\"quoted\\\"\",\"-\":\"\",\"string4\":\"unquoted\",\"String5\":\"\"}":1}` ,
500+ },
501+ {
502+ val : map [TjsontagsInt ]int {
503+ {Int1 : 1 , Int2 : 2 }: 3 ,
504+ },
505+ exp : `{"{\"int1\":1,\"-\":0,\"Int5\":0}":3}` ,
506+ },
507+ {
508+ val : map [[2 ]struct { S string }]int {
509+ {{S : `"quoted"` }, {S : "unquoted" }}: 1 ,
510+ },
511+ exp : `{"[{\"S\":\"\\\"quoted\\\"\"},{\"S\":\"unquoted\"}]":1}` ,
512+ },
441513 }
442514
443515 f := NewFormatter (Options {})
@@ -449,7 +521,7 @@ func TestPretty(t *testing.T) {
449521 } else {
450522 jb , err := json .Marshal (tc .val )
451523 if err != nil {
452- t .Errorf ("[%d]: unexpected error: %v" , i , err )
524+ t .Fatalf ("[%d]: unexpected error: %v\n got: %q " , i , err , ours )
453525 }
454526 want = string (jb )
455527 }
@@ -496,6 +568,13 @@ func TestRender(t *testing.T) {
496568 args : makeKV ("bool" , PseudoStruct (makeKV ("boolsub" , true ))),
497569 expectKV : `"int"={"intsub":1} "str"={"strsub":"2"} "bool"={"boolsub":true}` ,
498570 expectJSON : `{"int":{"intsub":1},"str":{"strsub":"2"},"bool":{"boolsub":true}}` ,
571+ }, {
572+ name : "escapes" ,
573+ builtins : makeKV ("\" 1\" " , 1 ), // will not be escaped, but should never happen
574+ values : makeKV ("\t str" , "ABC" ), // escaped
575+ args : makeKV ("bool\n " , true ), // escaped
576+ expectKV : `""1""=1 "\tstr"="ABC" "bool\n"=true` ,
577+ expectJSON : `{""1"":1,"\tstr":"ABC","bool\n":true}` ,
499578 }, {
500579 name : "missing value" ,
501580 builtins : makeKV ("builtin" ),
@@ -505,27 +584,27 @@ func TestRender(t *testing.T) {
505584 expectJSON : `{"builtin":"<no-value>","value":"<no-value>","arg":"<no-value>"}` ,
506585 }, {
507586 name : "non-string key int" ,
508- args : makeKV (123 , "val" ),
587+ builtins : makeKV (123 , "val" ), // should never happen
509588 values : makeKV (456 , "val" ),
510- builtins : makeKV (789 , "val" ),
511- expectKV : `"<non-string-key: 789 >"="val" "<non-string-key: 456>"="val" "<non-string-key: 123 >"="val"` ,
512- expectJSON : `{"<non-string-key: 789 >":"val","<non-string-key: 456>":"val","<non-string-key: 123 >":"val"}` ,
589+ args : makeKV (789 , "val" ),
590+ expectKV : `"<non-string-key: 123 >"="val" "<non-string-key: 456>"="val" "<non-string-key: 789 >"="val"` ,
591+ expectJSON : `{"<non-string-key: 123 >":"val","<non-string-key: 456>":"val","<non-string-key: 789 >":"val"}` ,
513592 }, {
514593 name : "non-string key struct" ,
515- args : makeKV (struct {
594+ builtins : makeKV (struct { // will not be escaped, but should never happen
516595 F1 string
517596 F2 int
518- }{"arg " , 123 }, "val" ),
597+ }{"builtin " , 123 }, "val" ),
519598 values : makeKV (struct {
520599 F1 string
521600 F2 int
522601 }{"value" , 456 }, "val" ),
523- builtins : makeKV (struct {
602+ args : makeKV (struct {
524603 F1 string
525604 F2 int
526- }{"builtin " , 789 }, "val" ),
527- expectKV : `"<non-string-key: {"F1":"builtin",>"="val" "<non-string-key: {"F1": "value", "F>"="val" "<non-string-key: {"F1": "arg", "F2">"="val"` ,
528- expectJSON : `{"<non-string-key: {"F1":"builtin",>":"val","<non-string-key: {"F1": "value", "F>":"val","<non-string-key: {"F1": "arg", "F2">":"val"}` ,
605+ }{"arg " , 789 }, "val" ),
606+ expectKV : `"<non-string-key: {"F1":"builtin",>"="val" "<non-string-key: {\ "F1\":\ "value\",\ "F>"="val" "<non-string-key: {\ "F1\":\ "arg\",\ "F2\ ">"="val"` ,
607+ expectJSON : `{"<non-string-key: {"F1":"builtin",>":"val","<non-string-key: {\ "F1\":\ "value\",\ "F>":"val","<non-string-key: {\ "F1\":\ "arg\",\ "F2\ ">":"val"}` ,
529608 }}
530609
531610 for _ , tc := range testCases {
@@ -534,7 +613,7 @@ func TestRender(t *testing.T) {
534613 formatter .AddValues (tc .values )
535614 r := formatter .render (tc .builtins , tc .args )
536615 if r != expect {
537- t .Errorf ("wrong output:\n expected %q \n got %q " , expect , r )
616+ t .Errorf ("wrong output:\n expected %v \n got %v " , expect , r )
538617 }
539618 }
540619 t .Run ("KV" , func (t * testing.T ) {
0 commit comments