1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

Add WASM FunC autotests (#673)

* feat: func wasm autotests

* fixes necessary for func wasm autotests

---------

Co-authored-by: krigga <krigga7@gmail.com>
This commit is contained in:
EmelyanenkoK 2023-04-19 21:29:41 +03:00 committed by GitHub
parent 8d919a5db9
commit 8b0d6a2665
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 172 additions and 3 deletions

View file

@ -166,7 +166,7 @@ AsmOp AsmOp::UnTuple(int a) {
AsmOp AsmOp::IntConst(td::RefInt256 x) {
if (x->signed_fits_bits(8)) {
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINT", x);
return AsmOp::Const(dec_string(x) + " PUSHINT", x);
}
if (!x->is_valid()) {
return AsmOp::Const("PUSHNAN", x);
@ -184,9 +184,9 @@ AsmOp AsmOp::IntConst(td::RefInt256 x) {
return AsmOp::Const(k, "PUSHNEGPOW2", x);
}
if (!x->mod_pow2_short(23)) {
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINTX", x);
return AsmOp::Const(dec_string(x) + " PUSHINTX", x);
}
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINT", x);
return AsmOp::Const(dec_string(x) + " PUSHINT", x);
}
AsmOp AsmOp::BoolConst(bool f) {

View file

@ -0,0 +1,27 @@
const fs = require('fs/promises');
const { compileWasm, compileFile } = require('./wasm_tests_common');
async function main() {
const tests = JSON.parse((await fs.readFile('../legacy_tests.json')).toString('utf-8'))
for (const [filename, hashstr] of tests) {
if (filename.includes('storage-provider')) continue;
const mod = await compileWasm()
const response = await compileFile(mod, filename);
if (response.status !== 'ok') {
console.error(response);
throw new Error('Could not compile ' + filename);
}
if (BigInt('0x' + response.codeHashHex) !== BigInt(hashstr)) {
throw new Error('Compilation result is different for ' + filename);
}
console.log(filename, 'ok');
}
}
main()

View file

@ -0,0 +1 @@
[["elector/elector-code.fc", "115226404411715505328583639896096915745686314074575650766750648324043316883483"], ["config/config-code.fc", "10913070768607625342121305745084703121685937915388357634624451844356456145601"], ["eth-bridge-multisig/multisig-code.fc", "101509909129354488841890823627011033360100627957439967918234053299675481277954"], ["bsc-bridge-collector/votes-collector.fc", "62190447221288642706570413295807615918589884489514159926097051017036969900417"], ["uni-lock-wallet/uni-lockup-wallet.fc", "61959738324779104851267145467044677651344601417998258530238254441977103654381"], ["nft-collection/nft-collection-editable.fc", "45561997735512210616567774035540357815786262097548276229169737015839077731274"], ["dns-collection/nft-collection.fc", "107999822699841936063083742021519765435859194241091312445235370766165379261859"], ["tele-nft-item/nft-item.fc", "69777543125381987786450436977742010705076866061362104025338034583422166453344"], ["storage/storage-contract.fc", "91377830060355733016937375216020277778264560226873154627574229667513068328151"], ["storage/storage-provider.fc", "13618336676213331164384407184540461509022654507176709588621016553953760588122"], ["nominator-pool/pool.fc", "69767057279163099864792356875696330339149706521019810113334238732928422055375"], ["jetton-minter/jetton-minter.fc", "9028309926287301331466371999814928201427184114165428257502393474125007156494"], ["gg-marketplace/nft-marketplace-v2.fc", "92199806964112524639740773542356508485601908152150843819273107618799016205930"], ["jetton-wallet/jetton-wallet.fc", "86251125787443633057458168028617933212663498001665054651523310772884328206542"], ["whales-nominators/nominators.fc", "8941364499854379927692172316865293429893094891593442801401542636695127885153"], ["tact-examples/treasure_Treasure.code.fc", "13962538639825790677138656603323869918938565499584297120566680287245364723897"], ["tact-examples/jetton_SampleJetton.code.fc", "94076762218493729104783735200107713211245710256802265203823917715299139499110"], ["tact-examples/jetton_JettonDefaultWallet.code.fc", "29421313492520031238091587108198906058157443241743283101866538036369069620563"], ["tact-examples/maps_MapTestContract.code.fc", "22556550222249123835909180266811414538971143565993192846012583552876721649744"]]

View file

@ -0,0 +1,77 @@
const fs = require('fs/promises');
const os = require('os');
const path = require('path');
const { compileWasm, compileFile } = require('./wasm_tests_common');
const { execSync } = require('child_process');
async function main() {
const compiledPath = path.join(os.tmpdir(), 'compiled.fif');
const runnerPath = path.join(os.tmpdir(), 'runner.fif');
const tests = (await fs.readdir('.')).filter(f => f.endsWith('.fc')).sort();
const mathChars = '0x123456789()+-*/<>'.split('')
for (const testFile of tests) {
const mod = await compileWasm()
const result = await compileFile(mod, testFile)
if (result.status !== 'ok') {
console.error(result);
throw new Error('Could not compile ' + filename);
}
const fileLines = (await fs.readFile(testFile)).toString('utf-8').split('\n');
const testCases = [];
for (const line of fileLines) {
const parts = line.split('|').map(c => c.trim());
if (parts.length !== 4 || parts[0] !== 'TESTCASE') continue;
const processedInputs = [];
for (const input of parts[2].split(' ')) {
if (input.includes('x{')) {
processedInputs.push(input);
continue;
}
if (input.length === 0) {
continue
}
const replacedInput = input.split('').filter(c => mathChars.includes(c)).join('').replace('//', '/').replace(/([0-9a-f])($|[^0-9a-fx])/gmi, '$1n$2')
processedInputs.push(eval(replacedInput).toString());
}
testCases.push([parts[1], processedInputs.join(' '), parts[3]]);
}
await fs.writeFile(compiledPath, '"Asm.fif" include\n' + JSON.parse('"' + result.fiftCode + '"'));
await fs.writeFile(runnerPath, `"${compiledPath}" include <s constant code\n${testCases.map(t => `${t[1]} ${t[0]} code 1 runvmx abort"exitcode is not 0" .s cr { drop } depth 1- times`).join('\n')}`)
const fiftResult = execSync(`${process.env.FIFT_EXECUTABLE || 'fift'} -I ${process.env.FIFT_LIBS} /tmp/runner.fif`, {
stdio: ['pipe', 'pipe', 'ignore']
}).toString('utf-8')
const testResults = fiftResult.split('\n').map(s => s.trim()).filter(s => s.length > 0)
if (testResults.length !== testCases.length) {
throw new Error(`Got ${testResults.length} results but there are ${testCases.length} cases`)
}
for (let i = 0; i < testResults.length; i++) {
if (testResults[i] !== testCases[i][2]) {
throw new Error(`Unequal result ${testResults[i]} and case ${testCases[i][2]}`)
}
}
console.log(testFile, 'ok')
}
}
main()

View file

@ -0,0 +1,63 @@
const fsSync = require('fs');
const copyToCString = (mod, str) => {
const len = mod.lengthBytesUTF8(str) + 1;
const ptr = mod._malloc(len);
mod.stringToUTF8(str, ptr, len);
return ptr;
};
const copyToCStringPtr = (mod, str, ptr) => {
const allocated = copyToCString(mod, str);
mod.setValue(ptr, allocated, '*');
return allocated;
};
const copyFromCString = (mod, ptr) => {
return mod.UTF8ToString(ptr);
};
async function compileFile(mod, filename) {
const callbackPtr = mod.addFunction((_kind, _data, contents, error) => {
const kind = copyFromCString(mod, _kind);
const data = copyFromCString(mod, _data);
if (kind === 'realpath') {
copyToCStringPtr(mod, fsSync.realpathSync(data), contents);
} else if (kind === 'source') {
const path = fsSync.realpathSync(data);
try {
copyToCStringPtr(mod, fsSync.readFileSync(path).toString('utf-8'), contents);
} catch (err) {
copyToCStringPtr(mod, e.message, error);
}
} else {
copyToCStringPtr(mod, 'Unknown callback kind ' + kind, error);
}
}, 'viiii');
const config = {
optLevel: 2,
sources: [filename]
};
const configPtr = copyToCString(mod, JSON.stringify(config));
const responsePtr = mod._func_compile(configPtr, callbackPtr);
return JSON.parse(copyFromCString(mod, responsePtr));
}
const wasmModule = require(process.env.FUNCFIFTLIB_MODULE)
const wasmBinary = new Uint8Array(fsSync.readFileSync(process.env.FUNCFIFTLIB_WASM))
async function compileWasm() {
const mod = await wasmModule({ wasmBinary })
return mod
}
module.exports = {
compileFile,
compileWasm
}

View file

@ -92,6 +92,7 @@ td::Result<std::string> compile_internal(char *config_json) {
result_obj("status", "ok");
result_obj("codeBoc", td::base64_encode(boc));
result_obj("fiftCode", escape_json(outs.str()));
result_obj("codeHashHex", code_cell->get_hash().to_hex());
result_obj.leave();
outs.clear();