Skip to content

Commit

Permalink
Refine InDeltaRelative
Browse files Browse the repository at this point in the history
  • Loading branch information
gavv committed Oct 7, 2023
1 parent d543978 commit 2b1131c
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 99 deletions.
197 changes: 99 additions & 98 deletions number.go
Expand Up @@ -197,7 +197,17 @@ func (n *Number) InDelta(value, delta float64) *Number {
return n
}

if math.IsNaN(n.value) || math.IsNaN(value) || math.IsNaN(delta) {
if math.IsNaN(delta) {
opChain.fail(AssertionFailure{
Type: AssertUsage,
Errors: []error{
errors.New("unexpected NaN delta argument"),
},
})
return n
}

if math.IsNaN(n.value) || math.IsNaN(value) {
opChain.fail(AssertionFailure{
Type: AssertEqual,
Actual: &AssertionValue{n.value},
Expand Down Expand Up @@ -242,7 +252,17 @@ func (n *Number) NotInDelta(value, delta float64) *Number {
return n
}

if math.IsNaN(n.value) || math.IsNaN(value) || math.IsNaN(delta) {
if math.IsNaN(delta) {
opChain.fail(AssertionFailure{
Type: AssertUsage,
Errors: []error{
errors.New("unexpected NaN delta argument"),
},
})
return n
}

if math.IsNaN(n.value) || math.IsNaN(value) {
opChain.fail(AssertionFailure{
Type: AssertNotEqual,
Actual: &AssertionValue{n.value},
Expand Down Expand Up @@ -273,6 +293,16 @@ func (n *Number) NotInDelta(value, delta float64) *Number {
return n
}

// Deprecated: use InDelta instead.
func (n *Number) EqualDelta(value, delta float64) *Number {
return n.InDelta(value, delta)
}

// Deprecated: use NotInDelta instead.
func (n *Number) NotEqualDelta(value, delta float64) *Number {
return n.NotInDelta(value, delta)
}

// InDeltaRelative succeeds if two numbers are within relative delta of each other.
//
// The relative delta is expressed as a decimal. For example, to determine if a number
Expand All @@ -296,37 +326,52 @@ func (n *Number) InDeltaRelative(value, delta float64) *Number {
return n
}

anyNumIsNaN := math.IsNaN(n.value) || math.IsNaN(value) || math.IsNaN(delta)

if anyNumIsNaN {
assertionErrors := numNaNCheck(n.value, value, delta)

if math.IsNaN(delta) || math.IsInf(delta, 0) {
opChain.fail(AssertionFailure{
Type: AssertEqual,
Actual: &AssertionValue{n.value},
Expected: &AssertionValue{value},
Delta: &AssertionValue{relativeDelta(delta)},
Errors: assertionErrors,
Type: AssertUsage,
Errors: []error{
fmt.Errorf("unexpected non-number delta argument: %v", delta),
},
})
return n
}

if math.IsInf(delta, 0) {
if delta < 0 {
opChain.fail(AssertionFailure{
Type: AssertUsage,
Errors: []error{
errors.New("unexpected Inf delta argument"),
fmt.Errorf("unexpected negative delta argument: %v", delta),
},
})
return n
}

if delta < 0 {
// Fail if any of the numbers is NaN with specific error message
anyNumIsNaN := math.IsNaN(n.value) || math.IsNaN(value)
if anyNumIsNaN {
var assertionErrors []error
assertionErrors = append(
assertionErrors,
errors.New("expected: can compare values with relative delta"),
)
if math.IsNaN(n.value) {
assertionErrors = append(
assertionErrors,
errors.New("actual value is NaN"),
)
}
if math.IsNaN(value) {
assertionErrors = append(
assertionErrors,
errors.New("expected value is NaN"),
)
}
opChain.fail(AssertionFailure{
Type: AssertUsage,
Errors: []error{
errors.New("unexpected negative delta argument"),
},
Type: AssertEqual,
Actual: &AssertionValue{n.value},
Expected: &AssertionValue{value},
Delta: &AssertionValue{relativeDelta(delta)},
Errors: assertionErrors,
})
return n
}
Expand Down Expand Up @@ -357,6 +402,7 @@ func (n *Number) InDeltaRelative(value, delta float64) *Number {
return n
}

// Normal comparison after filtering out all corner cases
deltaRelativeError := deltaRelativeErrorCheck(true, n.value, value, delta)
if deltaRelativeError {
opChain.fail(AssertionFailure{
Expand Down Expand Up @@ -397,37 +443,52 @@ func (n *Number) NotInDeltaRelative(value, delta float64) *Number {
return n
}

anyNumIsNaN := math.IsNaN(n.value) || math.IsNaN(value) || math.IsNaN(delta)

if anyNumIsNaN {
assertionErrors := numNaNCheck(n.value, value, delta)

if math.IsNaN(delta) || math.IsInf(delta, 0) {
opChain.fail(AssertionFailure{
Type: AssertEqual,
Actual: &AssertionValue{n.value},
Expected: &AssertionValue{value},
Delta: &AssertionValue{relativeDelta(delta)},
Errors: assertionErrors,
Type: AssertUsage,
Errors: []error{
fmt.Errorf("unexpected non-number delta argument: %v", delta),
},
})
return n
}

if math.IsInf(delta, 0) {
if delta < 0 {
opChain.fail(AssertionFailure{
Type: AssertUsage,
Errors: []error{
errors.New("unexpected Inf delta argument"),
fmt.Errorf("unexpected negative delta argument: %v", delta),
},
})
return n
}

if delta < 0 {
// Fail if any of the numbers is NaN with specific error message
anyNumIsNaN := math.IsNaN(n.value) || math.IsNaN(value)
if anyNumIsNaN {
var assertionErrors []error
assertionErrors = append(
assertionErrors,
errors.New("expected: can compare values with relative delta"),
)
if math.IsNaN(n.value) {
assertionErrors = append(
assertionErrors,
errors.New("actual value is NaN"),
)
}
if math.IsNaN(value) {
assertionErrors = append(
assertionErrors,
errors.New("expected value is NaN"),
)
}
opChain.fail(AssertionFailure{
Type: AssertUsage,
Errors: []error{
errors.New("unexpected negative delta argument"),
},
Type: AssertEqual,
Actual: &AssertionValue{n.value},
Expected: &AssertionValue{value},
Delta: &AssertionValue{relativeDelta(delta)},
Errors: assertionErrors,
})
return n
}
Expand All @@ -448,25 +509,13 @@ func (n *Number) NotInDeltaRelative(value, delta float64) *Number {
return n
}

// Fail is number and value are +=Inf and unequal with specific error message
// Pass if number and value are +=Inf and unequal
diffInfNumCheck := math.IsInf(n.value, 0) && math.IsInf(value, 0) && value != n.value
if diffInfNumCheck {
var assertionErrors []error
assertionErrors = append(
assertionErrors,
errors.New("expected: can compare values with relative delta"),
errors.New("actual value and expected value are opposite Infs"),
)
opChain.fail(AssertionFailure{
Type: AssertEqual,
Actual: &AssertionValue{n.value},
Expected: &AssertionValue{value},
Delta: &AssertionValue{relativeDelta(delta)},
Errors: assertionErrors,
})
return n
}

// Normal comparison after filtering out all corner cases
deltaRelativeError := deltaRelativeErrorCheck(false, n.value, value, delta)
if deltaRelativeError {
opChain.fail(AssertionFailure{
Expand All @@ -484,16 +533,6 @@ func (n *Number) NotInDeltaRelative(value, delta float64) *Number {
return n
}

// Deprecated: use InDelta instead.
func (n *Number) EqualDelta(value, delta float64) *Number {
return n.InDelta(value, delta)
}

// Deprecated: use NotInDelta instead.
func (n *Number) NotEqualDelta(value, delta float64) *Number {
return n.NotInDelta(value, delta)
}

// InRange succeeds if number is within given range [min; max].
//
// min and max should have numeric type convertible to float64. Before comparison,
Expand Down Expand Up @@ -1309,13 +1348,6 @@ func (rd relativeDelta) String() string {
return fmt.Sprintf("%v (%.f%%)", float64(rd), rd*100)
}

func appendError(errorSlice []error, errorMsg string) []error {
return append(
errorSlice,
errors.New(errorMsg),
)
}

func deltaRelativeErrorCheck(inDeltaRelative bool, number, value, delta float64) bool {
if (number == 0 || math.IsInf(number, 0)) && value != number {
return true
Expand All @@ -1331,34 +1363,3 @@ func deltaRelativeErrorCheck(inDeltaRelative bool, number, value, delta float64)
}
return false
}

func numNaNCheck(number, value, delta float64) []error {
var assertionErrors []error
assertionErrors = appendError(
assertionErrors,
"expected: can compare values with relative delta",
)

if math.IsNaN(number) {
assertionErrors = appendError(
assertionErrors,
"actual value is NaN",
)
}

if math.IsNaN(value) {
assertionErrors = appendError(
assertionErrors,
"expected value is NaN",
)
}

if math.IsNaN(delta) {
assertionErrors = appendError(
assertionErrors,
"delta is NaN",
)
}

return assertionErrors
}
34 changes: 33 additions & 1 deletion number_test.go
Expand Up @@ -400,6 +400,14 @@ func TestNumber_InDeltaRelative(t *testing.T) {
wantInDelta: failure,
wantNotInDelta: failure,
},
{
name: "delta is -Inf",
number: 1234.5,
value: 1234.0,
delta: math.Inf(-1),
wantInDelta: failure,
wantNotInDelta: failure,
},
{
name: "+Inf target",
number: math.Inf(1),
Expand Down Expand Up @@ -432,13 +440,37 @@ func TestNumber_InDeltaRelative(t *testing.T) {
wantInDelta: success,
wantNotInDelta: failure,
},
{
name: "+Inf number and target with non-zero delta",
number: math.Inf(1),
value: math.Inf(1),
delta: 10000,
wantInDelta: success,
wantNotInDelta: failure,
},
{
name: "-Inf number and target with non-zero delta",
number: math.Inf(-1),
value: math.Inf(-1),
delta: 10000,
wantInDelta: success,
wantNotInDelta: failure,
},
{
name: "+Inf number and -Inf target",
number: math.Inf(1),
value: math.Inf(-1),
delta: 0,
wantInDelta: failure,
wantNotInDelta: failure,
wantNotInDelta: success,
},
{
name: "-Inf number and +Inf target",
number: math.Inf(-1),
value: math.Inf(1),
delta: 0,
wantInDelta: failure,
wantNotInDelta: success,
},
{
name: "target is 0 in delta range",
Expand Down

0 comments on commit 2b1131c

Please sign in to comment.