diff --git a/internal/encoding/error_test.go b/internal/encoding/error_test.go new file mode 100644 index 0000000..61a8bd7 --- /dev/null +++ b/internal/encoding/error_test.go @@ -0,0 +1,17 @@ +package encoding + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_encodingError(t *testing.T) { + err1 := fmt.Errorf("test error") + err2 := encodingError("encoding error") + assert.NotErrorIs(t, err1, err2) + assert.NotErrorIs(t, err2, err1) + assert.ErrorIs(t, err2, encodingError("encoding error")) + assert.NotErrorIs(t, err2, encodingError("other encodingerror")) +} diff --git a/util.go b/util.go index 117c6ac..b6dfa3c 100644 --- a/util.go +++ b/util.go @@ -37,6 +37,12 @@ func (pe ConfigParseError) Unwrap() error { return pe.err } +// Is adds a check to see if the specified target is an error of this type, see [errors.Is] +func (pe ConfigParseError) Is(err error) bool { + _, ok := err.(*ConfigParseError) + return ok +} + // toCaseInsensitiveValue checks if the value is a map; // if so, create a copy and lower-case the keys recursively. func toCaseInsensitiveValue(value any) any { diff --git a/util_test.go b/util_test.go index 8d0bda8..c32ba4b 100644 --- a/util_test.go +++ b/util_test.go @@ -11,6 +11,7 @@ package viper import ( + "fmt" "os" "path/filepath" "testing" @@ -84,3 +85,13 @@ func TestAbsPathify(t *testing.T) { assert.Equal(t, test.output, got) } } + +func TestConfigParseError(t *testing.T) { + // test a generic error + err1 := fmt.Errorf("test error") + assert.NotErrorIs(t, err1, &ConfigParseError{}) + // test the wrapped generic error + err2 := ConfigParseError{err: err1} + assert.ErrorIs(t, err2, &ConfigParseError{}) + assert.ErrorIs(t, err2.Unwrap(), err1) +} diff --git a/viper.go b/viper.go index 20eb4da..5a8ca63 100644 --- a/viper.go +++ b/viper.go @@ -61,6 +61,17 @@ func (e ConfigMarshalError) Error() string { return fmt.Sprintf("While marshaling config: %s", e.err.Error()) } +// Unwrap returns the wrapped error. +func (e ConfigMarshalError) Unwrap() error { + return e.err +} + +// Is adds a check to see if the specified target is an error of this type, see [errors.Is] +func (e ConfigMarshalError) Is(err error) bool { + _, ok := err.(*ConfigMarshalError) + return ok +} + var v *Viper type RemoteResponse struct { @@ -118,6 +129,12 @@ func (fnfe ConfigFileNotFoundError) Error() string { return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations) } +// Is adds a check to see if the specified target is an error of this type, see [errors.Is] +func (e ConfigFileNotFoundError) Is(err error) bool { + _, ok := err.(*ConfigFileNotFoundError) + return ok +} + // ConfigFileAlreadyExistsError denotes failure to write new configuration file. type ConfigFileAlreadyExistsError string diff --git a/viper_test.go b/viper_test.go index 0b1f407..6dae9e5 100644 --- a/viper_test.go +++ b/viper_test.go @@ -8,6 +8,7 @@ package viper import ( "bytes" "encoding/json" + "fmt" "io" "os" "os/exec" @@ -2696,3 +2697,60 @@ func skipWindows(t *testing.T) { t.Skip("Skip test on Windows") } } + +// Test the ConfigMarshalError +func TestConfigMarshalError(t *testing.T) { + // test a generic error + err1 := fmt.Errorf("test error") + assert.NotErrorIs(t, err1, &ConfigMarshalError{}) + // test the wrapped generic error + err2 := ConfigMarshalError{err: err1} + assert.ErrorIs(t, err2, &ConfigMarshalError{}) + assert.ErrorIs(t, err2.Unwrap(), err1) +} + +func TestUnsupportedConfigError(t *testing.T) { + err1 := fmt.Errorf("test error") + err2 := UnsupportedConfigError("some string") + assert.NotErrorIs(t, err2, err1) + assert.NotErrorIs(t, err1, err2) + assert.ErrorIs(t, err2, UnsupportedConfigError("some string")) + assert.NotErrorIs(t, err2, UnsupportedConfigError("other string")) +} + +func TestUnsupportedRemoteProviderError(t *testing.T) { + err1 := fmt.Errorf("test error") + err2 := UnsupportedRemoteProviderError("some string") + assert.NotErrorIs(t, err1, err2) + assert.NotErrorIs(t, err2, err1) + assert.ErrorIs(t, err2, UnsupportedRemoteProviderError("some string")) + assert.NotErrorIs(t, err2, UnsupportedRemoteProviderError("other string")) +} + +func TestRemoteConfigError(t *testing.T) { + err1 := fmt.Errorf("test error") + err2 := RemoteConfigError("some string") + assert.NotErrorIs(t, err1, err2) + assert.NotErrorIs(t, err2, err1) + assert.ErrorIs(t, err2, RemoteConfigError("some string")) + assert.NotErrorIs(t, err2, RemoteConfigError("other string")) +} + +func TestConfigFileNotFoundError(t *testing.T) { + err1 := fmt.Errorf("test error") + err2 := ConfigFileNotFoundError{name: "name", locations: "locations"} + assert.NotErrorIs(t, err1, err2) + assert.NotErrorIs(t, err2, err1) + assert.ErrorIs(t, err2, &ConfigFileNotFoundError{}) + assert.ErrorIs(t, err2, &ConfigFileNotFoundError{name: "name", locations: "locations"}) + assert.ErrorIs(t, err2, &ConfigFileNotFoundError{name: "other name", locations: "other locations"}) +} + +func TestConfigFileAlreadyExistsError(t *testing.T) { + err1 := fmt.Errorf("test error") + err2 := ConfigFileAlreadyExistsError("some string") + assert.NotErrorIs(t, err1, err2) + assert.NotErrorIs(t, err2, err1) + assert.ErrorIs(t, err2, ConfigFileAlreadyExistsError("some string")) + assert.NotErrorIs(t, err2, ConfigFileAlreadyExistsError("other string")) +}