diff options
Diffstat (limited to 'packages/sol-doc/test/solidity_doc_generator_test.ts')
-rw-r--r-- | packages/sol-doc/test/solidity_doc_generator_test.ts | 237 |
1 files changed, 237 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..c780d3d31 --- /dev/null +++ b/packages/sol-doc/test/solidity_doc_generator_test.ts @@ -0,0 +1,237 @@ +import * as _ from 'lodash'; + +import * as chai from 'chai'; +import 'mocha'; + +import { DocAgnosticFormat, Event, SolidityMethod } from '@0xproject/types'; + +import { generateSolDocAsync } from '../src/solidity_doc_generator'; + +import { chaiSetup } from './util/chai_setup'; + +chaiSetup.configure(); +const expect = chai.expect; + +describe('#SolidityDocGenerator', () => { + it('should generate a doc object that matches the devdoc-free TokenTransferProxy fixture', async () => { + const doc = await generateSolDocAsync(`${__dirname}/../../test/fixtures/contracts`, [ + 'TokenTransferProxyNoDevdoc', + ]); + expect(doc).to.not.be.undefined(); + + verifyTokenTransferProxyABIIsDocumented(doc, 'TokenTransferProxyNoDevdoc'); + }); + const docPromises: Array<Promise<DocAgnosticFormat>> = [ + generateSolDocAsync(`${__dirname}/../../test/fixtures/contracts`), + 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 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 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 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); + }); +}); + +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(); +} |