aboutsummaryrefslogblamecommitdiffstats
path: root/packages/sol-doc/test/solidity_doc_generator_test.ts
blob: 896690ce6a3cd5a341fc2d30d4b723e35d3252da (plain) (tree)
1
2
3
4
5
6
7
8

                            


                             
                                                                            
 
                                                                    





                                              
                                         
                                                                                                            






                                                                                             





                                                                                                  
                                                                                                    

                                              
 
                                                                               
 




                                                                       
             



                                                                                           








































                                                                                                                        


                                                                                 


























                                                                                          


                                                                                   

































                                                                                                                                                                                                 
           

       
































































                                                                                                      
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`, []),
        generateSolDocAsync(`${__dirname}/../../test/fixtures/contracts`, ['TokenTransferProxy']),
    ];
    docPromises.forEach(docPromise => {
        it('should generate a doc object that matches the TokenTransferProxy fixture', async () => {
            const doc = await docPromise;
            expect(doc).to.not.be.undefined();

            verifyTokenTransferProxyABIIsDocumented(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);
        });
    });
    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 name', () => {
                expect(methodDoc.returnType.name).to.equal('r');
            });
            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 name', () => {
                expect(methodDoc.returnType.name).to.equal('r');
            });
            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');
        });
    });
});

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);

    expect(doc.Ownable).to.not.be.undefined();
    expect(doc.Ownable.constructors).to.not.be.undefined();
    expect(doc.Ownable.methods).to.not.be.undefined();
    const ownableConstructorCount = 1;
    const ownableMethodCount = 2;
    const ownableEventCount = 1;
    expect(doc.Ownable.constructors.length).to.equal(ownableConstructorCount);
    expect(doc.Ownable.methods.length).to.equal(ownableMethodCount);
    if (_.isUndefined(doc.Ownable.events)) {
        throw new Error('events should never be undefined');
    }
    expect(doc.Ownable.events.length).to.equal(ownableEventCount);

    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();
}