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 }