Files
seqlog/errors_test.go
bourdon 6862de12ff 新增:统一的错误类型系统 (errors.go)
主要功能:
- 定义哨兵错误(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>
2025-10-04 01:56:22 +08:00

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")
}
}
})
}