errors_test.go raw
1 package errors
2
3 import (
4 "errors"
5 "testing"
6 )
7
8 func TestValidationError(t *testing.T) {
9 err := ErrInvalidEventID
10 if err.Code() != "INVALID_ID" {
11 t.Errorf("expected code INVALID_ID, got %s", err.Code())
12 }
13 if err.Category() != "validation" {
14 t.Errorf("expected category validation, got %s", err.Category())
15 }
16 if err.Field != "id" {
17 t.Errorf("expected field id, got %s", err.Field)
18 }
19 if err.IsRetryable() {
20 t.Error("validation errors should not be retryable")
21 }
22 }
23
24 func TestAuthorizationError(t *testing.T) {
25 err := ErrAuthRequired
26 if err.Code() != "AUTH_REQUIRED" {
27 t.Errorf("expected code AUTH_REQUIRED, got %s", err.Code())
28 }
29 if !err.NeedsAuth() {
30 t.Error("ErrAuthRequired should indicate auth is needed")
31 }
32
33 err2 := ErrBanned
34 if err2.NeedsAuth() {
35 t.Error("ErrBanned should not indicate auth is needed")
36 }
37 }
38
39 func TestProcessingError(t *testing.T) {
40 err := ErrRateLimited
41 if err.Code() != "RATE_LIMITED" {
42 t.Errorf("expected code RATE_LIMITED, got %s", err.Code())
43 }
44 if !err.IsRetryable() {
45 t.Error("rate limit errors should be retryable")
46 }
47
48 err2 := ErrDuplicate
49 if err2.IsRetryable() {
50 t.Error("duplicate errors should not be retryable")
51 }
52 }
53
54 func TestStorageError(t *testing.T) {
55 err := ErrDatabaseUnavailable
56 if err.Code() != "DB_UNAVAILABLE" {
57 t.Errorf("expected code DB_UNAVAILABLE, got %s", err.Code())
58 }
59 if err.Category() != "storage" {
60 t.Errorf("expected category storage, got %s", err.Category())
61 }
62 if !err.IsRetryable() {
63 t.Error("database unavailable should be retryable")
64 }
65 }
66
67 func TestPolicyError(t *testing.T) {
68 err := NewPolicyBlocked("kind_whitelist", "kind 30023 not allowed")
69 if err.Code() != "POLICY_BLOCKED" {
70 t.Errorf("expected code POLICY_BLOCKED, got %s", err.Code())
71 }
72 if err.RuleName != "kind_whitelist" {
73 t.Errorf("expected rule name kind_whitelist, got %s", err.RuleName)
74 }
75 if err.Action != "block" {
76 t.Errorf("expected action block, got %s", err.Action)
77 }
78 }
79
80 func TestIsHelper(t *testing.T) {
81 if !Is(ErrInvalidEventID, ErrInvalidEventID) {
82 t.Error("Is should return true for same error")
83 }
84 if Is(ErrInvalidEventID, ErrInvalidSignature) {
85 t.Error("Is should return false for different errors")
86 }
87
88 // Test with non-domain error
89 stdErr := errors.New("standard error")
90 if Is(stdErr, ErrInvalidEventID) {
91 t.Error("Is should return false for non-domain errors")
92 }
93 }
94
95 func TestCodeHelper(t *testing.T) {
96 if Code(ErrInvalidEventID) != "INVALID_ID" {
97 t.Errorf("expected INVALID_ID, got %s", Code(ErrInvalidEventID))
98 }
99
100 stdErr := errors.New("standard error")
101 if Code(stdErr) != "" {
102 t.Errorf("expected empty string for non-domain error, got %s", Code(stdErr))
103 }
104 }
105
106 func TestCategoryHelper(t *testing.T) {
107 if Category(ErrInvalidEventID) != "validation" {
108 t.Errorf("expected validation, got %s", Category(ErrInvalidEventID))
109 }
110 if Category(ErrBanned) != "authorization" {
111 t.Errorf("expected authorization, got %s", Category(ErrBanned))
112 }
113 if Category(ErrDuplicate) != "processing" {
114 t.Errorf("expected processing, got %s", Category(ErrDuplicate))
115 }
116
117 stdErr := errors.New("standard error")
118 if Category(stdErr) != "unknown" {
119 t.Errorf("expected unknown for non-domain error, got %s", Category(stdErr))
120 }
121 }
122
123 func TestIsRetryableHelper(t *testing.T) {
124 if !IsRetryable(ErrRateLimited) {
125 t.Error("ErrRateLimited should be retryable")
126 }
127 if !IsRetryable(ErrDatabaseUnavailable) {
128 t.Error("ErrDatabaseUnavailable should be retryable")
129 }
130 if IsRetryable(ErrDuplicate) {
131 t.Error("ErrDuplicate should not be retryable")
132 }
133 if IsRetryable(ErrInvalidEventID) {
134 t.Error("ErrInvalidEventID should not be retryable")
135 }
136 }
137
138 func TestTypeCheckers(t *testing.T) {
139 if !IsValidation(ErrInvalidEventID) {
140 t.Error("ErrInvalidEventID should be a validation error")
141 }
142 if !IsAuthorization(ErrBanned) {
143 t.Error("ErrBanned should be an authorization error")
144 }
145 if !IsProcessing(ErrDuplicate) {
146 t.Error("ErrDuplicate should be a processing error")
147 }
148 if !IsPolicy(ErrKindBlocked) {
149 t.Error("ErrKindBlocked should be a policy error")
150 }
151 if !IsStorage(ErrDatabaseUnavailable) {
152 t.Error("ErrDatabaseUnavailable should be a storage error")
153 }
154 }
155
156 func TestNeedsAuthHelper(t *testing.T) {
157 if !NeedsAuth(ErrAuthRequired) {
158 t.Error("ErrAuthRequired should need auth")
159 }
160 if NeedsAuth(ErrBanned) {
161 t.Error("ErrBanned should not need auth")
162 }
163 if NeedsAuth(ErrInvalidEventID) {
164 t.Error("validation errors should not need auth")
165 }
166 }
167
168 func TestWithCause(t *testing.T) {
169 cause := errors.New("underlying error")
170 err := ErrDatabaseUnavailable.Base.WithCause(cause)
171 if err.Unwrap() != cause {
172 t.Error("WithCause should set the cause")
173 }
174 if err.Error() != "database not available: underlying error" {
175 t.Errorf("unexpected error message: %s", err.Error())
176 }
177 }
178
179 func TestWithMessage(t *testing.T) {
180 err := ErrInvalidEventID.Base.WithMessage("custom message")
181 if err.Error() != "custom message" {
182 t.Errorf("expected custom message, got %s", err.Error())
183 }
184 if err.Code() != "INVALID_ID" {
185 t.Error("code should be preserved")
186 }
187 }
188
189 func TestWithPubkey(t *testing.T) {
190 pubkey := []byte{1, 2, 3, 4}
191 err := ErrBanned.WithPubkey(pubkey)
192 if len(err.Pubkey) != 4 {
193 t.Error("pubkey should be set")
194 }
195 }
196
197 func TestWithEventID(t *testing.T) {
198 eventID := []byte{1, 2, 3, 4}
199 err := ErrDuplicate.WithEventID(eventID)
200 if len(err.EventID) != 4 {
201 t.Error("event ID should be set")
202 }
203 }
204
205 func TestWithKind(t *testing.T) {
206 err := ErrDuplicate.WithKind(30023)
207 if err.Kind != 30023 {
208 t.Errorf("expected kind 30023, got %d", err.Kind)
209 }
210 }
211