1// Copyright (c) 2016 Uber Technologies, Inc.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19// THE SOFTWARE.
20
21package zap
22
23import (
24	"net"
25	"sync"
26	"testing"
27	"time"
28
29	"github.com/stretchr/testify/assert"
30	"go.uber.org/zap/zapcore"
31)
32
33type username string
34
35func (n username) MarshalLogObject(enc zapcore.ObjectEncoder) error {
36	enc.AddString("username", string(n))
37	return nil
38}
39
40func assertCanBeReused(t testing.TB, field Field) {
41	var wg sync.WaitGroup
42
43	for i := 0; i < 100; i++ {
44		enc := zapcore.NewMapObjectEncoder()
45
46		// Ensure using the field in multiple encoders in separate goroutines
47		// does not cause any races or panics.
48		wg.Add(1)
49		go func() {
50			defer wg.Done()
51			assert.NotPanics(t, func() {
52				field.AddTo(enc)
53			}, "Reusing a field should not cause issues")
54		}()
55	}
56
57	wg.Wait()
58}
59
60func TestFieldConstructors(t *testing.T) {
61	// Interface types.
62	addr := net.ParseIP("1.2.3.4")
63	name := username("phil")
64	ints := []int{5, 6}
65
66	// Helpful values for use in constructing pointers to primitives below.
67	var (
68		boolVal       bool          = true
69		complex128Val complex128    = complex(0, 0)
70		complex64Val  complex64     = complex(0, 0)
71		durationVal   time.Duration = time.Second
72		float64Val    float64       = 1.0
73		float32Val    float32       = 1.0
74		intVal        int           = 1
75		int64Val      int64         = 1
76		int32Val      int32         = 1
77		int16Val      int16         = 1
78		int8Val       int8          = 1
79		stringVal     string        = "hello"
80		timeVal       time.Time     = time.Unix(100000, 0)
81		uintVal       uint          = 1
82		uint64Val     uint64        = 1
83		uint32Val     uint32        = 1
84		uint16Val     uint16        = 1
85		uint8Val      uint8         = 1
86		uintptrVal    uintptr       = 1
87	)
88
89	tests := []struct {
90		name   string
91		field  Field
92		expect Field
93	}{
94		{"Skip", Field{Type: zapcore.SkipType}, Skip()},
95		{"Binary", Field{Key: "k", Type: zapcore.BinaryType, Interface: []byte("ab12")}, Binary("k", []byte("ab12"))},
96		{"Bool", Field{Key: "k", Type: zapcore.BoolType, Integer: 1}, Bool("k", true)},
97		{"Bool", Field{Key: "k", Type: zapcore.BoolType, Integer: 1}, Bool("k", true)},
98		{"ByteString", Field{Key: "k", Type: zapcore.ByteStringType, Interface: []byte("ab12")}, ByteString("k", []byte("ab12"))},
99		{"Complex128", Field{Key: "k", Type: zapcore.Complex128Type, Interface: 1 + 2i}, Complex128("k", 1+2i)},
100		{"Complex64", Field{Key: "k", Type: zapcore.Complex64Type, Interface: complex64(1 + 2i)}, Complex64("k", 1+2i)},
101		{"Duration", Field{Key: "k", Type: zapcore.DurationType, Integer: 1}, Duration("k", 1)},
102		{"Int", Field{Key: "k", Type: zapcore.Int64Type, Integer: 1}, Int("k", 1)},
103		{"Int64", Field{Key: "k", Type: zapcore.Int64Type, Integer: 1}, Int64("k", 1)},
104		{"Int32", Field{Key: "k", Type: zapcore.Int32Type, Integer: 1}, Int32("k", 1)},
105		{"Int16", Field{Key: "k", Type: zapcore.Int16Type, Integer: 1}, Int16("k", 1)},
106		{"Int8", Field{Key: "k", Type: zapcore.Int8Type, Integer: 1}, Int8("k", 1)},
107		{"String", Field{Key: "k", Type: zapcore.StringType, String: "foo"}, String("k", "foo")},
108		{"Time", Field{Key: "k", Type: zapcore.TimeType, Integer: 0, Interface: time.UTC}, Time("k", time.Unix(0, 0).In(time.UTC))},
109		{"Time", Field{Key: "k", Type: zapcore.TimeType, Integer: 1000, Interface: time.UTC}, Time("k", time.Unix(0, 1000).In(time.UTC))},
110		{"Uint", Field{Key: "k", Type: zapcore.Uint64Type, Integer: 1}, Uint("k", 1)},
111		{"Uint64", Field{Key: "k", Type: zapcore.Uint64Type, Integer: 1}, Uint64("k", 1)},
112		{"Uint32", Field{Key: "k", Type: zapcore.Uint32Type, Integer: 1}, Uint32("k", 1)},
113		{"Uint16", Field{Key: "k", Type: zapcore.Uint16Type, Integer: 1}, Uint16("k", 1)},
114		{"Uint8", Field{Key: "k", Type: zapcore.Uint8Type, Integer: 1}, Uint8("k", 1)},
115		{"Uintptr", Field{Key: "k", Type: zapcore.UintptrType, Integer: 10}, Uintptr("k", 0xa)},
116		{"Reflect", Field{Key: "k", Type: zapcore.ReflectType, Interface: ints}, Reflect("k", ints)},
117		{"Reflect", Field{Key: "k", Type: zapcore.ReflectType}, Reflect("k", nil)},
118		{"Stringer", Field{Key: "k", Type: zapcore.StringerType, Interface: addr}, Stringer("k", addr)},
119		{"Object", Field{Key: "k", Type: zapcore.ObjectMarshalerType, Interface: name}, Object("k", name)},
120		{"Any:ObjectMarshaler", Any("k", name), Object("k", name)},
121		{"Any:ArrayMarshaler", Any("k", bools([]bool{true})), Array("k", bools([]bool{true}))},
122		{"Any:Stringer", Any("k", addr), Stringer("k", addr)},
123		{"Any:Bool", Any("k", true), Bool("k", true)},
124		{"Any:Bools", Any("k", []bool{true}), Bools("k", []bool{true})},
125		{"Any:Byte", Any("k", byte(1)), Uint8("k", 1)},
126		{"Any:Bytes", Any("k", []byte{1}), Binary("k", []byte{1})},
127		{"Any:Complex128", Any("k", 1+2i), Complex128("k", 1+2i)},
128		{"Any:Complex128s", Any("k", []complex128{1 + 2i}), Complex128s("k", []complex128{1 + 2i})},
129		{"Any:Complex64", Any("k", complex64(1+2i)), Complex64("k", 1+2i)},
130		{"Any:Complex64s", Any("k", []complex64{1 + 2i}), Complex64s("k", []complex64{1 + 2i})},
131		{"Any:Float64", Any("k", 3.14), Float64("k", 3.14)},
132		{"Any:Float64s", Any("k", []float64{3.14}), Float64s("k", []float64{3.14})},
133		{"Any:Float32", Any("k", float32(3.14)), Float32("k", 3.14)},
134		{"Any:Float32s", Any("k", []float32{3.14}), Float32s("k", []float32{3.14})},
135		{"Any:Int", Any("k", 1), Int("k", 1)},
136		{"Any:Ints", Any("k", []int{1}), Ints("k", []int{1})},
137		{"Any:Int64", Any("k", int64(1)), Int64("k", 1)},
138		{"Any:Int64s", Any("k", []int64{1}), Int64s("k", []int64{1})},
139		{"Any:Int32", Any("k", int32(1)), Int32("k", 1)},
140		{"Any:Int32s", Any("k", []int32{1}), Int32s("k", []int32{1})},
141		{"Any:Int16", Any("k", int16(1)), Int16("k", 1)},
142		{"Any:Int16s", Any("k", []int16{1}), Int16s("k", []int16{1})},
143		{"Any:Int8", Any("k", int8(1)), Int8("k", 1)},
144		{"Any:Int8s", Any("k", []int8{1}), Int8s("k", []int8{1})},
145		{"Any:Rune", Any("k", rune(1)), Int32("k", 1)},
146		{"Any:Runes", Any("k", []rune{1}), Int32s("k", []int32{1})},
147		{"Any:String", Any("k", "v"), String("k", "v")},
148		{"Any:Strings", Any("k", []string{"v"}), Strings("k", []string{"v"})},
149		{"Any:Uint", Any("k", uint(1)), Uint("k", 1)},
150		{"Any:Uints", Any("k", []uint{1}), Uints("k", []uint{1})},
151		{"Any:Uint64", Any("k", uint64(1)), Uint64("k", 1)},
152		{"Any:Uint64s", Any("k", []uint64{1}), Uint64s("k", []uint64{1})},
153		{"Any:Uint32", Any("k", uint32(1)), Uint32("k", 1)},
154		{"Any:Uint32s", Any("k", []uint32{1}), Uint32s("k", []uint32{1})},
155		{"Any:Uint16", Any("k", uint16(1)), Uint16("k", 1)},
156		{"Any:Uint16s", Any("k", []uint16{1}), Uint16s("k", []uint16{1})},
157		{"Any:Uint8", Any("k", uint8(1)), Uint8("k", 1)},
158		{"Any:Uint8s", Any("k", []uint8{1}), Binary("k", []uint8{1})},
159		{"Any:Uintptr", Any("k", uintptr(1)), Uintptr("k", 1)},
160		{"Any:Uintptrs", Any("k", []uintptr{1}), Uintptrs("k", []uintptr{1})},
161		{"Any:Time", Any("k", time.Unix(0, 0)), Time("k", time.Unix(0, 0))},
162		{"Any:Times", Any("k", []time.Time{time.Unix(0, 0)}), Times("k", []time.Time{time.Unix(0, 0)})},
163		{"Any:Duration", Any("k", time.Second), Duration("k", time.Second)},
164		{"Any:Durations", Any("k", []time.Duration{time.Second}), Durations("k", []time.Duration{time.Second})},
165		{"Any:Fallback", Any("k", struct{}{}), Reflect("k", struct{}{})},
166		{"Ptr:Bool", Boolp("k", nil), nilField("k")},
167		{"Ptr:Bool", Boolp("k", &boolVal), Bool("k", boolVal)},
168		{"Any:PtrBool", Any("k", (*bool)(nil)), nilField("k")},
169		{"Any:PtrBool", Any("k", &boolVal), Bool("k", boolVal)},
170		{"Ptr:Complex128", Complex128p("k", nil), nilField("k")},
171		{"Ptr:Complex128", Complex128p("k", &complex128Val), Complex128("k", complex128Val)},
172		{"Any:PtrComplex128", Any("k", (*complex128)(nil)), nilField("k")},
173		{"Any:PtrComplex128", Any("k", &complex128Val), Complex128("k", complex128Val)},
174		{"Ptr:Complex64", Complex64p("k", nil), nilField("k")},
175		{"Ptr:Complex64", Complex64p("k", &complex64Val), Complex64("k", complex64Val)},
176		{"Any:PtrComplex64", Any("k", (*complex64)(nil)), nilField("k")},
177		{"Any:PtrComplex64", Any("k", &complex64Val), Complex64("k", complex64Val)},
178		{"Ptr:Duration", Durationp("k", nil), nilField("k")},
179		{"Ptr:Duration", Durationp("k", &durationVal), Duration("k", durationVal)},
180		{"Any:PtrDuration", Any("k", (*time.Duration)(nil)), nilField("k")},
181		{"Any:PtrDuration", Any("k", &durationVal), Duration("k", durationVal)},
182		{"Ptr:Float64", Float64p("k", nil), nilField("k")},
183		{"Ptr:Float64", Float64p("k", &float64Val), Float64("k", float64Val)},
184		{"Any:PtrFloat64", Any("k", (*float64)(nil)), nilField("k")},
185		{"Any:PtrFloat64", Any("k", &float64Val), Float64("k", float64Val)},
186		{"Ptr:Float32", Float32p("k", nil), nilField("k")},
187		{"Ptr:Float32", Float32p("k", &float32Val), Float32("k", float32Val)},
188		{"Any:PtrFloat32", Any("k", (*float32)(nil)), nilField("k")},
189		{"Any:PtrFloat32", Any("k", &float32Val), Float32("k", float32Val)},
190		{"Ptr:Int", Intp("k", nil), nilField("k")},
191		{"Ptr:Int", Intp("k", &intVal), Int("k", intVal)},
192		{"Any:PtrInt", Any("k", (*int)(nil)), nilField("k")},
193		{"Any:PtrInt", Any("k", &intVal), Int("k", intVal)},
194		{"Ptr:Int64", Int64p("k", nil), nilField("k")},
195		{"Ptr:Int64", Int64p("k", &int64Val), Int64("k", int64Val)},
196		{"Any:PtrInt64", Any("k", (*int64)(nil)), nilField("k")},
197		{"Any:PtrInt64", Any("k", &int64Val), Int64("k", int64Val)},
198		{"Ptr:Int32", Int32p("k", nil), nilField("k")},
199		{"Ptr:Int32", Int32p("k", &int32Val), Int32("k", int32Val)},
200		{"Any:PtrInt32", Any("k", (*int32)(nil)), nilField("k")},
201		{"Any:PtrInt32", Any("k", &int32Val), Int32("k", int32Val)},
202		{"Ptr:Int16", Int16p("k", nil), nilField("k")},
203		{"Ptr:Int16", Int16p("k", &int16Val), Int16("k", int16Val)},
204		{"Any:PtrInt16", Any("k", (*int16)(nil)), nilField("k")},
205		{"Any:PtrInt16", Any("k", &int16Val), Int16("k", int16Val)},
206		{"Ptr:Int8", Int8p("k", nil), nilField("k")},
207		{"Ptr:Int8", Int8p("k", &int8Val), Int8("k", int8Val)},
208		{"Any:PtrInt8", Any("k", (*int8)(nil)), nilField("k")},
209		{"Any:PtrInt8", Any("k", &int8Val), Int8("k", int8Val)},
210		{"Ptr:String", Stringp("k", nil), nilField("k")},
211		{"Ptr:String", Stringp("k", &stringVal), String("k", stringVal)},
212		{"Any:PtrString", Any("k", (*string)(nil)), nilField("k")},
213		{"Any:PtrString", Any("k", &stringVal), String("k", stringVal)},
214		{"Ptr:Time", Timep("k", nil), nilField("k")},
215		{"Ptr:Time", Timep("k", &timeVal), Time("k", timeVal)},
216		{"Any:PtrTime", Any("k", (*time.Time)(nil)), nilField("k")},
217		{"Any:PtrTime", Any("k", &timeVal), Time("k", timeVal)},
218		{"Ptr:Uint", Uintp("k", nil), nilField("k")},
219		{"Ptr:Uint", Uintp("k", &uintVal), Uint("k", uintVal)},
220		{"Any:PtrUint", Any("k", (*uint)(nil)), nilField("k")},
221		{"Any:PtrUint", Any("k", &uintVal), Uint("k", uintVal)},
222		{"Ptr:Uint64", Uint64p("k", nil), nilField("k")},
223		{"Ptr:Uint64", Uint64p("k", &uint64Val), Uint64("k", uint64Val)},
224		{"Any:PtrUint64", Any("k", (*uint64)(nil)), nilField("k")},
225		{"Any:PtrUint64", Any("k", &uint64Val), Uint64("k", uint64Val)},
226		{"Ptr:Uint32", Uint32p("k", nil), nilField("k")},
227		{"Ptr:Uint32", Uint32p("k", &uint32Val), Uint32("k", uint32Val)},
228		{"Any:PtrUint32", Any("k", (*uint32)(nil)), nilField("k")},
229		{"Any:PtrUint32", Any("k", &uint32Val), Uint32("k", uint32Val)},
230		{"Ptr:Uint16", Uint16p("k", nil), nilField("k")},
231		{"Ptr:Uint16", Uint16p("k", &uint16Val), Uint16("k", uint16Val)},
232		{"Any:PtrUint16", Any("k", (*uint16)(nil)), nilField("k")},
233		{"Any:PtrUint16", Any("k", &uint16Val), Uint16("k", uint16Val)},
234		{"Ptr:Uint8", Uint8p("k", nil), nilField("k")},
235		{"Ptr:Uint8", Uint8p("k", &uint8Val), Uint8("k", uint8Val)},
236		{"Any:PtrUint8", Any("k", (*uint8)(nil)), nilField("k")},
237		{"Any:PtrUint8", Any("k", &uint8Val), Uint8("k", uint8Val)},
238		{"Ptr:Uintptr", Uintptrp("k", nil), nilField("k")},
239		{"Ptr:Uintptr", Uintptrp("k", &uintptrVal), Uintptr("k", uintptrVal)},
240		{"Any:PtrUintptr", Any("k", (*uintptr)(nil)), nilField("k")},
241		{"Any:PtrUintptr", Any("k", &uintptrVal), Uintptr("k", uintptrVal)},
242		{"Namespace", Namespace("k"), Field{Key: "k", Type: zapcore.NamespaceType}},
243	}
244
245	for _, tt := range tests {
246		if !assert.Equal(t, tt.expect, tt.field, "Unexpected output from convenience field constructor %s.", tt.name) {
247			t.Logf("type expected: %T\nGot: %T", tt.expect.Interface, tt.field.Interface)
248		}
249		assertCanBeReused(t, tt.field)
250	}
251}
252
253func TestStackField(t *testing.T) {
254	f := Stack("stacktrace")
255	assert.Equal(t, "stacktrace", f.Key, "Unexpected field key.")
256	assert.Equal(t, zapcore.StringType, f.Type, "Unexpected field type.")
257	assert.Equal(t, takeStacktrace(), f.String, "Unexpected stack trace")
258	assertCanBeReused(t, f)
259}
260