diff options
Diffstat (limited to '')
-rw-r--r-- | dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zapcore/field_test.go | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zapcore/field_test.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zapcore/field_test.go new file mode 100644 index 0000000..c436329 --- /dev/null +++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zapcore/field_test.go @@ -0,0 +1,318 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore_test + +import ( + "errors" + "fmt" + "math" + "net/url" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/zap" + . "go.uber.org/zap/zapcore" +) + +type users int + +func (u users) String() string { + return fmt.Sprintf("%d users", int(u)) +} + +func (u users) MarshalLogObject(enc ObjectEncoder) error { + if int(u) < 0 { + return errors.New("too few users") + } + enc.AddInt("users", int(u)) + return nil +} + +func (u users) MarshalLogArray(enc ArrayEncoder) error { + if int(u) < 0 { + return errors.New("too few users") + } + for i := 0; i < int(u); i++ { + enc.AppendString("user") + } + return nil +} + +type obj struct { + kind int +} + +func (o *obj) String() string { + if o == nil { + return "nil obj" + } + + if o.kind == 1 { + panic("panic with string") + } else if o.kind == 2 { + panic(errors.New("panic with error")) + } else if o.kind == 3 { + // panic with an arbitrary object that causes a panic itself + // when being converted to a string + panic((*url.URL)(nil)) + } + + return "obj" +} + +type errObj struct { + kind int + errMsg string +} + +func (eobj *errObj) Error() string { + if eobj.kind == 1 { + panic("panic in Error() method") + } else { + return eobj.errMsg + } +} + +func TestUnknownFieldType(t *testing.T) { + unknown := Field{Key: "k", String: "foo"} + assert.Equal(t, UnknownType, unknown.Type, "Expected zero value of FieldType to be UnknownType.") + assert.Panics(t, func() { + unknown.AddTo(NewMapObjectEncoder()) + }, "Expected using a field with unknown type to panic.") +} + +func TestFieldAddingError(t *testing.T) { + var empty interface{} + tests := []struct { + t FieldType + iface interface{} + want interface{} + err string + }{ + {t: ArrayMarshalerType, iface: users(-1), want: []interface{}{}, err: "too few users"}, + {t: ObjectMarshalerType, iface: users(-1), want: map[string]interface{}{}, err: "too few users"}, + {t: InlineMarshalerType, iface: users(-1), want: nil, err: "too few users"}, + {t: StringerType, iface: obj{}, want: empty, err: "PANIC=interface conversion: zapcore_test.obj is not fmt.Stringer: missing method String"}, + {t: StringerType, iface: &obj{1}, want: empty, err: "PANIC=panic with string"}, + {t: StringerType, iface: &obj{2}, want: empty, err: "PANIC=panic with error"}, + {t: StringerType, iface: &obj{3}, want: empty, err: "PANIC=<nil>"}, + {t: ErrorType, iface: &errObj{kind: 1}, want: empty, err: "PANIC=panic in Error() method"}, + } + for _, tt := range tests { + f := Field{Key: "k", Interface: tt.iface, Type: tt.t} + enc := NewMapObjectEncoder() + assert.NotPanics(t, func() { f.AddTo(enc) }, "Unexpected panic when adding fields returns an error.") + assert.Equal(t, tt.want, enc.Fields["k"], "On error, expected zero value in field.Key.") + assert.Equal(t, tt.err, enc.Fields["kError"], "Expected error message in log context.") + } +} + +func TestFields(t *testing.T) { + tests := []struct { + t FieldType + i int64 + s string + iface interface{} + want interface{} + }{ + {t: ArrayMarshalerType, iface: users(2), want: []interface{}{"user", "user"}}, + {t: ObjectMarshalerType, iface: users(2), want: map[string]interface{}{"users": 2}}, + {t: BoolType, i: 0, want: false}, + {t: ByteStringType, iface: []byte("foo"), want: "foo"}, + {t: Complex128Type, iface: 1 + 2i, want: 1 + 2i}, + {t: Complex64Type, iface: complex64(1 + 2i), want: complex64(1 + 2i)}, + {t: DurationType, i: 1000, want: time.Microsecond}, + {t: Float64Type, i: int64(math.Float64bits(3.14)), want: 3.14}, + {t: Float32Type, i: int64(math.Float32bits(3.14)), want: float32(3.14)}, + {t: Int64Type, i: 42, want: int64(42)}, + {t: Int32Type, i: 42, want: int32(42)}, + {t: Int16Type, i: 42, want: int16(42)}, + {t: Int8Type, i: 42, want: int8(42)}, + {t: StringType, s: "foo", want: "foo"}, + {t: TimeType, i: 1000, iface: time.UTC, want: time.Unix(0, 1000).In(time.UTC)}, + {t: TimeType, i: 1000, want: time.Unix(0, 1000)}, + {t: Uint64Type, i: 42, want: uint64(42)}, + {t: Uint32Type, i: 42, want: uint32(42)}, + {t: Uint16Type, i: 42, want: uint16(42)}, + {t: Uint8Type, i: 42, want: uint8(42)}, + {t: UintptrType, i: 42, want: uintptr(42)}, + {t: ReflectType, iface: users(2), want: users(2)}, + {t: NamespaceType, want: map[string]interface{}{}}, + {t: StringerType, iface: users(2), want: "2 users"}, + {t: StringerType, iface: &obj{}, want: "obj"}, + {t: StringerType, iface: (*obj)(nil), want: "nil obj"}, + {t: SkipType, want: interface{}(nil)}, + {t: StringerType, iface: (*url.URL)(nil), want: "<nil>"}, + {t: StringerType, iface: (*users)(nil), want: "<nil>"}, + {t: ErrorType, iface: (*errObj)(nil), want: "<nil>"}, + } + + for _, tt := range tests { + enc := NewMapObjectEncoder() + f := Field{Key: "k", Type: tt.t, Integer: tt.i, Interface: tt.iface, String: tt.s} + f.AddTo(enc) + assert.Equal(t, tt.want, enc.Fields["k"], "Unexpected output from field %+v.", f) + + delete(enc.Fields, "k") + assert.Equal(t, 0, len(enc.Fields), "Unexpected extra fields present.") + + assert.True(t, f.Equals(f), "Field does not equal itself") + } +} + +func TestInlineMarshaler(t *testing.T) { + enc := NewMapObjectEncoder() + + topLevelStr := Field{Key: "k", Type: StringType, String: "s"} + topLevelStr.AddTo(enc) + + inlineObj := Field{Key: "ignored", Type: InlineMarshalerType, Interface: users(10)} + inlineObj.AddTo(enc) + + nestedObj := Field{Key: "nested", Type: ObjectMarshalerType, Interface: users(11)} + nestedObj.AddTo(enc) + + assert.Equal(t, map[string]interface{}{ + "k": "s", + "users": 10, + "nested": map[string]interface{}{ + "users": 11, + }, + }, enc.Fields) +} + +func TestEquals(t *testing.T) { + // Values outside the UnixNano range were encoded incorrectly (#737, #803). + timeOutOfRangeHigh := time.Unix(0, math.MaxInt64).Add(time.Nanosecond) + timeOutOfRangeLow := time.Unix(0, math.MinInt64).Add(-time.Nanosecond) + timeOutOfRangeHighNano := time.Unix(0, timeOutOfRangeHigh.UnixNano()) + timeOutOfRangeLowNano := time.Unix(0, timeOutOfRangeLow.UnixNano()) + require.False(t, timeOutOfRangeHigh.Equal(timeOutOfRangeHighNano), "should be different as value is > UnixNano range") + require.False(t, timeOutOfRangeHigh.Equal(timeOutOfRangeHighNano), "should be different as value is < UnixNano range") + + tests := []struct { + a, b Field + want bool + }{ + { + a: zap.Int16("a", 1), + b: zap.Int32("a", 1), + want: false, + }, + { + a: zap.String("k", "a"), + b: zap.String("k", "a"), + want: true, + }, + { + a: zap.String("k", "a"), + b: zap.String("k2", "a"), + want: false, + }, + { + a: zap.String("k", "a"), + b: zap.String("k", "b"), + want: false, + }, + { + a: zap.Time("k", time.Unix(1000, 1000)), + b: zap.Time("k", time.Unix(1000, 1000)), + want: true, + }, + { + a: zap.Time("k", time.Unix(1000, 1000).In(time.UTC)), + b: zap.Time("k", time.Unix(1000, 1000).In(time.FixedZone("TEST", -8))), + want: false, + }, + { + a: zap.Time("k", timeOutOfRangeLow), + b: zap.Time("k", timeOutOfRangeLowNano), + want: false, + }, + { + a: zap.Time("k", timeOutOfRangeHigh), + b: zap.Time("k", timeOutOfRangeHighNano), + want: false, + }, + { + a: zap.Time("k", time.Unix(1000, 1000)), + b: zap.Time("k", time.Unix(1000, 2000)), + want: false, + }, + { + a: zap.Binary("k", []byte{1, 2}), + b: zap.Binary("k", []byte{1, 2}), + want: true, + }, + { + a: zap.Binary("k", []byte{1, 2}), + b: zap.Binary("k", []byte{1, 3}), + want: false, + }, + { + a: zap.ByteString("k", []byte("abc")), + b: zap.ByteString("k", []byte("abc")), + want: true, + }, + { + a: zap.ByteString("k", []byte("abc")), + b: zap.ByteString("k", []byte("abd")), + want: false, + }, + { + a: zap.Ints("k", []int{1, 2}), + b: zap.Ints("k", []int{1, 2}), + want: true, + }, + { + a: zap.Ints("k", []int{1, 2}), + b: zap.Ints("k", []int{1, 3}), + want: false, + }, + { + a: zap.Object("k", users(10)), + b: zap.Object("k", users(10)), + want: true, + }, + { + a: zap.Object("k", users(10)), + b: zap.Object("k", users(20)), + want: false, + }, + { + a: zap.Any("k", map[string]string{"a": "b"}), + b: zap.Any("k", map[string]string{"a": "b"}), + want: true, + }, + { + a: zap.Any("k", map[string]string{"a": "b"}), + b: zap.Any("k", map[string]string{"a": "d"}), + want: false, + }, + } + + for _, tt := range tests { + assert.Equal(t, tt.want, tt.a.Equals(tt.b), "a.Equals(b) a: %#v b: %#v", tt.a, tt.b) + assert.Equal(t, tt.want, tt.b.Equals(tt.a), "b.Equals(a) a: %#v b: %#v", tt.a, tt.b) + } +} |