@@ -21,7 +21,23 @@ type stringerMock struct{}
2121
2222func (s stringerMock ) String () string { return "stringer-value" }
2323
24- func Test_mapZapField (t * testing.T ) {
24+ type customError struct {}
25+
26+ func (e * customError ) Error () string {
27+ return "custom error"
28+ }
29+
30+ // panicError will panic if Error() is called on a nil receiver
31+ type panicError struct {
32+ msg string
33+ }
34+
35+ func (e * panicError ) Error () string {
36+ // This will panic if e is nil since we're accessing a field
37+ return e .msg
38+ }
39+
40+ func Test_otelAttrEncoder (t * testing.T ) {
2541 now := time .Now ()
2642 duration := time .Second * 42
2743
@@ -65,69 +81,73 @@ func Test_mapZapField(t *testing.T) {
6581 field : zapcore.Field {Key : "err" , Type : zapcore .ErrorType , Interface : errors .New ("fail" )},
6682 expected : attribute .String ("err" , "fail" ),
6783 },
68- {
69- name : "ErrorType invalid" ,
70- field : zapcore.Field {Key : "err" , Type : zapcore .ErrorType , Interface : "not-an-error" },
71- expected : attribute .String ("err" , "invalid error field" ),
72- },
7384 {
7485 name : "StringerType" ,
7586 field : zapcore.Field {Key : "stringer" , Type : zapcore .StringerType , Interface : stringerMock {}},
7687 expected : attribute .String ("stringer" , "stringer-value" ),
7788 },
7889 {
7990 name : "TimeType valid" ,
80- field : zapcore.Field {Key : "time" , Type : zapcore .TimeType , Interface : now },
91+ field : zapcore.Field {Key : "time" , Type : zapcore .TimeType , Integer : now . UnixNano (), Interface : now . Location () },
8192 expected : attribute .String ("time" , now .Format (time .RFC3339 )),
8293 },
83- {
84- name : "TimeType invalid" ,
85- field : zapcore.Field {Key : "time" , Type : zapcore .TimeType , Interface : "not-a-time" },
86- expected : attribute .String ("time" , "invalid time: not-a-time" ),
87- },
8894 {
8995 name : "DurationType valid" ,
90- field : zapcore.Field {Key : "dur" , Type : zapcore .DurationType , Interface : duration },
91- expected : attribute .String ("dur" , duration .String ()),
92- },
93- {
94- name : "DurationType invalid" ,
95- field : zapcore.Field {Key : "dur" , Type : zapcore .DurationType , Interface : "not-a-duration" },
96- expected : attribute .String ("dur" , "invalid duration: not-a-duration" ),
96+ field : zapcore.Field {Key : "dur" , Type : zapcore .DurationType , Integer : int64 (duration )},
97+ expected : attribute .Int64 ("dur" , int64 (duration )),
9798 },
9899 {
99100 name : "BinaryType valid" ,
100101 field : zapcore.Field {Key : "bin" , Type : zapcore .BinaryType , Interface : []byte {0x1 , 0x2 }},
101- expected : attribute .String ("bin" , "binary data: 0102" ),
102- },
103- {
104- name : "BinaryType invalid" ,
105- field : zapcore.Field {Key : "bin" , Type : zapcore .BinaryType , Interface : "not-bytes" },
106- expected : attribute .String ("bin" , "invalid binary: not-bytes" ),
102+ expected : attribute .String ("bin" , "\x01 \x02 " ),
107103 },
108104 {
109105 name : "ByteStringType valid" ,
110106 field : zapcore.Field {Key : "bs" , Type : zapcore .ByteStringType , Interface : []byte {0x3 , 0x4 }},
111- expected : attribute .String ("bs" , "byte string: 0304 " ),
107+ expected : attribute .String ("bs" , "\x03 \x04 " ),
112108 },
109+ }
110+
111+ for _ , tt := range tests {
112+ t .Run (tt .name , func (t * testing.T ) {
113+ encoder := & otelAttrEncoder {}
114+ tt .field .AddTo (encoder )
115+
116+ require .Len (t , encoder .attributes , 1 , "Expected exactly one attribute" )
117+ got := encoder .attributes [0 ]
118+
119+ assert .Equal (t , tt .expected .Key , got .Key )
120+ assert .Equal (t , tt .expected .Value .Type (), got .Value .Type ())
121+ assert .Equal (t , tt .expected .Value .AsInterface (), got .Value .AsInterface ())
122+ })
123+ }
124+ }
125+
126+ func Test_otelAttrEncoder_nilSafety (t * testing.T ) {
127+ tests := []struct {
128+ name string
129+ field zapcore.Field
130+ }{
113131 {
114- name : "ByteStringType invalid" ,
115- field : zapcore.Field {Key : "bs" , Type : zapcore .ByteStringType , Interface : "not-bytes" },
116- expected : attribute .String ("bs" , "invalid byte string: not-bytes" ),
132+ name : "StringerType with nil value - should not panic" ,
133+ field : zapcore.Field {Key : "nil-stringer" , Type : zapcore .StringerType , Interface : (* stringerMock )(nil )},
117134 },
118135 {
119- name : "Default" ,
120- field : zapcore.Field {Key : "def" , Type : zapcore .UnknownType , String : "default" },
121- expected : attribute .String ("def" , "default" ),
136+ name : "ErrorType with nil panic-causing value - should not panic" ,
137+ field : zapcore.Field {Key : "nil-panic-error" , Type : zapcore .ErrorType , Interface : (* panicError )(nil )},
122138 },
123139 }
124140
125141 for _ , tt := range tests {
126142 t .Run (tt .name , func (t * testing.T ) {
127- got := mapZapField (tt .field )
128- assert .Equal (t , tt .expected .Key , got .Key )
129- assert .Equal (t , tt .expected .Value .Type (), got .Value .Type ())
130- assert .Equal (t , tt .expected .Value .AsInterface (), got .Value .AsInterface ())
143+ encoder := & otelAttrEncoder {}
144+
145+ // This should not panic - zap's Field.AddTo handles the safety
146+ assert .NotPanics (t , func () {
147+ tt .field .AddTo (encoder )
148+ })
149+
150+ assert .NotEmpty (t , encoder .attributes )
131151 })
132152 }
133153}
0 commit comments