Initializable.test.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. const { expectEvent } = require('@openzeppelin/test-helpers');
  2. const { expect } = require('chai');
  3. const { expectRevertCustomError } = require('../../helpers/customError');
  4. const { MAX_UINT64 } = require('../../helpers/constants');
  5. const InitializableMock = artifacts.require('InitializableMock');
  6. const ConstructorInitializableMock = artifacts.require('ConstructorInitializableMock');
  7. const ChildConstructorInitializableMock = artifacts.require('ChildConstructorInitializableMock');
  8. const ReinitializerMock = artifacts.require('ReinitializerMock');
  9. const SampleChild = artifacts.require('SampleChild');
  10. const DisableBad1 = artifacts.require('DisableBad1');
  11. const DisableBad2 = artifacts.require('DisableBad2');
  12. const DisableOk = artifacts.require('DisableOk');
  13. contract('Initializable', function () {
  14. describe('basic testing without inheritance', function () {
  15. beforeEach('deploying', async function () {
  16. this.contract = await InitializableMock.new();
  17. });
  18. describe('before initialize', function () {
  19. it('initializer has not run', async function () {
  20. expect(await this.contract.initializerRan()).to.equal(false);
  21. });
  22. it('_initializing returns false before initialization', async function () {
  23. expect(await this.contract.isInitializing()).to.equal(false);
  24. });
  25. });
  26. describe('after initialize', function () {
  27. beforeEach('initializing', async function () {
  28. await this.contract.initialize();
  29. });
  30. it('initializer has run', async function () {
  31. expect(await this.contract.initializerRan()).to.equal(true);
  32. });
  33. it('_initializing returns false after initialization', async function () {
  34. expect(await this.contract.isInitializing()).to.equal(false);
  35. });
  36. it('initializer does not run again', async function () {
  37. await expectRevertCustomError(this.contract.initialize(), 'AlreadyInitialized', []);
  38. });
  39. });
  40. describe('nested under an initializer', function () {
  41. it('initializer modifier reverts', async function () {
  42. await expectRevertCustomError(this.contract.initializerNested(), 'AlreadyInitialized', []);
  43. });
  44. it('onlyInitializing modifier succeeds', async function () {
  45. await this.contract.onlyInitializingNested();
  46. expect(await this.contract.onlyInitializingRan()).to.equal(true);
  47. });
  48. });
  49. it('cannot call onlyInitializable function outside the scope of an initializable function', async function () {
  50. await expectRevertCustomError(this.contract.initializeOnlyInitializing(), 'NotInitializing', []);
  51. });
  52. });
  53. it('nested initializer can run during construction', async function () {
  54. const contract2 = await ConstructorInitializableMock.new();
  55. expect(await contract2.initializerRan()).to.equal(true);
  56. expect(await contract2.onlyInitializingRan()).to.equal(true);
  57. });
  58. it('multiple constructor levels can be initializers', async function () {
  59. const contract2 = await ChildConstructorInitializableMock.new();
  60. expect(await contract2.initializerRan()).to.equal(true);
  61. expect(await contract2.childInitializerRan()).to.equal(true);
  62. expect(await contract2.onlyInitializingRan()).to.equal(true);
  63. });
  64. describe('reinitialization', function () {
  65. beforeEach('deploying', async function () {
  66. this.contract = await ReinitializerMock.new();
  67. });
  68. it('can reinitialize', async function () {
  69. expect(await this.contract.counter()).to.be.bignumber.equal('0');
  70. await this.contract.initialize();
  71. expect(await this.contract.counter()).to.be.bignumber.equal('1');
  72. await this.contract.reinitialize(2);
  73. expect(await this.contract.counter()).to.be.bignumber.equal('2');
  74. await this.contract.reinitialize(3);
  75. expect(await this.contract.counter()).to.be.bignumber.equal('3');
  76. });
  77. it('can jump multiple steps', async function () {
  78. expect(await this.contract.counter()).to.be.bignumber.equal('0');
  79. await this.contract.initialize();
  80. expect(await this.contract.counter()).to.be.bignumber.equal('1');
  81. await this.contract.reinitialize(128);
  82. expect(await this.contract.counter()).to.be.bignumber.equal('2');
  83. });
  84. it('cannot nest reinitializers', async function () {
  85. expect(await this.contract.counter()).to.be.bignumber.equal('0');
  86. await expectRevertCustomError(this.contract.nestedReinitialize(2, 2), 'AlreadyInitialized', []);
  87. await expectRevertCustomError(this.contract.nestedReinitialize(2, 3), 'AlreadyInitialized', []);
  88. await expectRevertCustomError(this.contract.nestedReinitialize(3, 2), 'AlreadyInitialized', []);
  89. });
  90. it('can chain reinitializers', async function () {
  91. expect(await this.contract.counter()).to.be.bignumber.equal('0');
  92. await this.contract.chainReinitialize(2, 3);
  93. expect(await this.contract.counter()).to.be.bignumber.equal('2');
  94. });
  95. it('_getInitializedVersion returns right version', async function () {
  96. await this.contract.initialize();
  97. expect(await this.contract.getInitializedVersion()).to.be.bignumber.equal('1');
  98. await this.contract.reinitialize(12);
  99. expect(await this.contract.getInitializedVersion()).to.be.bignumber.equal('12');
  100. });
  101. describe('contract locking', function () {
  102. it('prevents initialization', async function () {
  103. await this.contract.disableInitializers();
  104. await expectRevertCustomError(this.contract.initialize(), 'AlreadyInitialized', []);
  105. });
  106. it('prevents re-initialization', async function () {
  107. await this.contract.disableInitializers();
  108. await expectRevertCustomError(this.contract.reinitialize(255), 'AlreadyInitialized', []);
  109. });
  110. it('can lock contract after initialization', async function () {
  111. await this.contract.initialize();
  112. await this.contract.disableInitializers();
  113. await expectRevertCustomError(this.contract.reinitialize(255), 'AlreadyInitialized', []);
  114. });
  115. });
  116. });
  117. describe('events', function () {
  118. it('constructor initialization emits event', async function () {
  119. const contract = await ConstructorInitializableMock.new();
  120. await expectEvent.inTransaction(contract.transactionHash, contract, 'Initialized', { version: '1' });
  121. });
  122. it('initialization emits event', async function () {
  123. const contract = await ReinitializerMock.new();
  124. const { receipt } = await contract.initialize();
  125. expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(1);
  126. expectEvent(receipt, 'Initialized', { version: '1' });
  127. });
  128. it('reinitialization emits event', async function () {
  129. const contract = await ReinitializerMock.new();
  130. const { receipt } = await contract.reinitialize(128);
  131. expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(1);
  132. expectEvent(receipt, 'Initialized', { version: '128' });
  133. });
  134. it('chained reinitialization emits multiple events', async function () {
  135. const contract = await ReinitializerMock.new();
  136. const { receipt } = await contract.chainReinitialize(2, 3);
  137. expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(2);
  138. expectEvent(receipt, 'Initialized', { version: '2' });
  139. expectEvent(receipt, 'Initialized', { version: '3' });
  140. });
  141. });
  142. describe('complex testing with inheritance', function () {
  143. const mother = '12';
  144. const gramps = '56';
  145. const father = '34';
  146. const child = '78';
  147. beforeEach('deploying', async function () {
  148. this.contract = await SampleChild.new();
  149. });
  150. beforeEach('initializing', async function () {
  151. await this.contract.initialize(mother, gramps, father, child);
  152. });
  153. it('initializes human', async function () {
  154. expect(await this.contract.isHuman()).to.be.equal(true);
  155. });
  156. it('initializes mother', async function () {
  157. expect(await this.contract.mother()).to.be.bignumber.equal(mother);
  158. });
  159. it('initializes gramps', async function () {
  160. expect(await this.contract.gramps()).to.be.bignumber.equal(gramps);
  161. });
  162. it('initializes father', async function () {
  163. expect(await this.contract.father()).to.be.bignumber.equal(father);
  164. });
  165. it('initializes child', async function () {
  166. expect(await this.contract.child()).to.be.bignumber.equal(child);
  167. });
  168. });
  169. describe('disabling initialization', function () {
  170. it('old and new patterns in bad sequence', async function () {
  171. await expectRevertCustomError(DisableBad1.new(), 'AlreadyInitialized', []);
  172. await expectRevertCustomError(DisableBad2.new(), 'AlreadyInitialized', []);
  173. });
  174. it('old and new patterns in good sequence', async function () {
  175. const ok = await DisableOk.new();
  176. await expectEvent.inConstruction(ok, 'Initialized', { version: '1' });
  177. await expectEvent.inConstruction(ok, 'Initialized', { version: MAX_UINT64 });
  178. });
  179. });
  180. });