Merge pull request #265 from ernesto-jimenez/issue-257

Fixes #257 - InEpsilon works when actual == 0
pull/269/head
Ernesto Jiménez 2016-01-09 17:54:56 +01:00
commit ac0e5818a1
2 changed files with 25 additions and 25 deletions

View File

@ -766,42 +766,40 @@ func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAn
return true
}
// min(|expected|, |actual|) * epsilon
func calcEpsilonDelta(expected, actual interface{}, epsilon float64) float64 {
func calcRelativeError(expected, actual interface{}) (float64, error) {
af, aok := toFloat(expected)
if !aok {
return 0, fmt.Errorf("expected value %q cannot be converted to float", expected)
}
if af == 0 {
return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error")
}
bf, bok := toFloat(actual)
if !aok || !bok {
// invalid input
return 0
if !bok {
return 0, fmt.Errorf("expected value %q cannot be converted to float", actual)
}
if af < 0 {
af = -af
}
if bf < 0 {
bf = -bf
}
var delta float64
if af < bf {
delta = af * epsilon
} else {
delta = bf * epsilon
}
return delta
return math.Abs(af-bf) / math.Abs(af), nil
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
delta := calcEpsilonDelta(expected, actual, epsilon)
actualEpsilon, err := calcRelativeError(expected, actual)
if err != nil {
return Fail(t, err.Error(), msgAndArgs...)
}
if actualEpsilon > epsilon {
return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
" < %#v (actual)", actualEpsilon, epsilon), msgAndArgs...)
}
return InDelta(t, expected, actual, delta, msgAndArgs...)
return true
}
// InEpsilonSlice is the same as InEpsilon, except it compares two slices.
func InEpsilonSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
if expected == nil || actual == nil ||
reflect.TypeOf(actual).Kind() != reflect.Slice ||
reflect.TypeOf(expected).Kind() != reflect.Slice {
@ -812,7 +810,7 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, delta float64, msg
expectedSlice := reflect.ValueOf(expected)
for i := 0; i < actualSlice.Len(); i++ {
result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta)
result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), epsilon)
if !result {
return result
}

View File

@ -830,10 +830,11 @@ func TestInEpsilon(t *testing.T) {
{-2.2, -2.1, 0.1},
{uint64(100), uint8(101), 0.01},
{0.1, -0.1, 2},
{0.1, 0, 2},
}
for _, tc := range cases {
True(t, InEpsilon(mockT, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
True(t, InEpsilon(t, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon), "test: %q", tc)
}
cases = []struct {
@ -847,6 +848,7 @@ func TestInEpsilon(t *testing.T) {
{2.1, -2.2, 1},
{2.1, "bla-bla", 0},
{0.1, -0.1, 1.99},
{0, 0.1, 2}, // expected must be different to zero
}
for _, tc := range cases {