| package assertions |
| |
| import ( |
| "encoding/json" |
| "errors" |
| "fmt" |
| "math" |
| "reflect" |
| "strings" |
| |
| "github.com/smartystreets/assertions/internal/go-render/render" |
| "github.com/smartystreets/assertions/internal/oglematchers" |
| ) |
| |
| // ShouldEqual receives exactly two parameters and does an equality check |
| // using the following semantics: |
| // 1. If the expected and actual values implement an Equal method in the form |
| // `func (this T) Equal(that T) bool` then call the method. If true, they are equal. |
| // 2. The expected and actual values are judged equal or not by oglematchers.Equals. |
| func ShouldEqual(actual interface{}, expected ...interface{}) string { |
| if message := need(1, expected); message != success { |
| return message |
| } |
| return shouldEqual(actual, expected[0]) |
| } |
| func shouldEqual(actual, expected interface{}) (message string) { |
| defer func() { |
| if r := recover(); r != nil { |
| message = serializer.serialize(expected, actual, composeEqualityMismatchMessage(expected, actual)) |
| } |
| }() |
| |
| if spec := newEqualityMethodSpecification(expected, actual); spec.IsSatisfied() && spec.AreEqual() { |
| return success |
| } else if matchError := oglematchers.Equals(expected).Matches(actual); matchError == nil { |
| return success |
| } |
| |
| return serializer.serialize(expected, actual, composeEqualityMismatchMessage(expected, actual)) |
| } |
| func composeEqualityMismatchMessage(expected, actual interface{}) string { |
| var ( |
| renderedExpected = fmt.Sprintf("%v", expected) |
| renderedActual = fmt.Sprintf("%v", actual) |
| ) |
| |
| if renderedExpected != renderedActual { |
| return fmt.Sprintf(shouldHaveBeenEqual+composePrettyDiff(renderedExpected, renderedActual), expected, actual) |
| } else if reflect.TypeOf(expected) != reflect.TypeOf(actual) { |
| return fmt.Sprintf(shouldHaveBeenEqualTypeMismatch, expected, expected, actual, actual) |
| } else { |
| return fmt.Sprintf(shouldHaveBeenEqualNoResemblance, renderedExpected) |
| } |
| } |
| |
| // ShouldNotEqual receives exactly two parameters and does an inequality check. |
| // See ShouldEqual for details on how equality is determined. |
| func ShouldNotEqual(actual interface{}, expected ...interface{}) string { |
| if fail := need(1, expected); fail != success { |
| return fail |
| } else if ShouldEqual(actual, expected[0]) == success { |
| return fmt.Sprintf(shouldNotHaveBeenEqual, actual, expected[0]) |
| } |
| return success |
| } |
| |
| // ShouldAlmostEqual makes sure that two parameters are close enough to being equal. |
| // The acceptable delta may be specified with a third argument, |
| // or a very small default delta will be used. |
| func ShouldAlmostEqual(actual interface{}, expected ...interface{}) string { |
| actualFloat, expectedFloat, deltaFloat, err := cleanAlmostEqualInput(actual, expected...) |
| |
| if err != "" { |
| return err |
| } |
| |
| if math.Abs(actualFloat-expectedFloat) <= deltaFloat { |
| return success |
| } else { |
| return fmt.Sprintf(shouldHaveBeenAlmostEqual, actualFloat, expectedFloat) |
| } |
| } |
| |
| // ShouldNotAlmostEqual is the inverse of ShouldAlmostEqual |
| func ShouldNotAlmostEqual(actual interface{}, expected ...interface{}) string { |
| actualFloat, expectedFloat, deltaFloat, err := cleanAlmostEqualInput(actual, expected...) |
| |
| if err != "" { |
| return err |
| } |
| |
| if math.Abs(actualFloat-expectedFloat) > deltaFloat { |
| return success |
| } else { |
| return fmt.Sprintf(shouldHaveNotBeenAlmostEqual, actualFloat, expectedFloat) |
| } |
| } |
| |
| func cleanAlmostEqualInput(actual interface{}, expected ...interface{}) (float64, float64, float64, string) { |
| deltaFloat := 0.0000000001 |
| |
| if len(expected) == 0 { |
| return 0.0, 0.0, 0.0, "This assertion requires exactly one comparison value and an optional delta (you provided neither)" |
| } else if len(expected) == 2 { |
| delta, err := getFloat(expected[1]) |
| |
| if err != nil { |
| return 0.0, 0.0, 0.0, "The delta value " + err.Error() |
| } |
| |
| deltaFloat = delta |
| } else if len(expected) > 2 { |
| return 0.0, 0.0, 0.0, "This assertion requires exactly one comparison value and an optional delta (you provided more values)" |
| } |
| |
| actualFloat, err := getFloat(actual) |
| if err != nil { |
| return 0.0, 0.0, 0.0, "The actual value " + err.Error() |
| } |
| |
| expectedFloat, err := getFloat(expected[0]) |
| if err != nil { |
| return 0.0, 0.0, 0.0, "The comparison value " + err.Error() |
| } |
| |
| return actualFloat, expectedFloat, deltaFloat, "" |
| } |
| |
| // returns the float value of any real number, or error if it is not a numerical type |
| func getFloat(num interface{}) (float64, error) { |
| numValue := reflect.ValueOf(num) |
| numKind := numValue.Kind() |
| |
| if numKind == reflect.Int || |
| numKind == reflect.Int8 || |
| numKind == reflect.Int16 || |
| numKind == reflect.Int32 || |
| numKind == reflect.Int64 { |
| return float64(numValue.Int()), nil |
| } else if numKind == reflect.Uint || |
| numKind == reflect.Uint8 || |
| numKind == reflect.Uint16 || |
| numKind == reflect.Uint32 || |
| numKind == reflect.Uint64 { |
| return float64(numValue.Uint()), nil |
| } else if numKind == reflect.Float32 || |
| numKind == reflect.Float64 { |
| return numValue.Float(), nil |
| } else { |
| return 0.0, errors.New("must be a numerical type, but was: " + numKind.String()) |
| } |
| } |
| |
| // ShouldEqualJSON receives exactly two parameters and does an equality check by marshalling to JSON |
| func ShouldEqualJSON(actual interface{}, expected ...interface{}) string { |
| if message := need(1, expected); message != success { |
| return message |
| } |
| |
| expectedString, expectedErr := remarshal(expected[0].(string)) |
| if expectedErr != nil { |
| return "Expected value not valid JSON: " + expectedErr.Error() |
| } |
| |
| actualString, actualErr := remarshal(actual.(string)) |
| if actualErr != nil { |
| return "Actual value not valid JSON: " + actualErr.Error() |
| } |
| |
| return ShouldEqual(actualString, expectedString) |
| } |
| func remarshal(value string) (string, error) { |
| var structured interface{} |
| err := json.Unmarshal([]byte(value), &structured) |
| if err != nil { |
| return "", err |
| } |
| canonical, _ := json.Marshal(structured) |
| return string(canonical), nil |
| } |
| |
| // ShouldResemble receives exactly two parameters and does a deep equal check (see reflect.DeepEqual) |
| func ShouldResemble(actual interface{}, expected ...interface{}) string { |
| if message := need(1, expected); message != success { |
| return message |
| } |
| |
| if matchError := oglematchers.DeepEquals(expected[0]).Matches(actual); matchError != nil { |
| renderedExpected, renderedActual := render.Render(expected[0]), render.Render(actual) |
| message := fmt.Sprintf(shouldHaveResembled, renderedExpected, renderedActual) + |
| composePrettyDiff(renderedExpected, renderedActual) |
| return serializer.serializeDetailed(expected[0], actual, message) |
| } |
| |
| return success |
| } |
| |
| // ShouldNotResemble receives exactly two parameters and does an inverse deep equal check (see reflect.DeepEqual) |
| func ShouldNotResemble(actual interface{}, expected ...interface{}) string { |
| if message := need(1, expected); message != success { |
| return message |
| } else if ShouldResemble(actual, expected[0]) == success { |
| return fmt.Sprintf(shouldNotHaveResembled, render.Render(actual), render.Render(expected[0])) |
| } |
| return success |
| } |
| |
| // ShouldPointTo receives exactly two parameters and checks to see that they point to the same address. |
| func ShouldPointTo(actual interface{}, expected ...interface{}) string { |
| if message := need(1, expected); message != success { |
| return message |
| } |
| return shouldPointTo(actual, expected[0]) |
| |
| } |
| func shouldPointTo(actual, expected interface{}) string { |
| actualValue := reflect.ValueOf(actual) |
| expectedValue := reflect.ValueOf(expected) |
| |
| if ShouldNotBeNil(actual) != success { |
| return fmt.Sprintf(shouldHaveBeenNonNilPointer, "first", "nil") |
| } else if ShouldNotBeNil(expected) != success { |
| return fmt.Sprintf(shouldHaveBeenNonNilPointer, "second", "nil") |
| } else if actualValue.Kind() != reflect.Ptr { |
| return fmt.Sprintf(shouldHaveBeenNonNilPointer, "first", "not") |
| } else if expectedValue.Kind() != reflect.Ptr { |
| return fmt.Sprintf(shouldHaveBeenNonNilPointer, "second", "not") |
| } else if ShouldEqual(actualValue.Pointer(), expectedValue.Pointer()) != success { |
| actualAddress := reflect.ValueOf(actual).Pointer() |
| expectedAddress := reflect.ValueOf(expected).Pointer() |
| return serializer.serialize(expectedAddress, actualAddress, fmt.Sprintf(shouldHavePointedTo, |
| actual, actualAddress, |
| expected, expectedAddress)) |
| } |
| return success |
| } |
| |
| // ShouldNotPointTo receives exactly two parameters and checks to see that they point to different addresess. |
| func ShouldNotPointTo(actual interface{}, expected ...interface{}) string { |
| if message := need(1, expected); message != success { |
| return message |
| } |
| compare := ShouldPointTo(actual, expected[0]) |
| if strings.HasPrefix(compare, shouldBePointers) { |
| return compare |
| } else if compare == success { |
| return fmt.Sprintf(shouldNotHavePointedTo, actual, expected[0], reflect.ValueOf(actual).Pointer()) |
| } |
| return success |
| } |
| |
| // ShouldBeNil receives a single parameter and ensures that it is nil. |
| func ShouldBeNil(actual interface{}, expected ...interface{}) string { |
| if fail := need(0, expected); fail != success { |
| return fail |
| } else if actual == nil { |
| return success |
| } else if interfaceHasNilValue(actual) { |
| return success |
| } |
| return fmt.Sprintf(shouldHaveBeenNil, actual) |
| } |
| func interfaceHasNilValue(actual interface{}) bool { |
| value := reflect.ValueOf(actual) |
| kind := value.Kind() |
| nilable := kind == reflect.Slice || |
| kind == reflect.Chan || |
| kind == reflect.Func || |
| kind == reflect.Ptr || |
| kind == reflect.Map |
| |
| // Careful: reflect.Value.IsNil() will panic unless it's an interface, chan, map, func, slice, or ptr |
| // Reference: http://golang.org/pkg/reflect/#Value.IsNil |
| return nilable && value.IsNil() |
| } |
| |
| // ShouldNotBeNil receives a single parameter and ensures that it is not nil. |
| func ShouldNotBeNil(actual interface{}, expected ...interface{}) string { |
| if fail := need(0, expected); fail != success { |
| return fail |
| } else if ShouldBeNil(actual) == success { |
| return fmt.Sprintf(shouldNotHaveBeenNil, actual) |
| } |
| return success |
| } |
| |
| // ShouldBeTrue receives a single parameter and ensures that it is true. |
| func ShouldBeTrue(actual interface{}, expected ...interface{}) string { |
| if fail := need(0, expected); fail != success { |
| return fail |
| } else if actual != true { |
| return fmt.Sprintf(shouldHaveBeenTrue, actual) |
| } |
| return success |
| } |
| |
| // ShouldBeFalse receives a single parameter and ensures that it is false. |
| func ShouldBeFalse(actual interface{}, expected ...interface{}) string { |
| if fail := need(0, expected); fail != success { |
| return fail |
| } else if actual != false { |
| return fmt.Sprintf(shouldHaveBeenFalse, actual) |
| } |
| return success |
| } |
| |
| // ShouldBeZeroValue receives a single parameter and ensures that it is |
| // the Go equivalent of the default value, or "zero" value. |
| func ShouldBeZeroValue(actual interface{}, expected ...interface{}) string { |
| if fail := need(0, expected); fail != success { |
| return fail |
| } |
| zeroVal := reflect.Zero(reflect.TypeOf(actual)).Interface() |
| if !reflect.DeepEqual(zeroVal, actual) { |
| return serializer.serialize(zeroVal, actual, fmt.Sprintf(shouldHaveBeenZeroValue, actual)) |
| } |
| return success |
| } |
| |
| // ShouldBeZeroValue receives a single parameter and ensures that it is NOT |
| // the Go equivalent of the default value, or "zero" value. |
| func ShouldNotBeZeroValue(actual interface{}, expected ...interface{}) string { |
| if fail := need(0, expected); fail != success { |
| return fail |
| } |
| zeroVal := reflect.Zero(reflect.TypeOf(actual)).Interface() |
| if reflect.DeepEqual(zeroVal, actual) { |
| return serializer.serialize(zeroVal, actual, fmt.Sprintf(shouldNotHaveBeenZeroValue, actual)) |
| } |
| return success |
| } |