github.com/ssgreg/logf@v1.4.1/field_test.go (about) 1 package logf 2 3 import ( 4 "errors" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/assert" 9 ) 10 11 func TestField(t *testing.T) { 12 cases := []struct { 13 name string 14 fn func(interface{}) Field 15 original interface{} 16 expected interface{} 17 }{ 18 { 19 name: "Bool", 20 fn: func(v interface{}) Field { return Bool("k", v.(bool)) }, 21 original: true, 22 expected: true, 23 }, 24 { 25 name: "Int", 26 fn: func(v interface{}) Field { return Int("k", v.(int)) }, 27 original: 42, 28 expected: int64(42), 29 }, 30 { 31 name: "Int64", 32 fn: func(v interface{}) Field { return Int64("k", v.(int64)) }, 33 original: int64(42), 34 expected: int64(42), 35 }, 36 { 37 name: "Int32", 38 fn: func(v interface{}) Field { return Int32("k", v.(int32)) }, 39 original: int32(42), 40 expected: int32(42), 41 }, 42 { 43 name: "Int16", 44 fn: func(v interface{}) Field { return Int16("k", v.(int16)) }, 45 original: int16(42), 46 expected: int16(42), 47 }, 48 { 49 name: "Int8", 50 fn: func(v interface{}) Field { return Int8("k", v.(int8)) }, 51 original: int8(42), 52 expected: int8(42), 53 }, 54 { 55 name: "Uint", 56 fn: func(v interface{}) Field { return Uint("k", v.(uint)) }, 57 original: uint(42), 58 expected: uint64(42), 59 }, 60 { 61 name: "Uint64", 62 fn: func(v interface{}) Field { return Uint64("k", v.(uint64)) }, 63 original: uint64(42), 64 expected: uint64(42), 65 }, 66 { 67 name: "Uint32", 68 fn: func(v interface{}) Field { return Uint32("k", v.(uint32)) }, 69 original: uint32(42), 70 expected: uint32(42), 71 }, 72 { 73 name: "Uint16", 74 fn: func(v interface{}) Field { return Uint16("k", v.(uint16)) }, 75 original: uint16(42), 76 expected: uint16(42), 77 }, 78 { 79 name: "Uint8", 80 fn: func(v interface{}) Field { return Uint8("k", v.(uint8)) }, 81 original: uint8(42), 82 expected: uint8(42), 83 }, 84 { 85 name: "Float64", 86 fn: func(v interface{}) Field { return Float64("k", v.(float64)) }, 87 original: float64(42), 88 expected: float64(42), 89 }, 90 { 91 name: "Float32", 92 fn: func(v interface{}) Field { return Float32("k", v.(float32)) }, 93 original: float32(42), 94 expected: float32(42), 95 }, 96 { 97 name: "Duration", 98 fn: func(v interface{}) Field { return Duration("k", v.(time.Duration)) }, 99 original: time.Second, 100 expected: time.Second, 101 }, 102 { 103 name: "String", 104 fn: func(v interface{}) Field { return String("k", v.(string)) }, 105 original: "42", 106 expected: "42", 107 }, 108 { 109 name: "ConstBytes", 110 fn: func(v interface{}) Field { return ConstBytes("k", v.([]byte)) }, 111 original: []byte{42}, 112 expected: []byte{42}, 113 }, 114 { 115 name: "ConstBools", 116 fn: func(v interface{}) Field { return ConstBools("k", v.([]bool)) }, 117 original: []bool{true}, 118 expected: []bool{true}, 119 }, 120 { 121 name: "ConstInts", 122 fn: func(v interface{}) Field { return ConstInts("k", v.([]int)) }, 123 original: []int{42}, 124 expected: []int64{42}, 125 }, 126 { 127 name: "ConstInts64", 128 fn: func(v interface{}) Field { return ConstInts64("k", v.([]int64)) }, 129 original: []int64{42}, 130 expected: []int64{42}, 131 }, 132 { 133 name: "ConstInts32", 134 fn: func(v interface{}) Field { return ConstInts32("k", v.([]int32)) }, 135 original: []int32{42}, 136 expected: []int32{42}, 137 }, 138 { 139 name: "ConstInts16", 140 fn: func(v interface{}) Field { return ConstInts16("k", v.([]int16)) }, 141 original: []int16{42}, 142 expected: []int16{42}, 143 }, 144 { 145 name: "ConstInts8", 146 fn: func(v interface{}) Field { return ConstInts8("k", v.([]int8)) }, 147 original: []int8{42}, 148 expected: []int8{42}, 149 }, 150 { 151 name: "ConstUints", 152 fn: func(v interface{}) Field { return ConstUints("k", v.([]uint)) }, 153 original: []uint{42}, 154 expected: []uint64{42}, 155 }, 156 { 157 name: "ConstUints64", 158 fn: func(v interface{}) Field { return ConstUints64("k", v.([]uint64)) }, 159 original: []uint64{42}, 160 expected: []uint64{42}, 161 }, 162 { 163 name: "ConstUints32", 164 fn: func(v interface{}) Field { return ConstUints32("k", v.([]uint32)) }, 165 original: []uint32{42}, 166 expected: []uint32{42}, 167 }, 168 { 169 name: "ConstUints16", 170 fn: func(v interface{}) Field { return ConstUints16("k", v.([]uint16)) }, 171 original: []uint16{42}, 172 expected: []uint16{42}, 173 }, 174 { 175 name: "ConstUints8", 176 fn: func(v interface{}) Field { return ConstUints8("k", v.([]uint8)) }, 177 original: []uint8{42}, 178 expected: []uint8{42}, 179 }, 180 { 181 name: "ConstFloats64", 182 fn: func(v interface{}) Field { return ConstFloats64("k", v.([]float64)) }, 183 original: []float64{42}, 184 expected: []float64{42}, 185 }, 186 { 187 name: "ConstFloats32", 188 fn: func(v interface{}) Field { return ConstFloats32("k", v.([]float32)) }, 189 original: []float32{42}, 190 expected: []float32{42}, 191 }, 192 { 193 name: "ConstDurations", 194 fn: func(v interface{}) Field { return ConstDurations("k", v.([]time.Duration)) }, 195 original: []time.Duration{time.Second}, 196 expected: []time.Duration{time.Second}, 197 }, 198 } 199 200 for _, c := range cases { 201 t.Run(c.name, func(t *testing.T) { 202 f := c.fn(c.original) 203 e := newTestFieldEncoder() 204 f.Accept(e) 205 assert.Equal(t, c.expected, e.result["k"]) 206 }) 207 t.Run(c.name+"->Any", func(t *testing.T) { 208 f := Any("k", c.original) 209 210 // Need to snapshot fields because Any could return raw byte 211 // types that need to be copied. 212 snapshotField(&f) 213 e := newTestFieldEncoder() 214 f.Accept(e) 215 216 assert.Equal(t, c.expected, e.result["k"]) 217 }) 218 } 219 } 220 221 func TestFieldStrings(t *testing.T) { 222 check := func(t *testing.T, f *Field) { 223 e := newTestFieldEncoder() 224 f.Accept(e) 225 226 ae := e.result["k"].(ArrayEncoder) 227 te := testTypeEncoder{} 228 ae.EncodeLogfArray(&te) 229 230 assert.Equal(t, "42", te.result) 231 } 232 233 t.Run("Time", func(t *testing.T) { 234 f := Strings("k", []string{"42"}) 235 check(t, &f) 236 }) 237 t.Run("Time->Any", func(t *testing.T) { 238 f := Any("k", []string{"42"}) 239 check(t, &f) 240 }) 241 } 242 243 func TestFieldArray(t *testing.T) { 244 golden := &testArrayEncoder{} 245 246 check := func(t *testing.T, f *Field) { 247 e := newTestFieldEncoder() 248 f.Accept(e) 249 assert.Equal(t, golden, e.result["k"]) 250 } 251 252 t.Run("Array", func(t *testing.T) { 253 f := Array("k", &testArrayEncoder{}) 254 check(t, &f) 255 }) 256 t.Run("Array->Any", func(t *testing.T) { 257 f := Any("k", &testArrayEncoder{}) 258 check(t, &f) 259 }) 260 } 261 262 func TestFieldNilArray(t *testing.T) { 263 e := newTestFieldEncoder() 264 f := Array("k", nil) 265 f.Accept(e) 266 assert.Equal(t, "nil", e.result["k"]) 267 } 268 269 func TestFieldObject(t *testing.T) { 270 golden := &testObjectEncoder{} 271 272 check := func(t *testing.T, f *Field) { 273 e := newTestFieldEncoder() 274 f.Accept(e) 275 assert.Equal(t, golden, e.result["k"]) 276 } 277 278 t.Run("Array", func(t *testing.T) { 279 f := Object("k", &testObjectEncoder{}) 280 check(t, &f) 281 }) 282 t.Run("Array->Any", func(t *testing.T) { 283 f := Any("k", &testObjectEncoder{}) 284 check(t, &f) 285 }) 286 } 287 288 func TestFieldNilObject(t *testing.T) { 289 e := newTestFieldEncoder() 290 f := Object("k", nil) 291 f.Accept(e) 292 assert.Equal(t, "nil", e.result["k"]) 293 } 294 295 func TestFieldTime(t *testing.T) { 296 golden := time.Now() 297 298 check := func(t *testing.T, f *Field) { 299 e := newTestFieldEncoder() 300 f.Accept(e) 301 302 assert.Equal(t, golden.Format(time.RFC3339Nano), (e.result["k"].(time.Time)).Format(time.RFC3339Nano)) 303 } 304 305 t.Run("Time", func(t *testing.T) { 306 f := Time("k", golden) 307 check(t, &f) 308 }) 309 t.Run("Any->Time", func(t *testing.T) { 310 f := Any("k", golden) 311 check(t, &f) 312 }) 313 } 314 315 func TestFieldTimeWithoutLocation(t *testing.T) { 316 golden := time.Unix(320836234, 0) 317 318 e := newTestFieldEncoder() 319 f := Field{Key: "k", Type: FieldTypeTime, Int: golden.UnixNano()} 320 f.Accept(e) 321 322 assert.Equal(t, golden.Format(time.RFC3339Nano), (e.result["k"].(time.Time)).Format(time.RFC3339Nano)) 323 } 324 325 func TestFieldStringer(t *testing.T) { 326 golden := "before" 327 str := &testStringer{golden} 328 329 e := newTestFieldEncoder() 330 f := Stringer("k", str) 331 332 // Change result returning by str. Stinger must call String() during a 333 // call of Stringer(). 334 str.result = "after" 335 336 f.Accept(e) 337 assert.Equal(t, golden, e.result["k"]) 338 } 339 340 func TestFieldNilStringer(t *testing.T) { 341 e := newTestFieldEncoder() 342 f := Stringer("k", nil) 343 344 f.Accept(e) 345 assert.Equal(t, "nil", e.result["k"]) 346 } 347 348 func TestFieldConstStringer(t *testing.T) { 349 golden := "before" 350 str := &testStringer{golden} 351 352 e := newTestFieldEncoder() 353 f := ConstStringer("k", str) 354 355 f.Accept(e) 356 assert.Equal(t, golden, e.result["k"]) 357 } 358 359 func TestFieldNilConstStringer(t *testing.T) { 360 e := newTestFieldEncoder() 361 f := ConstStringer("k", nil) 362 363 f.Accept(e) 364 assert.Equal(t, "nil", e.result["k"]) 365 } 366 func TestFieldConstFormatter(t *testing.T) { 367 golden := "42" 368 e := newTestFieldEncoder() 369 f := ConstFormatter("k", "%d", 42) 370 371 f.Accept(e) 372 assert.Equal(t, golden, e.result["k"]) 373 } 374 375 func TestFieldConstFormatterV(t *testing.T) { 376 type testFormatterV struct { 377 str string 378 } 379 380 e := newTestFieldEncoder() 381 f := ConstFormatterV("k", testFormatterV{"42"}) 382 383 f.Accept(e) 384 assert.Equal(t, `logf.testFormatterV{str:"42"}`, e.result["k"]) 385 } 386 387 func TestFieldFormatter(t *testing.T) { 388 type testFormatterV struct { 389 str string 390 } 391 testing := testFormatterV{"42"} 392 393 e := newTestFieldEncoder() 394 f := Formatter("k", "%s", &testing) 395 396 // Change testing value to check that ConstFormatter formats string 397 // during it's call. 398 testing.str = "66" 399 400 f.Accept(e) 401 assert.Equal(t, "&{42}", e.result["k"]) 402 } 403 404 func TestFieldFormatterV(t *testing.T) { 405 type testFormatterV struct { 406 str string 407 } 408 testing := testFormatterV{"42"} 409 410 e := newTestFieldEncoder() 411 f := FormatterV("k", &testing) 412 413 // Change testing value to check that ConstFormatter formats string 414 // during it's call. 415 testing.str = "66" 416 417 f.Accept(e) 418 assert.Equal(t, `&logf.testFormatterV{str:"42"}`, e.result["k"]) 419 } 420 421 func TestFieldNamedError(t *testing.T) { 422 golden := errors.New("named error") 423 424 check := func(t *testing.T, f *Field) { 425 e := newTestFieldEncoder() 426 f.Accept(e) 427 assert.Equal(t, golden, e.result["k"]) 428 } 429 430 t.Run("NamedError", func(t *testing.T) { 431 f := NamedError("k", golden) 432 check(t, &f) 433 }) 434 t.Run("NamedError->Any", func(t *testing.T) { 435 f := Any("k", golden) 436 check(t, &f) 437 }) 438 } 439 440 func TestFieldError(t *testing.T) { 441 golden := errors.New("common error") 442 443 e := newTestFieldEncoder() 444 f := Error(golden) 445 446 f.Accept(e) 447 assert.Equal(t, golden, e.result["error"]) 448 } 449 450 func TestFieldNilError(t *testing.T) { 451 f := Error(nil) 452 e := newTestFieldEncoder() 453 f.Accept(e) 454 assert.Equal(t, nil, e.result["error"]) 455 } 456 457 func TestFieldAnyWithCustomType(t *testing.T) { 458 type customType struct{} 459 customTypeValue := customType{} 460 461 f := Any("k", &customTypeValue) 462 e := newTestFieldEncoder() 463 f.Accept(e) 464 assert.Equal(t, &customTypeValue, e.result["k"]) 465 } 466 467 func TestFieldAnyReflect(t *testing.T) { 468 type customStringType string 469 type customBoolType bool 470 type customIntType int 471 type customInt64Type int64 472 type customInt32Type int32 473 type customInt16Type int16 474 type customInt8Type int8 475 type customUintType uint 476 type customUint64Type uint64 477 type customUint32Type uint32 478 type customUint16Type uint16 479 type customUint8Type uint8 480 type customFloat64Type float64 481 type customFloat32Type float32 482 483 cases := []struct { 484 name string 485 original interface{} 486 expected interface{} 487 }{ 488 { 489 name: "String", 490 original: customStringType("42"), 491 expected: "42", 492 }, 493 { 494 name: "Bool", 495 original: customBoolType(true), 496 expected: true, 497 }, 498 { 499 name: "Int", 500 original: customIntType(42), 501 expected: int64(42), 502 }, 503 { 504 name: "Int64", 505 original: customInt64Type(42), 506 expected: int64(42), 507 }, 508 { 509 name: "Int32", 510 original: customInt32Type(42), 511 expected: int64(42), 512 }, 513 { 514 name: "Int16", 515 original: customInt16Type(42), 516 expected: int64(42), 517 }, 518 { 519 name: "Int8", 520 original: customInt8Type(42), 521 expected: int64(42), 522 }, 523 { 524 name: "Uint", 525 original: customUintType(42), 526 expected: uint64(42), 527 }, 528 { 529 name: "Uint64", 530 original: customUint64Type(42), 531 expected: uint64(42), 532 }, 533 { 534 name: "Uint32", 535 original: customUint32Type(42), 536 expected: uint64(42), 537 }, 538 { 539 name: "Uint16", 540 original: customUint16Type(42), 541 expected: uint64(42), 542 }, 543 { 544 name: "Uint8", 545 original: customUint8Type(42), 546 expected: uint64(42), 547 }, 548 { 549 name: "Float64", 550 original: customFloat64Type(42), 551 expected: float64(42), 552 }, 553 { 554 name: "Float32", 555 original: customFloat32Type(42), 556 expected: float64(42), 557 }, 558 { 559 name: "nil", 560 original: nil, 561 expected: nil, 562 }, 563 } 564 565 for _, c := range cases { 566 t.Run(c.name, func(t *testing.T) { 567 f := Any("k", c.original) 568 e := newTestFieldEncoder() 569 f.Accept(e) 570 assert.Equal(t, c.expected, e.result["k"]) 571 }) 572 } 573 574 }