Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
husio committed Feb 25, 2019
1 parent 2d05128 commit 7649fa3
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 9 deletions.
4 changes: 4 additions & 0 deletions errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ var (
// ErrExpired stands for expired entities, normally has to do with block height expirations
ErrExpired = Register(15, "expired")

// ErrOverflow s returned when a computation cannot be completed
// because the result value exceeds the type.
ErrOverflow = Register(16, "an operation cannot be completed due to value overflow")

// ErrPanic is only set when we recover from a panic, so we know to redact potentially sensitive system info
ErrPanic = Register(111222, "panic")
)
Expand Down
14 changes: 12 additions & 2 deletions x/coin.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ func (c Coin) Divide(pieces int64) (Coin, Coin, error) {
}

// Multiply returns the result of a coin value multiplication.
func (c Coin) Multiply(times int64) Coin {
func (c Coin) Multiply(times int64) (Coin, error) {
if times == 0 {
return Coin{Ticker: c.Ticker}, nil
}

whole := c.Whole * times
frac := c.Fractional * times

Expand All @@ -86,11 +90,17 @@ func (c Coin) Multiply(times int64) Coin {
frac = frac % FracUnit
}

return Coin{
wantPositive := times > 0 == (c.Whole >= 0 && c.Fractional >= 0)
if whole >= 0 && frac >= 0 && !wantPositive {
return Coin{}, errors.ErrOverflow
}

res := Coin{
Ticker: c.Ticker,
Whole: whole,
Fractional: frac,
}
return res, nil
}

// Add combines two coins.
Expand Down
47 changes: 40 additions & 7 deletions x/coin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package x

import (
"fmt"
"math"
"testing"

"github.com/iov-one/weave/errors"
Expand Down Expand Up @@ -340,16 +341,17 @@ func TestCoinDivide(t *testing.T) {

func TestCoinMultiply(t *testing.T) {
cases := map[string]struct {
coin Coin
times int64
want Coin
coin Coin
times int64
want Coin
wantErr error
}{
"zero value coin": {
coin: NewCoin(0, 0, "DOGE"),
times: 666,
want: NewCoin(0, 0, "DOGE"),
},
"multiply": {
"simple multiply": {
coin: NewCoin(1, 0, "DOGE"),
times: 3,
want: NewCoin(3, 0, "DOGE"),
Expand All @@ -369,12 +371,43 @@ func TestCoinMultiply(t *testing.T) {
times: -2,
want: NewCoin(-2, -2, "DOGE"),
},
"overflow of a negative and a positive value": {
coin: NewCoin(math.MaxInt64, 0, "DOGE"),
times: -math.MaxInt64,
wantErr: errors.ErrOverflow,
},
"overflow of two negative values": {
coin: NewCoin(-math.MaxInt64, 0, "DOGE"),
times: -math.MaxInt64,
wantErr: errors.ErrOverflow,
},
"overflow of two positive values": {
coin: NewCoin(math.MaxInt64, 0, "DOGE"),
times: math.MaxInt64,
wantErr: errors.ErrOverflow,
},
"overflow with a big multiply": {
coin: NewCoin(1000, 0, "DOGE"),
times: math.MaxInt64 / 10,
wantErr: errors.ErrOverflow,
},
"overflow with a small multiply": {
coin: NewCoin(math.MaxInt64/10, 0, "DOGE"),
times: 1000,
wantErr: errors.ErrOverflow,
},
}
for testName, tc := range cases {
t.Run(testName, func(t *testing.T) {
got := tc.coin.Multiply(tc.times)
if !got.Equals(tc.want) {
t.Fatalf("got %v", got)
got, err := tc.coin.Multiply(tc.times)
if !errors.Is(tc.wantErr, err) {
t.Logf("got coin: %+v", got)
t.Fatalf("got error %v", err)
}
if tc.wantErr == nil {
if !got.Equals(tc.want) {
t.Fatalf("got %v", got)
}
}
})
}
Expand Down

0 comments on commit 7649fa3

Please sign in to comment.