diff options
| author | Paul Buetow <paul@buetow.org> | 2025-06-19 20:29:21 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-06-19 20:29:21 +0300 |
| commit | 2f20d0eacfbc16111fa273f4d6cac339cc61ef51 (patch) | |
| tree | 43057356276c3971e410d21c909de69eaee0f605 /internal/errors/errors.go | |
| parent | 1a9259eb9a10202c28dbd959e6cfa2e2fcf3e064 (diff) | |
Implement Phase 1: Foundation for improved maintainability and testability
- Add standardized error handling package (internal/errors)
- Sentinel errors for common conditions
- Error wrapping and chaining support
- MultiError for batch operations
- Add comprehensive test utilities package (internal/testutil)
- File/directory test helpers
- Assertion functions for common test patterns
- Mock SSH server for integration testing
- Test data generators
- Add unit tests for core packages
- Protocol package: delimiter validation and usage tests
- Config package: comprehensive configuration tests
- Discovery package: server discovery method tests
- IO/FS package: stats tracking and grep processor tests
All tests passing. This establishes a solid foundation for further improvements.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'internal/errors/errors.go')
| -rw-r--r-- | internal/errors/errors.go | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/internal/errors/errors.go b/internal/errors/errors.go new file mode 100644 index 0000000..bb53efd --- /dev/null +++ b/internal/errors/errors.go @@ -0,0 +1,137 @@ +package errors + +import ( + "errors" + "fmt" +) + +// Sentinel errors for common error conditions +var ( + // Connection errors + ErrConnectionFailed = errors.New("connection failed") + ErrConnectionTimeout = errors.New("connection timeout") + ErrConnectionRefused = errors.New("connection refused") + ErrTooManyConnections = errors.New("too many connections") + + // Authentication/Permission errors + ErrPermissionDenied = errors.New("permission denied") + ErrAuthenticationFailed = errors.New("authentication failed") + ErrUnauthorized = errors.New("unauthorized") + ErrInvalidCredentials = errors.New("invalid credentials") + + // Configuration errors + ErrInvalidConfig = errors.New("invalid configuration") + ErrMissingConfig = errors.New("missing configuration") + ErrConfigValidation = errors.New("configuration validation failed") + + // File/IO errors + ErrFileNotFound = errors.New("file not found") + ErrFileAccessDenied = errors.New("file access denied") + ErrInvalidPath = errors.New("invalid path") + ErrReadFailed = errors.New("read failed") + ErrWriteFailed = errors.New("write failed") + + // Protocol errors + ErrInvalidProtocol = errors.New("invalid protocol") + ErrProtocolMismatch = errors.New("protocol version mismatch") + ErrInvalidCommand = errors.New("invalid command") + ErrInvalidQuery = errors.New("invalid query") + + // Resource errors + ErrResourceExhausted = errors.New("resource exhausted") + ErrBufferFull = errors.New("buffer full") + ErrTimeout = errors.New("operation timeout") + + // General errors + ErrInvalidArgument = errors.New("invalid argument") + ErrNotImplemented = errors.New("not implemented") + ErrInternal = errors.New("internal error") +) + +// Error wrapping functions + +// Wrap wraps an error with additional context +func Wrap(err error, msg string) error { + if err == nil { + return nil + } + return fmt.Errorf("%s: %w", msg, err) +} + +// Wrapf wraps an error with formatted context +func Wrapf(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + return fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err) +} + +// New creates a new error with formatted message +func New(format string, args ...interface{}) error { + return fmt.Errorf(format, args...) +} + +// Is checks if an error is of a specific type +func Is(err, target error) bool { + return errors.Is(err, target) +} + +// As attempts to extract a specific error type +func As(err error, target interface{}) bool { + return errors.As(err, target) +} + +// Unwrap returns the wrapped error +func Unwrap(err error) error { + return errors.Unwrap(err) +} + +// Multi-error support for operations that can have multiple failures + +// MultiError represents multiple errors +type MultiError struct { + errors []error +} + +// NewMultiError creates a new MultiError +func NewMultiError() *MultiError { + return &MultiError{ + errors: make([]error, 0), + } +} + +// Add adds an error to the MultiError +func (m *MultiError) Add(err error) { + if err != nil { + m.errors = append(m.errors, err) + } +} + +// HasErrors returns true if there are any errors +func (m *MultiError) HasErrors() bool { + return len(m.errors) > 0 +} + +// Error implements the error interface +func (m *MultiError) Error() string { + if len(m.errors) == 0 { + return "" + } + if len(m.errors) == 1 { + return m.errors[0].Error() + } + return fmt.Sprintf("multiple errors occurred: %v", m.errors) +} + +// Errors returns all collected errors +func (m *MultiError) Errors() []error { + return m.errors +} + +// ErrorOrNil returns nil if no errors, otherwise returns the MultiError +func (m *MultiError) ErrorOrNil() error { + if m.HasErrors() { + return m + } + return nil +}
\ No newline at end of file |
