diff options
author | Brandon Millman <brandon.millman@gmail.com> | 2018-10-03 07:13:16 +0800 |
---|---|---|
committer | Brandon Millman <brandon.millman@gmail.com> | 2018-10-03 07:13:16 +0800 |
commit | 343b922ec11a6108caaf3095e59be0e56d45ee4a (patch) | |
tree | ad38a124853c4cd153f5a290a0dc461447f8c799 /packages/sol-doc/test/solidity_doc_generator_test.ts | |
parent | 6deb027bdf4e57f8918fd2413f0fdc55311508d3 (diff) | |
parent | f1ecb8c5cb28a0a7ca6f7ad2ff11194091df62a4 (diff) | |
download | dexon-sol-tools-343b922ec11a6108caaf3095e59be0e56d45ee4a.tar dexon-sol-tools-343b922ec11a6108caaf3095e59be0e56d45ee4a.tar.gz dexon-sol-tools-343b922ec11a6108caaf3095e59be0e56d45ee4a.tar.bz2 dexon-sol-tools-343b922ec11a6108caaf3095e59be0e56d45ee4a.tar.lz dexon-sol-tools-343b922ec11a6108caaf3095e59be0e56d45ee4a.tar.xz dexon-sol-tools-343b922ec11a6108caaf3095e59be0e56d45ee4a.tar.zst dexon-sol-tools-343b922ec11a6108caaf3095e59be0e56d45ee4a.zip |
Merge branch 'development' into feature/asset-buyer/improve-asset-buyer-manager
* development: (178 commits)
Change cache key back to repo from repo-built
Change the lint command back
Merge build & install
Remove deps cache all together
Cache all nested node_modules directories
Explicitly specify yarn cache folder
Ignore linter issues
Fix linter issue
Separate deps and built caches
Build tslint rules before running linter
Cache yarn cache directory without node modules
Run linter before prettier as it fails more often
Add yarn cache path
Split CI install and build steps
Move bundle-size out of static tests and don't wait for a build with static tests
Introduce a build:ci command that doesn't build webpack bundles
Measure only one bundle size as they're the same
Fix linter errors
Fix no_website CI builds
Check bundle size on CI
...
Diffstat (limited to 'packages/sol-doc/test/solidity_doc_generator_test.ts')
-rw-r--r-- | packages/sol-doc/test/solidity_doc_generator_test.ts | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/packages/sol-doc/test/solidity_doc_generator_test.ts b/packages/sol-doc/test/solidity_doc_generator_test.ts new file mode 100644 index 000000000..f166fb143 --- /dev/null +++ b/packages/sol-doc/test/solidity_doc_generator_test.ts @@ -0,0 +1,273 @@ +import * as _ from 'lodash'; + +import * as chai from 'chai'; +import 'mocha'; + +import { DocAgnosticFormat, Event, SolidityMethod } from '@0xproject/types'; + +import { SolDoc } from '../src/sol_doc'; + +import { chaiSetup } from './util/chai_setup'; + +chaiSetup.configure(); +const expect = chai.expect; +const solDoc = new SolDoc(); + +describe('#SolidityDocGenerator', () => { + it('should generate a doc object that matches the devdoc-free TokenTransferProxy fixture', async () => { + const doc = await solDoc.generateSolDocAsync(`${__dirname}/../../test/fixtures/contracts`, [ + 'TokenTransferProxyNoDevdoc', + ]); + expect(doc).to.not.be.undefined(); + + verifyTokenTransferProxyABIIsDocumented(doc, 'TokenTransferProxyNoDevdoc'); + }); + const docPromises: Array<Promise<DocAgnosticFormat>> = [ + solDoc.generateSolDocAsync(`${__dirname}/../../test/fixtures/contracts`), + solDoc.generateSolDocAsync(`${__dirname}/../../test/fixtures/contracts`, []), + ]; + docPromises.forEach(docPromise => { + it('should generate a doc object that matches the TokenTransferProxy fixture with its dependencies', async () => { + const doc = await docPromise; + expect(doc).to.not.be.undefined(); + + verifyTokenTransferProxyAndDepsABIsAreDocumented(doc, 'TokenTransferProxy'); + + let addAuthorizedAddressMethod: SolidityMethod | undefined; + for (const method of doc.TokenTransferProxy.methods) { + if (method.name === 'addAuthorizedAddress') { + addAuthorizedAddressMethod = method; + } + } + const tokenTransferProxyAddAuthorizedAddressComment = 'Authorizes an address.'; + expect((addAuthorizedAddressMethod as SolidityMethod).comment).to.equal( + tokenTransferProxyAddAuthorizedAddressComment, + ); + + const expectedParamComment = 'Address to authorize.'; + expect((addAuthorizedAddressMethod as SolidityMethod).parameters[0].comment).to.equal(expectedParamComment); + }); + }); + it('should generate a doc object that matches the TokenTransferProxy fixture', async () => { + const doc: DocAgnosticFormat = await solDoc.generateSolDocAsync(`${__dirname}/../../test/fixtures/contracts`, [ + 'TokenTransferProxy', + ]); + verifyTokenTransferProxyABIIsDocumented(doc, 'TokenTransferProxy'); + }); + describe('when processing all the permutations of devdoc stuff that we use in our contracts', () => { + let doc: DocAgnosticFormat; + before(async () => { + doc = await solDoc.generateSolDocAsync(`${__dirname}/../../test/fixtures/contracts`, ['NatspecEverything']); + expect(doc).to.not.be.undefined(); + expect(doc.NatspecEverything).to.not.be.undefined(); + }); + it('should emit the contract @title as its comment', () => { + expect(doc.NatspecEverything.comment).to.equal('Contract Title'); + }); + describe('should emit public method documentation for', () => { + let methodDoc: SolidityMethod; + before(() => { + // tslint:disable-next-line:no-unnecessary-type-assertion + methodDoc = doc.NatspecEverything.methods.find(method => { + return method.name === 'publicMethod'; + }) as SolidityMethod; + if (_.isUndefined(methodDoc)) { + throw new Error('publicMethod not found'); + } + }); + it('method name', () => { + expect(methodDoc.name).to.equal('publicMethod'); + }); + it('method comment', () => { + expect(methodDoc.comment).to.equal('publicMethod @dev'); + }); + it('parameter name', () => { + expect(methodDoc.parameters[0].name).to.equal('p'); + }); + it('parameter comment', () => { + expect(methodDoc.parameters[0].comment).to.equal('publicMethod @param'); + }); + it('return type', () => { + expect(methodDoc.returnType.name).to.equal('int256'); + }); + it('return comment', () => { + expect(methodDoc.returnComment).to.equal('publicMethod @return'); + }); + }); + describe('should emit external method documentation for', () => { + let methodDoc: SolidityMethod; + before(() => { + // tslint:disable-next-line:no-unnecessary-type-assertion + methodDoc = doc.NatspecEverything.methods.find(method => { + return method.name === 'externalMethod'; + }) as SolidityMethod; + if (_.isUndefined(methodDoc)) { + throw new Error('externalMethod not found'); + } + }); + it('method name', () => { + expect(methodDoc.name).to.equal('externalMethod'); + }); + it('method comment', () => { + expect(methodDoc.comment).to.equal('externalMethod @dev'); + }); + it('parameter name', () => { + expect(methodDoc.parameters[0].name).to.equal('p'); + }); + it('parameter comment', () => { + expect(methodDoc.parameters[0].comment).to.equal('externalMethod @param'); + }); + it('return type', () => { + expect(methodDoc.returnType.name).to.equal('int256'); + }); + it('return comment', () => { + expect(methodDoc.returnComment).to.equal('externalMethod @return'); + }); + }); + it('should not truncate a multi-line devdoc comment', () => { + // tslint:disable-next-line:no-unnecessary-type-assertion + const methodDoc: SolidityMethod = doc.NatspecEverything.methods.find(method => { + return method.name === 'methodWithLongDevdoc'; + }) as SolidityMethod; + if (_.isUndefined(methodDoc)) { + throw new Error('methodWithLongDevdoc not found'); + } + expect(methodDoc.comment).to.equal( + 'Here is a really long developer documentation comment, which spans multiple lines, for the purposes of making sure that broken lines are consolidated into one devdoc comment.', + ); + }); + describe('should emit event documentation for', () => { + let eventDoc: Event; + before(() => { + eventDoc = (doc.NatspecEverything.events as Event[])[0]; + }); + it('event name', () => { + expect(eventDoc.name).to.equal('AnEvent'); + }); + it('parameter name', () => { + expect(eventDoc.eventArgs[0].name).to.equal('p'); + }); + }); + it('should not let solhint directives obscure natspec content', () => { + // tslint:disable-next-line:no-unnecessary-type-assertion + const methodDoc: SolidityMethod = doc.NatspecEverything.methods.find(method => { + return method.name === 'methodWithSolhintDirective'; + }) as SolidityMethod; + if (_.isUndefined(methodDoc)) { + throw new Error('methodWithSolhintDirective not found'); + } + expect(methodDoc.comment).to.equal('methodWithSolhintDirective @dev'); + }); + }); + it('should document a method that returns multiple values', async () => { + const doc = await solDoc.generateSolDocAsync(`${__dirname}/../../test/fixtures/contracts`, [ + 'MultipleReturnValues', + ]); + expect(doc.MultipleReturnValues).to.not.be.undefined(); + expect(doc.MultipleReturnValues.methods).to.not.be.undefined(); + let methodWithMultipleReturnValues: SolidityMethod | undefined; + for (const method of doc.MultipleReturnValues.methods) { + if (method.name === 'methodWithMultipleReturnValues') { + methodWithMultipleReturnValues = method; + } + } + if (_.isUndefined(methodWithMultipleReturnValues)) { + throw new Error('method should not be undefined'); + } + const returnType = methodWithMultipleReturnValues.returnType; + expect(returnType.typeDocType).to.equal('tuple'); + if (_.isUndefined(returnType.tupleElements)) { + throw new Error('returnType.tupleElements should not be undefined'); + } + expect(returnType.tupleElements.length).to.equal(2); + }); + it('should document a method that has a struct param and return value', async () => { + const doc = await solDoc.generateSolDocAsync(`${__dirname}/../../test/fixtures/contracts`, [ + 'StructParamAndReturn', + ]); + expect(doc.StructParamAndReturn).to.not.be.undefined(); + expect(doc.StructParamAndReturn.methods).to.not.be.undefined(); + let methodWithStructParamAndReturn: SolidityMethod | undefined; + for (const method of doc.StructParamAndReturn.methods) { + if (method.name === 'methodWithStructParamAndReturn') { + methodWithStructParamAndReturn = method; + } + } + if (_.isUndefined(methodWithStructParamAndReturn)) { + throw new Error('method should not be undefined'); + } + /** + * Solc maps devDoc comments to methods using a method signature. If we incorrectly + * generate the methodSignatures, the devDoc comments won't be correctly associated + * with their methods and they won't show up in the output. By checking that the comments + * are included for a method with structs as params/returns, we are sure that the methodSignature + * generation is correct for this case. + */ + expect(methodWithStructParamAndReturn.comment).to.be.equal('DEV_COMMENT'); + expect(methodWithStructParamAndReturn.returnComment).to.be.equal('RETURN_COMMENT'); + expect(methodWithStructParamAndReturn.parameters[0].comment).to.be.equal('STUFF_COMMENT'); + }); + it('should document the structs included in a contract', async () => { + const doc = await solDoc.generateSolDocAsync(`${__dirname}/../../test/fixtures/contracts`, [ + 'StructParamAndReturn', + ]); + expect(doc.structs).to.not.be.undefined(); + expect(doc.structs.types.length).to.be.equal(1); + }); +}); + +function verifyTokenTransferProxyABIIsDocumented(doc: DocAgnosticFormat, contractName: string): void { + expect(doc[contractName]).to.not.be.undefined(); + expect(doc[contractName].constructors).to.not.be.undefined(); + const tokenTransferProxyConstructorCount = 0; + const tokenTransferProxyMethodCount = 8; + const tokenTransferProxyEventCount = 3; + expect(doc[contractName].constructors.length).to.equal(tokenTransferProxyConstructorCount); + expect(doc[contractName].methods.length).to.equal(tokenTransferProxyMethodCount); + const events = doc[contractName].events; + if (_.isUndefined(events)) { + throw new Error('events should never be undefined'); + } + expect(events.length).to.equal(tokenTransferProxyEventCount); +} + +function verifyTokenTransferProxyAndDepsABIsAreDocumented(doc: DocAgnosticFormat, contractName: string): void { + verifyTokenTransferProxyABIIsDocumented(doc, contractName); + + expect(doc.ERC20).to.not.be.undefined(); + expect(doc.ERC20.constructors).to.not.be.undefined(); + expect(doc.ERC20.methods).to.not.be.undefined(); + const erc20ConstructorCount = 0; + const erc20MethodCount = 6; + const erc20EventCount = 2; + expect(doc.ERC20.constructors.length).to.equal(erc20ConstructorCount); + expect(doc.ERC20.methods.length).to.equal(erc20MethodCount); + if (_.isUndefined(doc.ERC20.events)) { + throw new Error('events should never be undefined'); + } + expect(doc.ERC20.events.length).to.equal(erc20EventCount); + + expect(doc.ERC20Basic).to.not.be.undefined(); + expect(doc.ERC20Basic.constructors).to.not.be.undefined(); + expect(doc.ERC20Basic.methods).to.not.be.undefined(); + const erc20BasicConstructorCount = 0; + const erc20BasicMethodCount = 3; + const erc20BasicEventCount = 1; + expect(doc.ERC20Basic.constructors.length).to.equal(erc20BasicConstructorCount); + expect(doc.ERC20Basic.methods.length).to.equal(erc20BasicMethodCount); + if (_.isUndefined(doc.ERC20Basic.events)) { + throw new Error('events should never be undefined'); + } + expect(doc.ERC20Basic.events.length).to.equal(erc20BasicEventCount); + + let addAuthorizedAddressMethod: SolidityMethod | undefined; + for (const method of doc[contractName].methods) { + if (method.name === 'addAuthorizedAddress') { + addAuthorizedAddressMethod = method; + } + } + expect( + addAuthorizedAddressMethod, + `method addAuthorizedAddress not found in ${JSON.stringify(doc[contractName].methods)}`, + ).to.not.be.undefined(); +} |