@@ -20,7 +20,7 @@ func TestNew(t *testing.T) {
2020 // Test with options
2121 tag := goerr .NewTag ("test" )
2222 err = goerr .New ("test error" , goerr .Tag (tag ), goerr .Value ("key" , "value" ))
23-
23+
2424 if ! err .HasTag (tag ) {
2525 t .Error ("Error should have the tag" )
2626 }
@@ -46,7 +46,7 @@ func TestWrap(t *testing.T) {
4646
4747func TestUnwrap (t * testing.T ) {
4848 err := goerr .New ("test error" )
49-
49+
5050 // Test unwrapping goerr.Error
5151 unwrapped := goerr .Unwrap (err )
5252 if unwrapped == nil {
@@ -62,7 +62,7 @@ func TestUnwrap(t *testing.T) {
6262}
6363
6464func TestErrorValues (t * testing.T ) {
65- err := goerr .New ("test error" ,
65+ err := goerr .New ("test error" ,
6666 goerr .Value ("key1" , "value1" ),
6767 goerr .Value ("key2" , 42 ))
6868
@@ -85,7 +85,7 @@ func TestErrorValues(t *testing.T) {
8585func TestErrorTags (t * testing.T ) {
8686 tag1 := goerr .NewTag ("tag1" )
8787 tag2 := goerr .NewTag ("tag2" )
88-
88+
8989 err := goerr .New ("test error" , goerr .Tag (tag1 ), goerr .Tag (tag2 ))
9090
9191 tags := goerr .Tags (err )
@@ -109,7 +109,7 @@ func TestErrorTags(t *testing.T) {
109109
110110func TestErrorMarshalJSON (t * testing.T ) {
111111 tag := goerr .NewTag ("test" )
112- err := goerr .New ("test error" ,
112+ err := goerr .New ("test error" ,
113113 goerr .Tag (tag ),
114114 goerr .Value ("key" , "value" ))
115115
@@ -140,7 +140,7 @@ func TestErrorMarshalJSON(t *testing.T) {
140140
141141func TestErrorLogValue (t * testing.T ) {
142142 err := goerr .New ("test error" , goerr .Value ("key" , "value" ))
143-
143+
144144 logValue := err .LogValue ()
145145 if logValue .Kind () != slog .KindGroup {
146146 t .Error ("LogValue should return a group" )
@@ -181,9 +181,108 @@ func TestErrorFormat(t *testing.T) {
181181 }
182182}
183183
184+ func TestErrorFormatWrapped (t * testing.T ) {
185+ // Create a chain of wrapped errors with different values
186+ baseErr := goerr .New ("base error" ,
187+ goerr .Value ("base_key" , "base_value" ),
188+ goerr .Value ("shared_key" , "base_shared" )) // This should be overwritten
189+
190+ middleErr := goerr .Wrap (baseErr , "middle error" ,
191+ goerr .Value ("middle_key" , "middle_value" ),
192+ goerr .Value ("shared_key" , "middle_shared" )) // This overwrites base_shared
193+
194+ topErr := goerr .Wrap (middleErr , "top error" ,
195+ goerr .Value ("top_key" , "top_value" ),
196+ goerr .Value ("shared_key" , "top_shared" )) // This overwrites middle_shared
197+
198+ // Test %+v format with wrapped errors
199+ detailedResult := fmt .Sprintf ("%+v" , topErr )
200+
201+ // Should contain the complete error message chain
202+ if ! strings .Contains (detailedResult , "top error: middle error: base error" ) {
203+ t .Error ("Detailed format should contain complete error message chain" )
204+ }
205+
206+ // Should contain Values section
207+ if ! strings .Contains (detailedResult , "Values:" ) {
208+ t .Error ("Detailed format should contain Values section" )
209+ }
210+
211+ // Should contain values from base error
212+ if ! strings .Contains (detailedResult , "base_key: base_value" ) {
213+ t .Error ("Detailed format should contain values from base error" )
214+ }
215+
216+ // Should contain values from middle error
217+ if ! strings .Contains (detailedResult , "middle_key: middle_value" ) {
218+ t .Error ("Detailed format should contain values from middle error" )
219+ }
220+
221+ // Should contain values from top error
222+ if ! strings .Contains (detailedResult , "top_key: top_value" ) {
223+ t .Error ("Detailed format should contain values from top error" )
224+ }
225+
226+ // Should show the final value for overwritten key (top-level wins)
227+ if ! strings .Contains (detailedResult , "shared_key: top_shared" ) {
228+ t .Error ("Detailed format should show final value for overwritten key" )
229+ }
230+
231+ // Should NOT contain overwritten values
232+ if strings .Contains (detailedResult , "base_shared" ) {
233+ t .Error ("Detailed format should not contain overwritten base value" )
234+ }
235+ if strings .Contains (detailedResult , "middle_shared" ) {
236+ t .Error ("Detailed format should not contain overwritten middle value" )
237+ }
238+
239+ // Verify keys are sorted alphabetically
240+ valuesSection := detailedResult [strings .Index (detailedResult , "Values:" ):]
241+ baseKeyPos := strings .Index (valuesSection , "base_key:" )
242+ middleKeyPos := strings .Index (valuesSection , "middle_key:" )
243+ sharedKeyPos := strings .Index (valuesSection , "shared_key:" )
244+ topKeyPos := strings .Index (valuesSection , "top_key:" )
245+
246+ // All positions should be found
247+ if baseKeyPos == - 1 || middleKeyPos == - 1 || sharedKeyPos == - 1 || topKeyPos == - 1 {
248+ t .Error ("All keys should be present in values section" )
249+ }
250+
251+ // Keys should appear in alphabetical order
252+ if ! (baseKeyPos < middleKeyPos && middleKeyPos < sharedKeyPos && sharedKeyPos < topKeyPos ) {
253+ t .Error ("Keys should be sorted alphabetically in values section" )
254+ }
255+ }
256+
257+ func TestErrorFormatTypedValues (t * testing.T ) {
258+ // Test that TypedValues from wrapped errors are also included
259+ // Note: We need to use the typed values functionality here
260+ // Since TypedValues is not directly exposed via options, we test the formatting
261+ // by creating errors that would have typed values through internal mechanisms
262+
263+ baseErr := goerr .New ("base error" , goerr .Value ("regular_key" , "regular_value" ))
264+ wrappedErr := goerr .Wrap (baseErr , "wrapped error" , goerr .Value ("wrapped_key" , "wrapped_value" ))
265+
266+ // Test %+v format includes all values
267+ detailedResult := fmt .Sprintf ("%+v" , wrappedErr )
268+
269+ // Should contain both regular values
270+ if ! strings .Contains (detailedResult , "regular_key: regular_value" ) {
271+ t .Error ("Should contain base error values" )
272+ }
273+ if ! strings .Contains (detailedResult , "wrapped_key: wrapped_value" ) {
274+ t .Error ("Should contain wrapped error values" )
275+ }
276+
277+ // Should contain Values section (since we have regular values)
278+ if ! strings .Contains (detailedResult , "Values:" ) {
279+ t .Error ("Should contain Values section" )
280+ }
281+ }
282+
184283func TestErrorStackTrace (t * testing.T ) {
185284 err := goerr .New ("test error" )
186-
285+
187286 stacks := err .Stacks ()
188287 if len (stacks ) == 0 {
189288 t .Error ("Error should have stack trace" )
@@ -226,7 +325,7 @@ func TestErrorIs(t *testing.T) {
226325}
227326
228327func TestErrorCopy (t * testing.T ) {
229- original := goerr .New ("original" ,
328+ original := goerr .New ("original" ,
230329 goerr .ID ("test-id" ),
231330 goerr .Value ("key" , "value" ))
232331
@@ -267,7 +366,7 @@ func TestErrorUnstack(t *testing.T) {
267366 // Test UnstackN(1) should have same effect as Unstack
268367 err2 := goerr .New ("test error 2" )
269368 unstackedN1 := err2 .UnstackN (1 )
270-
369+
271370 if unstackedN1 != err2 {
272371 t .Error ("UnstackN should return the same instance" )
273372 }
@@ -300,4 +399,4 @@ func TestPrintable(t *testing.T) {
300399 if len (printable .StackTrace ) == 0 {
301400 t .Error ("Printable should have stack trace" )
302401 }
303- }
402+ }
0 commit comments