diff --git a/.github/workflows/build-revive-wasm.yml b/.github/workflows/build-revive-wasm.yml index 528894c..dd1db44 100644 --- a/.github/workflows/build-revive-wasm.yml +++ b/.github/workflows/build-revive-wasm.yml @@ -10,6 +10,7 @@ env: CARGO_TERM_COLOR: always REVIVE_WASM_INSTALL_DIR: ${{ github.workspace }}/target/wasm32-unknown-emscripten/release EMSCRIPTEN_VERSION: 3.1.64 + BUN_VERSION: 1.1.43 jobs: build-revive-wasm: @@ -77,3 +78,51 @@ jobs: ${{ env.REVIVE_WASM_INSTALL_DIR }}/resolc.js ${{ env.REVIVE_WASM_INSTALL_DIR }}/resolc.wasm retention-days: 1 + + test-revive-wasm: + needs: build-revive-wasm + strategy: + matrix: + os: ['ubuntu-24.04', 'macos-14', 'windows-2022'] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + + - name: Create Target Directory + run: mkdir -p ${{ env.REVIVE_WASM_INSTALL_DIR }} + + - name: Download Artifact + uses: actions/download-artifact@v4 + with: + name: revive-wasm + path: ${{ env.REVIVE_WASM_INSTALL_DIR }} + + - name: Set Up Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' + + - name: Install Bun on Windows + if: runner.os == 'Windows' + run: | + Set-ExecutionPolicy RemoteSigned -Scope CurrentUser + iex (new-object net.webclient).downloadstring('https://get.scoop.sh') + scoop install bun@${{ env.BUN_VERSION }} + Join-Path (Resolve-Path ~).Path "scoop\shims" >> $Env:GITHUB_PATH + + - name: Install Bun on macOS and Linux + if: runner.os != 'Windows' + run: | + curl -fsSL https://bun.sh/install | bash -s bun-v${{ env.BUN_VERSION }} + echo "$HOME/.bun/bin" >> $GITHUB_PATH + + - name: Confirm Installations + run: | + node --version + bun --version + + - name: Test revive + run: | + echo "Running tests for ${{ matrix.os }}" + npm install + npm run test:wasm diff --git a/Makefile b/Makefile index 9f1491d..abcd342 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: install format test test-solidity test-cli test-integration test-workspace clean docs docs-build +.PHONY: install format test test-solidity test-cli test-integration test-workspace test-wasm clean docs docs-build RUSTFLAGS_EMSCRIPTEN := \ -C link-arg=-sEXPORTED_FUNCTIONS=_main,_free,_malloc \ @@ -25,9 +25,11 @@ install-bin: install-npm: npm install && npm fund -install-wasm: +install-wasm: install-npm RUSTFLAGS='$(RUSTFLAGS_EMSCRIPTEN)' cargo build --target wasm32-unknown-emscripten -p revive-solidity --release --no-default-features - npm install + +test-wasm: install-wasm + npm run test:wasm # install-revive: Build and install to the directory specified in REVIVE_INSTALL_DIR ifeq ($(origin REVIVE_INSTALL_DIR), undefined) diff --git a/js/examples/node/revive.js b/js/examples/node/revive.js new file mode 100644 index 0000000..912b826 --- /dev/null +++ b/js/examples/node/revive.js @@ -0,0 +1,32 @@ +const soljson = require('solc/soljson'); +const createRevive = require('./resolc.js'); + +async function compile(standardJsonInput) { + if (!standardJsonInput) { + throw new Error('Input JSON for the Solidity compiler is required.'); + } + + // Initialize the compiler + const compiler = createRevive(); + compiler.soljson = soljson; + + // Provide input to the compiler + compiler.writeToStdin(JSON.stringify(standardJsonInput)); + + // Run the compiler + compiler.callMain(['--standard-json']); + + // Collect output + const stdout = compiler.readFromStdout(); + const stderr = compiler.readFromStderr(); + + // Check for errors and throw if stderr exists + if (stderr) { + throw new Error(`Compilation failed: ${stderr}`); + } + + // Return the output if no errors + return stdout; +} + +module.exports = { compile }; \ No newline at end of file diff --git a/js/examples/node/run_revive.js b/js/examples/node/run_revive.js index dec99ac..a3c6888 100644 --- a/js/examples/node/run_revive.js +++ b/js/examples/node/run_revive.js @@ -1,5 +1,4 @@ -const soljson = require('solc/soljson'); -const createRevive = require('./resolc.js'); +const { compile } = require('./revive.js'); const compilerStandardJsonInput = { language: 'Solidity', @@ -30,16 +29,8 @@ const compilerStandardJsonInput = { }; async function runCompiler() { - const m = createRevive(); - m.soljson = soljson; - - // Set input data for stdin - m.writeToStdin(JSON.stringify(compilerStandardJsonInput)); - - // Compile the Solidity source code - let x = m.callMain(['--standard-json']); - console.log("Stdout: " + m.readFromStdout()); - console.error("Stderr: " + m.readFromStderr()); + let output = await compile(compilerStandardJsonInput) + console.log("Output: " + output); } runCompiler().catch(err => { diff --git a/js/package.json b/js/package.json index 9de29b2..a3a7b50 100644 --- a/js/package.json +++ b/js/package.json @@ -7,9 +7,14 @@ "scripts": { "fetch:soljson": "wget https://binaries.soliditylang.org/wasm/soljson-v0.8.28+commit.7893614a.js -O ./examples/web/soljson.js", "example:web": "npm run fetch:soljson && http-server ./examples/web/", - "example:node": "node ./examples/node/run_revive.js" + "example:node": "node ./examples/node/run_revive.js", + "test:node": "mocha --timeout 10000 ./tests", + "test:bun": "bun test", + "test:all": "npm run test:node && npm run test:bun" }, "devDependencies": { - "http-server": "^14.1.1" + "chai": "^5.1.2", + "http-server": "^14.1.1", + "mocha": "^11.0.1" } } diff --git a/js/tests/node.test.mjs b/js/tests/node.test.mjs new file mode 100644 index 0000000..fcd9083 --- /dev/null +++ b/js/tests/node.test.mjs @@ -0,0 +1,102 @@ +import { expect } from 'chai'; +import { compile } from '../examples/node/revive.js'; + +const validCompilerInput = { + language: 'Solidity', + sources: { + 'MyContract.sol': { + content: ` + // SPDX-License-Identifier: UNLICENSED + pragma solidity ^0.8.0; + contract MyContract { + function greet() public pure returns (string memory) { + return "Hello"; + } + } + `, + }, + }, + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + outputSelection: { + '*': { + '*': ['abi', 'evm.bytecode'], + }, + }, + }, +}; + +describe('Compile Function Tests', function () { + it('should successfully compile valid Solidity code', async function () { + const result = await compile(validCompilerInput); + + // Ensure result contains compiled contract + expect(result).to.be.a('string'); + const output = JSON.parse(result); + expect(output).to.have.property('contracts'); + expect(output.contracts['MyContract.sol']).to.have.property('MyContract'); + expect(output.contracts['MyContract.sol'].MyContract).to.have.property('abi'); + expect(output.contracts['MyContract.sol'].MyContract).to.have.property('evm'); + expect(output.contracts['MyContract.sol'].MyContract.evm).to.have.property('bytecode'); + }); + + it('should throw an error for invalid Solidity code', async function () { + const invalidCompilerInput = { + ...validCompilerInput, + sources: { + 'MyContract.sol': { + content: ` + // SPDX-License-Identifier: UNLICENSED + pragma solidity ^0.8.0; + import "nonexistent/console.sol"; + contract MyContract { + function greet() public pure returns (string memory) { + return "Hello" // Missing semicolon + } + } + `, + }, + }, + }; + + const result = await compile(invalidCompilerInput); + expect(result).to.be.a('string'); + const output = JSON.parse(result); + expect(output).to.have.property('errors'); + expect(output.errors).to.be.an('array'); + expect(output.errors.length).to.be.greaterThan(0); + expect(output.errors[0].type).to.exist; + expect(output.errors[0].type).to.contain("ParserError"); + }); + + it('should return not found error for missing imports', async function () { + const compilerInputWithImport = { + ...validCompilerInput, + sources: { + 'MyContract.sol': { + content: ` + // SPDX-License-Identifier: UNLICENSED + pragma solidity ^0.8.0; + import "nonexistent/console.sol"; + contract MyContract { + function greet() public pure returns (string memory) { + return "Hello"; + } + } + `, + }, + }, + }; + + let result = await compile(compilerInputWithImport); + const output = JSON.parse(result); + expect(output).to.have.property('errors'); + expect(output.errors).to.be.an('array'); + expect(output.errors.length).to.be.greaterThan(0); + expect(output.errors[0].message).to.exist; + expect(output.errors[0].message).to.include('Source "nonexistent/console.sol" not found'); + }); +}); diff --git a/package.json b/package.json index 71dacf7..4abb963 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "private": true, "scripts": { "test:cli": "npm run test -w crates/solidity/src/tests/cli-tests", - "test:revive": "npm run example:node -w js" + "test:wasm": "npm run test:all -w js" }, "workspaces": [ "crates/solidity/src/tests/cli-tests",