SafeCast.test.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. const { ethers } = require('hardhat');
  2. const { expect } = require('chai');
  3. const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
  4. const { range } = require('../../../scripts/helpers');
  5. async function fixture() {
  6. const mock = await ethers.deployContract('$SafeCast');
  7. return { mock };
  8. }
  9. describe('SafeCast', function () {
  10. beforeEach(async function () {
  11. Object.assign(this, await loadFixture(fixture));
  12. });
  13. for (const bits of range(8, 256, 8).map(ethers.toBigInt)) {
  14. const maxValue = 2n ** bits - 1n;
  15. describe(`toUint${bits}`, () => {
  16. it('downcasts 0', async function () {
  17. expect(await this.mock[`$toUint${bits}`](0n)).is.equal(0n);
  18. });
  19. it('downcasts 1', async function () {
  20. expect(await this.mock[`$toUint${bits}`](1n)).is.equal(1n);
  21. });
  22. it(`downcasts 2^${bits} - 1 (${maxValue})`, async function () {
  23. expect(await this.mock[`$toUint${bits}`](maxValue)).is.equal(maxValue);
  24. });
  25. it(`reverts when downcasting 2^${bits} (${maxValue + 1n})`, async function () {
  26. await expect(this.mock[`$toUint${bits}`](maxValue + 1n))
  27. .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintDowncast')
  28. .withArgs(bits, maxValue + 1n);
  29. });
  30. it(`reverts when downcasting 2^${bits} + 1 (${maxValue + 2n})`, async function () {
  31. await expect(this.mock[`$toUint${bits}`](maxValue + 2n))
  32. .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintDowncast')
  33. .withArgs(bits, maxValue + 2n);
  34. });
  35. });
  36. }
  37. describe('toUint256', () => {
  38. it('casts 0', async function () {
  39. expect(await this.mock.$toUint256(0n)).is.equal(0n);
  40. });
  41. it('casts 1', async function () {
  42. expect(await this.mock.$toUint256(1n)).is.equal(1n);
  43. });
  44. it(`casts INT256_MAX (${ethers.MaxInt256})`, async function () {
  45. expect(await this.mock.$toUint256(ethers.MaxInt256)).is.equal(ethers.MaxInt256);
  46. });
  47. it('reverts when casting -1', async function () {
  48. await expect(this.mock.$toUint256(-1n))
  49. .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntToUint')
  50. .withArgs(-1n);
  51. });
  52. it(`reverts when casting INT256_MIN (${ethers.MinInt256})`, async function () {
  53. await expect(this.mock.$toUint256(ethers.MinInt256))
  54. .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntToUint')
  55. .withArgs(ethers.MinInt256);
  56. });
  57. });
  58. for (const bits of range(8, 256, 8).map(ethers.toBigInt)) {
  59. const minValue = -(2n ** (bits - 1n));
  60. const maxValue = 2n ** (bits - 1n) - 1n;
  61. describe(`toInt${bits}`, () => {
  62. it('downcasts 0', async function () {
  63. expect(await this.mock[`$toInt${bits}`](0n)).is.equal(0n);
  64. });
  65. it('downcasts 1', async function () {
  66. expect(await this.mock[`$toInt${bits}`](1n)).is.equal(1n);
  67. });
  68. it('downcasts -1', async function () {
  69. expect(await this.mock[`$toInt${bits}`](-1n)).is.equal(-1n);
  70. });
  71. it(`downcasts -2^${bits - 1n} (${minValue})`, async function () {
  72. expect(await this.mock[`$toInt${bits}`](minValue)).is.equal(minValue);
  73. });
  74. it(`downcasts 2^${bits - 1n} - 1 (${maxValue})`, async function () {
  75. expect(await this.mock[`$toInt${bits}`](maxValue)).is.equal(maxValue);
  76. });
  77. it(`reverts when downcasting -2^${bits - 1n} - 1 (${minValue - 1n})`, async function () {
  78. await expect(this.mock[`$toInt${bits}`](minValue - 1n))
  79. .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast')
  80. .withArgs(bits, minValue - 1n);
  81. });
  82. it(`reverts when downcasting -2^${bits - 1n} - 2 (${minValue - 2n})`, async function () {
  83. await expect(this.mock[`$toInt${bits}`](minValue - 2n))
  84. .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast')
  85. .withArgs(bits, minValue - 2n);
  86. });
  87. it(`reverts when downcasting 2^${bits - 1n} (${maxValue + 1n})`, async function () {
  88. await expect(this.mock[`$toInt${bits}`](maxValue + 1n))
  89. .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast')
  90. .withArgs(bits, maxValue + 1n);
  91. });
  92. it(`reverts when downcasting 2^${bits - 1n} + 1 (${maxValue + 2n})`, async function () {
  93. await expect(this.mock[`$toInt${bits}`](maxValue + 2n))
  94. .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast')
  95. .withArgs(bits, maxValue + 2n);
  96. });
  97. });
  98. }
  99. describe('toInt256', () => {
  100. it('casts 0', async function () {
  101. expect(await this.mock.$toInt256(0)).is.equal(0n);
  102. });
  103. it('casts 1', async function () {
  104. expect(await this.mock.$toInt256(1)).is.equal(1n);
  105. });
  106. it(`casts INT256_MAX (${ethers.MaxInt256})`, async function () {
  107. expect(await this.mock.$toInt256(ethers.MaxInt256)).is.equal(ethers.MaxInt256);
  108. });
  109. it(`reverts when casting INT256_MAX + 1 (${ethers.MaxInt256 + 1n})`, async function () {
  110. await expect(this.mock.$toInt256(ethers.MaxInt256 + 1n))
  111. .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintToInt')
  112. .withArgs(ethers.MaxInt256 + 1n);
  113. });
  114. it(`reverts when casting UINT256_MAX (${ethers.MaxUint256})`, async function () {
  115. await expect(this.mock.$toInt256(ethers.MaxUint256))
  116. .to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintToInt')
  117. .withArgs(ethers.MaxUint256);
  118. });
  119. });
  120. });