gitlab.com/SiaPrime/SiaPrime@v1.4.1/types/currency_test.go (about)

     1  package types
     2  
     3  import (
     4  	"math"
     5  	"math/big"
     6  	"testing"
     7  )
     8  
     9  // TestNewCurrency initializes a standard new currency.
    10  func TestNewCurrency(t *testing.T) {
    11  	b := big.NewInt(481)
    12  	c := NewCurrency(b)
    13  	if b.String() != c.String() {
    14  		t.Error("NewCurrency does't seem to work properly")
    15  	}
    16  }
    17  
    18  // TestCurrencyAdd probes the addition function of the currency type.
    19  func TestCurrencyAdd(t *testing.T) {
    20  	c7 := NewCurrency64(7)
    21  	c12 := NewCurrency64(12)
    22  	c19 := NewCurrency64(19)
    23  
    24  	if c7.Add(c12).Cmp(c19) != 0 {
    25  		t.Error("Add doesn't seem to work right")
    26  	}
    27  }
    28  
    29  // TestCurrencyToBig tests the Big method for the currency type
    30  func TestCurrencyToBig(t *testing.T) {
    31  	c := NewCurrency64(125)
    32  	cb := c.Big()
    33  	b := big.NewInt(125)
    34  
    35  	if b.Cmp(cb) != 0 {
    36  		t.Error("currency to big has failed")
    37  	}
    38  }
    39  
    40  // TestCurrencyCmp tests the Cmp method for the currency type
    41  func TestCurrencyCmp(t *testing.T) {
    42  	tests := []struct {
    43  		x, y Currency
    44  		exp  int
    45  	}{
    46  		{NewCurrency64(0), NewCurrency64(0), 0},
    47  		{NewCurrency64(0), NewCurrency64(1), -1},
    48  		{NewCurrency64(1), NewCurrency64(0), 1},
    49  		{NewCurrency64(100), NewCurrency64(7), 1},
    50  		{NewCurrency64(777), NewCurrency(big.NewInt(777)), 0},
    51  		{NewCurrency(big.NewInt(7)), NewCurrency(big.NewInt(8)), -1},
    52  	}
    53  
    54  	for _, test := range tests {
    55  		if c := test.x.Cmp(test.y); c != test.exp {
    56  			t.Errorf("expected %v.Cmp(%v) == %v, got %v", test.x, test.y, test.exp, c)
    57  		} else if bc := test.x.Big().Cmp(test.y.Big()); c != bc {
    58  			t.Errorf("Currency.Cmp (%v) does not match big.Int.Cmp (%v) for %v.Cmp(%v)", c, bc, test.x, test.y)
    59  		}
    60  	}
    61  }
    62  
    63  // TestCurrencyCmp64 tests the Cmp64 method for the currency type
    64  func TestCurrencyCmp64(t *testing.T) {
    65  	tests := []struct {
    66  		x   Currency
    67  		y   uint64
    68  		exp int
    69  	}{
    70  		{NewCurrency64(0), 0, 0},
    71  		{NewCurrency64(0), 1, -1},
    72  		{NewCurrency64(1), 0, 1},
    73  		{NewCurrency64(100), 7, 1},
    74  		{NewCurrency64(777), 777, 0},
    75  		{NewCurrency(big.NewInt(7)), 8, -1},
    76  	}
    77  
    78  	for _, test := range tests {
    79  		if c := test.x.Cmp64(test.y); c != test.exp {
    80  			t.Errorf("expected %v.Cmp64(%v) == %v, got %v", test.x, test.y, test.exp, c)
    81  		} else if bc := test.x.Big().Cmp(big.NewInt(int64(test.y))); c != bc {
    82  			t.Errorf("Currency.Cmp64 (%v) does not match big.Int.Cmp (%v) for %v.Cmp64(%v)", c, bc, test.x, test.y)
    83  		}
    84  	}
    85  }
    86  
    87  // TestCurrencyDiv checks that the div function has been correctly implemented.
    88  func TestCurrencyDiv(t *testing.T) {
    89  	c9 := NewCurrency64(9)
    90  	c10 := NewCurrency64(10)
    91  	c90 := NewCurrency64(90)
    92  	c97 := NewCurrency64(97)
    93  
    94  	c90D10 := c90.Div(c10)
    95  	if c90D10.Cmp(c9) != 0 {
    96  		t.Error("Dividing 90 by 10 should produce 9")
    97  	}
    98  	c97D10 := c97.Div(c10)
    99  	if c97D10.Cmp(c9) != 0 {
   100  		t.Error("Dividing 97 by 10 should produce 9")
   101  	}
   102  }
   103  
   104  // TestCurrencyDiv64 checks that the Div64 function has been correctly implemented.
   105  func TestCurrencyDiv64(t *testing.T) {
   106  	c9 := NewCurrency64(9)
   107  	u10 := uint64(10)
   108  	c90 := NewCurrency64(90)
   109  	c97 := NewCurrency64(97)
   110  
   111  	c90D10 := c90.Div64(u10)
   112  	if c90D10.Cmp(c9) != 0 {
   113  		t.Error("Dividing 90 by 10 should produce 9")
   114  	}
   115  	c97D10 := c97.Div64(u10)
   116  	if c97D10.Cmp(c9) != 0 {
   117  		t.Error("Dividing 97 by 10 should produce 9")
   118  	}
   119  }
   120  
   121  // TestCurrencyEquals tests the Equals method for the currency type
   122  func TestCurrencyEquals(t *testing.T) {
   123  	tests := []struct {
   124  		x, y Currency
   125  		exp  bool
   126  	}{
   127  		{NewCurrency64(0), NewCurrency64(0), true},
   128  		{NewCurrency64(0), NewCurrency64(1), false},
   129  		{NewCurrency64(1), NewCurrency64(0), false},
   130  		{NewCurrency64(100), NewCurrency64(7), false},
   131  		{NewCurrency64(777), NewCurrency(big.NewInt(777)), true},
   132  		{NewCurrency(big.NewInt(7)), NewCurrency(big.NewInt(8)), false},
   133  	}
   134  
   135  	for _, test := range tests {
   136  		if eq := test.x.Equals(test.y); eq != test.exp {
   137  			t.Errorf("expected %v.Equals(%v) == %v, got %v", test.x, test.y, test.exp, eq)
   138  		} else if bc := test.x.Big().Cmp(test.y.Big()); (bc == 0) != eq {
   139  			t.Errorf("Currency.Equals (%v) does not match big.Int.Cmp (%v) for %v.Equals(%v)", eq, bc, test.x, test.y)
   140  		}
   141  	}
   142  }
   143  
   144  // TestCurrencyEquals64 tests the Equals64 method for the currency type
   145  func TestCurrencyEquals64(t *testing.T) {
   146  	tests := []struct {
   147  		x   Currency
   148  		y   uint64
   149  		exp bool
   150  	}{
   151  		{NewCurrency64(0), 0, true},
   152  		{NewCurrency64(0), 1, false},
   153  		{NewCurrency64(1), 0, false},
   154  		{NewCurrency64(100), 7, false},
   155  		{NewCurrency64(777), 777, true},
   156  		{NewCurrency(big.NewInt(7)), 8, false},
   157  	}
   158  
   159  	for _, test := range tests {
   160  		if eq := test.x.Equals64(test.y); eq != test.exp {
   161  			t.Errorf("expected %v.Equals64(%v) == %v, got %v", test.x, test.y, test.exp, eq)
   162  		} else if bc := test.x.Big().Cmp(big.NewInt(int64(test.y))); (bc == 0) != eq {
   163  			t.Errorf("Currency.Equals64 (%v) does not match big.Int.Cmp (%v) for %v.Equals64(%v)", eq, bc, test.x, test.y)
   164  		}
   165  	}
   166  }
   167  
   168  // TestCurrencyFloat64 checks that the float64 function is implemented
   169  // correctly.
   170  func TestCurrencyFloat64(t *testing.T) {
   171  	c := ZeroCurrency
   172  	c64, exact := c.Float64()
   173  	if !exact {
   174  		t.Error("Float64 doesn't return exact value when converting zero currency")
   175  	}
   176  	if c64 != 0 {
   177  		t.Error("wrong value returned by Float64")
   178  	}
   179  
   180  	c = NewCurrency64(1)
   181  	c64, exact = c.Float64()
   182  	if !exact {
   183  		t.Error("Float64 doesn't return exact value when converting zero currency")
   184  	}
   185  	if c64 != 1 {
   186  		t.Error("wrong value returned by Float64")
   187  	}
   188  
   189  	c = NewCurrency64(1000)
   190  	c64, exact = c.Float64()
   191  	if !exact {
   192  		t.Error("Float64 doesn't return exact value when converting zero currency")
   193  	}
   194  	if c64 != 1000 {
   195  		t.Error("wrong value returned by Float64")
   196  	}
   197  
   198  	c = NewCurrency64(1e12)
   199  	c64, exact = c.Float64()
   200  	if !exact {
   201  		t.Error("Float64 doesn't return exact value when converting zero currency")
   202  	}
   203  	if c64 != 1e12 {
   204  		t.Error("wrong value returned by Float64")
   205  	}
   206  
   207  	c = NewCurrency64(1e12).Mul64(1e12)
   208  	c64, exact = c.Float64()
   209  	if c64 <= 999e21 || c64 > 1001e21 {
   210  		t.Error("wrong value returned by Float64")
   211  	}
   212  
   213  	c = NewCurrency64(1e12).Mul64(1e12).Mul64(1e12)
   214  	c64, exact = c.Float64()
   215  	if c64 <= 999e33 || c64 > 1001e33 {
   216  		t.Error("wrong value returned by Float64")
   217  	}
   218  
   219  	c = NewCurrency64(1e12).Mul64(1e12).Mul64(1e12).Mul64(1e12)
   220  	c64, exact = c.Float64()
   221  	if c64 <= 999e45 || c64 > 1001e45 {
   222  		t.Error(len(c.String()))
   223  		t.Error("wrong value returned by Float64", c64)
   224  	}
   225  
   226  	c = NewCurrency64(1e12).Mul64(1e12).Mul64(1e12).Mul64(1e12).Mul64(1e12).Mul64(1e12)
   227  	c64, exact = c.Float64()
   228  	if c64 <= 999e69 || c64 > 1001e69 {
   229  		t.Error(len(c.String()))
   230  		t.Error("wrong value returned by Float64", c64)
   231  	}
   232  
   233  	c = NewCurrency64(1e12).Mul64(1e12).Mul64(1e12).Mul64(1e12).Mul64(1e12).Mul64(1e12).Mul64(1e12).Mul64(1e12).Mul64(1e12).Mul64(1e12).Mul64(1e12)
   234  	c64, exact = c.Float64()
   235  	if c64 <= 999e129 || c64 > 1001e129 {
   236  		t.Error(len(c.String()))
   237  		t.Error("wrong value returned by Float64", c64)
   238  	}
   239  }
   240  
   241  // TestCurrencyMul probes the Mul function of the currency type.
   242  func TestCurrencyMul(t *testing.T) {
   243  	c5 := NewCurrency64(5)
   244  	c6 := NewCurrency64(6)
   245  	c30 := NewCurrency64(30)
   246  	if c5.Mul(c6).Cmp(c30) != 0 {
   247  		t.Error("Multiplying 5 by 6 should equal 30")
   248  	}
   249  }
   250  
   251  // TestCurrencyMul64 probes the Mul64 function of the currency type.
   252  func TestCurrencyMul64(t *testing.T) {
   253  	c5 := NewCurrency64(5)
   254  	u6 := uint64(6)
   255  	c30 := NewCurrency64(30)
   256  	if c5.Mul64(u6).Cmp(c30) != 0 {
   257  		t.Error("Multiplying 5 by 6 should equal 30")
   258  	}
   259  }
   260  
   261  // TestCurrencyMulRat probes the MulRat function of the currency type.
   262  func TestCurrencyMulRat(t *testing.T) {
   263  	c5 := NewCurrency64(5)
   264  	c7 := NewCurrency64(7)
   265  	c10 := NewCurrency64(10)
   266  	if c5.MulRat(big.NewRat(2, 1)).Cmp(c10) != 0 {
   267  		t.Error("Multiplying 5 by 2 should return 10")
   268  	}
   269  	if c5.MulRat(big.NewRat(3, 2)).Cmp(c7) != 0 {
   270  		t.Error("Multiplying 5 by 1.5 should return 7")
   271  	}
   272  }
   273  
   274  // TestCurrencyRoundDown probes the RoundDown function of the currency type.
   275  func TestCurrencyRoundDown(t *testing.T) {
   276  	// 10,000 is chosen because that's how many siafunds there usually are.
   277  	c40000 := NewCurrency64(40000)
   278  	c45000 := NewCurrency64(45000)
   279  	if c45000.RoundDown(NewCurrency64(10000)).Cmp(c40000) != 0 {
   280  		t.Error("rounding down 45000 to the nearest 10000 didn't work")
   281  	}
   282  }
   283  
   284  // TestCurrencyIsZero probes the IsZero function of the currency type.
   285  func TestCurrencyIsZero(t *testing.T) {
   286  	c0 := NewCurrency64(0)
   287  	c1 := NewCurrency64(1)
   288  	if !c0.IsZero() {
   289  		t.Error("IsZero returns wrong value for 0")
   290  	}
   291  	if c1.IsZero() {
   292  		t.Error("IsZero returns wrong value for 1")
   293  	}
   294  }
   295  
   296  // TestCurrencySqrt probes the Sqrt function of the currency type.
   297  func TestCurrencySqrt(t *testing.T) {
   298  	c8 := NewCurrency64(8)
   299  	c64 := NewCurrency64(64)
   300  	c80 := NewCurrency64(80)
   301  	sqrt64 := c64.Sqrt()
   302  	sqrt80 := c80.Sqrt()
   303  
   304  	if c8.Cmp(sqrt64) != 0 {
   305  		t.Error("square root of 64 should be 8")
   306  	}
   307  	if c8.Cmp(sqrt80) != 0 {
   308  		t.Error("square root of 80 should be 8")
   309  	}
   310  }
   311  
   312  // TestCurrencySub probes the Sub function of the currency type.
   313  func TestCurrencySub(t *testing.T) {
   314  	c3 := NewCurrency64(3)
   315  	c13 := NewCurrency64(13)
   316  	c16 := NewCurrency64(16)
   317  	if c16.Sub(c3).Cmp(c13) != 0 {
   318  		t.Error("16 minus 3 should equal 13")
   319  	}
   320  }
   321  
   322  // TestNegativeCurrencyMulRat checks that negative numbers are rejected when
   323  // calling MulRat on the currency type.
   324  func TestNegativeCurrencyMulRat(t *testing.T) {
   325  	// In debug mode, attempting to get a negative currency results in a panic.
   326  	defer func() {
   327  		r := recover()
   328  		if r == nil {
   329  			t.Error("no panic occurred when trying to create a negative currency")
   330  		}
   331  	}()
   332  
   333  	c := NewCurrency64(12)
   334  	_ = c.MulRat(big.NewRat(-1, 1))
   335  }
   336  
   337  // TestNegativeCurrencySub checks that negative numbers are prevented when
   338  // using subtraction on the currency type.
   339  func TestNegativeCurrencySub(t *testing.T) {
   340  	// In debug mode, attempting to get a negative currency results in a panic.
   341  	defer func() {
   342  		r := recover()
   343  		if r == nil {
   344  			t.Error("no panic occurred when trying to create a negative currency")
   345  		}
   346  	}()
   347  
   348  	c1 := NewCurrency64(1)
   349  	c2 := NewCurrency64(2)
   350  	_ = c1.Sub(c2)
   351  }
   352  
   353  // TestNegativeCurrencies tries an array of ways to produce a negative currency.
   354  func TestNegativeNewCurrency(t *testing.T) {
   355  	// In debug mode, attempting to get a negative currency results in a panic.
   356  	defer func() {
   357  		r := recover()
   358  		if r == nil {
   359  			t.Error("no panic occurred when trying to create a negative currency")
   360  		}
   361  	}()
   362  
   363  	// Try to create a new currency from a negative number.
   364  	negBig := big.NewInt(-1)
   365  	_ = NewCurrency(negBig)
   366  }
   367  
   368  // TestCurrencyUint64 tests that a currency is correctly converted to a uint64.
   369  func TestCurrencyUint64(t *testing.T) {
   370  	// Try a set of valid values.
   371  	values := []uint64{0, 1, 2, 3, 4, 25e3, math.MaxUint64 - 1e6, math.MaxUint64}
   372  	for _, value := range values {
   373  		c := NewCurrency64(value)
   374  		result, err := c.Uint64()
   375  		if err != nil {
   376  			t.Error(err)
   377  		}
   378  		if value != result {
   379  			t.Error("uint64 conversion failed")
   380  		}
   381  	}
   382  
   383  	// Try an overflow.
   384  	c := NewCurrency64(math.MaxUint64)
   385  	c = c.Mul(NewCurrency64(2))
   386  	result, err := c.Uint64()
   387  	if err != ErrUint64Overflow {
   388  		t.Error(err)
   389  	}
   390  	if result != 0 {
   391  		t.Error("result is not being zeroed in the event of an error")
   392  	}
   393  }