Skip to content

Commit

Permalink
adds basic error assertions (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
ppapapetrou76 authored Apr 23, 2021
1 parent eb11bec commit 8a747c0
Show file tree
Hide file tree
Showing 6 changed files with 479 additions and 233 deletions.
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ issues:
- golint
- paralleltest
- testpackage
- goerr113
- path: github/client
linters:
- gosec
Expand Down
225 changes: 55 additions & 170 deletions assert/error.go
Original file line number Diff line number Diff line change
@@ -1,190 +1,75 @@
package assert

import (
"fmt"
"reflect"
"strings"
"testing"

utils2 "github.com/ppapapetrou76/go-testing/internal/pkg/utils"
"github.com/ppapapetrou76/go-testing/types"
"github.com/r3labs/diff/v2"
"github.com/ppapapetrou76/go-testing/internal/pkg/values"
)

func shouldBeEqual(actual types.Assertable, expected interface{}) string {
diffMessage := strings.Builder{}
skipDetailedDiff := utils2.HasUnexportedFields(reflect.ValueOf(expected)) || utils2.HasUnexportedFields(reflect.ValueOf(actual.Value()))

if !skipDetailedDiff {
diffs, _ := diff.Diff(expected, actual.Value())
for _, d := range diffs {
if len(d.Path) == 0 {
continue
}
switch d.Type {
case "delete":
path := strings.Join(d.Path, ":")
diffMessage.WriteString(fmt.Sprintf("actual value of %+v is expected but missing from %s\n", d.To, path))
case "create":
path := strings.Join(d.Path, ":")
diffMessage.WriteString(fmt.Sprintf("actual value of %+v is not expected in %s\n", d.To, path))
case "update":
path := strings.Join(d.Path, ":")
diffMessage.WriteString(fmt.Sprintf("actual value of %+v is different in %s from %+v\n", d.To, path, d.From))
}
}
}

return fmt.Sprintf("assertion failed:\nexpected value\t:%+v\nactual value\t:%+v\n%s", expected, actual.Value(), diffMessage.String())
}

func shouldNotBeEqual(actual types.Assertable, expected interface{}) string {
return fmt.Sprintf("assertion failed: expected value of = %+v, to be other than %+v", actual.Value(), expected)
}

func shouldBeGreater(actual types.Assertable, expected interface{}) string {
return fmt.Sprintf("assertion failed: expected value of = %+v, to be greater than %+v", actual.Value(), expected)
}

func shouldBeGreaterOrEqual(actual types.Assertable, expected interface{}) string {
return fmt.Sprintf("assertion failed: expected value of = %+v, to be greater than or equal to %+v", actual.Value(), expected)
}

func shouldBeLessThan(actual types.Assertable, expected interface{}) string {
return fmt.Sprintf("assertion failed: expected value of = %+v, to be less than %+v", actual.Value(), expected)
}

func shouldBeLessOrEqual(actual types.Assertable, expected interface{}) string {
return fmt.Sprintf("assertion failed: expected value of = %+v, to be less than or equal to %+v", actual.Value(), expected)
}

func shouldBeEmpty(actual types.Assertable) string {
return fmt.Sprintf("assertion failed: expected %+v to be empty, but it's not", actual.Value())
}

func shouldNotBeEmpty(actual types.Assertable) string {
return fmt.Sprintf("assertion failed: expected %+v not to be empty, but it is", actual.Value())
}

func shouldBeNil(actual types.Assertable) string {
return fmt.Sprintf("assertion failed: expected value of = %+v, to be nil but it wasn't", actual.Value())
}

func shouldNotBeNil(actual types.Assertable) string {
return fmt.Sprintf("assertion failed: expected value of = %+v, to be non-nil but it was", actual.Value())
}

func shouldHaveSize(actual types.Sizeable, expected int) string {
return fmt.Sprintf("assertion failed: expected size of = [%d], to be but it has size of [%d] ", actual.Size(), expected)
}

func shouldContain(actual types.Assertable, elements interface{}) string {
return fmt.Sprintf("assertion failed: containable [%v] should contain [%+v], but it doesn't", actual.Value(), elements)
}

func shouldContainIgnoringCase(actual types.Assertable, elements interface{}) string {
return fmt.Sprintf("assertion failed: containable [%v] should contain [%+v] ignoring case, but it doesn't", actual.Value(), elements)
}

func shouldContainOnly(actual types.Assertable, elements interface{}) string {
return fmt.Sprintf("assertion failed: containable [%v] should contain only [%+v], but it doesn't", actual.Value(), elements)
}

func shouldContainOnlyOnce(actual types.Assertable, elements interface{}) string {
return fmt.Sprintf("assertion failed: containable [%v] should contain [%+v] only once, but it doesn't", actual.Value(), elements)
}

func shouldContainWhiteSpace(actual types.Assertable) string {
return fmt.Sprintf("assertion failed: containable [%v] should contain whitespace(s), but it doesn't", actual.Value())
}

func shouldNotContainAnyWhiteSpace(actual types.Assertable) string {
return fmt.Sprintf("assertion failed: containable [%v] should not contain any whitespace, but it does", actual.Value())
}

func shouldNotContain(actual types.Assertable, elements interface{}) string {
return fmt.Sprintf("assertion failed: containable [%v] should not contain [%+v], but it does", actual.Value(), elements)
// AssertableError is the assertable structure for error values.
type AssertableError struct {
t *testing.T
actual values.ErrorValue
}

func shouldBeMap(actual types.Assertable) string {
return fmt.Sprintf("assertion failed: assertable should be a map but it is %T", reflect.ValueOf(actual.Value()).Kind())
}

func shouldHaveKey(actual types.Assertable, elements interface{}) string {
return fmt.Sprintf("assertion failed: map [%v] should have the key [%+v], but it doesn't", actual.Value(), elements)
}

func shouldHaveValue(actual types.Assertable, elements interface{}) string {
return fmt.Sprintf("assertion failed: map [%v] should have the value [%+v], but it doesn't", actual.Value(), elements)
}

func shouldHaveEntry(actual types.Assertable, entry types.MapEntry) string {
return fmt.Sprintf("assertion failed: map [%v] should have the entry [%+v], but it doesn't", actual.Value(), entry)
}

func shouldNotHaveKey(actual types.Assertable, elements interface{}) string {
return fmt.Sprintf("assertion failed: map [%v] should not have the key [%+v], but it does", actual.Value(), elements)
}

func shouldNotHaveValue(actual types.Assertable, elements interface{}) string {
return fmt.Sprintf("assertion failed: map [%v] should not have the value [%+v], but it does", actual.Value(), elements)
}

func shouldNotHaveEntry(actual types.Assertable, entry types.MapEntry) string {
return fmt.Sprintf("assertion failed: map [%v] should not have the entry [%+v], but it does", actual.Value(), entry)
}

func shouldStartWith(actual types.Assertable, substr string) string {
return fmt.Sprintf("assertion failed: expected value of [%v] to start with [%+v], but it doesn't", actual.Value(), substr)
}

func shouldNotStartWith(actual types.Assertable, substr string) string {
return fmt.Sprintf("assertion failed: expected value of [%v] to not start with [%+v], but it does", actual.Value(), substr)
}

func shouldEndWith(actual types.Assertable, substr string) string {
return fmt.Sprintf("assertion failed: expected value of [%v] to end with [%+v], but it doesn't", actual.Value(), substr)
}

func shouldNotEndWith(actual types.Assertable, substr string) string {
return fmt.Sprintf("assertion failed: expected value of [%v] to not end with [%+v], but it does", actual.Value(), substr)
}

func shouldHaveSameSizeAs(actual types.Assertable, substr string) string {
return fmt.Sprintf("assertion failed: expected size of [%v] should be same as the size of [%+v], but it isn't", actual.Value(), substr)
}

func shouldHaveType(actual types.Assertable, value interface{}) string {
return fmt.Sprintf("assertion failed: expected value of = %+v, to have type of %T but it hasn't", actual.Value(), value)
}

func shouldBeShorter(actual types.Assertable, expected interface{}) string {
return fmt.Sprintf("assertion failed: expected value of = %+v, to be greater than %+v", actual.Value(), expected)
// ThatError returns an AssertableError structure initialized with the test reference and the actual value to assert.
func ThatError(t *testing.T, actual error) AssertableError {
t.Helper()
return AssertableError{
t: t,
actual: values.NewErrorValue(actual),
}
}

func shouldBeLonger(actual types.Assertable, expected interface{}) string {
return fmt.Sprintf("assertion failed: expected value of = %+v, to be longer than %+v", actual.Value(), expected)
// IsNil asserts if the expected error is nil.
func (a AssertableError) IsNil() AssertableError {
errAnyValue := values.NewAnyValue(a.actual.Value())
if errAnyValue.IsNotNil() {
a.t.Error(shouldBeNil(errAnyValue))
}
return a
}

func shouldContainOnlyDigits(actual types.Assertable) string {
return fmt.Sprintf("assertion failed: expected %+v to have only digits, but it's not", actual.Value())
// IsNotNil asserts if the expected error is nil.
func (a AssertableError) IsNotNil() AssertableError {
errAnyValue := values.NewAnyValue(a.actual.Value())
if errAnyValue.IsNil() {
a.t.Error(shouldNotBeNil(errAnyValue))
}
return a
}

func shouldBeLowerCase(actual types.Assertable) string {
return fmt.Sprintf("assertion failed: expected %+v to be lower case, but it's not", actual.Value())
}
// HasExactMessage asserts if the expected error contains exactly the given message.
func (a AssertableError) HasExactMessage(expectedMessage string) AssertableError {
errAnyValue := values.NewAnyValue(a.actual.Value())
if errAnyValue.IsNil() {
a.t.Error(shouldContain(errAnyValue, expectedMessage))
return a
}

func shouldBeUpperCase(actual types.Assertable) string {
return fmt.Sprintf("assertion failed: expected %+v to be upper case, but it's not", actual.Value())
errStringValue := values.NewStringValue(a.actual.Error().Error())
if !errStringValue.ContainsOnly(expectedMessage) {
a.t.Error(shouldContain(errAnyValue, expectedMessage))
}
return a
}

func shouldBeAlmostSame(actual types.Assertable, expected interface{}) string {
return fmt.Sprintf("assertion failed: expected value of = %+v, to be almost the same as %+v", actual.Value(), expected)
}
// IsSameAs asserts if the expected error is the same with the given error.
func (a AssertableError) IsSameAs(err error) AssertableError {
actualAnyValue := values.NewAnyValue(a.actual.Value())
expectedAnyValue := values.NewAnyValue(err)

func shouldBeDefined(actual types.Assertable) string {
return fmt.Sprintf("assertion failed: expected value of = %+v, to be defined but it was not", actual.Value())
}
if actualAnyValue.IsNil() != expectedAnyValue.IsNil() {
a.t.Error(shouldBeEqual(a.actual, expectedAnyValue))
return a
}
if actualAnyValue.IsNil() && expectedAnyValue.IsNil() {
return a
}

func shouldNotBeDefined(actual types.Assertable) string {
return fmt.Sprintf("assertion failed: expected value of = %+v, to be un-defined but it was", actual.Value())
actualStringValue := values.NewStringValue(a.actual.Error().Error())
if !actualStringValue.IsEqualTo(err.Error()) {
a.t.Error(shouldBeEqual(a.actual, err.Error()))
}
return a
}
Loading

0 comments on commit 8a747c0

Please sign in to comment.