-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample_test.go
More file actions
251 lines (213 loc) · 7.83 KB
/
example_test.go
File metadata and controls
251 lines (213 loc) · 7.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// example_test.go: Examples for the go-errors AGILira library
//
// Copyright (c) 2025 AGILira - A. Giordano
// Series: an AGLIra library
// SPDX-License-Identifier: MPL-2.0
package errors_test
import (
"encoding/json"
"fmt"
"log"
"github.com/agilira/go-errors"
)
// Example error codes - define these as constants in your application
const (
ErrCodeValidation = "VALIDATION_ERROR"
ErrCodeDatabase = "DATABASE_ERROR"
ErrCodeNetwork = "NETWORK_ERROR"
ErrCodeAuth = "AUTHENTICATION_ERROR"
)
// ExampleNew demonstrates basic error creation
func ExampleNew() {
err := errors.New(ErrCodeValidation, "Username is required")
fmt.Println(err.Error())
fmt.Printf("Code: %s\n", err.ErrorCode())
// Output:
// [VALIDATION_ERROR]: Username is required
// Code: VALIDATION_ERROR
}
// ExampleNewWithField demonstrates field-specific validation errors
func ExampleNewWithField() {
err := errors.NewWithField(ErrCodeValidation, "Invalid email format", "email", "invalid@")
fmt.Printf("Error: %s\n", err.Error())
fmt.Printf("Field: %s, Value: %s\n", err.Field, err.Value)
// Output:
// Error: [VALIDATION_ERROR]: Invalid email format
// Field: email, Value: invalid@
}
// ExampleError_WithUserMessage demonstrates user-friendly error messages
func ExampleError_WithUserMessage() {
err := errors.New(ErrCodeDatabase, "Connection timeout after 30 seconds").
WithUserMessage("We're experiencing technical difficulties. Please try again later.")
fmt.Printf("Technical: %s\n", err.Message)
fmt.Printf("User-friendly: %s\n", err.UserMessage())
// Output:
// Technical: Connection timeout after 30 seconds
// User-friendly: We're experiencing technical difficulties. Please try again later.
}
// ExampleError_WithContext demonstrates adding debugging context
func ExampleError_WithContext() {
err := errors.New(ErrCodeDatabase, "Query failed").
WithContext("query", "SELECT * FROM users").
WithContext("duration_ms", 5000).
WithContext("connection_pool", "primary")
fmt.Printf("Error: %s\n", err.Error())
fmt.Printf("Query: %s\n", err.Context["query"])
fmt.Printf("Duration: %v ms\n", err.Context["duration_ms"])
// Output:
// Error: [DATABASE_ERROR]: Query failed
// Query: SELECT * FROM users
// Duration: 5000 ms
}
// ExampleWrap demonstrates error wrapping with stack traces
func ExampleWrap() {
// Simulate a low-level error
originalErr := fmt.Errorf("connection refused")
// Wrap with structured error
wrappedErr := errors.Wrap(originalErr, ErrCodeNetwork, "Failed to connect to service")
fmt.Printf("Wrapped: %s\n", wrappedErr.Error())
fmt.Printf("Root cause: %s\n", errors.RootCause(wrappedErr).Error())
// Output:
// Wrapped: [NETWORK_ERROR]: Failed to connect to service
// Root cause: connection refused
}
// ExampleError_severity demonstrates severity levels
func ExampleError_severity() {
// Using predefined severity constants
criticalErr := errors.New(ErrCodeDatabase, "Data corruption detected").
WithCriticalSeverity()
warningErr := errors.New(ErrCodeValidation, "Optional field missing").
WithWarningSeverity()
infoErr := errors.New("INFO_CODE", "Operation completed successfully").
WithInfoSeverity()
fmt.Printf("Critical: %s (severity: %s)\n", criticalErr.Message, criticalErr.Severity)
fmt.Printf("Warning: %s (severity: %s)\n", warningErr.Message, warningErr.Severity)
fmt.Printf("Info: %s (severity: %s)\n", infoErr.Message, infoErr.Severity)
// Output:
// Critical: Data corruption detected (severity: critical)
// Warning: Optional field missing (severity: warning)
// Info: Operation completed successfully (severity: info)
}
// ExampleError_AsRetryable demonstrates retry logic
func ExampleError_AsRetryable() {
retryableErr := errors.New(ErrCodeNetwork, "Temporary service unavailable").
AsRetryable().
WithUserMessage("Service temporarily unavailable. Please try again.")
if retryableErr.IsRetryable() {
fmt.Println("This error can be retried")
fmt.Printf("User message: %s\n", retryableErr.UserMessage())
}
// Output:
// This error can be retried
// User message: Service temporarily unavailable. Please try again.
}
// ExampleError_MarshalJSON demonstrates JSON serialization
func ExampleError_MarshalJSON() {
err := errors.New(ErrCodeAuth, "Invalid credentials").
WithUserMessage("Please check your username and password").
WithContext("attempt", 3).
WithContext("ip", "192.168.1.1").
WithWarningSeverity()
jsonData, _ := json.Marshal(err)
// Parse to show structure without exact timestamp
var result map[string]interface{}
_ = json.Unmarshal(jsonData, &result)
fmt.Printf("Code: %s\n", result["code"])
fmt.Printf("Message: %s\n", result["message"])
fmt.Printf("Severity: %s\n", result["severity"])
fmt.Printf("User Message: %s\n", result["user_msg"])
fmt.Printf("Has Context: %t\n", result["context"] != nil)
fmt.Printf("Has Timestamp: %t\n", result["timestamp"] != nil)
// Output:
// Code: AUTHENTICATION_ERROR
// Message: Invalid credentials
// Severity: warning
// User Message: Please check your username and password
// Has Context: true
// Has Timestamp: true
}
// ExampleHasCode demonstrates error code checking
func ExampleHasCode() {
// Create a chain of wrapped errors
originalErr := fmt.Errorf("disk full")
wrappedErr := errors.Wrap(originalErr, ErrCodeDatabase, "Failed to write data")
doubleWrapped := errors.Wrap(wrappedErr, "OPERATION_FAILED", "User save operation failed")
// Check for specific error codes in the chain
if errors.HasCode(doubleWrapped, ErrCodeDatabase) {
fmt.Println("Database error detected in chain")
}
if errors.HasCode(doubleWrapped, ErrCodeValidation) {
fmt.Println("This won't print - no validation error in chain")
} else {
fmt.Println("No validation error in chain")
}
// Output:
// Database error detected in chain
// No validation error in chain
}
// ExampleError_chainMethods demonstrates fluent API usage
func ExampleError_chainMethods() {
err := errors.New(ErrCodeValidation, "User data validation failed").
WithUserMessage("Please check your information and try again").
WithContext("user_id", "12345").
WithContext("validation_errors", []string{"email", "phone"}).
AsRetryable().
WithWarningSeverity()
fmt.Printf("Code: %s\n", err.ErrorCode())
fmt.Printf("Retryable: %t\n", err.IsRetryable())
fmt.Printf("Severity: %s\n", err.Severity)
// Output:
// Code: VALIDATION_ERROR
// Retryable: true
// Severity: warning
}
// Example of real-world usage patterns
func Example_realWorldUsage() {
// Simulate a service layer function
processUser := func(userID string) error {
// Validate input
if userID == "" {
return errors.NewWithField(ErrCodeValidation, "User ID is required", "user_id", userID).
WithUserMessage("Please provide a valid user ID")
}
// Simulate database error
if userID == "invalid" {
dbErr := fmt.Errorf("user not found")
return errors.Wrap(dbErr, ErrCodeDatabase, "Failed to fetch user").
WithContext("user_id", userID).
WithUserMessage("User not found")
}
return nil
}
// Handle errors
handleError := func(err error) {
if err == nil {
return
}
structErr, ok := err.(*errors.Error)
if !ok {
log.Printf("Unknown error: %v", err)
return
}
// Log technical details
log.Printf("Error [%s]: %s", structErr.ErrorCode(), structErr.Error())
// Show user-friendly message
fmt.Printf("User message: %s\n", structErr.UserMessage())
// Handle specific error types
switch {
case errors.HasCode(err, ErrCodeValidation):
fmt.Println("Handling validation error")
case errors.HasCode(err, ErrCodeDatabase):
fmt.Println("Handling database error")
}
}
// Test cases
handleError(processUser("")) // Validation error
handleError(processUser("invalid")) // Database error
handleError(processUser("valid")) // No error
// Output:
// User message: Please provide a valid user ID
// Handling validation error
// User message: User not found
// Handling database error
}