diff --git a/internal/cli/errors.go b/internal/cli/errors.go index 580e703..58597e1 100644 --- a/internal/cli/errors.go +++ b/internal/cli/errors.go @@ -10,6 +10,10 @@ func (e printedError) Error() string { return e.err.Error() } +func (e printedError) Unwrap() error { + return e.err +} + func markError(err error) error { if err == nil { return nil diff --git a/internal/cli/errors_test.go b/internal/cli/errors_test.go new file mode 100644 index 0000000..c67329b --- /dev/null +++ b/internal/cli/errors_test.go @@ -0,0 +1,70 @@ +package cli + +import ( + "errors" + "fmt" + "testing" + + "github.com/JulienTant/blogwatcher-cli/internal/controller" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMarkErrorReturnsNilForNilInput(t *testing.T) { + require.NoError(t, markError(nil)) +} + +func TestIsPrintedReturnsTrueForMarkedError(t *testing.T) { + err := markError(errors.New("something")) + assert.True(t, isPrinted(err)) +} + +func TestIsPrintedReturnsFalseForUnmarkedError(t *testing.T) { + err := errors.New("not printed") + assert.False(t, isPrinted(err)) +} + +func TestPrintedErrorUnwrapWithErrorsIs(t *testing.T) { + sentinel := errors.New("sentinel") + wrapped := markError(sentinel) + + assert.ErrorIs(t, wrapped, sentinel) +} + +func TestPrintedErrorUnwrapWithBlogNotFoundError(t *testing.T) { + original := controller.BlogNotFoundError{Name: "myblog"} + wrapped := markError(original) + + var target controller.BlogNotFoundError + require.ErrorAs(t, wrapped, &target) + assert.Equal(t, "myblog", target.Name) +} + +func TestPrintedErrorUnwrapWithBlogAlreadyExistsError(t *testing.T) { + original := controller.BlogAlreadyExistsError{Field: "name", Value: "dup"} + wrapped := markError(original) + + var target controller.BlogAlreadyExistsError + require.ErrorAs(t, wrapped, &target) + assert.Equal(t, "name", target.Field) + assert.Equal(t, "dup", target.Value) +} + +func TestPrintedErrorUnwrapWithArticleNotFoundError(t *testing.T) { + original := controller.ArticleNotFoundError{ID: 42} + wrapped := markError(original) + + var target controller.ArticleNotFoundError + require.ErrorAs(t, wrapped, &target) + assert.Equal(t, int64(42), target.ID) +} + +func TestPrintedErrorUnwrapDoubleWrapped(t *testing.T) { + original := controller.BlogNotFoundError{Name: "deep"} + fmtWrapped := fmt.Errorf("wrapper: %w", original) + printed := markError(fmtWrapped) + + var target controller.BlogNotFoundError + require.ErrorAs(t, printed, &target) + assert.Equal(t, "deep", target.Name) +} diff --git a/internal/controller/errors_test.go b/internal/controller/errors_test.go new file mode 100644 index 0000000..ec5b780 --- /dev/null +++ b/internal/controller/errors_test.go @@ -0,0 +1,52 @@ +package controller + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestBlogNotFoundErrorMessage(t *testing.T) { + err := BlogNotFoundError{Name: "testblog"} + assert.Equal(t, "Blog 'testblog' not found", err.Error()) +} + +func TestBlogAlreadyExistsErrorMessage(t *testing.T) { + err := BlogAlreadyExistsError{Field: "URL", Value: "https://example.com"} + assert.Equal(t, "Blog with URL 'https://example.com' already exists", err.Error()) +} + +func TestArticleNotFoundErrorMessage(t *testing.T) { + err := ArticleNotFoundError{ID: 99} + assert.Equal(t, "Article 99 not found", err.Error()) +} + +func TestBlogNotFoundErrorWrappedWithFmtErrorf(t *testing.T) { + original := BlogNotFoundError{Name: "wrapped"} + wrapped := fmt.Errorf("operation failed: %w", original) + + var target BlogNotFoundError + require.ErrorAs(t, wrapped, &target) + assert.Equal(t, "wrapped", target.Name) +} + +func TestBlogAlreadyExistsErrorWrappedWithFmtErrorf(t *testing.T) { + original := BlogAlreadyExistsError{Field: "name", Value: "dup"} + wrapped := fmt.Errorf("add failed: %w", original) + + var target BlogAlreadyExistsError + require.ErrorAs(t, wrapped, &target) + assert.Equal(t, "name", target.Field) + assert.Equal(t, "dup", target.Value) +} + +func TestArticleNotFoundErrorWrappedWithFmtErrorf(t *testing.T) { + original := ArticleNotFoundError{ID: 7} + wrapped := fmt.Errorf("mark read failed: %w", original) + + var target ArticleNotFoundError + require.ErrorAs(t, wrapped, &target) + assert.Equal(t, int64(7), target.ID) +}