github.com/neilotoole/jsoncolor@v0.6.0/jsoncolor_test.go (about) 1 package jsoncolor_test 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "testing" 8 9 "github.com/segmentio/encoding/json" 10 11 "github.com/neilotoole/jsoncolor" 12 "github.com/stretchr/testify/require" 13 14 stdjson "encoding/json" 15 ) 16 17 // TestPackageDropIn checks that jsoncolor satisfies basic requirements 18 // to be a drop-in for encoding/json. 19 func TestPackageDropIn(t *testing.T) { 20 // Verify encoding/json types exists 21 var ( 22 _ = jsoncolor.Decoder{} 23 _ = jsoncolor.Delim(0) 24 _ = jsoncolor.Encoder{} 25 _ = jsoncolor.InvalidUTF8Error{} 26 _ = jsoncolor.InvalidUnmarshalError{} 27 _ = jsoncolor.Marshaler(nil) 28 _ = jsoncolor.MarshalerError{} 29 _ = jsoncolor.Number("0") 30 _ = jsoncolor.RawMessage{} 31 _ = jsoncolor.SyntaxError{} 32 _ = jsoncolor.Token(nil) 33 _ = jsoncolor.UnmarshalFieldError{} 34 _ = jsoncolor.UnmarshalTypeError{} 35 _ = jsoncolor.Unmarshaler(nil) 36 _ = jsoncolor.UnsupportedTypeError{} 37 _ = jsoncolor.UnsupportedValueError{} 38 ) 39 40 const prefix, indent = "", " " 41 42 testCases := []string{"testdata/sakila_actor.json", "testdata/sakila_payment.json"} 43 for _, tc := range testCases { 44 tc := tc 45 t.Run(tc, func(t *testing.T) { 46 b, readErr := ioutil.ReadFile(tc) 47 require.NoError(t, readErr) 48 49 // Test json.Valid equivalence 50 var fv1, fv2 = json.Valid, jsoncolor.Valid 51 require.Equal(t, fv1(b), fv2(b)) 52 53 // Test json.Unmarshal equivalence 54 var fu1, fu2 = json.Unmarshal, jsoncolor.Unmarshal 55 var m1, m2 interface{} 56 err1, err2 := fu1(b, &m1), fu2(b, &m2) 57 require.NoError(t, err1) 58 require.NoError(t, err2) 59 require.EqualValues(t, m1, m2) 60 61 // Test json.Marshal equivalence 62 var fm1, fm2 = json.Marshal, jsoncolor.Marshal 63 gotMarshalB1, err1 := fm1(m1) 64 require.NoError(t, err1) 65 gotMarshalB2, err2 := fm2(m1) 66 require.NoError(t, err2) 67 require.Equal(t, gotMarshalB1, gotMarshalB2) 68 69 // Test json.MarshalIndent equivalence 70 var fmi1, fmi2 = json.MarshalIndent, jsoncolor.MarshalIndent 71 gotMarshallIndentB1, err1 := fmi1(m1, prefix, indent) 72 require.NoError(t, err1) 73 gotMarshalIndentB2, err2 := fmi2(m1, prefix, indent) 74 require.NoError(t, err2) 75 require.Equal(t, gotMarshallIndentB1, gotMarshalIndentB2) 76 77 // Test json.Compact equivalence 78 var fc1, fc2 = json.Compact, jsoncolor.Compact 79 var buf1, buf2 = &bytes.Buffer{}, &bytes.Buffer{} 80 err1 = fc1(buf1, gotMarshallIndentB1) 81 require.NoError(t, err1) 82 err2 = fc2(buf2, gotMarshalIndentB2) 83 require.NoError(t, err2) 84 require.Equal(t, buf1.Bytes(), buf2.Bytes()) 85 // Double-check 86 require.Equal(t, buf1.Bytes(), gotMarshalB1) 87 require.Equal(t, buf2.Bytes(), gotMarshalB2) 88 buf1.Reset() 89 buf2.Reset() 90 91 // Test json.Indent equivalence 92 var fi1, fi2 = json.Indent, jsoncolor.Indent 93 err1 = fi1(buf1, gotMarshalB1, prefix, indent) 94 require.NoError(t, err1) 95 err2 = fi2(buf2, gotMarshalB2, prefix, indent) 96 require.NoError(t, err2) 97 require.Equal(t, buf1.Bytes(), buf2.Bytes()) 98 buf1.Reset() 99 buf2.Reset() 100 101 // Test json.HTMLEscape equivalence 102 var fh1, fh2 = json.HTMLEscape, jsoncolor.HTMLEscape 103 fh1(buf1, gotMarshalB1) 104 fh2(buf2, gotMarshalB2) 105 require.Equal(t, buf1.Bytes(), buf2.Bytes()) 106 }) 107 } 108 } 109 110 func TestEncode(t *testing.T) { 111 testCases := []struct { 112 name string 113 pretty bool 114 color bool 115 sortMap bool 116 v interface{} 117 want string 118 }{ 119 {name: "nil", pretty: false, v: nil, want: "null\n"}, 120 {name: "slice_empty", pretty: true, v: []int{}, want: "[]\n"}, 121 {name: "slice_1_pretty", pretty: true, v: []interface{}{1}, want: "[\n 1\n]\n"}, 122 {name: "slice_1_no_pretty", v: []interface{}{1}, want: "[1]\n"}, 123 {name: "slice_2_pretty", pretty: true, v: []interface{}{1, true}, want: "[\n 1,\n true\n]\n"}, 124 {name: "slice_2_no_pretty", v: []interface{}{1, true}, want: "[1,true]\n"}, 125 {name: "map_int_empty", pretty: true, v: map[string]int{}, want: "{}\n"}, 126 {name: "map_interface_empty", pretty: true, v: map[string]interface{}{}, want: "{}\n"}, 127 {name: "map_interface_empty_sorted", pretty: true, sortMap: true, v: map[string]interface{}{}, want: "{}\n"}, 128 {name: "map_1_pretty", pretty: true, sortMap: true, v: map[string]interface{}{"one": 1}, want: "{\n \"one\": 1\n}\n"}, 129 {name: "map_1_no_pretty", sortMap: true, v: map[string]interface{}{"one": 1}, want: "{\"one\":1}\n"}, 130 {name: "map_2_pretty", pretty: true, sortMap: true, v: map[string]interface{}{"one": 1, "two": 2}, want: "{\n \"one\": 1,\n \"two\": 2\n}\n"}, 131 {name: "map_2_no_pretty", sortMap: true, v: map[string]interface{}{"one": 1, "two": 2}, want: "{\"one\":1,\"two\":2}\n"}, 132 {name: "tinystruct", pretty: true, v: TinyStruct{FBool: true}, want: "{\n \"f_bool\": true\n}\n"}, 133 } 134 135 for _, tc := range testCases { 136 tc := tc 137 138 t.Run(tc.name, func(t *testing.T) { 139 buf := &bytes.Buffer{} 140 enc := jsoncolor.NewEncoder(buf) 141 enc.SetEscapeHTML(false) 142 enc.SetSortMapKeys(tc.sortMap) 143 if tc.pretty { 144 enc.SetIndent("", " ") 145 } 146 if tc.color { 147 clrs := jsoncolor.DefaultColors() 148 enc.SetColors(clrs) 149 } 150 151 require.NoError(t, enc.Encode(tc.v)) 152 require.True(t, stdjson.Valid(buf.Bytes())) 153 require.Equal(t, tc.want, buf.String()) 154 }) 155 } 156 } 157 158 func TestEncode_Slice(t *testing.T) { 159 testCases := []struct { 160 name string 161 pretty bool 162 color bool 163 v []interface{} 164 want string 165 }{ 166 {name: "nil", pretty: true, v: nil, want: "null\n"}, 167 {name: "empty", pretty: true, v: []interface{}{}, want: "[]\n"}, 168 {name: "one", pretty: true, v: []interface{}{1}, want: "[\n 1\n]\n"}, 169 {name: "two", pretty: true, v: []interface{}{1, true}, want: "[\n 1,\n true\n]\n"}, 170 {name: "three", pretty: true, v: []interface{}{1, true, "hello"}, want: "[\n 1,\n true,\n \"hello\"\n]\n"}, 171 } 172 173 for _, tc := range testCases { 174 tc := tc 175 176 t.Run(tc.name, func(t *testing.T) { 177 buf := &bytes.Buffer{} 178 enc := jsoncolor.NewEncoder(buf) 179 enc.SetEscapeHTML(false) 180 if tc.pretty { 181 enc.SetIndent("", " ") 182 } 183 if tc.color { 184 enc.SetColors(jsoncolor.DefaultColors()) 185 } 186 187 require.NoError(t, enc.Encode(tc.v)) 188 require.True(t, stdjson.Valid(buf.Bytes())) 189 require.Equal(t, tc.want, buf.String()) 190 }) 191 } 192 } 193 194 func TestEncode_SmallStruct(t *testing.T) { 195 v := SmallStruct{ 196 FInt: 7, 197 FSlice: []interface{}{64, true}, 198 FMap: map[string]interface{}{ 199 "m_float64": 64.64, 200 "m_string": "hello", 201 }, 202 FTinyStruct: TinyStruct{FBool: true}, 203 FString: "hello", 204 } 205 206 testCases := []struct { 207 pretty bool 208 color bool 209 want string 210 }{ 211 {pretty: false, color: false, want: "{\"f_int\":7,\"f_slice\":[64,true],\"f_map\":{\"m_float64\":64.64,\"m_string\":\"hello\"},\"f_tinystruct\":{\"f_bool\":true},\"f_string\":\"hello\"}\n"}, 212 {pretty: true, color: false, want: "{\n \"f_int\": 7,\n \"f_slice\": [\n 64,\n true\n ],\n \"f_map\": {\n \"m_float64\": 64.64,\n \"m_string\": \"hello\"\n },\n \"f_tinystruct\": {\n \"f_bool\": true\n },\n \"f_string\": \"hello\"\n}\n"}, 213 } 214 215 for _, tc := range testCases { 216 tc := tc 217 218 t.Run(fmt.Sprintf("pretty_%v__color_%v", tc.pretty, tc.color), func(t *testing.T) { 219 buf := &bytes.Buffer{} 220 enc := jsoncolor.NewEncoder(buf) 221 enc.SetEscapeHTML(false) 222 enc.SetSortMapKeys(true) 223 224 if tc.pretty { 225 enc.SetIndent("", " ") 226 } 227 if tc.color { 228 enc.SetColors(jsoncolor.DefaultColors()) 229 } 230 231 require.NoError(t, enc.Encode(v)) 232 require.True(t, stdjson.Valid(buf.Bytes())) 233 require.Equal(t, tc.want, buf.String()) 234 }) 235 } 236 } 237 238 func TestEncode_Map_Nested(t *testing.T) { 239 v := map[string]interface{}{ 240 "m_bool1": true, 241 "m_nest1": map[string]interface{}{ 242 "m_nest1_bool": true, 243 "m_nest2": map[string]interface{}{ 244 "m_nest2_bool": true, 245 "m_nest3": map[string]interface{}{ 246 "m_nest3_bool": true, 247 }, 248 }, 249 }, 250 "m_string1": "hello", 251 } 252 253 testCases := []struct { 254 pretty bool 255 color bool 256 want string 257 }{ 258 {pretty: false, want: "{\"m_bool1\":true,\"m_nest1\":{\"m_nest1_bool\":true,\"m_nest2\":{\"m_nest2_bool\":true,\"m_nest3\":{\"m_nest3_bool\":true}}},\"m_string1\":\"hello\"}\n"}, 259 {pretty: true, want: "{\n \"m_bool1\": true,\n \"m_nest1\": {\n \"m_nest1_bool\": true,\n \"m_nest2\": {\n \"m_nest2_bool\": true,\n \"m_nest3\": {\n \"m_nest3_bool\": true\n }\n }\n },\n \"m_string1\": \"hello\"\n}\n"}, 260 } 261 262 for _, tc := range testCases { 263 tc := tc 264 265 t.Run(fmt.Sprintf("pretty_%v__color_%v", tc.pretty, tc.color), func(t *testing.T) { 266 buf := &bytes.Buffer{} 267 enc := jsoncolor.NewEncoder(buf) 268 enc.SetEscapeHTML(false) 269 enc.SetSortMapKeys(true) 270 if tc.pretty { 271 enc.SetIndent("", " ") 272 } 273 if tc.color { 274 enc.SetColors(jsoncolor.DefaultColors()) 275 } 276 277 require.NoError(t, enc.Encode(v)) 278 require.True(t, stdjson.Valid(buf.Bytes())) 279 require.Equal(t, tc.want, buf.String()) 280 }) 281 } 282 } 283 284 // TestEncode_Map_StringNotInterface tests maps with a string key 285 // but the value type is not interface{}. 286 // For example, map[string]bool. This test is necessary because the 287 // encoder has a fast path for map[string]interface{} 288 func TestEncode_Map_StringNotInterface(t *testing.T) { 289 testCases := []struct { 290 pretty bool 291 color bool 292 sortMap bool 293 v map[string]bool 294 want string 295 }{ 296 {pretty: false, sortMap: true, v: map[string]bool{}, want: "{}\n"}, 297 {pretty: false, sortMap: false, v: map[string]bool{}, want: "{}\n"}, 298 {pretty: true, sortMap: true, v: map[string]bool{}, want: "{}\n"}, 299 {pretty: true, sortMap: false, v: map[string]bool{}, want: "{}\n"}, 300 {pretty: false, sortMap: true, v: map[string]bool{"one": true}, want: "{\"one\":true}\n"}, 301 {pretty: false, sortMap: false, v: map[string]bool{"one": true}, want: "{\"one\":true}\n"}, 302 {pretty: false, sortMap: true, v: map[string]bool{"one": true, "two": false}, want: "{\"one\":true,\"two\":false}\n"}, 303 {pretty: true, sortMap: true, v: map[string]bool{"one": true, "two": false}, want: "{\n \"one\": true,\n \"two\": false\n}\n"}, 304 } 305 306 for _, tc := range testCases { 307 tc := tc 308 309 t.Run(fmt.Sprintf("size_%d__pretty_%v__color_%v", len(tc.v), tc.pretty, tc.color), func(t *testing.T) { 310 buf := &bytes.Buffer{} 311 enc := jsoncolor.NewEncoder(buf) 312 enc.SetEscapeHTML(false) 313 enc.SetSortMapKeys(tc.sortMap) 314 if tc.pretty { 315 enc.SetIndent("", " ") 316 } 317 if tc.color { 318 enc.SetColors(jsoncolor.DefaultColors()) 319 } 320 321 require.NoError(t, enc.Encode(tc.v)) 322 require.True(t, stdjson.Valid(buf.Bytes())) 323 require.Equal(t, tc.want, buf.String()) 324 }) 325 } 326 } 327 328 func TestEncode_RawMessage(t *testing.T) { 329 type RawStruct struct { 330 FString string `json:"f_string"` 331 FRaw jsoncolor.RawMessage `json:"f_raw"` 332 } 333 334 raw := jsoncolor.RawMessage(`{"one":1,"two":2}`) 335 336 testCases := []struct { 337 name string 338 pretty bool 339 color bool 340 v interface{} 341 want string 342 }{ 343 {name: "empty", pretty: false, v: jsoncolor.RawMessage(`{}`), want: "{}\n"}, 344 {name: "no_pretty", pretty: false, v: raw, want: "{\"one\":1,\"two\":2}\n"}, 345 {name: "pretty", pretty: true, v: raw, want: "{\n \"one\": 1,\n \"two\": 2\n}\n"}, 346 {name: "pretty_struct", pretty: true, v: RawStruct{FString: "hello", FRaw: raw}, want: "{\n \"f_string\": \"hello\",\n \"f_raw\": {\n \"one\": 1,\n \"two\": 2\n }\n}\n"}, 347 } 348 349 for _, tc := range testCases { 350 tc := tc 351 352 t.Run(tc.name, func(t *testing.T) { 353 buf := &bytes.Buffer{} 354 enc := jsoncolor.NewEncoder(buf) 355 enc.SetEscapeHTML(false) 356 enc.SetSortMapKeys(true) 357 if tc.pretty { 358 enc.SetIndent("", " ") 359 } 360 if tc.color { 361 enc.SetColors(jsoncolor.DefaultColors()) 362 } 363 364 err := enc.Encode(tc.v) 365 require.NoError(t, err) 366 require.True(t, stdjson.Valid(buf.Bytes())) 367 require.Equal(t, tc.want, buf.String()) 368 }) 369 } 370 } 371 372 // TestEncode_Map_StringNotInterface tests map[string]json.RawMessage. 373 // This test is necessary because the encoder has a fast path 374 // for map[string]interface{} 375 func TestEncode_Map_StringRawMessage(t *testing.T) { 376 raw := jsoncolor.RawMessage(`{"one":1,"two":2}`) 377 378 testCases := []struct { 379 pretty bool 380 color bool 381 sortMap bool 382 v map[string]jsoncolor.RawMessage 383 want string 384 }{ 385 {pretty: false, sortMap: true, v: map[string]jsoncolor.RawMessage{}, want: "{}\n"}, 386 {pretty: false, sortMap: false, v: map[string]jsoncolor.RawMessage{}, want: "{}\n"}, 387 {pretty: true, sortMap: true, v: map[string]jsoncolor.RawMessage{}, want: "{}\n"}, 388 {pretty: true, sortMap: false, v: map[string]jsoncolor.RawMessage{}, want: "{}\n"}, 389 {pretty: false, sortMap: true, v: map[string]jsoncolor.RawMessage{"msg1": raw, "msg2": raw}, want: "{\"msg1\":{\"one\":1,\"two\":2},\"msg2\":{\"one\":1,\"two\":2}}\n"}, 390 {pretty: true, sortMap: true, v: map[string]jsoncolor.RawMessage{"msg1": raw, "msg2": raw}, want: "{\n \"msg1\": {\n \"one\": 1,\n \"two\": 2\n },\n \"msg2\": {\n \"one\": 1,\n \"two\": 2\n }\n}\n"}, 391 {pretty: true, sortMap: false, v: map[string]jsoncolor.RawMessage{"msg1": raw}, want: "{\n \"msg1\": {\n \"one\": 1,\n \"two\": 2\n }\n}\n"}, 392 } 393 394 for _, tc := range testCases { 395 tc := tc 396 397 name := fmt.Sprintf("size_%d__pretty_%v__color_%v__sort_%v", len(tc.v), tc.pretty, tc.color, tc.sortMap) 398 t.Run(name, func(t *testing.T) { 399 400 buf := &bytes.Buffer{} 401 enc := jsoncolor.NewEncoder(buf) 402 enc.SetEscapeHTML(false) 403 enc.SetSortMapKeys(tc.sortMap) 404 if tc.pretty { 405 enc.SetIndent("", " ") 406 } 407 if tc.color { 408 enc.SetColors(jsoncolor.DefaultColors()) 409 } 410 411 require.NoError(t, enc.Encode(tc.v)) 412 require.True(t, stdjson.Valid(buf.Bytes())) 413 require.Equal(t, tc.want, buf.String()) 414 }) 415 } 416 } 417 418 func TestEncode_BigStruct(t *testing.T) { 419 v := newBigStruct() 420 421 testCases := []struct { 422 pretty bool 423 color bool 424 want string 425 }{ 426 {pretty: false, want: "{\"f_int\":-7,\"f_int8\":-8,\"f_int16\":-16,\"f_int32\":-32,\"f_int64\":-64,\"f_uint\":7,\"f_uint8\":8,\"f_uint16\":16,\"f_uint32\":32,\"f_uint64\":64,\"f_float32\":32.32,\"f_float64\":64.64,\"f_bool\":true,\"f_bytes\":\"aGVsbG8=\",\"f_nil\":null,\"f_string\":\"hello\",\"f_map\":{\"m_bool\":true,\"m_int64\":64,\"m_nil\":null,\"m_smallstruct\":{\"f_int\":7,\"f_slice\":[64,true],\"f_map\":{\"m_float64\":64.64,\"m_string\":\"hello\"},\"f_tinystruct\":{\"f_bool\":true},\"f_string\":\"hello\"},\"m_string\":\"hello\"},\"f_smallstruct\":{\"f_int\":7,\"f_slice\":[64,true],\"f_map\":{\"m_float64\":64.64,\"m_string\":\"hello\"},\"f_tinystruct\":{\"f_bool\":true},\"f_string\":\"hello\"},\"f_interface\":\"hello\",\"f_interfaces\":[64,\"hello\",true]}\n"}, 427 {pretty: true, want: "{\n \"f_int\": -7,\n \"f_int8\": -8,\n \"f_int16\": -16,\n \"f_int32\": -32,\n \"f_int64\": -64,\n \"f_uint\": 7,\n \"f_uint8\": 8,\n \"f_uint16\": 16,\n \"f_uint32\": 32,\n \"f_uint64\": 64,\n \"f_float32\": 32.32,\n \"f_float64\": 64.64,\n \"f_bool\": true,\n \"f_bytes\": \"aGVsbG8=\",\n \"f_nil\": null,\n \"f_string\": \"hello\",\n \"f_map\": {\n \"m_bool\": true,\n \"m_int64\": 64,\n \"m_nil\": null,\n \"m_smallstruct\": {\n \"f_int\": 7,\n \"f_slice\": [\n 64,\n true\n ],\n \"f_map\": {\n \"m_float64\": 64.64,\n \"m_string\": \"hello\"\n },\n \"f_tinystruct\": {\n \"f_bool\": true\n },\n \"f_string\": \"hello\"\n },\n \"m_string\": \"hello\"\n },\n \"f_smallstruct\": {\n \"f_int\": 7,\n \"f_slice\": [\n 64,\n true\n ],\n \"f_map\": {\n \"m_float64\": 64.64,\n \"m_string\": \"hello\"\n },\n \"f_tinystruct\": {\n \"f_bool\": true\n },\n \"f_string\": \"hello\"\n },\n \"f_interface\": \"hello\",\n \"f_interfaces\": [\n 64,\n \"hello\",\n true\n ]\n}\n"}, 428 } 429 430 for _, tc := range testCases { 431 tc := tc 432 433 t.Run(fmt.Sprintf("pretty_%v__color_%v", tc.pretty, tc.color), func(t *testing.T) { 434 435 buf := &bytes.Buffer{} 436 enc := jsoncolor.NewEncoder(buf) 437 enc.SetEscapeHTML(false) 438 enc.SetSortMapKeys(true) 439 if tc.pretty { 440 enc.SetIndent("", " ") 441 } 442 if tc.color { 443 enc.SetColors(jsoncolor.DefaultColors()) 444 } 445 446 require.NoError(t, enc.Encode(v)) 447 require.True(t, stdjson.Valid(buf.Bytes())) 448 require.Equal(t, tc.want, buf.String()) 449 }) 450 } 451 } 452 453 // TestEncode_Map_Not_StringInterface tests map encoding where 454 // the map is not map[string]interface{} (for which the encoder 455 // has a fast path). 456 // 457 // NOTE: Currently the encoder is broken wrt colors enabled 458 // for non-string map keys, though that is kinda JSON-illegal anyway. 459 func TestEncode_Map_Not_StringInterface(t *testing.T) { 460 buf := &bytes.Buffer{} 461 enc := jsoncolor.NewEncoder(buf) 462 enc.SetEscapeHTML(false) 463 enc.SetSortMapKeys(true) 464 enc.SetColors(jsoncolor.DefaultColors()) 465 enc.SetIndent("", " ") 466 467 v := map[int32]string{ 468 0: "zero", 469 1: "one", 470 2: "two", 471 } 472 473 require.NoError(t, enc.Encode(v)) 474 require.False(t, stdjson.Valid(buf.Bytes()), 475 "expected to be invalid JSON because the encoder currently doesn't handle maps with non-string keys") 476 } 477 478 // BigStruct is a big test struct. 479 type BigStruct struct { 480 FInt int `json:"f_int"` 481 FInt8 int8 `json:"f_int8"` 482 FInt16 int16 `json:"f_int16"` 483 FInt32 int32 `json:"f_int32"` 484 FInt64 int64 `json:"f_int64"` 485 FUint uint `json:"f_uint"` 486 FUint8 uint8 `json:"f_uint8"` 487 FUint16 uint16 `json:"f_uint16"` 488 FUint32 uint32 `json:"f_uint32"` 489 FUint64 uint64 `json:"f_uint64"` 490 FFloat32 float32 `json:"f_float32"` 491 FFloat64 float64 `json:"f_float64"` 492 FBool bool `json:"f_bool"` 493 FBytes []byte `json:"f_bytes"` 494 FNil interface{} `json:"f_nil"` 495 FString string `json:"f_string"` 496 FMap map[string]interface{} `json:"f_map"` 497 FSmallStruct SmallStruct `json:"f_smallstruct"` 498 FInterface interface{} `json:"f_interface"` 499 FInterfaces []interface{} `json:"f_interfaces"` 500 } 501 502 // SmallStruct is a small test struct. 503 type SmallStruct struct { 504 FInt int `json:"f_int"` 505 FSlice []interface{} `json:"f_slice"` 506 FMap map[string]interface{} `json:"f_map"` 507 FTinyStruct TinyStruct `json:"f_tinystruct"` 508 FString string `json:"f_string"` 509 } 510 511 // Tiny Struct is a tiny test struct. 512 type TinyStruct struct { 513 FBool bool `json:"f_bool"` 514 } 515 516 func newBigStruct() BigStruct { 517 return BigStruct{ 518 FInt: -7, 519 FInt8: -8, 520 FInt16: -16, 521 FInt32: -32, 522 FInt64: -64, 523 FUint: 7, 524 FUint8: 8, 525 FUint16: 16, 526 FUint32: 32, 527 FUint64: 64, 528 FFloat32: 32.32, 529 FFloat64: 64.64, 530 FBool: true, 531 FBytes: []byte("hello"), 532 FNil: nil, 533 FString: "hello", 534 FMap: map[string]interface{}{ 535 "m_int64": int64(64), 536 "m_string": "hello", 537 "m_bool": true, 538 "m_nil": nil, 539 "m_smallstruct": newSmallStruct(), 540 }, 541 FSmallStruct: newSmallStruct(), 542 FInterface: interface{}("hello"), 543 FInterfaces: []interface{}{int64(64), "hello", true}, 544 } 545 } 546 547 func newSmallStruct() SmallStruct { 548 return SmallStruct{ 549 FInt: 7, 550 FSlice: []interface{}{64, true}, 551 FMap: map[string]interface{}{ 552 "m_float64": 64.64, 553 "m_string": "hello", 554 }, 555 FTinyStruct: TinyStruct{FBool: true}, 556 FString: "hello", 557 } 558 } 559 560 func TestEquivalenceRecords(t *testing.T) { 561 rec := makeRecords(t, 10000)[0] 562 563 bufStdj := &bytes.Buffer{} 564 err := stdjson.NewEncoder(bufStdj).Encode(rec) 565 require.NoError(t, err) 566 567 bufSegmentj := &bytes.Buffer{} 568 err = json.NewEncoder(bufSegmentj).Encode(rec) 569 require.NoError(t, err) 570 require.NotEqual(t, bufStdj.String(), bufSegmentj.String(), "segmentj encodes time.Duration to string; stdlib does not") 571 572 bufJ := &bytes.Buffer{} 573 err = jsoncolor.NewEncoder(bufJ).Encode(rec) 574 require.Equal(t, bufStdj.String(), bufJ.String()) 575 }