...

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

Documentation: go.uber.org/zap/zapcore

     1  // Copyright (c) 2017 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_test
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  	"testing"
    28  
    29  	"github.com/stretchr/testify/assert"
    30  
    31  	"go.uber.org/multierr"
    32  	//revive:disable:dot-imports
    33  	. "go.uber.org/zap/zapcore"
    34  )
    35  
    36  type errTooManyUsers int
    37  
    38  func (e errTooManyUsers) Error() string {
    39  	return fmt.Sprintf("%d too many users", int(e))
    40  }
    41  
    42  func (e errTooManyUsers) Format(s fmt.State, verb rune) {
    43  	// Implement fmt.Formatter, but don't add any information beyond the basic
    44  	// Error method.
    45  	if verb == 'v' && s.Flag('+') {
    46  		io.WriteString(s, e.Error())
    47  	}
    48  }
    49  
    50  type customMultierr struct{}
    51  
    52  func (e customMultierr) Error() string {
    53  	return "great sadness"
    54  }
    55  
    56  func (e customMultierr) Errors() []error {
    57  	return []error{
    58  		errors.New("foo"),
    59  		nil,
    60  		multierr.Append(
    61  			errors.New("bar"),
    62  			errors.New("baz"),
    63  		),
    64  	}
    65  }
    66  
    67  func TestErrorEncoding(t *testing.T) {
    68  	tests := []struct {
    69  		k     string
    70  		t     FieldType // defaults to ErrorType
    71  		iface interface{}
    72  		want  map[string]interface{}
    73  	}{
    74  		{
    75  			k:     "k",
    76  			iface: errTooManyUsers(2),
    77  			want: map[string]interface{}{
    78  				"k": "2 too many users",
    79  			},
    80  		},
    81  		{
    82  			k: "err",
    83  			iface: multierr.Combine(
    84  				errors.New("foo"),
    85  				errors.New("bar"),
    86  				errors.New("baz"),
    87  			),
    88  			want: map[string]interface{}{
    89  				"err": "foo; bar; baz",
    90  				"errCauses": []interface{}{
    91  					map[string]interface{}{"error": "foo"},
    92  					map[string]interface{}{"error": "bar"},
    93  					map[string]interface{}{"error": "baz"},
    94  				},
    95  			},
    96  		},
    97  		{
    98  			k:     "e",
    99  			iface: customMultierr{},
   100  			want: map[string]interface{}{
   101  				"e": "great sadness",
   102  				"eCauses": []interface{}{
   103  					map[string]interface{}{"error": "foo"},
   104  					map[string]interface{}{
   105  						"error": "bar; baz",
   106  						"errorCauses": []interface{}{
   107  							map[string]interface{}{"error": "bar"},
   108  							map[string]interface{}{"error": "baz"},
   109  						},
   110  					},
   111  				},
   112  			},
   113  		},
   114  		{
   115  			k:     "k",
   116  			iface: fmt.Errorf("failed: %w", errors.New("egad")),
   117  			want: map[string]interface{}{
   118  				"k": "failed: egad",
   119  			},
   120  		},
   121  		{
   122  			k: "error",
   123  			iface: multierr.Combine(
   124  				fmt.Errorf("hello: %w",
   125  					multierr.Combine(errors.New("foo"), errors.New("bar")),
   126  				),
   127  				errors.New("baz"),
   128  				fmt.Errorf("world: %w", errors.New("qux")),
   129  			),
   130  			want: map[string]interface{}{
   131  				"error": "hello: foo; bar; baz; world: qux",
   132  				"errorCauses": []interface{}{
   133  					map[string]interface{}{
   134  						"error": "hello: foo; bar",
   135  					},
   136  					map[string]interface{}{"error": "baz"},
   137  					map[string]interface{}{"error": "world: qux"},
   138  				},
   139  			},
   140  		},
   141  	}
   142  
   143  	for _, tt := range tests {
   144  		if tt.t == UnknownType {
   145  			tt.t = ErrorType
   146  		}
   147  
   148  		enc := NewMapObjectEncoder()
   149  		f := Field{Key: tt.k, Type: tt.t, Interface: tt.iface}
   150  		f.AddTo(enc)
   151  		assert.Equal(t, tt.want, enc.Fields, "Unexpected output from field %+v.", f)
   152  	}
   153  }
   154  
   155  func TestRichErrorSupport(t *testing.T) {
   156  	f := Field{
   157  		Type:      ErrorType,
   158  		Interface: fmt.Errorf("failed: %w", errors.New("egad")),
   159  		Key:       "k",
   160  	}
   161  	enc := NewMapObjectEncoder()
   162  	f.AddTo(enc)
   163  	assert.Equal(t, "failed: egad", enc.Fields["k"], "Unexpected basic error message.")
   164  }
   165  
   166  func TestErrArrayBrokenEncoder(t *testing.T) {
   167  	t.Parallel()
   168  
   169  	f := Field{
   170  		Key:  "foo",
   171  		Type: ErrorType,
   172  		Interface: multierr.Combine(
   173  			errors.New("foo"),
   174  			errors.New("bar"),
   175  		),
   176  	}
   177  
   178  	failWith := errors.New("great sadness")
   179  	enc := NewMapObjectEncoder()
   180  	f.AddTo(brokenArrayObjectEncoder{
   181  		Err:           failWith,
   182  		ObjectEncoder: enc,
   183  	})
   184  
   185  	// Failure to add the field to the encoder
   186  	// causes the error to be added as a string field.
   187  	assert.Equal(t, "great sadness", enc.Fields["fooError"],
   188  		"Unexpected error message.")
   189  }
   190  
   191  // brokenArrayObjectEncoder is an ObjectEncoder
   192  // that builds a broken ArrayEncoder.
   193  type brokenArrayObjectEncoder struct {
   194  	ObjectEncoder
   195  	ArrayEncoder
   196  
   197  	Err error // error to return
   198  }
   199  
   200  func (enc brokenArrayObjectEncoder) AddArray(key string, marshaler ArrayMarshaler) error {
   201  	return enc.ObjectEncoder.AddArray(key,
   202  		ArrayMarshalerFunc(func(ae ArrayEncoder) error {
   203  			enc.ArrayEncoder = ae
   204  			return marshaler.MarshalLogArray(enc)
   205  		}))
   206  }
   207  
   208  func (enc brokenArrayObjectEncoder) AppendObject(ObjectMarshaler) error {
   209  	return enc.Err
   210  }
   211  

View as plain text