github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/std/coin_test.go (about) 1 package std 2 3 import ( 4 "strings" 5 "testing" 6 7 "github.com/gnolang/gno/tm2/pkg/amino" 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 ) 11 12 var ( 13 testDenom1 = "atom" 14 testDenom2 = "muon" 15 ) 16 17 // ---------------------------------------------------------------------------- 18 // Coin tests 19 20 func TestCoin(t *testing.T) { 21 t.Parallel() 22 23 require.Panics(t, func() { NewCoin(testDenom1, -1) }) 24 require.Panics(t, func() { NewCoin(strings.ToUpper(testDenom1), 10) }) 25 require.Equal(t, int64(5), NewCoin(testDenom1, 5).Amount) 26 } 27 28 func TestIsEqualCoin(t *testing.T) { 29 t.Parallel() 30 31 cases := []struct { 32 inputOne Coin 33 inputTwo Coin 34 expected bool 35 panics bool 36 }{ 37 {NewCoin(testDenom1, 1), NewCoin(testDenom1, 1), true, false}, 38 {NewCoin(testDenom1, 1), NewCoin(testDenom2, 1), false, true}, 39 {NewCoin("stake", 1), NewCoin("stake", 10), false, false}, 40 } 41 42 for tcIndex, tc := range cases { 43 if tc.panics { 44 require.Panics(t, func() { tc.inputOne.IsEqual(tc.inputTwo) }) 45 } else { 46 res := tc.inputOne.IsEqual(tc.inputTwo) 47 require.Equal(t, tc.expected, res, "coin equality relation is incorrect, tc #%d", tcIndex) 48 } 49 } 50 } 51 52 func TestCoinIsValid(t *testing.T) { 53 t.Parallel() 54 55 cases := []struct { 56 coin Coin 57 expectPass bool 58 }{ 59 {Coin{testDenom1, int64(-1)}, false}, 60 {Coin{testDenom1, int64(0)}, true}, 61 {Coin{testDenom1, int64(1)}, true}, 62 {Coin{"Atom", int64(1)}, false}, 63 {Coin{"a", int64(1)}, false}, 64 {Coin{"a very long coin denom", int64(1)}, false}, 65 {Coin{"atOm", int64(1)}, false}, 66 {Coin{" ", int64(1)}, false}, 67 } 68 69 for i, tc := range cases { 70 require.Equal(t, tc.expectPass, tc.coin.IsValid(), "unexpected result for IsValid, tc #%d", i) 71 } 72 } 73 74 func TestAddCoin(t *testing.T) { 75 t.Parallel() 76 77 cases := []struct { 78 inputOne Coin 79 inputTwo Coin 80 expected Coin 81 shouldPanic bool 82 }{ 83 {NewCoin(testDenom1, 1), NewCoin(testDenom1, 1), NewCoin(testDenom1, 2), false}, 84 {NewCoin(testDenom1, 1), NewCoin(testDenom1, 0), NewCoin(testDenom1, 1), false}, 85 {NewCoin(testDenom1, 1), NewCoin(testDenom2, 1), NewCoin(testDenom1, 1), true}, 86 } 87 88 for tcIndex, tc := range cases { 89 if tc.shouldPanic { 90 require.Panics(t, func() { tc.inputOne.Add(tc.inputTwo) }) 91 } else { 92 res := tc.inputOne.Add(tc.inputTwo) 93 require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex) 94 } 95 } 96 } 97 98 func TestSubCoin(t *testing.T) { 99 t.Parallel() 100 101 cases := []struct { 102 inputOne Coin 103 inputTwo Coin 104 expected Coin 105 shouldPanic bool 106 }{ 107 {NewCoin(testDenom1, 1), NewCoin(testDenom2, 1), NewCoin(testDenom1, 1), true}, 108 {NewCoin(testDenom1, 10), NewCoin(testDenom1, 1), NewCoin(testDenom1, 9), false}, 109 {NewCoin(testDenom1, 5), NewCoin(testDenom1, 3), NewCoin(testDenom1, 2), false}, 110 {NewCoin(testDenom1, 5), NewCoin(testDenom1, 0), NewCoin(testDenom1, 5), false}, 111 {NewCoin(testDenom1, 1), NewCoin(testDenom1, 5), Coin{}, true}, 112 } 113 114 for tcIndex, tc := range cases { 115 if tc.shouldPanic { 116 require.Panics(t, func() { tc.inputOne.Sub(tc.inputTwo) }) 117 } else { 118 res := tc.inputOne.Sub(tc.inputTwo) 119 require.Equal(t, tc.expected, res, "difference of coins is incorrect, tc #%d", tcIndex) 120 } 121 } 122 123 tc := struct { 124 inputOne Coin 125 inputTwo Coin 126 expected int64 127 }{NewCoin(testDenom1, 1), NewCoin(testDenom1, 1), 0} 128 res := tc.inputOne.Sub(tc.inputTwo) 129 require.Equal(t, tc.expected, res.Amount) 130 } 131 132 func TestIsGTECoin(t *testing.T) { 133 t.Parallel() 134 135 cases := []struct { 136 inputOne Coin 137 inputTwo Coin 138 expected bool 139 panics bool 140 }{ 141 {NewCoin(testDenom1, 1), NewCoin(testDenom1, 1), true, false}, 142 {NewCoin(testDenom1, 2), NewCoin(testDenom1, 1), true, false}, 143 {NewCoin(testDenom1, 1), NewCoin(testDenom2, 1), false, true}, 144 } 145 146 for tcIndex, tc := range cases { 147 if tc.panics { 148 require.Panics(t, func() { tc.inputOne.IsGTE(tc.inputTwo) }) 149 } else { 150 res := tc.inputOne.IsGTE(tc.inputTwo) 151 require.Equal(t, tc.expected, res, "coin GTE relation is incorrect, tc #%d", tcIndex) 152 } 153 } 154 } 155 156 func TestIsLTCoin(t *testing.T) { 157 t.Parallel() 158 159 cases := []struct { 160 inputOne Coin 161 inputTwo Coin 162 expected bool 163 panics bool 164 }{ 165 {NewCoin(testDenom1, 1), NewCoin(testDenom1, 1), false, false}, 166 {NewCoin(testDenom1, 2), NewCoin(testDenom1, 1), false, false}, 167 {NewCoin(testDenom1, 0), NewCoin(testDenom2, 1), false, true}, 168 {NewCoin(testDenom1, 1), NewCoin(testDenom2, 1), false, true}, 169 {NewCoin(testDenom1, 1), NewCoin(testDenom1, 1), false, false}, 170 {NewCoin(testDenom1, 1), NewCoin(testDenom1, 2), true, false}, 171 } 172 173 for tcIndex, tc := range cases { 174 if tc.panics { 175 require.Panics(t, func() { tc.inputOne.IsLT(tc.inputTwo) }) 176 } else { 177 res := tc.inputOne.IsLT(tc.inputTwo) 178 require.Equal(t, tc.expected, res, "coin LT relation is incorrect, tc #%d", tcIndex) 179 } 180 } 181 } 182 183 func TestCoinIsZero(t *testing.T) { 184 t.Parallel() 185 186 coin := NewCoin(testDenom1, 0) 187 res := coin.IsZero() 188 require.True(t, res) 189 190 coin = NewCoin(testDenom1, 1) 191 res = coin.IsZero() 192 require.False(t, res) 193 } 194 195 // ---------------------------------------------------------------------------- 196 // Coins tests 197 198 func TestIsZeroCoins(t *testing.T) { 199 t.Parallel() 200 201 cases := []struct { 202 inputOne Coins 203 expected bool 204 }{ 205 {Coins{}, true}, 206 {Coins{NewCoin(testDenom1, 0)}, true}, 207 {Coins{NewCoin(testDenom1, 0), NewCoin(testDenom2, 0)}, true}, 208 {Coins{NewCoin(testDenom1, 1)}, false}, 209 {Coins{NewCoin(testDenom1, 0), NewCoin(testDenom2, 1)}, false}, 210 } 211 212 for _, tc := range cases { 213 res := tc.inputOne.IsZero() 214 require.Equal(t, tc.expected, res) 215 } 216 } 217 218 func TestEqualCoins(t *testing.T) { 219 t.Parallel() 220 221 cases := []struct { 222 inputOne Coins 223 inputTwo Coins 224 expected bool 225 panics bool 226 }{ 227 {Coins{}, Coins{}, true, false}, 228 {Coins{NewCoin(testDenom1, 0)}, Coins{NewCoin(testDenom1, 0)}, true, false}, 229 {Coins{NewCoin(testDenom1, 0), NewCoin(testDenom2, 1)}, Coins{NewCoin(testDenom1, 0), NewCoin(testDenom2, 1)}, true, false}, 230 {Coins{NewCoin(testDenom1, 0)}, Coins{NewCoin(testDenom2, 0)}, false, true}, 231 {Coins{NewCoin(testDenom1, 0)}, Coins{NewCoin(testDenom1, 1)}, false, false}, 232 {Coins{NewCoin(testDenom1, 0)}, Coins{NewCoin(testDenom1, 0), NewCoin(testDenom2, 1)}, false, false}, 233 {Coins{NewCoin(testDenom1, 0), NewCoin(testDenom2, 1)}, Coins{NewCoin(testDenom1, 0), NewCoin(testDenom2, 1)}, true, false}, 234 } 235 236 for tcnum, tc := range cases { 237 if tc.panics { 238 require.Panics(t, func() { tc.inputOne.IsEqual(tc.inputTwo) }) 239 } else { 240 res := tc.inputOne.IsEqual(tc.inputTwo) 241 require.Equal(t, tc.expected, res, "Equality is differed from exported. tc #%d, expected %b, actual %b.", tcnum, tc.expected, res) 242 } 243 } 244 } 245 246 func TestAddCoins(t *testing.T) { 247 t.Parallel() 248 249 zero := int64(0) 250 one := int64(1) 251 two := int64(2) 252 253 cases := []struct { 254 inputOne Coins 255 inputTwo Coins 256 expected Coins 257 }{ 258 {Coins{{testDenom1, one}, {testDenom2, one}}, Coins{{testDenom1, one}, {testDenom2, one}}, Coins{{testDenom1, two}, {testDenom2, two}}}, 259 {Coins{{testDenom1, zero}, {testDenom2, one}}, Coins{{testDenom1, zero}, {testDenom2, zero}}, Coins{{testDenom2, one}}}, 260 {Coins{{testDenom1, two}}, Coins{{testDenom2, zero}}, Coins{{testDenom1, two}}}, 261 {Coins{{testDenom1, one}}, Coins{{testDenom1, one}, {testDenom2, two}}, Coins{{testDenom1, two}, {testDenom2, two}}}, 262 {Coins{{testDenom1, zero}, {testDenom2, zero}}, Coins{{testDenom1, zero}, {testDenom2, zero}}, Coins(nil)}, 263 } 264 265 for tcIndex, tc := range cases { 266 res := tc.inputOne.Add(tc.inputTwo) 267 assert.True(t, res.IsValid()) 268 require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex) 269 } 270 } 271 272 func TestSubCoins(t *testing.T) { 273 t.Parallel() 274 275 zero := int64(0) 276 one := int64(1) 277 two := int64(2) 278 279 testCases := []struct { 280 inputOne Coins 281 inputTwo Coins 282 expected Coins 283 shouldPanic bool 284 }{ 285 {Coins{{testDenom1, two}}, Coins{{testDenom1, one}, {testDenom2, two}}, Coins{{testDenom1, one}, {testDenom2, two}}, true}, 286 {Coins{{testDenom1, two}}, Coins{{testDenom2, zero}}, Coins{{testDenom1, two}}, false}, 287 {Coins{{testDenom1, one}}, Coins{{testDenom2, zero}}, Coins{{testDenom1, one}}, false}, 288 {Coins{{testDenom1, one}, {testDenom2, one}}, Coins{{testDenom1, one}}, Coins{{testDenom2, one}}, false}, 289 {Coins{{testDenom1, one}, {testDenom2, one}}, Coins{{testDenom1, two}}, Coins{}, true}, 290 } 291 292 for i, tc := range testCases { 293 if tc.shouldPanic { 294 require.Panics(t, func() { tc.inputOne.Sub(tc.inputTwo) }) 295 } else { 296 res := tc.inputOne.Sub(tc.inputTwo) 297 assert.True(t, res.IsValid()) 298 require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", i) 299 } 300 } 301 } 302 303 func TestCoins(t *testing.T) { 304 t.Parallel() 305 306 good := Coins{ 307 {"gas", int64(1)}, 308 {"mineral", int64(1)}, 309 {"tree", int64(1)}, 310 } 311 mixedCase1 := Coins{ 312 {"gAs", int64(1)}, 313 {"MineraL", int64(1)}, 314 {"TREE", int64(1)}, 315 } 316 mixedCase2 := Coins{ 317 {"gAs", int64(1)}, 318 {"mineral", int64(1)}, 319 } 320 mixedCase3 := Coins{ 321 {"gAs", int64(1)}, 322 } 323 empty := NewCoins() 324 badSort1 := Coins{ 325 {"tree", int64(1)}, 326 {"gas", int64(1)}, 327 {"mineral", int64(1)}, 328 } 329 330 // both are after the first one, but the second and third are in the wrong order 331 badSort2 := Coins{ 332 {"gas", int64(1)}, 333 {"tree", int64(1)}, 334 {"mineral", int64(1)}, 335 } 336 badAmt := Coins{ 337 {"gas", int64(1)}, 338 {"tree", int64(0)}, 339 {"mineral", int64(1)}, 340 } 341 dup := Coins{ 342 {"gas", int64(1)}, 343 {"gas", int64(1)}, 344 {"mineral", int64(1)}, 345 } 346 neg := Coins{ 347 {"gas", int64(-1)}, 348 {"mineral", int64(1)}, 349 } 350 351 assert.True(t, good.IsValid(), "Coins are valid") 352 assert.False(t, mixedCase1.IsValid(), "Coins denoms contain upper case characters") 353 assert.False(t, mixedCase2.IsValid(), "First Coins denoms contain upper case characters") 354 assert.False(t, mixedCase3.IsValid(), "Single denom in Coins contains upper case characters") 355 assert.True(t, good.IsAllPositive(), "Expected coins to be positive: %v", good) 356 assert.False(t, empty.IsAllPositive(), "Expected coins to not be positive: %v", empty) 357 assert.True(t, good.IsAllGTE(empty), "Expected %v to be >= %v", good, empty) 358 assert.False(t, good.IsAllLT(empty), "Expected %v to be < %v", good, empty) 359 assert.True(t, empty.IsAllLT(good), "Expected %v to be < %v", empty, good) 360 assert.False(t, badSort1.IsValid(), "Coins are not sorted") 361 assert.False(t, badSort2.IsValid(), "Coins are not sorted") 362 assert.False(t, badAmt.IsValid(), "Coins cannot include 0 amounts") 363 assert.False(t, dup.IsValid(), "Duplicate coin") 364 assert.False(t, neg.IsValid(), "Negative first-denom coin") 365 } 366 367 func TestCoinsGT(t *testing.T) { 368 t.Parallel() 369 370 one := int64(1) 371 two := int64(2) 372 373 assert.False(t, Coins{}.IsAllGT(Coins{})) 374 assert.True(t, Coins{{testDenom1, one}}.IsAllGT(Coins{})) 375 assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom1, one}})) 376 assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom2, one}})) 377 assert.True(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGT(Coins{{testDenom2, one}})) 378 assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGT(Coins{{testDenom2, two}})) 379 } 380 381 func TestCoinsLT(t *testing.T) { 382 t.Parallel() 383 384 one := int64(1) 385 two := int64(2) 386 387 assert.False(t, Coins{}.IsAllLT(Coins{})) 388 assert.False(t, Coins{{testDenom1, one}}.IsAllLT(Coins{})) 389 assert.False(t, Coins{{testDenom1, one}}.IsAllLT(Coins{{testDenom1, one}})) 390 assert.False(t, Coins{{testDenom1, one}}.IsAllLT(Coins{{testDenom2, one}})) 391 assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(Coins{{testDenom2, one}})) 392 assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(Coins{{testDenom2, two}})) 393 assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(Coins{{testDenom1, one}, {testDenom2, one}})) 394 assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(Coins{{testDenom1, two}, {testDenom2, two}})) 395 assert.True(t, Coins{}.IsAllLT(Coins{{testDenom1, one}})) 396 } 397 398 func TestCoinsLTE(t *testing.T) { 399 t.Parallel() 400 401 one := int64(1) 402 two := int64(2) 403 404 assert.True(t, Coins{}.IsAllLTE(Coins{})) 405 assert.False(t, Coins{{testDenom1, one}}.IsAllLTE(Coins{})) 406 assert.True(t, Coins{{testDenom1, one}}.IsAllLTE(Coins{{testDenom1, one}})) 407 assert.False(t, Coins{{testDenom1, one}}.IsAllLTE(Coins{{testDenom2, one}})) 408 assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(Coins{{testDenom2, one}})) 409 assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(Coins{{testDenom2, two}})) 410 assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(Coins{{testDenom1, one}, {testDenom2, one}})) 411 assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(Coins{{testDenom1, one}, {testDenom2, two}})) 412 assert.True(t, Coins{}.IsAllLTE(Coins{{testDenom1, one}})) 413 } 414 415 func TestParse(t *testing.T) { 416 t.Parallel() 417 418 one := int64(1) 419 420 cases := []struct { 421 input string 422 valid bool // if false, we expect an error on parse 423 expected Coins // if valid is true, make sure this is returned 424 }{ 425 {"", true, nil}, 426 {"1foo", true, Coins{{"foo", one}}}, 427 {"10bar", true, Coins{{"bar", int64(10)}}}, 428 {"99bar,1foo", true, Coins{{"bar", int64(99)}, {"foo", one}}}, 429 {"98 bar , 1 foo ", true, Coins{{"bar", int64(98)}, {"foo", one}}}, 430 {" 55\t \t bling\n", true, Coins{{"bling", int64(55)}}}, 431 {"2foo, 97 bar", true, Coins{{"bar", int64(97)}, {"foo", int64(2)}}}, 432 {"5foo-bar", false, nil}, 433 {"5 mycoin,", false, nil}, // no empty coins in a list 434 {"2 3foo, 97 bar", false, nil}, // 3foo is invalid coin name 435 {"11me coin, 12you coin", false, nil}, // no spaces in coin names 436 {"1.2btc", false, nil}, // amount must be integer 437 } 438 439 for tcIndex, tc := range cases { 440 res, err := ParseCoins(tc.input) 441 if !tc.valid { 442 require.NotNil(t, err, "%s: %#v. tc #%d", tc.input, res, tcIndex) 443 } else if assert.Nil(t, err, "%s: %+v", tc.input, err) { 444 require.Equal(t, tc.expected, res, "coin parsing was incorrect, tc #%d", tcIndex) 445 } 446 } 447 } 448 449 func TestSortCoins(t *testing.T) { 450 t.Parallel() 451 452 good := Coins{ 453 NewCoin("gas", 1), 454 NewCoin("mineral", 1), 455 NewCoin("tree", 1), 456 } 457 empty := Coins{ 458 NewCoin("gold", 0), 459 } 460 badSort1 := Coins{ 461 NewCoin("tree", 1), 462 NewCoin("gas", 1), 463 NewCoin("mineral", 1), 464 } 465 badSort2 := Coins{ // both are after the first one, but the second and third are in the wrong order 466 NewCoin("gas", 1), 467 NewCoin("tree", 1), 468 NewCoin("mineral", 1), 469 } 470 badAmt := Coins{ 471 NewCoin("gas", 1), 472 NewCoin("tree", 0), 473 NewCoin("mineral", 1), 474 } 475 dup := Coins{ 476 NewCoin("gas", 1), 477 NewCoin("gas", 1), 478 NewCoin("mineral", 1), 479 } 480 481 cases := []struct { 482 coins Coins 483 before, after bool // valid before/after sort 484 }{ 485 {good, true, true}, 486 {empty, false, false}, 487 {badSort1, false, true}, 488 {badSort2, false, true}, 489 {badAmt, false, false}, 490 {dup, false, false}, 491 } 492 493 for tcIndex, tc := range cases { 494 require.Equal(t, tc.before, tc.coins.IsValid(), "coin validity is incorrect before sorting, tc #%d", tcIndex) 495 tc.coins.Sort() 496 require.Equal(t, tc.after, tc.coins.IsValid(), "coin validity is incorrect after sorting, tc #%d", tcIndex) 497 } 498 } 499 500 func TestAmountOf(t *testing.T) { 501 t.Parallel() 502 503 case0 := Coins{} 504 case1 := Coins{ 505 NewCoin("gold", 0), 506 } 507 case2 := Coins{ 508 NewCoin("gas", 1), 509 NewCoin("mineral", 1), 510 NewCoin("tree", 1), 511 } 512 case3 := Coins{ 513 NewCoin("mineral", 1), 514 NewCoin("tree", 1), 515 } 516 case4 := Coins{ 517 NewCoin("gas", 8), 518 } 519 520 cases := []struct { 521 coins Coins 522 amountOf int64 523 amountOfSpace int64 524 amountOfGAS int64 525 amountOfMINERAL int64 526 amountOfTREE int64 527 }{ 528 {case0, 0, 0, 0, 0, 0}, 529 {case1, 0, 0, 0, 0, 0}, 530 {case2, 0, 0, 1, 1, 1}, 531 {case3, 0, 0, 0, 1, 1}, 532 {case4, 0, 0, 8, 0, 0}, 533 } 534 535 for _, tc := range cases { 536 assert.Equal(t, tc.amountOfGAS, tc.coins.AmountOf("gas")) 537 assert.Equal(t, tc.amountOfMINERAL, tc.coins.AmountOf("mineral")) 538 assert.Equal(t, tc.amountOfTREE, tc.coins.AmountOf("tree")) 539 } 540 541 assert.Panics(t, func() { cases[0].coins.AmountOf("Invalid") }) 542 } 543 544 func TestCoinsIsAnyGTE(t *testing.T) { 545 t.Parallel() 546 547 one := int64(1) 548 two := int64(2) 549 550 assert.False(t, Coins{}.IsAnyGTE(Coins{})) 551 assert.False(t, Coins{{testDenom1, one}}.IsAnyGTE(Coins{})) 552 assert.False(t, Coins{}.IsAnyGTE(Coins{{testDenom1, one}})) 553 assert.False(t, Coins{{testDenom1, one}}.IsAnyGTE(Coins{{testDenom1, two}})) 554 assert.False(t, Coins{{testDenom1, one}}.IsAnyGTE(Coins{{testDenom2, one}})) 555 assert.True(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAnyGTE(Coins{{testDenom1, two}, {testDenom2, one}})) 556 assert.True(t, Coins{{testDenom1, one}}.IsAnyGTE(Coins{{testDenom1, one}})) 557 assert.True(t, Coins{{testDenom1, two}}.IsAnyGTE(Coins{{testDenom1, one}})) 558 assert.True(t, Coins{{testDenom1, one}}.IsAnyGTE(Coins{{testDenom1, one}, {testDenom2, two}})) 559 assert.True(t, Coins{{testDenom2, two}}.IsAnyGTE(Coins{{testDenom1, one}, {testDenom2, two}})) 560 assert.False(t, Coins{{testDenom2, one}}.IsAnyGTE(Coins{{testDenom1, one}, {testDenom2, two}})) 561 assert.True(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAnyGTE(Coins{{testDenom1, one}, {testDenom2, one}})) 562 assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAnyGTE(Coins{{testDenom1, one}, {testDenom2, two}})) 563 assert.True(t, Coins{{"xxx", one}, {"yyy", one}}.IsAnyGTE(Coins{{testDenom2, one}, {"ccc", one}, {"yyy", one}, {"zzz", one}})) 564 } 565 566 func TestCoinsIsAllGT(t *testing.T) { 567 t.Parallel() 568 569 one := int64(1) 570 two := int64(2) 571 572 assert.False(t, Coins{}.IsAllGT(Coins{})) 573 assert.True(t, Coins{{testDenom1, one}}.IsAllGT(Coins{})) 574 assert.False(t, Coins{}.IsAllGT(Coins{{testDenom1, one}})) 575 assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom1, two}})) 576 assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom2, one}})) 577 assert.False(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGT(Coins{{testDenom1, two}, {testDenom2, one}})) 578 assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom1, one}})) 579 assert.True(t, Coins{{testDenom1, two}}.IsAllGT(Coins{{testDenom1, one}})) 580 assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom1, one}, {testDenom2, two}})) 581 assert.False(t, Coins{{testDenom2, two}}.IsAllGT(Coins{{testDenom1, one}, {testDenom2, two}})) 582 assert.False(t, Coins{{testDenom2, one}}.IsAllGT(Coins{{testDenom1, one}, {testDenom2, two}})) 583 assert.False(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGT(Coins{{testDenom1, one}, {testDenom2, one}})) 584 assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGT(Coins{{testDenom1, one}, {testDenom2, two}})) 585 assert.False(t, Coins{{"xxx", one}, {"yyy", one}}.IsAllGT(Coins{{testDenom2, one}, {"ccc", one}, {"yyy", one}, {"zzz", one}})) 586 } 587 588 func TestCoinsIsAllGTE(t *testing.T) { 589 t.Parallel() 590 591 one := int64(1) 592 two := int64(2) 593 594 assert.True(t, Coins{}.IsAllGTE(Coins{})) 595 assert.True(t, Coins{{testDenom1, one}}.IsAllGTE(Coins{})) 596 assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(Coins{{testDenom2, one}})) 597 assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(Coins{{testDenom2, two}})) 598 assert.False(t, Coins{}.IsAllGTE(Coins{{testDenom1, one}})) 599 assert.False(t, Coins{{testDenom1, one}}.IsAllGTE(Coins{{testDenom1, two}})) 600 assert.False(t, Coins{{testDenom1, one}}.IsAllGTE(Coins{{testDenom2, one}})) 601 assert.False(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGTE(Coins{{testDenom1, two}, {testDenom2, one}})) 602 assert.True(t, Coins{{testDenom1, one}}.IsAllGTE(Coins{{testDenom1, one}})) 603 assert.True(t, Coins{{testDenom1, two}}.IsAllGTE(Coins{{testDenom1, one}})) 604 assert.False(t, Coins{{testDenom1, one}}.IsAllGTE(Coins{{testDenom1, one}, {testDenom2, two}})) 605 assert.False(t, Coins{{testDenom2, two}}.IsAllGTE(Coins{{testDenom1, one}, {testDenom2, two}})) 606 assert.False(t, Coins{{testDenom2, one}}.IsAllGTE(Coins{{testDenom1, one}, {testDenom2, two}})) 607 assert.True(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGTE(Coins{{testDenom1, one}, {testDenom2, one}})) 608 assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(Coins{{testDenom1, one}, {testDenom2, two}})) 609 assert.False(t, Coins{{"xxx", one}, {"yyy", one}}.IsAllGTE(Coins{{testDenom2, one}, {"ccc", one}, {"yyy", one}, {"zzz", one}})) 610 } 611 612 func TestNewCoins(t *testing.T) { 613 t.Parallel() 614 615 tenatom := NewCoin("atom", 10) 616 tenbtc := NewCoin("btc", 10) 617 zeroeth := NewCoin("eth", 0) 618 tests := []struct { 619 name string 620 coins Coins 621 want Coins 622 wantPanic bool 623 }{ 624 {"empty args", []Coin{}, Coins{}, false}, 625 {"one coin", []Coin{tenatom}, Coins{tenatom}, false}, 626 {"sort after create", []Coin{tenbtc, tenatom}, Coins{tenatom, tenbtc}, false}, 627 {"sort and remove zeroes", []Coin{zeroeth, tenbtc, tenatom}, Coins{tenatom, tenbtc}, false}, 628 {"panic on dups", []Coin{tenatom, tenatom}, Coins{}, true}, 629 } 630 for _, tt := range tests { 631 tt := tt 632 t.Run(tt.name, func(t *testing.T) { 633 t.Parallel() 634 635 if tt.wantPanic { 636 require.Panics(t, func() { NewCoins(tt.coins...) }) 637 return 638 } 639 got := NewCoins(tt.coins...) 640 require.True(t, got.IsEqual(tt.want)) 641 }) 642 } 643 } 644 645 func TestCoinsIsAnyGT(t *testing.T) { 646 t.Parallel() 647 648 twoAtom := NewCoin("atom", 2) 649 fiveAtom := NewCoin("atom", 5) 650 threeEth := NewCoin("eth", 3) 651 sixEth := NewCoin("eth", 6) 652 twoBtc := NewCoin("btc", 2) 653 654 require.False(t, Coins{}.IsAnyGT(Coins{})) 655 656 require.False(t, Coins{fiveAtom}.IsAnyGT(Coins{})) 657 require.False(t, Coins{}.IsAnyGT(Coins{fiveAtom})) 658 require.True(t, Coins{fiveAtom}.IsAnyGT(Coins{twoAtom})) 659 require.False(t, Coins{twoAtom}.IsAnyGT(Coins{fiveAtom})) 660 661 require.True(t, Coins{twoAtom, sixEth}.IsAnyGT(Coins{twoBtc, fiveAtom, threeEth})) 662 require.False(t, Coins{twoBtc, twoAtom, threeEth}.IsAnyGT(Coins{fiveAtom, sixEth})) 663 require.False(t, Coins{twoAtom, sixEth}.IsAnyGT(Coins{twoBtc, fiveAtom})) 664 } 665 666 func TestFindDup(t *testing.T) { 667 t.Parallel() 668 669 abc := NewCoin("abc", 10) 670 def := NewCoin("def", 10) 671 ghi := NewCoin("ghi", 10) 672 673 type args struct { 674 coins Coins 675 } 676 tests := []struct { 677 name string 678 args args 679 want int 680 }{ 681 {"empty", args{NewCoins()}, -1}, 682 {"one coin", args{NewCoins(NewCoin("xyz", 10))}, -1}, 683 {"no dups", args{Coins{abc, def, ghi}}, -1}, 684 {"dup at first position", args{Coins{abc, abc, def}}, 1}, 685 {"dup after first position", args{Coins{abc, def, def}}, 2}, 686 } 687 for _, tt := range tests { 688 tt := tt 689 t.Run(tt.name, func(t *testing.T) { 690 t.Parallel() 691 692 if got := findDup(tt.args.coins); got != tt.want { 693 t.Errorf("findDup() = %v, want %v", got, tt.want) 694 } 695 }) 696 } 697 } 698 699 func TestMarshalJSONCoins(t *testing.T) { 700 t.Parallel() 701 702 testCases := []struct { 703 name string 704 input Coins 705 strOutput string 706 }{ 707 {"nil coins", nil, `""`}, 708 {"empty coins", Coins{}, `""`}, 709 {"non-empty coins", NewCoins(NewCoin("foo", 50)), `"50foo"`}, 710 } 711 712 for _, tc := range testCases { 713 tc := tc 714 715 t.Run(tc.name, func(t *testing.T) { 716 t.Parallel() 717 718 bz, err := amino.MarshalJSON(tc.input) 719 require.NoError(t, err) 720 require.Equal(t, tc.strOutput, string(bz)) 721 722 var newCoins Coins 723 require.NoError(t, amino.UnmarshalJSON(bz, &newCoins)) 724 725 if tc.input.Empty() { 726 require.Nil(t, newCoins) 727 } else { 728 require.Equal(t, tc.input, newCoins) 729 } 730 }) 731 } 732 }