Pack resolc.wasm and resolc.js to resolc_packed.js

This commit is contained in:
Sebastian Miasojed
2025-01-23 11:59:50 +01:00
parent 888723eb0d
commit 8a18f08aff
16 changed files with 420 additions and 377 deletions
+11
View File
@@ -28,8 +28,19 @@ install-bin:
install-npm: install-npm:
npm install && npm fund npm install && npm fund
TARGET_PATH=target/wasm32-unknown-emscripten/release
WASM_FILE=$(TARGET_PATH)/resolc.wasm
JS_FILE=$(TARGET_PATH)/resolc.js
OUTPUT_FILE=$(TARGET_PATH)/resolc_packed.js
install-wasm: install-npm install-wasm: install-npm
cargo build --target wasm32-unknown-emscripten -p revive-solidity --release --no-default-features cargo build --target wasm32-unknown-emscripten -p revive-solidity --release --no-default-features
@if [ ! -f $(WASM_FILE) ]; then echo "Error: Missing $(WASM_FILE)"; exit 1; fi
@if [ ! -f $(JS_FILE) ]; then echo "Error: Missing $(JS_FILE)"; exit 1; fi
@echo "let moduleArgs = { wasmBinary: readBinary(\"data:application/octet-stream;base64,$$(base64 -w 0 $(WASM_FILE))\") };" > $(OUTPUT_FILE)
@cat $(JS_FILE) >> $(OUTPUT_FILE)
@echo "createRevive = createRevive.bind(null, moduleArgs);" >> $(OUTPUT_FILE)
@echo "Combined script written to $(OUTPUT_FILE)"
install-llvm-builder: install-llvm-builder:
cargo install --path crates/llvm-builder cargo install --path crates/llvm-builder
+51 -33
View File
@@ -1,16 +1,16 @@
const { test, expect } = require('@playwright/test'); const { test, expect } = require("@playwright/test");
const fs = require('fs'); const fs = require("fs");
const path = require('path'); const path = require("path");
function loadFixture(fixture) { function loadFixture(fixture) {
const fixturePath = path.resolve(__dirname, `../fixtures/${fixture}`); const fixturePath = path.resolve(__dirname, `../fixtures/${fixture}`);
return JSON.parse(fs.readFileSync(fixturePath, 'utf-8')); return JSON.parse(fs.readFileSync(fixturePath, "utf-8"));
} }
async function runWorker(page, input) { async function runWorker(page, input) {
return await page.evaluate((input) => { return await page.evaluate((input) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const worker = new Worker('worker.js'); const worker = new Worker("worker.js");
worker.postMessage(JSON.stringify(input)); worker.postMessage(JSON.stringify(input));
worker.onmessage = (event) => { worker.onmessage = (event) => {
@@ -26,62 +26,80 @@ async function runWorker(page, input) {
}, input); }, input);
} }
test('should successfully compile valid Solidity code in browser', async ({ page }) => { test("should successfully compile valid Solidity code in browser", async ({
page,
}) => {
await page.goto("http://127.0.0.1:8080"); await page.goto("http://127.0.0.1:8080");
await page.setContent(""); await page.setContent("");
const standardInput = loadFixture('storage.json') const standardInput = loadFixture("storage.json");
const result = await runWorker(page, standardInput); const result = await runWorker(page, standardInput);
expect(typeof result).toBe('string'); expect(typeof result).toBe("string");
let output = JSON.parse(result); let output = JSON.parse(result);
expect(output).toHaveProperty('contracts'); expect(output).toHaveProperty("contracts");
expect(output.contracts['fixtures/storage.sol']).toHaveProperty('Storage'); expect(output.contracts["fixtures/storage.sol"]).toHaveProperty("Storage");
expect(output.contracts['fixtures/storage.sol'].Storage).toHaveProperty('abi'); expect(output.contracts["fixtures/storage.sol"].Storage).toHaveProperty(
expect(output.contracts['fixtures/storage.sol'].Storage).toHaveProperty('evm'); "abi",
expect(output.contracts['fixtures/storage.sol'].Storage.evm).toHaveProperty('bytecode'); );
expect(output.contracts["fixtures/storage.sol"].Storage).toHaveProperty(
"evm",
);
expect(output.contracts["fixtures/storage.sol"].Storage.evm).toHaveProperty(
"bytecode",
);
}); });
test('should successfully compile large valid Solidity code in browser', async ({ page }) => { test("should successfully compile large valid Solidity code in browser", async ({
page,
}) => {
await page.goto("http://127.0.0.1:8080"); await page.goto("http://127.0.0.1:8080");
await page.setContent(""); await page.setContent("");
const standardInput = loadFixture('token.json') const standardInput = loadFixture("token.json");
const result = await runWorker(page, standardInput); const result = await runWorker(page, standardInput);
expect(typeof result).toBe('string'); expect(typeof result).toBe("string");
let output = JSON.parse(result); let output = JSON.parse(result);
expect(output).toHaveProperty('contracts'); expect(output).toHaveProperty("contracts");
expect(output.contracts['fixtures/token.sol']).toHaveProperty('MyToken'); expect(output.contracts["fixtures/token.sol"]).toHaveProperty("MyToken");
expect(output.contracts['fixtures/token.sol'].MyToken).toHaveProperty('abi'); expect(output.contracts["fixtures/token.sol"].MyToken).toHaveProperty("abi");
expect(output.contracts['fixtures/token.sol'].MyToken).toHaveProperty('evm'); expect(output.contracts["fixtures/token.sol"].MyToken).toHaveProperty("evm");
expect(output.contracts['fixtures/token.sol'].MyToken.evm).toHaveProperty('bytecode'); expect(output.contracts["fixtures/token.sol"].MyToken.evm).toHaveProperty(
"bytecode",
);
}); });
test('should throw an error for invalid Solidity code in browser', async ({ page }) => { test("should throw an error for invalid Solidity code in browser", async ({
page,
}) => {
await page.goto("http://127.0.0.1:8080"); await page.goto("http://127.0.0.1:8080");
await page.setContent(""); await page.setContent("");
const standardInput = loadFixture('invalid_contract_content.json') const standardInput = loadFixture("invalid_contract_content.json");
const result = await runWorker(page, standardInput); const result = await runWorker(page, standardInput);
expect(typeof result).toBe('string'); expect(typeof result).toBe("string");
let output = JSON.parse(result); let output = JSON.parse(result);
expect(output).toHaveProperty('errors'); expect(output).toHaveProperty("errors");
expect(Array.isArray(output.errors)).toBeTruthy(); // Check if it's an array expect(Array.isArray(output.errors)).toBeTruthy(); // Check if it's an array
expect(output.errors.length).toBeGreaterThan(0); expect(output.errors.length).toBeGreaterThan(0);
expect(output.errors[0]).toHaveProperty('type'); expect(output.errors[0]).toHaveProperty("type");
expect(output.errors[0].type).toContain('ParserError'); expect(output.errors[0].type).toContain("ParserError");
}); });
test('should return not found error for missing imports in browser', async ({page}) => { test("should return not found error for missing imports in browser", async ({
page,
}) => {
await page.goto("http://127.0.0.1:8080"); await page.goto("http://127.0.0.1:8080");
await page.setContent(""); await page.setContent("");
const standardInput = loadFixture('missing_import.json') const standardInput = loadFixture("missing_import.json");
const result = await runWorker(page, standardInput); const result = await runWorker(page, standardInput);
expect(typeof result).toBe('string'); expect(typeof result).toBe("string");
let output = JSON.parse(result); let output = JSON.parse(result);
expect(output).toHaveProperty('errors'); expect(output).toHaveProperty("errors");
expect(Array.isArray(output.errors)).toBeTruthy(); // Check if it's an array expect(Array.isArray(output.errors)).toBeTruthy(); // Check if it's an array
expect(output.errors.length).toBeGreaterThan(0); expect(output.errors.length).toBeGreaterThan(0);
expect(output.errors[0]).toHaveProperty('message'); expect(output.errors[0]).toHaveProperty("message");
expect(output.errors[0].message).toContain('Source "nonexistent/console.sol" not found'); expect(output.errors[0].message).toContain(
'Source "nonexistent/console.sol" not found',
);
}); });
+55 -52
View File
@@ -1,54 +1,57 @@
var Module = { Module.stdinData = null;
stdinData: null, Module.stdinDataPosition = 0;
stdinDataPosition: 0, Module.stdoutData = [];
stdoutData: [], Module.stderrData = [];
stderrData: [],
// Function to read and return all collected stdout data as a string // Method to read all collected stdout data
readFromStdout: function() { Module.readFromStdout = function () {
if (!this.stdoutData.length) return ""; if (!Module.stdoutData.length) return "";
const decoder = new TextDecoder('utf-8'); const decoder = new TextDecoder("utf-8");
const data = decoder.decode(new Uint8Array(this.stdoutData)); const data = decoder.decode(new Uint8Array(Module.stdoutData));
this.stdoutData = []; Module.stdoutData = [];
return data; return data;
},
// Function to read and return all collected stderr data as a string
readFromStderr: function() {
if (!this.stderrData.length) return "";
const decoder = new TextDecoder('utf-8');
const data = decoder.decode(new Uint8Array(this.stderrData));
this.stderrData = [];
return data;
},
// Function to set input data for stdin
writeToStdin: function(data) {
const encoder = new TextEncoder();
this.stdinData = encoder.encode(data);
this.stdinDataPosition = 0;
},
// `preRun` is called before the program starts running
preRun: function() {
// Define a custom stdin function
function customStdin() {
if (!Module.stdinData || Module.stdinDataPosition >= Module.stdinData.length) {
return null; // End of input (EOF)
}
return Module.stdinData[Module.stdinDataPosition++];
}
// Define a custom stdout function
function customStdout(char) {
Module.stdoutData.push(char);
}
// Define a custom stderr function
function customStderr(char) {
Module.stderrData.push(char);
}
FS.init(customStdin, customStdout, customStderr);
},
}; };
// Method to read all collected stderr data
Module.readFromStderr = function () {
if (!Module.stderrData.length) return "";
const decoder = new TextDecoder("utf-8");
const data = decoder.decode(new Uint8Array(Module.stderrData));
Module.stderrData = [];
return data;
};
// Method to write data to stdin
Module.writeToStdin = function (data) {
const encoder = new TextEncoder();
Module.stdinData = encoder.encode(data);
Module.stdinDataPosition = 0;
};
// Override the `preRun` method to customize file system initialization
Module.preRun = Module.preRun || [];
Module.preRun.push(function () {
// Custom stdin function
function customStdin() {
if (
!Module.stdinData ||
Module.stdinDataPosition >= Module.stdinData.length
) {
return null; // End of input (EOF)
}
return Module.stdinData[Module.stdinDataPosition++];
}
// Custom stdout function
function customStdout(char) {
Module.stdoutData.push(char);
}
// Custom stderr function
function customStderr(char) {
Module.stderrData.push(char);
}
// Initialize the FS (File System) with custom handlers
FS.init(customStdin, customStdout, customStderr);
});
+30 -25
View File
@@ -1,29 +1,34 @@
mergeInto(LibraryManager.library, { mergeInto(LibraryManager.library, {
soljson_compile: function(inputPtr, inputLen) { soljson_compile: function (inputPtr, inputLen) {
const inputJson = UTF8ToString(inputPtr, inputLen); const inputJson = UTF8ToString(inputPtr, inputLen);
const output = Module.soljson.cwrap('solidity_compile', 'string', ['string'])(inputJson); const output = Module.soljson.cwrap("solidity_compile", "string", [
return stringToNewUTF8(output); "string",
}, ])(inputJson);
soljson_version: function() { return stringToNewUTF8(output);
const version = Module.soljson.cwrap("solidity_version", "string", [])(); },
return stringToNewUTF8(version); soljson_version: function () {
}, const version = Module.soljson.cwrap("solidity_version", "string", [])();
resolc_compile: function(inputPtr, inputLen) { return stringToNewUTF8(version);
const inputJson = UTF8ToString(inputPtr, inputLen); },
var revive = createRevive(); resolc_compile: function (inputPtr, inputLen) {
revive.writeToStdin(inputJson); const inputJson = UTF8ToString(inputPtr, inputLen);
var revive = createRevive();
revive.writeToStdin(inputJson);
// Call main on the new instance // Call main on the new instance
const result = revive.callMain(['--recursive-process']); const result = revive.callMain(["--recursive-process"]);
if (result) { if (result) {
const stderrString = revive.readFromStderr(); const stderrString = revive.readFromStderr();
const error = JSON.stringify({ type: 'error', message: stderrString || "Unknown error" }); const error = JSON.stringify({
return stringToNewUTF8(error); type: "error",
} else { message: stderrString || "Unknown error",
const stdoutString = revive.readFromStdout(); });
const json = JSON.stringify({ type: 'success', data: stdoutString }); return stringToNewUTF8(error);
return stringToNewUTF8(json); } else {
} const stdoutString = revive.readFromStdout();
}, const json = JSON.stringify({ type: "success", data: stdoutString });
return stringToNewUTF8(json);
}
},
}); });
+4 -4
View File
@@ -1,9 +1,9 @@
const soljson = require('solc/soljson'); const soljson = require("solc/soljson");
const createRevive = require('./resolc.js'); const createRevive = require("./resolc.js");
async function compile(standardJsonInput) { async function compile(standardJsonInput) {
if (!standardJsonInput) { if (!standardJsonInput) {
throw new Error('Input JSON for the Solidity compiler is required.'); throw new Error("Input JSON for the Solidity compiler is required.");
} }
// Initialize the compiler // Initialize the compiler
@@ -14,7 +14,7 @@ async function compile(standardJsonInput) {
compiler.writeToStdin(JSON.stringify(standardJsonInput)); compiler.writeToStdin(JSON.stringify(standardJsonInput));
// Run the compiler // Run the compiler
compiler.callMain(['--standard-json']); compiler.callMain(["--standard-json"]);
// Collect output // Collect output
const stdout = compiler.readFromStdout(); const stdout = compiler.readFromStdout();
+20 -20
View File
@@ -1,10 +1,10 @@
const { compile } = require('./revive.js'); const { compile } = require("./revive.js");
const compilerStandardJsonInput = { const compilerStandardJsonInput = {
language: 'Solidity', language: "Solidity",
sources: { sources: {
'MyContract.sol': { "MyContract.sol": {
content: ` content: `
// SPDX-License-Identifier: UNLICENSED // SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0; pragma solidity ^0.8.0;
contract MyContract { contract MyContract {
@@ -13,26 +13,26 @@ const compilerStandardJsonInput = {
} }
} }
`, `,
},
},
settings: {
optimizer: {
enabled: true,
runs: 200,
},
outputSelection: {
"*": {
"*": ["abi"],
}, },
}, },
settings: { },
optimizer: { };
enabled: true,
runs: 200,
},
outputSelection: {
'*': {
'*': ['abi'],
},
},
},
};
async function runCompiler() { async function runCompiler() {
let output = await compile(compilerStandardJsonInput) let output = await compile(compilerStandardJsonInput);
console.log("Output: " + output); console.log("Output: " + output);
} }
runCompiler().catch(err => { runCompiler().catch((err) => {
console.error('Error:', err); console.error("Error:", err);
}); });
+49 -47
View File
@@ -1,51 +1,53 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<head>
<meta charset="utf-8" />
<title>Web Worker Example</title>
<style>
/* Ensure the pre tag wraps long lines */
pre {
white-space: pre-wrap; /* Wrap long lines */
word-wrap: break-word; /* Break long words */
max-width: 100%; /* Optional: Ensures it doesn't overflow container */
overflow-wrap: break-word; /* Another method for wrapping */
}
</style>
</head>
<head> <body>
<meta charset="utf-8" /> <h1>Revive Compilation Output</h1>
<title>Web Worker Example</title> <pre id="output"></pre>
<style> <script>
/* Ensure the pre tag wraps long lines */ var outputElement = document.getElementById("output");
pre { var worker = new Worker("./worker.js");
white-space: pre-wrap; /* Wrap long lines */ const standardJsonInput = {
word-wrap: break-word; /* Break long words */ language: "Solidity",
max-width: 100%; /* Optional: Ensures it doesn't overflow container */ sources: {
overflow-wrap: break-word; /* Another method for wrapping */ contract: {
} content: "contract MyContract { function f() public { } }",
</style> },
</head> },
settings: {
<body> optimizer: {
<h1>Revive Compilation Output</h1> enabled: true,
<pre id="output"></pre> runs: 200,
<script> },
var outputElement = document.getElementById('output'); outputSelection: {
var worker = new Worker('./worker.js'); "*": {
const standardJsonInput = { "*": ["abi"],
language: 'Solidity', },
sources: { },
contract: { },
content: 'contract MyContract { function f() public { } }', };
} worker.addEventListener(
}, "message",
settings: { function (e) {
optimizer: { outputElement.textContent = e.data.output;
enabled: true, },
runs: 200, false,
}, );
outputSelection: {
'*': {
'*': ['abi'],
}
}
}
};
worker.addEventListener('message', function (e) {
outputElement.textContent = e.data.output;
}, false);
worker.postMessage(JSON.stringify(standardJsonInput));
</script>
</body>
worker.postMessage(JSON.stringify(standardJsonInput));
</script>
</body>
</html> </html>
-1
View File
@@ -1 +0,0 @@
../../../target/wasm32-unknown-emscripten/release/resolc.wasm
+9 -11
View File
@@ -1,18 +1,16 @@
importScripts("./soljson.js");
importScripts('./soljson.js'); importScripts("./resolc.js");
importScripts('./resolc.js');
// Handle messages from the main thread // Handle messages from the main thread
onmessage = async function (e) { onmessage = async function (e) {
const m = createRevive(); const m = createRevive();
m.soljson = Module;
m.soljson = Module; // Set input data for stdin
m.writeToStdin(e.data);
// Set input data for stdin // Compile the Solidity source code
m.writeToStdin(e.data); m.callMain(["--standard-json"]);
// Compile the Solidity source code postMessage({ output: m.readFromStdout() || m.readFromStderr() });
m.callMain(['--standard-json']);
postMessage({output: m.readFromStdout() || m.readFromStderr()});
}; };
+14 -17
View File
@@ -1,22 +1,19 @@
{ {
"language": "Solidity", "language": "Solidity",
"sources": { "sources": {
"fixtures/storage.sol": { "fixtures/storage.sol": {
"content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\nimport \"nonexistent/console.sol\";\ncontract MyContract { function greet() public pure returns (string memory) { return \"Hello\" // Missing semicolon }}" "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\nimport \"nonexistent/console.sol\";\ncontract MyContract { function greet() public pure returns (string memory) { return \"Hello\" // Missing semicolon }}"
} }
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
}, },
"settings": { "outputSelection": {
"optimizer": { "*": {
"enabled": true, "*": ["abi"]
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi"
]
}
} }
} }
} }
}
+14 -17
View File
@@ -1,22 +1,19 @@
{ {
"language": "Solidity", "language": "Solidity",
"sources": { "sources": {
"fixtures/storage.sol": { "fixtures/storage.sol": {
"content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\nimport \"nonexistent/console.sol\";\ncontract MyContract { function f() public { } }" "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\nimport \"nonexistent/console.sol\";\ncontract MyContract { function f() public { } }"
} }
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
}, },
"settings": { "outputSelection": {
"optimizer": { "*": {
"enabled": true, "*": ["abi"]
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi"
]
}
} }
} }
} }
}
+14 -17
View File
@@ -1,22 +1,19 @@
{ {
"language": "Solidity", "language": "Solidity",
"sources": { "sources": {
"fixtures/storage.sol": { "fixtures/storage.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.2 <0.9.0;\ncontract Storage {\n uint256 number;\n function store(uint256 num) public { number = num; }\n function retrieve() public view returns (uint256){ return number; }\n}" "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.2 <0.9.0;\ncontract Storage {\n uint256 number;\n function store(uint256 num) public { number = num; }\n function retrieve() public view returns (uint256){ return number; }\n}"
} }
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
}, },
"settings": { "outputSelection": {
"optimizer": { "*": {
"enabled": true, "*": ["abi"]
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi"
]
}
} }
} }
} }
}
+74 -77
View File
File diff suppressed because one or more lines are too long
+4 -2
View File
@@ -10,12 +10,14 @@
"example:node": "node ./examples/node/run_revive.js", "example:node": "node ./examples/node/run_revive.js",
"test:node": "mocha --timeout 60000 ./tests", "test:node": "mocha --timeout 60000 ./tests",
"test:bun": "bun test --timeout 60000 node.test", "test:bun": "bun test --timeout 60000 node.test",
"test:all": "npm run test:node && npm run test:bun" "test:all": "npm run test:node && npm run test:bun",
"format": "prettier --write ."
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.49.1", "@playwright/test": "^1.49.1",
"chai": "^5.1.2", "chai": "^5.1.2",
"http-server": "^14.1.1", "http-server": "^14.1.1",
"mocha": "^11.0.1" "mocha": "^11.0.1",
"prettier": "^3.4.2"
} }
} }
+14 -15
View File
@@ -1,10 +1,10 @@
const { defineConfig, devices } = require('@playwright/test'); const { defineConfig, devices } = require("@playwright/test");
/** /**
* @see https://playwright.dev/docs/test-configuration * @see https://playwright.dev/docs/test-configuration
*/ */
module.exports = defineConfig({ module.exports = defineConfig({
testDir: './e2e', testDir: "./e2e",
/* Run tests in files in parallel */ /* Run tests in files in parallel */
fullyParallel: true, fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */ /* Fail the build on CI if you accidentally left test.only in the source code. */
@@ -14,39 +14,38 @@ module.exports = defineConfig({
/* Opt out of parallel tests on CI. */ /* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined, workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'list', reporter: "list",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: { use: {
/* Base URL to use in actions like `await page.goto('/')`. */ /* Base URL to use in actions like `await page.goto('/')`. */
baseURL: 'http://127.0.0.1:8080', baseURL: "http://127.0.0.1:8080",
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry', trace: "on-first-retry",
}, },
timeout: 480000, timeout: 480000,
/* Configure projects for major browsers */ /* Configure projects for major browsers */
projects: [ projects: [
{ {
name: 'chromium', name: "chromium",
use: { ...devices['Desktop Chrome'] }, use: { ...devices["Desktop Chrome"] },
}, },
{ {
name: 'firefox', name: "firefox",
use: { ...devices['Desktop Firefox'] }, use: { ...devices["Desktop Firefox"] },
}, },
{ {
name: 'webkit', name: "webkit",
use: { ...devices['Desktop Safari'] }, use: { ...devices["Desktop Safari"] },
} },
], ],
/* Run your local dev server before starting the tests */ /* Run your local dev server before starting the tests */
webServer: { webServer: {
command: 'npm run example:web', command: "npm run example:web",
url: 'http://127.0.0.1:8080', url: "http://127.0.0.1:8080",
reuseExistingServer: !process.env.CI, reuseExistingServer: !process.env.CI,
}, },
}); });
+52 -34
View File
@@ -1,70 +1,88 @@
import { expect } from 'chai'; import { expect } from "chai";
import { compile } from '../examples/node/revive.js'; import { compile } from "../examples/node/revive.js";
import { fileURLToPath } from 'url'; import { fileURLToPath } from "url";
import path from 'path'; import path from "path";
import fs from 'fs'; import fs from "fs";
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
function loadFixture(fixture) { function loadFixture(fixture) {
const fixturePath = path.resolve(__dirname, `../fixtures/${fixture}`); const fixturePath = path.resolve(__dirname, `../fixtures/${fixture}`);
return JSON.parse(fs.readFileSync(fixturePath, 'utf-8')); return JSON.parse(fs.readFileSync(fixturePath, "utf-8"));
} }
describe('Compile Function Tests', function () { describe("Compile Function Tests", function () {
it('should successfully compile valid Solidity code', async function () { it("should successfully compile valid Solidity code", async function () {
const standardInput = loadFixture('storage.json') const standardInput = loadFixture("storage.json");
const result = await compile(standardInput); const result = await compile(standardInput);
expect(result).to.be.a('string'); expect(result).to.be.a("string");
const output = JSON.parse(result); const output = JSON.parse(result);
expect(output).to.have.property('contracts'); expect(output).to.have.property("contracts");
expect(output.contracts['fixtures/storage.sol']).to.have.property('Storage'); expect(output.contracts["fixtures/storage.sol"]).to.have.property(
expect(output.contracts['fixtures/storage.sol'].Storage).to.have.property('abi'); "Storage",
expect(output.contracts['fixtures/storage.sol'].Storage).to.have.property('evm'); );
expect(output.contracts['fixtures/storage.sol'].Storage.evm).to.have.property('bytecode'); expect(output.contracts["fixtures/storage.sol"].Storage).to.have.property(
"abi",
);
expect(output.contracts["fixtures/storage.sol"].Storage).to.have.property(
"evm",
);
expect(
output.contracts["fixtures/storage.sol"].Storage.evm,
).to.have.property("bytecode");
}); });
if (typeof globalThis.Bun == 'undefined') { if (typeof globalThis.Bun == "undefined") {
// Running this test with Bun on a Linux host causes: // Running this test with Bun on a Linux host causes:
// RuntimeError: Out of bounds memory access (evaluating 'getWasmTableEntry(index)(a1, a2, a3, a4, a5)') // RuntimeError: Out of bounds memory access (evaluating 'getWasmTableEntry(index)(a1, a2, a3, a4, a5)')
// Once this issue is resolved, the test will be re-enabled. // Once this issue is resolved, the test will be re-enabled.
it('should successfully compile large Solidity code', async function () { it("should successfully compile large Solidity code", async function () {
const standardInput = loadFixture('token.json') const standardInput = loadFixture("token.json");
const result = await compile(standardInput); const result = await compile(standardInput);
expect(result).to.be.a('string'); expect(result).to.be.a("string");
const output = JSON.parse(result); const output = JSON.parse(result);
expect(output).to.have.property('contracts'); expect(output).to.have.property("contracts");
expect(output.contracts['fixtures/token.sol']).to.have.property('MyToken'); expect(output.contracts["fixtures/token.sol"]).to.have.property(
expect(output.contracts['fixtures/token.sol'].MyToken).to.have.property('abi'); "MyToken",
expect(output.contracts['fixtures/token.sol'].MyToken).to.have.property('evm'); );
expect(output.contracts['fixtures/token.sol'].MyToken.evm).to.have.property('bytecode'); expect(output.contracts["fixtures/token.sol"].MyToken).to.have.property(
"abi",
);
expect(output.contracts["fixtures/token.sol"].MyToken).to.have.property(
"evm",
);
expect(
output.contracts["fixtures/token.sol"].MyToken.evm,
).to.have.property("bytecode");
}); });
} }
it('should throw an error for invalid Solidity code', async function () { it("should throw an error for invalid Solidity code", async function () {
const standardInput = loadFixture('invalid_contract_content.json') const standardInput = loadFixture("invalid_contract_content.json");
const result = await compile(standardInput); const result = await compile(standardInput);
expect(result).to.be.a('string'); expect(result).to.be.a("string");
const output = JSON.parse(result); const output = JSON.parse(result);
expect(output).to.have.property('errors'); expect(output).to.have.property("errors");
expect(output.errors).to.be.an('array'); expect(output.errors).to.be.an("array");
expect(output.errors.length).to.be.greaterThan(0); expect(output.errors.length).to.be.greaterThan(0);
expect(output.errors[0].type).to.exist; expect(output.errors[0].type).to.exist;
expect(output.errors[0].type).to.contain("ParserError"); expect(output.errors[0].type).to.contain("ParserError");
}); });
it('should return not found error for missing imports', async function () { it("should return not found error for missing imports", async function () {
const standardInput = loadFixture('missing_import.json') const standardInput = loadFixture("missing_import.json");
const result = await compile(standardInput); const result = await compile(standardInput);
const output = JSON.parse(result); const output = JSON.parse(result);
expect(output).to.have.property('errors'); expect(output).to.have.property("errors");
expect(output.errors).to.be.an('array'); expect(output.errors).to.be.an("array");
expect(output.errors.length).to.be.greaterThan(0); expect(output.errors.length).to.be.greaterThan(0);
expect(output.errors[0].message).to.exist; expect(output.errors[0].message).to.exist;
expect(output.errors[0].message).to.include('Source "nonexistent/console.sol" not found'); expect(output.errors[0].message).to.include(
'Source "nonexistent/console.sol" not found',
);
}); });
}); });