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