主要功能:
- 定义哨兵错误(Sentinel Errors):ErrNilParameter, ErrInvalidCount,
ErrInvalidRange, ErrAlreadyRunning, ErrNotFound, ErrCRCMismatch 等
- 实现结构化错误类型:TopicError, FileError, IndexError, ValidationError
- 提供错误检查辅助函数:IsTopicNotFound, IsIndexOutOfRange, IsCRCMismatch
- 支持 errors.Is 和 errors.As 进行错误判断
更新相关文件使用新错误类型:
- cursor.go: 使用 ValidationError 和 ErrCRCMismatch
- index.go: 使用 IndexError 处理索引越界
- query.go: 使用 ValidationError 验证参数
- seqlog_manager.go: 使用 TopicError 和 ErrAlreadyRegistered
- topic_processor.go: 使用 ErrAlreadyRunning 和 ErrInvalidConfig
测试覆盖:
- errors_test.go 提供完整的错误类型测试
- 所有现有测试继续通过
使用示例:
```go
// 检查 topic 是否存在
if IsTopicNotFound(err) {
// 处理 topic 不存在的情况
}
// 检查索引越界
if IsIndexOutOfRange(err) {
var indexErr *IndexError
errors.As(err, &indexErr)
fmt.Printf("index %d out of range\n", indexErr.Index)
}
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
114 lines
2.8 KiB
Go
114 lines
2.8 KiB
Go
package seqlog
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
func TestErrorTypes(t *testing.T) {
|
|
t.Run("TopicError", func(t *testing.T) {
|
|
err := NewTopicError("app", "write", ErrNotFound)
|
|
if err.Error() != "topic app: write: not found" {
|
|
t.Errorf("unexpected error message: %v", err)
|
|
}
|
|
|
|
// 测试 Unwrap
|
|
if !errors.Is(err, ErrNotFound) {
|
|
t.Error("expected ErrNotFound")
|
|
}
|
|
|
|
// 测试 errors.As
|
|
var topicErr *TopicError
|
|
if !errors.As(err, &topicErr) {
|
|
t.Error("expected TopicError")
|
|
}
|
|
if topicErr.Topic != "app" {
|
|
t.Errorf("expected topic 'app', got '%s'", topicErr.Topic)
|
|
}
|
|
})
|
|
|
|
t.Run("FileError", func(t *testing.T) {
|
|
err := NewFileError("/path/to/file", "open", errors.New("permission denied"))
|
|
if err.Error() != "file /path/to/file: open: permission denied" {
|
|
t.Errorf("unexpected error message: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("IndexError", func(t *testing.T) {
|
|
err := NewIndexError(100, 50)
|
|
if err.Error() != "index 100 out of range [0, 50): invalid index or range" {
|
|
t.Errorf("unexpected error message: %v", err)
|
|
}
|
|
|
|
// 测试 errors.Is
|
|
if !errors.Is(err, ErrInvalidRange) {
|
|
t.Error("expected ErrInvalidRange")
|
|
}
|
|
|
|
// 测试 IsIndexOutOfRange
|
|
if !IsIndexOutOfRange(err) {
|
|
t.Error("expected IsIndexOutOfRange to return true")
|
|
}
|
|
})
|
|
|
|
t.Run("ValidationError", func(t *testing.T) {
|
|
err := NewValidationError("count", "must be greater than 0", ErrInvalidCount)
|
|
if err.Error() != "validation error: count: must be greater than 0: count must be greater than 0" {
|
|
t.Errorf("unexpected error message: %v", err)
|
|
}
|
|
|
|
// 测试 errors.Is
|
|
if !errors.Is(err, ErrInvalidCount) {
|
|
t.Error("expected ErrInvalidCount")
|
|
}
|
|
})
|
|
|
|
t.Run("IsTopicNotFound", func(t *testing.T) {
|
|
err := NewTopicError("app", "get", ErrNotFound)
|
|
if !IsTopicNotFound(err) {
|
|
t.Error("expected IsTopicNotFound to return true")
|
|
}
|
|
|
|
// 测试其他错误
|
|
if IsTopicNotFound(ErrInvalidCount) {
|
|
t.Error("expected IsTopicNotFound to return false for ErrInvalidCount")
|
|
}
|
|
})
|
|
|
|
t.Run("IsCRCMismatch", func(t *testing.T) {
|
|
if !IsCRCMismatch(ErrCRCMismatch) {
|
|
t.Error("expected IsCRCMismatch to return true")
|
|
}
|
|
|
|
// 测试其他错误
|
|
if IsCRCMismatch(ErrNotFound) {
|
|
t.Error("expected IsCRCMismatch to return false for ErrNotFound")
|
|
}
|
|
})
|
|
|
|
t.Run("SentinelErrors", func(t *testing.T) {
|
|
// 测试所有哨兵错误都不为 nil
|
|
sentinelErrors := []error{
|
|
ErrNilParameter,
|
|
ErrInvalidCount,
|
|
ErrInvalidRange,
|
|
ErrAlreadyRunning,
|
|
ErrNotRunning,
|
|
ErrAlreadyRegistered,
|
|
ErrNotFound,
|
|
ErrCRCMismatch,
|
|
ErrInvalidUUID,
|
|
ErrInvalidConfig,
|
|
}
|
|
|
|
for _, err := range sentinelErrors {
|
|
if err == nil {
|
|
t.Error("sentinel error should not be nil")
|
|
}
|
|
if err.Error() == "" {
|
|
t.Error("sentinel error should have a message")
|
|
}
|
|
}
|
|
})
|
|
}
|