...

Source file src/go.uber.org/zap/zapcore/memory_encoder_test.go

Documentation: go.uber.org/zap/zapcore

     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  
    21  package zapcore
    22  
    23  import (
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  func TestMapObjectEncoderAdd(t *testing.T) {
    32  	// Expected output of a turducken.
    33  	wantTurducken := map[string]interface{}{
    34  		"ducks": []interface{}{
    35  			map[string]interface{}{"in": "chicken"},
    36  			map[string]interface{}{"in": "chicken"},
    37  		},
    38  	}
    39  
    40  	tests := []struct {
    41  		desc     string
    42  		f        func(ObjectEncoder)
    43  		expected interface{}
    44  	}{
    45  		{
    46  			desc: "AddObject",
    47  			f: func(e ObjectEncoder) {
    48  				assert.NoError(t, e.AddObject("k", loggable{true}), "Expected AddObject to succeed.")
    49  			},
    50  			expected: map[string]interface{}{"loggable": "yes"},
    51  		},
    52  		{
    53  			desc: "AddObject (nested)",
    54  			f: func(e ObjectEncoder) {
    55  				assert.NoError(t, e.AddObject("k", turducken{}), "Expected AddObject to succeed.")
    56  			},
    57  			expected: wantTurducken,
    58  		},
    59  		{
    60  			desc: "AddArray",
    61  			f: func(e ObjectEncoder) {
    62  				assert.NoError(t, e.AddArray("k", ArrayMarshalerFunc(func(arr ArrayEncoder) error {
    63  					arr.AppendBool(true)
    64  					arr.AppendBool(false)
    65  					arr.AppendBool(true)
    66  					return nil
    67  				})), "Expected AddArray to succeed.")
    68  			},
    69  			expected: []interface{}{true, false, true},
    70  		},
    71  		{
    72  			desc: "AddArray (nested)",
    73  			f: func(e ObjectEncoder) {
    74  				assert.NoError(t, e.AddArray("k", turduckens(2)), "Expected AddArray to succeed.")
    75  			},
    76  			expected: []interface{}{wantTurducken, wantTurducken},
    77  		},
    78  		{
    79  			desc: "AddArray (empty)",
    80  			f: func(e ObjectEncoder) {
    81  				assert.NoError(t, e.AddArray("k", turduckens(0)), "Expected AddArray to succeed.")
    82  			},
    83  			expected: []interface{}{},
    84  		},
    85  		{
    86  			desc:     "AddBinary",
    87  			f:        func(e ObjectEncoder) { e.AddBinary("k", []byte("foo")) },
    88  			expected: []byte("foo"),
    89  		},
    90  		{
    91  			desc:     "AddByteString",
    92  			f:        func(e ObjectEncoder) { e.AddByteString("k", []byte("foo")) },
    93  			expected: "foo",
    94  		},
    95  		{
    96  			desc:     "AddBool",
    97  			f:        func(e ObjectEncoder) { e.AddBool("k", true) },
    98  			expected: true,
    99  		},
   100  		{
   101  			desc:     "AddComplex128",
   102  			f:        func(e ObjectEncoder) { e.AddComplex128("k", 1+2i) },
   103  			expected: 1 + 2i,
   104  		},
   105  		{
   106  			desc:     "AddComplex64",
   107  			f:        func(e ObjectEncoder) { e.AddComplex64("k", 1+2i) },
   108  			expected: complex64(1 + 2i),
   109  		},
   110  		{
   111  			desc:     "AddDuration",
   112  			f:        func(e ObjectEncoder) { e.AddDuration("k", time.Millisecond) },
   113  			expected: time.Millisecond,
   114  		},
   115  		{
   116  			desc:     "AddFloat64",
   117  			f:        func(e ObjectEncoder) { e.AddFloat64("k", 3.14) },
   118  			expected: 3.14,
   119  		},
   120  		{
   121  			desc:     "AddFloat32",
   122  			f:        func(e ObjectEncoder) { e.AddFloat32("k", 3.14) },
   123  			expected: float32(3.14),
   124  		},
   125  		{
   126  			desc:     "AddInt",
   127  			f:        func(e ObjectEncoder) { e.AddInt("k", 42) },
   128  			expected: 42,
   129  		},
   130  		{
   131  			desc:     "AddInt64",
   132  			f:        func(e ObjectEncoder) { e.AddInt64("k", 42) },
   133  			expected: int64(42),
   134  		},
   135  		{
   136  			desc:     "AddInt32",
   137  			f:        func(e ObjectEncoder) { e.AddInt32("k", 42) },
   138  			expected: int32(42),
   139  		},
   140  		{
   141  			desc:     "AddInt16",
   142  			f:        func(e ObjectEncoder) { e.AddInt16("k", 42) },
   143  			expected: int16(42),
   144  		},
   145  		{
   146  			desc:     "AddInt8",
   147  			f:        func(e ObjectEncoder) { e.AddInt8("k", 42) },
   148  			expected: int8(42),
   149  		},
   150  		{
   151  			desc:     "AddString",
   152  			f:        func(e ObjectEncoder) { e.AddString("k", "v") },
   153  			expected: "v",
   154  		},
   155  		{
   156  			desc:     "AddTime",
   157  			f:        func(e ObjectEncoder) { e.AddTime("k", time.Unix(0, 100)) },
   158  			expected: time.Unix(0, 100),
   159  		},
   160  		{
   161  			desc:     "AddUint",
   162  			f:        func(e ObjectEncoder) { e.AddUint("k", 42) },
   163  			expected: uint(42),
   164  		},
   165  		{
   166  			desc:     "AddUint64",
   167  			f:        func(e ObjectEncoder) { e.AddUint64("k", 42) },
   168  			expected: uint64(42),
   169  		},
   170  		{
   171  			desc:     "AddUint32",
   172  			f:        func(e ObjectEncoder) { e.AddUint32("k", 42) },
   173  			expected: uint32(42),
   174  		},
   175  		{
   176  			desc:     "AddUint16",
   177  			f:        func(e ObjectEncoder) { e.AddUint16("k", 42) },
   178  			expected: uint16(42),
   179  		},
   180  		{
   181  			desc:     "AddUint8",
   182  			f:        func(e ObjectEncoder) { e.AddUint8("k", 42) },
   183  			expected: uint8(42),
   184  		},
   185  		{
   186  			desc:     "AddUintptr",
   187  			f:        func(e ObjectEncoder) { e.AddUintptr("k", 42) },
   188  			expected: uintptr(42),
   189  		},
   190  		{
   191  			desc: "AddReflected",
   192  			f: func(e ObjectEncoder) {
   193  				assert.NoError(t, e.AddReflected("k", map[string]interface{}{"foo": 5}), "Expected AddReflected to succeed.")
   194  			},
   195  			expected: map[string]interface{}{"foo": 5},
   196  		},
   197  		{
   198  			desc: "OpenNamespace",
   199  			f: func(e ObjectEncoder) {
   200  				e.OpenNamespace("k")
   201  				e.AddInt("foo", 1)
   202  				e.OpenNamespace("middle")
   203  				e.AddInt("foo", 2)
   204  				e.OpenNamespace("inner")
   205  				e.AddInt("foo", 3)
   206  			},
   207  			expected: map[string]interface{}{
   208  				"foo": 1,
   209  				"middle": map[string]interface{}{
   210  					"foo": 2,
   211  					"inner": map[string]interface{}{
   212  						"foo": 3,
   213  					},
   214  				},
   215  			},
   216  		},
   217  		{
   218  			desc: "object (no nested namespace) then string",
   219  			f: func(e ObjectEncoder) {
   220  				e.OpenNamespace("k")
   221  				assert.NoError(t, e.AddObject("obj", maybeNamespace{false}))
   222  				e.AddString("not-obj", "should-be-outside-obj")
   223  			},
   224  			expected: map[string]interface{}{
   225  				"obj": map[string]interface{}{
   226  					"obj-out": "obj-outside-namespace",
   227  				},
   228  				"not-obj": "should-be-outside-obj",
   229  			},
   230  		},
   231  		{
   232  			desc: "object (with nested namespace) then string",
   233  			f: func(e ObjectEncoder) {
   234  				e.OpenNamespace("k")
   235  				assert.NoError(t, e.AddObject("obj", maybeNamespace{true}))
   236  				e.AddString("not-obj", "should-be-outside-obj")
   237  			},
   238  			expected: map[string]interface{}{
   239  				"obj": map[string]interface{}{
   240  					"obj-out": "obj-outside-namespace",
   241  					"obj-namespace": map[string]interface{}{
   242  						"obj-in": "obj-inside-namespace",
   243  					},
   244  				},
   245  				"not-obj": "should-be-outside-obj",
   246  			},
   247  		},
   248  	}
   249  
   250  	for _, tt := range tests {
   251  		t.Run(tt.desc, func(t *testing.T) {
   252  			enc := NewMapObjectEncoder()
   253  			tt.f(enc)
   254  			assert.Equal(t, tt.expected, enc.Fields["k"], "Unexpected encoder output.")
   255  		})
   256  	}
   257  }
   258  
   259  func TestSliceArrayEncoderAppend(t *testing.T) {
   260  	tests := []struct {
   261  		desc     string
   262  		f        func(ArrayEncoder)
   263  		expected interface{}
   264  	}{
   265  		// AppendObject and AppendArray are covered by the AddObject (nested) and
   266  		// AddArray (nested) cases above.
   267  		{"AppendBool", func(e ArrayEncoder) { e.AppendBool(true) }, true},
   268  		{"AppendByteString", func(e ArrayEncoder) { e.AppendByteString([]byte("foo")) }, "foo"},
   269  		{"AppendComplex128", func(e ArrayEncoder) { e.AppendComplex128(1 + 2i) }, 1 + 2i},
   270  		{"AppendComplex64", func(e ArrayEncoder) { e.AppendComplex64(1 + 2i) }, complex64(1 + 2i)},
   271  		{"AppendDuration", func(e ArrayEncoder) { e.AppendDuration(time.Second) }, time.Second},
   272  		{"AppendFloat64", func(e ArrayEncoder) { e.AppendFloat64(3.14) }, 3.14},
   273  		{"AppendFloat32", func(e ArrayEncoder) { e.AppendFloat32(3.14) }, float32(3.14)},
   274  		{"AppendInt", func(e ArrayEncoder) { e.AppendInt(42) }, 42},
   275  		{"AppendInt64", func(e ArrayEncoder) { e.AppendInt64(42) }, int64(42)},
   276  		{"AppendInt32", func(e ArrayEncoder) { e.AppendInt32(42) }, int32(42)},
   277  		{"AppendInt16", func(e ArrayEncoder) { e.AppendInt16(42) }, int16(42)},
   278  		{"AppendInt8", func(e ArrayEncoder) { e.AppendInt8(42) }, int8(42)},
   279  		{"AppendString", func(e ArrayEncoder) { e.AppendString("foo") }, "foo"},
   280  		{"AppendTime", func(e ArrayEncoder) { e.AppendTime(time.Unix(0, 100)) }, time.Unix(0, 100)},
   281  		{"AppendUint", func(e ArrayEncoder) { e.AppendUint(42) }, uint(42)},
   282  		{"AppendUint64", func(e ArrayEncoder) { e.AppendUint64(42) }, uint64(42)},
   283  		{"AppendUint32", func(e ArrayEncoder) { e.AppendUint32(42) }, uint32(42)},
   284  		{"AppendUint16", func(e ArrayEncoder) { e.AppendUint16(42) }, uint16(42)},
   285  		{"AppendUint8", func(e ArrayEncoder) { e.AppendUint8(42) }, uint8(42)},
   286  		{"AppendUintptr", func(e ArrayEncoder) { e.AppendUintptr(42) }, uintptr(42)},
   287  		{
   288  			desc: "AppendReflected",
   289  			f: func(e ArrayEncoder) {
   290  				assert.NoError(t, e.AppendReflected(map[string]interface{}{"foo": 5}))
   291  			},
   292  			expected: map[string]interface{}{"foo": 5},
   293  		},
   294  		{
   295  			desc: "AppendArray (arrays of arrays)",
   296  			f: func(e ArrayEncoder) {
   297  				err := e.AppendArray(ArrayMarshalerFunc(func(inner ArrayEncoder) error {
   298  					inner.AppendBool(true)
   299  					inner.AppendBool(false)
   300  					return nil
   301  				}))
   302  				assert.NoError(t, err)
   303  			},
   304  			expected: []interface{}{true, false},
   305  		},
   306  		{
   307  			desc: "object (no nested namespace) then string",
   308  			f: func(e ArrayEncoder) {
   309  				err := e.AppendArray(ArrayMarshalerFunc(func(inner ArrayEncoder) error {
   310  					err := inner.AppendObject(maybeNamespace{false})
   311  					inner.AppendString("should-be-outside-obj")
   312  					return err
   313  				}))
   314  				assert.NoError(t, err)
   315  			},
   316  			expected: []interface{}{
   317  				map[string]interface{}{
   318  					"obj-out": "obj-outside-namespace",
   319  				},
   320  				"should-be-outside-obj",
   321  			},
   322  		},
   323  		{
   324  			desc: "object (with nested namespace) then string",
   325  			f: func(e ArrayEncoder) {
   326  				err := e.AppendArray(ArrayMarshalerFunc(func(inner ArrayEncoder) error {
   327  					err := inner.AppendObject(maybeNamespace{true})
   328  					inner.AppendString("should-be-outside-obj")
   329  					return err
   330  				}))
   331  				assert.NoError(t, err)
   332  			},
   333  			expected: []interface{}{
   334  				map[string]interface{}{
   335  					"obj-out": "obj-outside-namespace",
   336  					"obj-namespace": map[string]interface{}{
   337  						"obj-in": "obj-inside-namespace",
   338  					},
   339  				},
   340  				"should-be-outside-obj",
   341  			},
   342  		},
   343  	}
   344  
   345  	for _, tt := range tests {
   346  		t.Run(tt.desc, func(t *testing.T) {
   347  			enc := NewMapObjectEncoder()
   348  			assert.NoError(t, enc.AddArray("k", ArrayMarshalerFunc(func(arr ArrayEncoder) error {
   349  				tt.f(arr)
   350  				tt.f(arr)
   351  				return nil
   352  			})), "Expected AddArray to succeed.")
   353  
   354  			arr, ok := enc.Fields["k"].([]interface{})
   355  			require.True(t, ok, "Test case %s didn't encode an array.", tt.desc)
   356  			assert.Equal(t, []interface{}{tt.expected, tt.expected}, arr, "Unexpected encoder output.")
   357  		})
   358  	}
   359  }
   360  
   361  func TestMapObjectEncoderReflectionFailures(t *testing.T) {
   362  	enc := NewMapObjectEncoder()
   363  	assert.Error(t, enc.AddObject("object", loggable{false}), "Expected AddObject to fail.")
   364  	assert.Equal(
   365  		t,
   366  		map[string]interface{}{"object": map[string]interface{}{}},
   367  		enc.Fields,
   368  		"Expected encoder to use empty values on errors.",
   369  	)
   370  }
   371  

View as plain text