UNPKG

11.4 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5var __importStar = (this && this.__importStar) || function (mod) {
6 if (mod && mod.__esModule) return mod;
7 var result = {};
8 if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
9 result["default"] = mod;
10 return result;
11};
12Object.defineProperty(exports, "__esModule", { value: true });
13var async_1 = __importDefault(require("async"));
14var changeCase = __importStar(require("change-case"));
15var web3_1 = __importDefault(require("web3"));
16/**
17 * @dev Get function name using method signature
18 * @param signature siganture
19 * @param methodIdentifiers Object containing all methods identifier
20 */
21function getFunctionFullName(signature, methodIdentifiers) {
22 for (var method in methodIdentifiers) {
23 if (signature.replace('0x', '') === methodIdentifiers[method].replace('0x', '')) {
24 return method;
25 }
26 }
27 return null;
28}
29/**
30 * @dev Check if function is constant using function ABI
31 * @param funcABI function ABI
32 */
33function isConstant(funcABI) {
34 return (funcABI.constant || funcABI.stateMutability === 'view' || funcABI.stateMutability === 'pure');
35}
36/**
37 * @dev Check if function is payable using function ABI
38 * @param funcABI function ABI
39 */
40function isPayable(funcABI) {
41 return (funcABI.payable || funcABI.stateMutability === 'payable');
42}
43/**
44 * @dev Get overrided sender provided using natspec
45 * @param userdoc method user documentaion
46 * @param signature signature
47 * @param methodIdentifiers Object containing all methods identifier
48 */
49function getOverridedSender(userdoc, signature, methodIdentifiers) {
50 var fullName = getFunctionFullName(signature, methodIdentifiers);
51 var senderRegex = /#sender: account-+(\d)/g;
52 var accountIndex = fullName && userdoc.methods[fullName] ? senderRegex.exec(userdoc.methods[fullName].notice) : null;
53 return fullName && accountIndex ? accountIndex[1] : null;
54}
55/**
56 * @dev Get value provided using natspec
57 * @param userdoc method user documentaion
58 * @param signature signature
59 * @param methodIdentifiers Object containing all methods identifier
60 */
61function getProvidedValue(userdoc, signature, methodIdentifiers) {
62 var fullName = getFunctionFullName(signature, methodIdentifiers);
63 var valueRegex = /#value: (\d+)/g;
64 var value = fullName && userdoc.methods[fullName] ? valueRegex.exec(userdoc.methods[fullName].notice) : null;
65 return fullName && value ? value[1] : null;
66}
67/**
68 * @dev returns functions of a test contract file in same sequence they appear in file (using passed AST)
69 * @param fileAST AST of test contract file source
70 * @param testContractName Name of test contract
71 */
72function getAvailableFunctions(fileAST, testContractName) {
73 var funcList = [];
74 if (fileAST.nodes && fileAST.nodes.length > 0) {
75 var contractAST = fileAST.nodes.filter(function (node) { return node.name === testContractName && node.nodeType === 'ContractDefinition'; });
76 if (contractAST.length > 0 && contractAST[0].nodes) {
77 var funcNodes = contractAST[0].nodes.filter(function (node) { return ((node.kind === "function" && node.nodeType === "FunctionDefinition") || (node.nodeType === "FunctionDefinition")); });
78 funcList = funcNodes.map(function (node) { return node.name; });
79 }
80 }
81 return funcList;
82}
83/**
84 * @dev returns ABI of passed method list from passed interface
85 * @param jsonInterface Json Interface
86 * @param funcList Methods to extract the interface of
87 */
88function getTestFunctionsInterface(jsonInterface, funcList) {
89 var functionsInterface = [];
90 var specialFunctions = ['beforeAll', 'beforeEach', 'afterAll', 'afterEach'];
91 var _loop_1 = function (func) {
92 if (!specialFunctions.includes(func)) {
93 var funcInterface = jsonInterface.find(function (node) { return node.type === 'function' && node.name === func; });
94 if (funcInterface)
95 functionsInterface.push(funcInterface);
96 }
97 };
98 for (var _i = 0, funcList_1 = funcList; _i < funcList_1.length; _i++) {
99 var func = funcList_1[_i];
100 _loop_1(func);
101 }
102 return functionsInterface;
103}
104/**
105 * @dev Prepare a list of tests to run using test contract file ABI, AST & contract name
106 * @param jsonInterface File JSON interface
107 * @param fileAST File AST
108 * @param testContractName Test contract name
109 */
110function createRunList(jsonInterface, fileAST, testContractName) {
111 var availableFunctions = getAvailableFunctions(fileAST, testContractName);
112 var testFunctionsInterface = getTestFunctionsInterface(jsonInterface, availableFunctions);
113 var runList = [];
114 if (availableFunctions.indexOf('beforeAll') >= 0) {
115 runList.push({ name: 'beforeAll', type: 'internal', constant: false, payable: false });
116 }
117 for (var _i = 0, testFunctionsInterface_1 = testFunctionsInterface; _i < testFunctionsInterface_1.length; _i++) {
118 var func = testFunctionsInterface_1[_i];
119 if (availableFunctions.indexOf('beforeEach') >= 0) {
120 runList.push({ name: 'beforeEach', type: 'internal', constant: false, payable: false });
121 }
122 if (func.name)
123 runList.push({ name: func.name, signature: func.signature, type: 'test', constant: isConstant(func), payable: isPayable(func) });
124 if (availableFunctions.indexOf('afterEach') >= 0) {
125 runList.push({ name: 'afterEach', type: 'internal', constant: false, payable: false });
126 }
127 }
128 if (availableFunctions.indexOf('afterAll') >= 0) {
129 runList.push({ name: 'afterAll', type: 'internal', constant: false, payable: false });
130 }
131 return runList;
132}
133function runTest(testName, testObject, contractDetails, fileAST, opts, testCallback, resultsCallback) {
134 var passingNum = 0;
135 var failureNum = 0;
136 var timePassed = 0;
137 var isJSONInterfaceAvailable = testObject && testObject.options && testObject.options.jsonInterface;
138 if (!isJSONInterfaceAvailable)
139 return resultsCallback(new Error('Contract interface not available'), { passingNum: passingNum, failureNum: failureNum, timePassed: timePassed });
140 var runList = createRunList(testObject.options.jsonInterface, fileAST, testName);
141 var web3 = new web3_1.default();
142 var accts = {
143 type: 'accountList',
144 value: opts.accounts
145 };
146 testCallback(undefined, accts);
147 var resp = {
148 type: 'contract',
149 value: testName,
150 filename: testObject.filename
151 };
152 testCallback(undefined, resp);
153 async_1.default.eachOfLimit(runList, 1, function (func, index, next) {
154 var sender = null;
155 if (func.signature) {
156 sender = getOverridedSender(contractDetails.userdoc, func.signature, contractDetails.evm.methodIdentifiers);
157 if (opts.accounts && sender) {
158 sender = opts.accounts[sender];
159 }
160 }
161 var sendParams = null;
162 if (sender)
163 sendParams = { from: sender };
164 var method = testObject.methods[func.name].apply(testObject.methods[func.name], []);
165 var startTime = Date.now();
166 if (func.constant) {
167 method.call(sendParams).then(function (result) {
168 var time = (Date.now() - startTime) / 1000.0;
169 if (result) {
170 var resp_1 = {
171 type: 'testPass',
172 value: changeCase.sentenceCase(func.name),
173 time: time,
174 context: testName
175 };
176 testCallback(undefined, resp_1);
177 passingNum += 1;
178 timePassed += time;
179 }
180 else {
181 var resp_2 = {
182 type: 'testFailure',
183 value: changeCase.sentenceCase(func.name),
184 time: time,
185 errMsg: 'function returned false',
186 context: testName
187 };
188 testCallback(undefined, resp_2);
189 failureNum += 1;
190 }
191 next();
192 });
193 }
194 else {
195 if (func.payable) {
196 var value = getProvidedValue(contractDetails.userdoc, func.signature, contractDetails.evm.methodIdentifiers);
197 if (value) {
198 if (sendParams)
199 sendParams.value = value;
200 else
201 sendParams = { value: value };
202 }
203 }
204 method.send(sendParams).on('receipt', function (receipt) {
205 try {
206 var time = (Date.now() - startTime) / 1000.0;
207 var topic = web3_1.default.utils.sha3('AssertionEvent(bool,string)');
208 var testPassed = false;
209 for (var i in receipt.events) {
210 var event_1 = receipt.events[i];
211 if (event_1.raw.topics.indexOf(topic) >= 0) {
212 var testEvent = web3.eth.abi.decodeParameters(['bool', 'string'], event_1.raw.data);
213 if (!testEvent[0]) {
214 var resp_3 = {
215 type: 'testFailure',
216 value: changeCase.sentenceCase(func.name),
217 time: time,
218 errMsg: testEvent[1],
219 context: testName
220 };
221 testCallback(undefined, resp_3);
222 failureNum += 1;
223 return next();
224 }
225 testPassed = true;
226 }
227 }
228 if (testPassed) {
229 var resp_4 = {
230 type: 'testPass',
231 value: changeCase.sentenceCase(func.name),
232 time: time,
233 context: testName
234 };
235 testCallback(undefined, resp_4);
236 passingNum += 1;
237 }
238 return next();
239 }
240 catch (err) {
241 console.error(err);
242 return next(err);
243 }
244 }).on('error', function (err) {
245 console.error(err);
246 var time = (Date.now() - startTime) / 1000.0;
247 var resp = {
248 type: 'testFailure',
249 value: changeCase.sentenceCase(func.name),
250 time: time,
251 errMsg: err.message,
252 context: testName
253 };
254 testCallback(undefined, resp);
255 failureNum += 1;
256 return next();
257 });
258 }
259 }, function (error) {
260 resultsCallback(error, { passingNum: passingNum, failureNum: failureNum, timePassed: timePassed });
261 });
262}
263exports.runTest = runTest;
264//# sourceMappingURL=testRunner.js.map
\No newline at end of file