115 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			115 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { join } from 'path';
 | |
| 
 | |
| import * as chai from 'chai';
 | |
| import { CompilerOptions, ContractArtifact } from 'ethereum-types';
 | |
| import 'mocha';
 | |
| 
 | |
| import { Compiler } from '../src/compiler';
 | |
| import { fsWrapper } from '../src/utils/fs_wrapper';
 | |
| 
 | |
| import { exchange_binary } from './fixtures/exchange_bin';
 | |
| import { chaiSetup } from './util/chai_setup';
 | |
| import { constants } from './util/constants';
 | |
| 
 | |
| chaiSetup.configure();
 | |
| const expect = chai.expect;
 | |
| 
 | |
| describe('#Compiler', function(): void {
 | |
|     this.timeout(constants.timeoutMs); // tslint:disable-line:no-invalid-this
 | |
|     const artifactsDir = `${__dirname}/fixtures/artifacts`;
 | |
|     const contractsDir = `${__dirname}/fixtures/contracts`;
 | |
|     const compilerOpts: CompilerOptions = {
 | |
|         artifactsDir,
 | |
|         contractsDir,
 | |
|         contracts: constants.contracts,
 | |
|     };
 | |
|     it('should create an Exchange artifact with the correct unlinked binary', async () => {
 | |
|         compilerOpts.contracts = ['Exchange'];
 | |
| 
 | |
|         const exchangeArtifactPath = `${artifactsDir}/Exchange.json`;
 | |
|         if (fsWrapper.doesPathExistSync(exchangeArtifactPath)) {
 | |
|             await fsWrapper.removeFileAsync(exchangeArtifactPath);
 | |
|         }
 | |
| 
 | |
|         await new Compiler(compilerOpts).compileAsync();
 | |
| 
 | |
|         const opts = {
 | |
|             encoding: 'utf8',
 | |
|         };
 | |
|         const exchangeArtifactString = await fsWrapper.readFileAsync(exchangeArtifactPath, opts);
 | |
|         const exchangeArtifact: ContractArtifact = JSON.parse(exchangeArtifactString);
 | |
|         // The last 43 bytes of the binaries are metadata which may not be equivalent
 | |
|         const metadataByteLength = 43;
 | |
|         const metadataHexLength = metadataByteLength * 2;
 | |
|         const unlinkedBinaryWithoutMetadata = exchangeArtifact.compilerOutput.evm.bytecode.object.slice(
 | |
|             2,
 | |
|             -metadataHexLength,
 | |
|         );
 | |
|         const exchangeBinaryWithoutMetadata = exchange_binary.slice(0, -metadataHexLength);
 | |
|         expect(unlinkedBinaryWithoutMetadata).to.equal(exchangeBinaryWithoutMetadata);
 | |
|     });
 | |
|     it("should throw when Whatever.sol doesn't contain a Whatever contract", async () => {
 | |
|         const contract = 'BadContractName';
 | |
| 
 | |
|         const exchangeArtifactPath = `${artifactsDir}/${contract}.json`;
 | |
|         if (fsWrapper.doesPathExistSync(exchangeArtifactPath)) {
 | |
|             await fsWrapper.removeFileAsync(exchangeArtifactPath);
 | |
|         }
 | |
| 
 | |
|         compilerOpts.contracts = [contract];
 | |
|         const compiler = new Compiler(compilerOpts);
 | |
| 
 | |
|         expect(compiler.compileAsync()).to.be.rejected();
 | |
|     });
 | |
|     describe('after a successful compilation', () => {
 | |
|         const contract = 'Exchange';
 | |
|         let artifactPath: string;
 | |
|         let artifactCreatedAtMs: number;
 | |
|         beforeEach(async () => {
 | |
|             compilerOpts.contracts = [contract];
 | |
| 
 | |
|             artifactPath = `${artifactsDir}/${contract}.json`;
 | |
|             if (fsWrapper.doesPathExistSync(artifactPath)) {
 | |
|                 await fsWrapper.removeFileAsync(artifactPath);
 | |
|             }
 | |
| 
 | |
|             await new Compiler(compilerOpts).compileAsync();
 | |
| 
 | |
|             artifactCreatedAtMs = (await fsWrapper.statAsync(artifactPath)).mtimeMs;
 | |
|         });
 | |
|         it('recompilation should update artifact when source has changed', async () => {
 | |
|             // append some meaningless data to the contract, so that its hash
 | |
|             // will change, so that the compiler will decide to recompile it.
 | |
|             await fsWrapper.appendFileAsync(join(contractsDir, `${contract}.sol`), ' ');
 | |
| 
 | |
|             await new Compiler(compilerOpts).compileAsync();
 | |
| 
 | |
|             const artifactModifiedAtMs = (await fsWrapper.statAsync(artifactPath)).mtimeMs;
 | |
| 
 | |
|             expect(artifactModifiedAtMs).to.be.greaterThan(artifactCreatedAtMs);
 | |
|         });
 | |
|         it("recompilation should NOT update artifact when source hasn't changed", async () => {
 | |
|             await new Compiler(compilerOpts).compileAsync();
 | |
| 
 | |
|             const artifactModifiedAtMs = (await fsWrapper.statAsync(artifactPath)).mtimeMs;
 | |
| 
 | |
|             expect(artifactModifiedAtMs).to.equal(artifactCreatedAtMs);
 | |
|         });
 | |
|     });
 | |
|     it('should only compile what was requested', async () => {
 | |
|         // remove all artifacts
 | |
|         for (const artifact of await fsWrapper.readdirAsync(artifactsDir)) {
 | |
|             await fsWrapper.removeFileAsync(join(artifactsDir, artifact));
 | |
|         }
 | |
| 
 | |
|         // compile EmptyContract
 | |
|         compilerOpts.contracts = ['EmptyContract'];
 | |
|         await new Compiler(compilerOpts).compileAsync();
 | |
| 
 | |
|         // make sure the artifacts dir only contains EmptyContract.json
 | |
|         for (const artifact of await fsWrapper.readdirAsync(artifactsDir)) {
 | |
|             expect(artifact).to.equal('EmptyContract.json');
 | |
|         }
 | |
|     });
 | |
| });
 |