featurebase/pql/decimal_internal_test.go
2022-09-02 13:23:39 -07:00

90 lines
2.8 KiB
Go

package pql
import (
"fmt"
"math/big"
"testing"
)
type testAddDecimalCase struct {
a Decimal
b Decimal
exp Decimal
}
func TestAddDecimal(t *testing.T) {
toDecimal := func(a interface{}) Decimal {
switch ac := a.(type) {
case string:
return mustParse(t, ac)
case Decimal:
return ac
default:
t.Fatalf("cannot support type %T", ac)
}
return Decimal{}
}
newTestAddDecimalCase := func(a, b, exp interface{}) testAddDecimalCase {
return testAddDecimalCase{
a: toDecimal(a),
b: toDecimal(b),
exp: toDecimal(exp),
}
}
tests := []testAddDecimalCase{
newTestAddDecimalCase("40.37", "40.37", "80.74"),
newTestAddDecimalCase("18.5", "9.25", "27.75"),
newTestAddDecimalCase("18.50", "9.25", "27.75"),
newTestAddDecimalCase("-18.50", "-9.25", "-27.75"),
newTestAddDecimalCase("-40.37", "40.37", NewDecimal(0, 0)),
newTestAddDecimalCase("-50.38", "-50.38", "-100.76"),
newTestAddDecimalCase("-40.381", "-40.38", "-80.761"),
newTestAddDecimalCase("-40.3700000000000000000001", "-50.38", "-90.7500000000000000000001"),
newTestAddDecimalCase("10.37000000000000001", "-10", "0.37000000000000001"),
// this is a weird one. because we reduce precision when we parse strings, we
// expect the value to be smaller than it really should be if you did
// the math yourself.
//
// there's not really a good way around this unless we use math/big.Int to represent
// our Value/Scale.
//
// but if we did this, to quote seebs: "i suspect that
// our performance would tank so badly by the time we were doing >63-bit
// numbers that there's no real-world benefit to us."
newTestAddDecimalCase("10.370000000000000001", "-10", "0.37"),
newTestAddDecimalCase("-9223372036854775807", "-9223372036854775807", "-18446744073709551614"),
newTestAddDecimalCase("9223372036854775807", "9223372036854775807", "18446744073709551614"),
newTestAddDecimalCase(NewDecimal(0, 0), NewDecimal(1, 4), NewDecimal(1, 4)),
}
for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
t.Logf("first %#v %#v", test.a, test.b)
if got := AddDecimal(test.a, test.b); !got.EqualTo(test.exp) {
t.Logf("LOG: %#v + %#v, expected %#v, got %#v", test.a, test.b, test.exp, got)
t.Errorf("%v + %v, expected %v, got %v", test.a, test.b, test.exp, got)
}
t.Logf("second %v %v", test.a, test.b)
if got := AddDecimal(test.b, test.a); !got.EqualTo(test.exp) {
t.Logf("LOG: %#v + %#v, expected %#v, got %#v", test.a, test.b, test.exp, got)
t.Errorf("%v + %v, expected %v, got %v", test.b, test.a, test.exp, got)
}
})
}
}
func mustParse(t *testing.T, num string) Decimal {
t.Helper()
d, err := ParseDecimal(num)
if err != nil {
v := big.NewInt(0)
if _, ok := v.SetString(num, 10); !ok {
t.Fatalf("unexpected error parsing %s to Decimal: %v", num, err)
}
d.value = *v
}
return d
}