github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/types/currency_test.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"math"
     7  	"math/big"
     8  	"testing"
     9  
    10  	"github.com/NebulousLabs/Sia/encoding"
    11  )
    12  
    13  // TestNewCurrency initializes a standard new currency.
    14  func TestNewCurrency(t *testing.T) {
    15  	b := big.NewInt(481)
    16  	c := NewCurrency(b)
    17  	if b.String() != c.String() {
    18  		t.Error("NewCurrency does't seem to work properly")
    19  	}
    20  }
    21  
    22  // TestCurrencyAdd probes the addition function of the currency type.
    23  func TestCurrencyAdd(t *testing.T) {
    24  	c7 := NewCurrency64(7)
    25  	c12 := NewCurrency64(12)
    26  	c19 := NewCurrency64(19)
    27  
    28  	if c7.Add(c12).Cmp(c19) != 0 {
    29  		t.Error("Add doesn't seem to work right")
    30  	}
    31  }
    32  
    33  // TestCurrencyToBig tests the Big method for the currency type
    34  func TestCurrencyToBig(t *testing.T) {
    35  	c := NewCurrency64(125)
    36  	cb := c.Big()
    37  	b := big.NewInt(125)
    38  
    39  	if b.Cmp(cb) != 0 {
    40  		t.Error("currency to big has failed")
    41  	}
    42  }
    43  
    44  // TestCurrencyDiv checks that the div function has been correctly implemented.
    45  func TestCurrencyDiv(t *testing.T) {
    46  	c9 := NewCurrency64(9)
    47  	c10 := NewCurrency64(10)
    48  	c90 := NewCurrency64(90)
    49  	c97 := NewCurrency64(97)
    50  
    51  	c90D10 := c90.Div(c10)
    52  	if c90D10.Cmp(c9) != 0 {
    53  		t.Error("Dividing 90 by 10 should produce 9")
    54  	}
    55  	c97D10 := c97.Div(c10)
    56  	if c97D10.Cmp(c9) != 0 {
    57  		t.Error("Dividing 97 by 10 should produce 9")
    58  	}
    59  }
    60  
    61  // TestCurrencyDiv64 checks that the Div64 function has been correctly implemented.
    62  func TestCurrencyDiv64(t *testing.T) {
    63  	c9 := NewCurrency64(9)
    64  	u10 := uint64(10)
    65  	c90 := NewCurrency64(90)
    66  	c97 := NewCurrency64(97)
    67  
    68  	c90D10 := c90.Div64(u10)
    69  	if c90D10.Cmp(c9) != 0 {
    70  		t.Error("Dividing 90 by 10 should produce 9")
    71  	}
    72  	c97D10 := c97.Div64(u10)
    73  	if c97D10.Cmp(c9) != 0 {
    74  		t.Error("Dividing 97 by 10 should produce 9")
    75  	}
    76  }
    77  
    78  // TestCurrencyMul probes the Mul function of the currency type.
    79  func TestCurrencyMul(t *testing.T) {
    80  	c5 := NewCurrency64(5)
    81  	c6 := NewCurrency64(6)
    82  	c30 := NewCurrency64(30)
    83  	if c5.Mul(c6).Cmp(c30) != 0 {
    84  		t.Error("Multiplying 5 by 6 should equal 30")
    85  	}
    86  }
    87  
    88  // TestCurrencyMul64 probes the Mul64 function of the currency type.
    89  func TestCurrencyMul64(t *testing.T) {
    90  	c5 := NewCurrency64(5)
    91  	u6 := uint64(6)
    92  	c30 := NewCurrency64(30)
    93  	if c5.Mul64(u6).Cmp(c30) != 0 {
    94  		t.Error("Multiplying 5 by 6 should equal 30")
    95  	}
    96  }
    97  
    98  // TestCurrencyMulRat probes the MulRat function of the currency type.
    99  func TestCurrencyMulRat(t *testing.T) {
   100  	c5 := NewCurrency64(5)
   101  	c7 := NewCurrency64(7)
   102  	c10 := NewCurrency64(10)
   103  	if c5.MulRat(big.NewRat(2, 1)).Cmp(c10) != 0 {
   104  		t.Error("Multiplying 5 by 2 should return 10")
   105  	}
   106  	if c5.MulRat(big.NewRat(3, 2)).Cmp(c7) != 0 {
   107  		t.Error("Multiplying 5 by 1.5 should return 7")
   108  	}
   109  }
   110  
   111  // TestCurrencyRoundDown probes the RoundDown function of the currency type.
   112  func TestCurrencyRoundDown(t *testing.T) {
   113  	// 10,000 is chosen because that's how many siafunds there usually are.
   114  	c40000 := NewCurrency64(40000)
   115  	c45000 := NewCurrency64(45000)
   116  	if c45000.RoundDown(NewCurrency64(10000)).Cmp(c40000) != 0 {
   117  		t.Error("rounding down 45000 to the nearest 10000 didn't work")
   118  	}
   119  }
   120  
   121  // TestCurrencyIsZero probes the IsZero function of the currency type.
   122  func TestCurrencyIsZero(t *testing.T) {
   123  	c0 := NewCurrency64(0)
   124  	c1 := NewCurrency64(1)
   125  	if !c0.IsZero() {
   126  		t.Error("IsZero returns wrong value for 0")
   127  	}
   128  	if c1.IsZero() {
   129  		t.Error("IsZero returns wrong value for 1")
   130  	}
   131  }
   132  
   133  // TestCurrencySqrt probes the Sqrt function of the currency type.
   134  func TestCurrencySqrt(t *testing.T) {
   135  	c8 := NewCurrency64(8)
   136  	c64 := NewCurrency64(64)
   137  	c80 := NewCurrency64(80)
   138  	sqrt64 := c64.Sqrt()
   139  	sqrt80 := c80.Sqrt()
   140  
   141  	if c8.Cmp(sqrt64) != 0 {
   142  		t.Error("square root of 64 should be 8")
   143  	}
   144  	if c8.Cmp(sqrt80) != 0 {
   145  		t.Error("square root of 80 should be 8")
   146  	}
   147  }
   148  
   149  // TestCurrencySub probes the Sub function of the currency type.
   150  func TestCurrencySub(t *testing.T) {
   151  	c3 := NewCurrency64(3)
   152  	c13 := NewCurrency64(13)
   153  	c16 := NewCurrency64(16)
   154  	if c16.Sub(c3).Cmp(c13) != 0 {
   155  		t.Error("16 minus 3 should equal 13")
   156  	}
   157  }
   158  
   159  // TestCurrencyMarshalJSON probes the MarshalJSON and UnmarshalJSON functions
   160  // of the currency type.
   161  func TestCurrencyMarshalJSON(t *testing.T) {
   162  	b30 := big.NewInt(30)
   163  	c30 := NewCurrency64(30)
   164  
   165  	bMar30, err := b30.MarshalJSON()
   166  	if err != nil {
   167  		t.Fatal(err)
   168  	}
   169  	cMar30, err := c30.MarshalJSON()
   170  	if err != nil {
   171  		t.Fatal(err)
   172  	}
   173  	if !bytes.Equal(bMar30, bytes.Trim(cMar30, `"`)) {
   174  		t.Error("Currency does not match the marshalling of its math/big equivalent")
   175  	}
   176  
   177  	var cUmar30 Currency
   178  	err = cUmar30.UnmarshalJSON(cMar30)
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  	if c30.Cmp(cUmar30) != 0 {
   183  		t.Error("Incorrect unmarshalling of currency type.")
   184  	}
   185  
   186  	cMar30[0] = 0
   187  	err = cUmar30.UnmarshalJSON(cMar30)
   188  	if err == nil {
   189  		t.Error("JSON decoded nonsense input")
   190  	}
   191  }
   192  
   193  // TestCurrencyMarshalSia probes the MarshalSia and UnmarshalSia functions of
   194  // the currency type.
   195  func TestCurrencyMarshalSia(t *testing.T) {
   196  	c := NewCurrency64(1656)
   197  	buf := new(bytes.Buffer)
   198  	err := c.MarshalSia(buf)
   199  	if err != nil {
   200  		t.Fatal(err)
   201  	}
   202  	var cUmar Currency
   203  	cUmar.UnmarshalSia(buf)
   204  	if c.Cmp(cUmar) != 0 {
   205  		t.Error("marshal and unmarshal mismatch for currency type")
   206  	}
   207  }
   208  
   209  // TestCurrencyString probes the String function of the currency type.
   210  func TestCurrencyString(t *testing.T) {
   211  	b := big.NewInt(7135)
   212  	c := NewCurrency64(7135)
   213  	if b.String() != c.String() {
   214  		t.Error("string function not behaving as expected")
   215  	}
   216  }
   217  
   218  // TestCurrencyScan probes the Scan function of the currency type.
   219  func TestCurrencyScan(t *testing.T) {
   220  	var c0 Currency
   221  	c1 := NewCurrency64(81293)
   222  	_, err := fmt.Sscan("81293", &c0)
   223  	if err != nil {
   224  		t.Fatal(err)
   225  	}
   226  	if c0.Cmp(c1) != 0 {
   227  		t.Error("scanned number does not equal expected value")
   228  	}
   229  	_, err = fmt.Sscan("z", &c0)
   230  	if err == nil {
   231  		t.Fatal("scan is accepting garbage input")
   232  	}
   233  }
   234  
   235  // TestCurrencyEncoding checks that a currency can encode and decode without
   236  // error.
   237  func TestCurrencyEncoding(t *testing.T) {
   238  	c := NewCurrency64(351)
   239  	cMar := encoding.Marshal(c)
   240  	var cUmar Currency
   241  	err := encoding.Unmarshal(cMar, &cUmar)
   242  	if err != nil {
   243  		t.Error("Error unmarshalling a currency:", err)
   244  	}
   245  	if cUmar.Cmp(c) != 0 {
   246  		t.Error("Marshalling and Unmarshalling a currency did not work correctly")
   247  	}
   248  }
   249  
   250  // TestNegativeCurrencyMulRat checks that negative numbers are rejected when
   251  // calling MulRat on the currency type.
   252  func TestNegativeCurrencyMulRat(t *testing.T) {
   253  	// In debug mode, attempting to get a negative currency results in a panic.
   254  	defer func() {
   255  		r := recover()
   256  		if r == nil {
   257  			t.Error("no panic occurred when trying to create a negative currency")
   258  		}
   259  	}()
   260  
   261  	c := NewCurrency64(12)
   262  	_ = c.MulRat(big.NewRat(-1, 1))
   263  }
   264  
   265  // TestNegativeCurrencySub checks that negative numbers are prevented when
   266  // using subtraction on the currency type.
   267  func TestNegativeCurrencySub(t *testing.T) {
   268  	// In debug mode, attempting to get a negative currency results in a panic.
   269  	defer func() {
   270  		r := recover()
   271  		if r == nil {
   272  			t.Error("no panic occurred when trying to create a negative currency")
   273  		}
   274  	}()
   275  
   276  	c1 := NewCurrency64(1)
   277  	c2 := NewCurrency64(2)
   278  	_ = c1.Sub(c2)
   279  }
   280  
   281  // TestNegativeCurrencyUnmarshalJSON tries to unmarshal a negative number from
   282  // JSON.
   283  func TestNegativeCurrencyUnmarshalJSON(t *testing.T) {
   284  	// Marshal a 2 digit number.
   285  	c := NewCurrency64(35)
   286  	cMar, err := c.MarshalJSON()
   287  	if err != nil {
   288  		t.Fatal(err)
   289  	}
   290  
   291  	// Change the first digit to a negative character.
   292  	cMar[0] = 45
   293  
   294  	// Try unmarshalling the negative currency.
   295  	var cNeg Currency
   296  	err = cNeg.UnmarshalJSON(cMar)
   297  	if err != ErrNegativeCurrency {
   298  		t.Error("expecting ErrNegativeCurrency:", err)
   299  	}
   300  	if cNeg.i.Sign() < 0 {
   301  		t.Error("negative currency returned")
   302  	}
   303  }
   304  
   305  // TestNegativeCurrencyScan tries to scan in a negative number and checks for
   306  // an error.
   307  func TestNegativeCurrencyScan(t *testing.T) {
   308  	var c Currency
   309  	_, err := fmt.Sscan("-23", &c)
   310  	if err != ErrNegativeCurrency {
   311  		t.Error("expecting ErrNegativeCurrency:", err)
   312  	}
   313  }
   314  
   315  // TestNegativeCurrencies tries an array of ways to produce a negative currency.
   316  func TestNegativeNewCurrency(t *testing.T) {
   317  	// In debug mode, attempting to get a negative currency results in a panic.
   318  	defer func() {
   319  		r := recover()
   320  		if r == nil {
   321  			t.Error("no panic occurred when trying to create a negative currency")
   322  		}
   323  	}()
   324  
   325  	// Try to create a new currency from a negative number.
   326  	negBig := big.NewInt(-1)
   327  	_ = NewCurrency(negBig)
   328  }
   329  
   330  // TestCurrencyUint64 tests that a currency is correctly converted to a uint64.
   331  func TestCurrencyUint64(t *testing.T) {
   332  	// Try a set of valid values.
   333  	values := []uint64{0, 1, 2, 3, 4, 25e3, math.MaxUint64 - 1e6, math.MaxUint64}
   334  	for _, value := range values {
   335  		c := NewCurrency64(value)
   336  		result, err := c.Uint64()
   337  		if err != nil {
   338  			t.Error(err)
   339  		}
   340  		if value != result {
   341  			t.Error("uint64 conversion failed")
   342  		}
   343  	}
   344  
   345  	// Try an overflow.
   346  	c := NewCurrency64(math.MaxUint64)
   347  	c = c.Mul(NewCurrency64(2))
   348  	result, err := c.Uint64()
   349  	if err != ErrUint64Overflow {
   350  		t.Error(err)
   351  	}
   352  	if result != 0 {
   353  		t.Error("result is not being zeroed in the event of an error")
   354  	}
   355  }