mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-21 17:21:07 +00:00
Separate compilation and linker phases (#376)
Separate between compilation and linker phases to allow deploy time linking and back-porting era compiler changes to fix #91. Unlinked contract binaries (caused by missing libraries or missing factory dependencies in turn) are emitted as raw ELF object. Few drive by fixes: - #98 - A compiler panic on missing libraries definitions. - Fixes some incosistent type forwarding in JSON output (empty string vs. null object). - Remove the unused fallback for size optimization setting. - Remove the broken `--lvm-ir` mode. - CI workflow fixes. --------- Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com> Signed-off-by: xermicus <bigcyrill@hotmail.com> Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
//! The tests for running resolc with asm option.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use crate::tests::cli::utils;
|
||||
|
||||
const ASM_OPTION: &str = "--asm";
|
||||
@@ -30,10 +28,7 @@ fn fails_without_input_file() {
|
||||
utils::assert_command_failure(&resolc_result, "Omitting an input file");
|
||||
|
||||
let output = resolc_result.stderr.to_lowercase();
|
||||
assert!(
|
||||
output.contains("no input sources specified") || output.contains("compilation aborted"),
|
||||
"Expected the output to contain a specific error message."
|
||||
);
|
||||
assert!(output.contains("no input sources specified"));
|
||||
|
||||
let solc_result = utils::execute_solc(arguments);
|
||||
utils::assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
//! The tests for running resolc with combined JSON option.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use revive_common;
|
||||
use revive_solc_json_interface::CombinedJsonInvalidSelectorMessage;
|
||||
|
||||
use crate::tests::cli::utils;
|
||||
|
||||
@@ -53,10 +51,9 @@ fn fails_with_invalid_json_argument() {
|
||||
let resolc_result = utils::execute_resolc(arguments);
|
||||
utils::assert_command_failure(&resolc_result, "Providing an invalid json argument");
|
||||
|
||||
assert!(
|
||||
resolc_result.stdout.contains("Invalid option"),
|
||||
"Expected the output to contain a specific error message."
|
||||
);
|
||||
assert!(resolc_result
|
||||
.stderr
|
||||
.contains(CombinedJsonInvalidSelectorMessage));
|
||||
|
||||
let solc_result = utils::execute_solc(arguments);
|
||||
utils::assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
@@ -73,16 +70,12 @@ fn fails_with_multiple_json_arguments() {
|
||||
let resolc_result = utils::execute_resolc(arguments);
|
||||
utils::assert_command_failure(&resolc_result, "Providing multiple json arguments");
|
||||
|
||||
assert!(
|
||||
resolc_result
|
||||
.stderr
|
||||
.contains("reading error: No such file or directory"),
|
||||
"Expected the output to contain a specific error message."
|
||||
);
|
||||
assert!(resolc_result
|
||||
.stderr
|
||||
.contains(&format!("Error: \"{}\" is not found.", JSON_ARGUMENTS[1])),);
|
||||
|
||||
// FIX: Resolc exit code == 101
|
||||
// let solc_result = utils::execute_solc(arguments);
|
||||
// utils::assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
let solc_result = utils::execute_solc(arguments);
|
||||
utils::assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -91,12 +84,9 @@ fn fails_without_json_argument() {
|
||||
let resolc_result = utils::execute_resolc(arguments);
|
||||
utils::assert_command_failure(&resolc_result, "Omitting a JSON argument");
|
||||
|
||||
assert!(
|
||||
resolc_result.stderr.contains(
|
||||
"a value is required for '--combined-json <COMBINED_JSON>' but none was supplied"
|
||||
),
|
||||
"Expected the output to contain a specific error message."
|
||||
);
|
||||
assert!(resolc_result.stderr.contains(
|
||||
"a value is required for '--combined-json <COMBINED_JSON>' but none was supplied"
|
||||
));
|
||||
|
||||
let solc_result = utils::execute_solc(arguments);
|
||||
utils::assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
@@ -108,10 +98,7 @@ fn fails_without_solidity_input_file() {
|
||||
let resolc_result = utils::execute_resolc(arguments);
|
||||
utils::assert_command_failure(&resolc_result, "Omitting a Solidity input file");
|
||||
|
||||
assert!(
|
||||
resolc_result.stderr.contains("No input sources specified"),
|
||||
"Expected the output to contain a specific error message."
|
||||
);
|
||||
assert!(resolc_result.stderr.contains("Error: No input files given"),);
|
||||
|
||||
let solc_result = utils::execute_solc(arguments);
|
||||
utils::assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
@@ -124,12 +111,9 @@ fn fails_with_yul_input_file() {
|
||||
let resolc_result = utils::execute_resolc(arguments);
|
||||
utils::assert_command_failure(&resolc_result, "Providing a Yul input file");
|
||||
|
||||
assert!(
|
||||
resolc_result
|
||||
.stderr
|
||||
.contains("ParserError: Expected identifier"),
|
||||
"Expected the output to contain a specific error message."
|
||||
);
|
||||
assert!(resolc_result
|
||||
.stderr
|
||||
.contains("Error: Expected identifier but got 'StringLiteral'"));
|
||||
|
||||
let solc_result = utils::execute_solc(arguments);
|
||||
utils::assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
use crate::tests::cli::utils::{assert_command_success, execute_resolc, DEPENDENCY_CONTRACT_PATH};
|
||||
|
||||
/// Test deploy time linking a contract with unresolved factory dependencies.
|
||||
#[test]
|
||||
fn deploy_time_linking_works() {
|
||||
let temp_dir = tempfile::TempDir::new().unwrap();
|
||||
let output_directory = temp_dir.path().to_path_buf();
|
||||
let source_path = temp_dir.path().to_path_buf().join("dependency.sol");
|
||||
std::fs::copy(DEPENDENCY_CONTRACT_PATH, &source_path).unwrap();
|
||||
|
||||
assert_command_success(
|
||||
&execute_resolc(&[
|
||||
source_path.to_str().unwrap(),
|
||||
"--bin",
|
||||
"-o",
|
||||
&output_directory.to_string_lossy(),
|
||||
]),
|
||||
"Missing libraries should compile fine",
|
||||
);
|
||||
|
||||
let dependency_blob_path = temp_dir
|
||||
.path()
|
||||
.to_path_buf()
|
||||
.join("dependency.sol:Dependency.pvm");
|
||||
let blob_path = temp_dir
|
||||
.path()
|
||||
.to_path_buf()
|
||||
.join("dependency.sol:TestAssert.pvm");
|
||||
|
||||
let output = execute_resolc(&[
|
||||
"--link",
|
||||
blob_path.to_str().unwrap(),
|
||||
dependency_blob_path.to_str().unwrap(),
|
||||
]);
|
||||
assert_command_success(&output, "The linker mode with missing library should work");
|
||||
assert!(output.stdout.contains("still unresolved"));
|
||||
|
||||
let assert_library_path = format!(
|
||||
"{}:Assert=0x0000000000000000000000000000000000000001",
|
||||
source_path.to_str().unwrap()
|
||||
);
|
||||
let assert_ne_library_path = format!(
|
||||
"{}:AssertNe=0x0000000000000000000000000000000000000002",
|
||||
source_path.to_str().unwrap()
|
||||
);
|
||||
let output = execute_resolc(&[
|
||||
"--link",
|
||||
"--libraries",
|
||||
&assert_library_path,
|
||||
"--libraries",
|
||||
&assert_ne_library_path,
|
||||
blob_path.to_str().unwrap(),
|
||||
dependency_blob_path.to_str().unwrap(),
|
||||
]);
|
||||
assert_command_success(&output, "The linker mode with all library should work");
|
||||
assert!(!output.stdout.contains("still unresolved"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn emits_unlinked_binary_warning() {
|
||||
let output = execute_resolc(&[DEPENDENCY_CONTRACT_PATH, "--bin"]);
|
||||
assert_command_success(&output, "Missing libraries should compile fine");
|
||||
assert!(output.stderr.contains("is unlinked"));
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
use crate::tests::cli::utils::{
|
||||
assert_command_success, execute_resolc, RESOLC_YUL_FLAG, YUL_CONTRACT_PATH,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn llvm_arguments_work_with_yul_input() {
|
||||
let output_with_argument = execute_resolc(&[
|
||||
RESOLC_YUL_FLAG,
|
||||
YUL_CONTRACT_PATH,
|
||||
"--llvm-arg=-riscv-soften-spills'",
|
||||
"--bin",
|
||||
]);
|
||||
assert_command_success(&output_with_argument, "Providing LLVM arguments");
|
||||
assert!(output_with_argument.success);
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
//! The CLI tests.
|
||||
|
||||
#![cfg(test)]
|
||||
//! The `resolc` CLI tests.
|
||||
|
||||
mod asm;
|
||||
mod combined_json;
|
||||
mod linker;
|
||||
mod llvm_arguments;
|
||||
mod optimization;
|
||||
mod output_dir;
|
||||
mod standard_json;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
//! The tests for running resolc with explicit optimization.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use revive_common;
|
||||
|
||||
use crate::tests::cli::{utils, yul};
|
||||
use crate::tests::cli::utils::{
|
||||
self, assert_command_failure, assert_command_success, assert_equal_exit_codes, execute_resolc,
|
||||
execute_solc, RESOLC_YUL_FLAG, SOLIDITY_CONTRACT_PATH, YUL_MEMSET_CONTRACT_PATH,
|
||||
};
|
||||
|
||||
const LEVELS: &[char] = &['0', '1', '2', '3', 's', 'z'];
|
||||
|
||||
@@ -12,11 +11,7 @@ const LEVELS: &[char] = &['0', '1', '2', '3', 's', 'z'];
|
||||
fn runs_with_valid_level() {
|
||||
for level in LEVELS {
|
||||
let optimization_argument = format!("-O{level}");
|
||||
let arguments = &[
|
||||
utils::YUL_MEMSET_CONTRACT_PATH,
|
||||
yul::YUL_OPTION,
|
||||
&optimization_argument,
|
||||
];
|
||||
let arguments = &[YUL_MEMSET_CONTRACT_PATH, "--yul", &optimization_argument];
|
||||
let resolc_result = utils::execute_resolc(arguments);
|
||||
assert!(
|
||||
resolc_result.success,
|
||||
@@ -37,17 +32,27 @@ fn runs_with_valid_level() {
|
||||
|
||||
#[test]
|
||||
fn fails_with_invalid_level() {
|
||||
let arguments = &[utils::YUL_MEMSET_CONTRACT_PATH, yul::YUL_OPTION, "-O9"];
|
||||
let resolc_result = utils::execute_resolc(arguments);
|
||||
utils::assert_command_failure(&resolc_result, "Providing an invalid optimization level");
|
||||
let arguments = &[YUL_MEMSET_CONTRACT_PATH, RESOLC_YUL_FLAG, "-O9"];
|
||||
let resolc_result = execute_resolc(arguments);
|
||||
assert_command_failure(&resolc_result, "Providing an invalid optimization level");
|
||||
|
||||
assert!(
|
||||
resolc_result
|
||||
.stderr
|
||||
.contains("Unexpected optimization option"),
|
||||
"Expected the output to contain a specific error message."
|
||||
);
|
||||
assert!(resolc_result
|
||||
.stderr
|
||||
.contains("Unexpected optimization option"));
|
||||
|
||||
let solc_result = utils::execute_solc(arguments);
|
||||
utils::assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
let solc_result = execute_solc(arguments);
|
||||
assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disable_solc_optimzer() {
|
||||
let arguments = &[SOLIDITY_CONTRACT_PATH, "--bin", "--disable-solc-optimizer"];
|
||||
let disabled = execute_resolc(arguments);
|
||||
assert_command_success(&disabled, "Disabling the solc optimizer");
|
||||
|
||||
let arguments = &[SOLIDITY_CONTRACT_PATH, "--bin"];
|
||||
let enabled = execute_resolc(arguments);
|
||||
assert_command_success(&disabled, "Enabling the solc optimizer");
|
||||
|
||||
assert_ne!(enabled.stdout, disabled.stdout);
|
||||
}
|
||||
|
||||
@@ -1,52 +1,41 @@
|
||||
//! The tests for running resolc with output directory option.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use tempfile::tempdir;
|
||||
|
||||
use crate::tests::cli::utils;
|
||||
|
||||
const OUTPUT_DIRECTORY: &str = "src/tests/cli/artifacts";
|
||||
const OUTPUT_BIN_FILE_PATH: &str = "src/tests/cli/artifacts/contract.sol:C.pvm";
|
||||
const OUTPUT_ASM_FILE_PATH: &str = "src/tests/cli/artifacts/contract.sol:C.pvmasm";
|
||||
const OUTPUT_LLVM_OPTIMIZED_FILE_PATH: &str =
|
||||
"src/tests/cli/artifacts/src_tests_cli_contracts_solidity_contract.sol.C.optimized.ll";
|
||||
const OUTPUT_BIN_FILE_PATH: &str = "contract.sol:C.pvm";
|
||||
const OUTPUT_ASM_FILE_PATH: &str = "contract.sol:C.pvmasm";
|
||||
const OUTPUT_LLVM_OPTIMIZED_FILE_PATH: &str = "src_tests_data_solidity_contract.sol.C.optimized.ll";
|
||||
const OUTPUT_LLVM_UNOPTIMIZED_FILE_PATH: &str =
|
||||
"src/tests/cli/artifacts/src_tests_cli_contracts_solidity_contract.sol.C.unoptimized.ll";
|
||||
|
||||
fn file_exists(path: &str) -> bool {
|
||||
Path::new(path).try_exists().unwrap()
|
||||
}
|
||||
|
||||
fn file_is_empty(path: &str) -> bool {
|
||||
Path::new(path).metadata().unwrap().len() == 0
|
||||
}
|
||||
"src_tests_data_solidity_contract.sol.C.unoptimized.ll";
|
||||
|
||||
fn assert_valid_output_file(
|
||||
result: &utils::CommandResult,
|
||||
output_file_type: &str,
|
||||
output_file_path: &str,
|
||||
debug_output_directory: &Path,
|
||||
output_file_name: &str,
|
||||
) {
|
||||
utils::assert_command_success(result, "Providing an output directory");
|
||||
|
||||
assert!(
|
||||
result.stderr.contains("Compiler run successful"),
|
||||
"Expected the compiler output to contain a success message.",
|
||||
);
|
||||
assert!(result.stderr.contains("Compiler run successful"),);
|
||||
|
||||
assert!(
|
||||
file_exists(output_file_path),
|
||||
"Expected the {output_file_type} output file `{output_file_path}` to exist."
|
||||
);
|
||||
let file = debug_output_directory.to_path_buf().join(output_file_name);
|
||||
|
||||
assert!(
|
||||
!file_is_empty(output_file_path),
|
||||
"Expected the {output_file_type} output file `{output_file_path}` to not be empty."
|
||||
assert!(file.exists(), "Artifact should exist: {}", file.display());
|
||||
|
||||
assert_ne!(
|
||||
file.metadata().unwrap().len(),
|
||||
0,
|
||||
"Artifact shouldn't be empty: {}",
|
||||
file.display()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn writes_to_file() {
|
||||
let temp_dir = tempdir().unwrap();
|
||||
let arguments = &[
|
||||
utils::SOLIDITY_CONTRACT_PATH,
|
||||
"--overwrite",
|
||||
@@ -54,15 +43,16 @@ fn writes_to_file() {
|
||||
"--bin",
|
||||
"--asm",
|
||||
"--output-dir",
|
||||
OUTPUT_DIRECTORY,
|
||||
temp_dir.path().to_str().unwrap(),
|
||||
];
|
||||
let result = utils::execute_resolc(arguments);
|
||||
assert_valid_output_file(&result, "--bin", OUTPUT_BIN_FILE_PATH);
|
||||
assert_valid_output_file(&result, "--asm", OUTPUT_ASM_FILE_PATH);
|
||||
assert_valid_output_file(&result, temp_dir.path(), OUTPUT_BIN_FILE_PATH);
|
||||
assert_valid_output_file(&result, temp_dir.path(), OUTPUT_ASM_FILE_PATH);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn writes_debug_info_to_file_unoptimized() {
|
||||
let temp_dir = tempdir().unwrap();
|
||||
let arguments = &[
|
||||
utils::SOLIDITY_CONTRACT_PATH,
|
||||
"-g",
|
||||
@@ -71,15 +61,16 @@ fn writes_debug_info_to_file_unoptimized() {
|
||||
"--bin",
|
||||
"--asm",
|
||||
"--output-dir",
|
||||
OUTPUT_DIRECTORY,
|
||||
temp_dir.path().to_str().unwrap(),
|
||||
];
|
||||
let result = utils::execute_resolc(arguments);
|
||||
assert_valid_output_file(&result, "--bin", OUTPUT_BIN_FILE_PATH);
|
||||
assert_valid_output_file(&result, "--asm", OUTPUT_ASM_FILE_PATH);
|
||||
assert_valid_output_file(&result, temp_dir.path(), OUTPUT_BIN_FILE_PATH);
|
||||
assert_valid_output_file(&result, temp_dir.path(), OUTPUT_ASM_FILE_PATH);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn writes_debug_info_to_file_optimized() {
|
||||
let temp_dir = tempdir().unwrap();
|
||||
let arguments = &[
|
||||
utils::SOLIDITY_CONTRACT_PATH,
|
||||
"-g",
|
||||
@@ -87,36 +78,38 @@ fn writes_debug_info_to_file_optimized() {
|
||||
"--bin",
|
||||
"--asm",
|
||||
"--output-dir",
|
||||
OUTPUT_DIRECTORY,
|
||||
temp_dir.path().to_str().unwrap(),
|
||||
];
|
||||
let result = utils::execute_resolc(arguments);
|
||||
assert_valid_output_file(&result, "--bin", OUTPUT_BIN_FILE_PATH);
|
||||
assert_valid_output_file(&result, "--asm", OUTPUT_ASM_FILE_PATH);
|
||||
assert_valid_output_file(&result, temp_dir.path(), OUTPUT_BIN_FILE_PATH);
|
||||
assert_valid_output_file(&result, temp_dir.path(), OUTPUT_ASM_FILE_PATH);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn writes_llvm_debug_info_to_file_unoptimized() {
|
||||
let temp_dir = tempdir().unwrap();
|
||||
let arguments = &[
|
||||
utils::SOLIDITY_CONTRACT_PATH,
|
||||
"-g",
|
||||
"--disable-solc-optimizer",
|
||||
"--overwrite",
|
||||
"--debug-output-dir",
|
||||
OUTPUT_DIRECTORY,
|
||||
temp_dir.path().to_str().unwrap(),
|
||||
];
|
||||
let result = utils::execute_resolc(arguments);
|
||||
assert_valid_output_file(&result, "llvm", OUTPUT_LLVM_UNOPTIMIZED_FILE_PATH);
|
||||
assert_valid_output_file(&result, temp_dir.path(), OUTPUT_LLVM_UNOPTIMIZED_FILE_PATH);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn writes_llvm_debug_info_to_file_optimized() {
|
||||
let temp_dir = tempdir().unwrap();
|
||||
let arguments = &[
|
||||
utils::SOLIDITY_CONTRACT_PATH,
|
||||
"-g",
|
||||
"--overwrite",
|
||||
"--debug-output-dir",
|
||||
OUTPUT_DIRECTORY,
|
||||
temp_dir.path().to_str().unwrap(),
|
||||
];
|
||||
let result = utils::execute_resolc(arguments);
|
||||
assert_valid_output_file(&result, "llvm", OUTPUT_LLVM_OPTIMIZED_FILE_PATH);
|
||||
assert_valid_output_file(&result, temp_dir.path(), OUTPUT_LLVM_OPTIMIZED_FILE_PATH);
|
||||
}
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
//! The tests for running resolc with standard JSON option.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use crate::tests::cli::utils;
|
||||
use crate::tests::cli::utils::{
|
||||
assert_command_success, assert_equal_exit_codes, execute_resolc_with_stdin_input,
|
||||
execute_solc_with_stdin_input, STANDARD_JSON_CONTRACTS_PATH,
|
||||
};
|
||||
|
||||
const JSON_OPTION: &str = "--standard-json";
|
||||
|
||||
#[test]
|
||||
fn runs_with_valid_input_file() {
|
||||
let arguments = &[JSON_OPTION];
|
||||
let resolc_result =
|
||||
utils::execute_resolc_with_stdin_input(arguments, utils::STANDARD_JSON_CONTRACTS_PATH);
|
||||
utils::assert_command_success(&resolc_result, "Providing a valid input file to stdin");
|
||||
let resolc_result = execute_resolc_with_stdin_input(arguments, STANDARD_JSON_CONTRACTS_PATH);
|
||||
assert_command_success(&resolc_result, "Providing a valid input file to stdin");
|
||||
|
||||
assert!(
|
||||
resolc_result.stdout.contains("contracts"),
|
||||
"Expected the output to contain a `contracts` field."
|
||||
);
|
||||
|
||||
let solc_result =
|
||||
utils::execute_solc_with_stdin_input(arguments, utils::STANDARD_JSON_CONTRACTS_PATH);
|
||||
utils::assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
let solc_result = execute_solc_with_stdin_input(arguments, STANDARD_JSON_CONTRACTS_PATH);
|
||||
assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
}
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
//! The tests for running resolc when expecting usage output.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use crate::tests::cli::utils;
|
||||
|
||||
#[test]
|
||||
#[ignore = "Fix: 'resolc --help' should exit with success exit code"]
|
||||
fn shows_usage_with_help() {
|
||||
let arguments = &["--help"];
|
||||
let resolc_result = utils::execute_resolc(arguments);
|
||||
utils::assert_command_success(&resolc_result, "Providing the `--help` option");
|
||||
|
||||
assert!(
|
||||
resolc_result.stdout.contains("Usage: resolc"),
|
||||
"Expected the output to contain usage information."
|
||||
);
|
||||
assert!(resolc_result.stdout.contains("Usage: resolc"));
|
||||
|
||||
let solc_result = utils::execute_solc(arguments);
|
||||
utils::assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
@@ -25,10 +19,7 @@ fn fails_without_options() {
|
||||
let resolc_result = utils::execute_resolc(&[]);
|
||||
utils::assert_command_failure(&resolc_result, "Omitting options");
|
||||
|
||||
assert!(
|
||||
resolc_result.stderr.contains("Usage: resolc"),
|
||||
"Expected the output to contain usage information."
|
||||
);
|
||||
assert!(resolc_result.stderr.contains("Usage: resolc"));
|
||||
|
||||
let solc_result = utils::execute_solc(&[]);
|
||||
utils::assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
|
||||
@@ -5,15 +5,28 @@ use std::{
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
use revive_common;
|
||||
|
||||
use crate::SolcCompiler;
|
||||
|
||||
pub const SOLIDITY_CONTRACT_PATH: &str = "src/tests/cli/contracts/solidity/contract.sol";
|
||||
pub const YUL_CONTRACT_PATH: &str = "src/tests/cli/contracts/yul/contract.yul";
|
||||
pub const YUL_MEMSET_CONTRACT_PATH: &str = "src/tests/cli/contracts/yul/memset.yul";
|
||||
/// The simple Solidity contract test fixture path.
|
||||
pub const SOLIDITY_CONTRACT_PATH: &str = "src/tests/data/solidity/contract.sol";
|
||||
/// The dependency Solidity contract test fixture path.
|
||||
pub const DEPENDENCY_CONTRACT_PATH: &str = "src/tests/data/solidity/dependency.sol";
|
||||
|
||||
/// The simple YUL contract test fixture path.
|
||||
pub const YUL_CONTRACT_PATH: &str = "src/tests/data/yul/contract.yul";
|
||||
|
||||
/// The memeset YUL contract test fixture path.
|
||||
pub const YUL_MEMSET_CONTRACT_PATH: &str = "src/tests/data/yul/memset.yul";
|
||||
/// The standard JSON contracts test fixture path.
|
||||
///
|
||||
pub const STANDARD_JSON_CONTRACTS_PATH: &str =
|
||||
"src/tests/cli/contracts/standard_json/solidity_contracts.json";
|
||||
"src/tests/data/standard_json/solidity_contracts.json";
|
||||
|
||||
/// The `resolc` YUL mode flag.
|
||||
pub const RESOLC_YUL_FLAG: &str = "--yul";
|
||||
/// The `--yul` option was deprecated in Solidity 0.8.27 in favor of `--strict-assembly`.
|
||||
/// See section `--strict-assembly vs. --yul` in https://soliditylang.org/blog/2024/09/04/solidity-0.8.27-release-announcement/
|
||||
pub const SOLC_YUL_FLAG: &str = "--strict-assembly";
|
||||
|
||||
/// The result of executing a command.
|
||||
pub struct CommandResult {
|
||||
@@ -52,6 +65,14 @@ fn execute_command(
|
||||
arguments: &[&str],
|
||||
stdin_file_path: Option<&str>,
|
||||
) -> CommandResult {
|
||||
println!(
|
||||
"executing command: '{command} {}{}'",
|
||||
arguments.join(" "),
|
||||
stdin_file_path
|
||||
.map(|argument| format!("< {argument}"))
|
||||
.unwrap_or_default()
|
||||
);
|
||||
|
||||
let stdin_config = match stdin_file_path {
|
||||
Some(path) => Stdio::from(File::open(path).unwrap()),
|
||||
None => Stdio::null(),
|
||||
@@ -73,10 +94,7 @@ fn execute_command(
|
||||
}
|
||||
|
||||
pub fn assert_equal_exit_codes(solc_result: &CommandResult, resolc_result: &CommandResult) {
|
||||
assert_eq!(
|
||||
solc_result.code, resolc_result.code,
|
||||
"Expected solc and resolc to have the same exit code."
|
||||
);
|
||||
assert_eq!(solc_result.code, resolc_result.code,);
|
||||
}
|
||||
|
||||
pub fn assert_command_success(result: &CommandResult, error_message_prefix: &str) {
|
||||
|
||||
@@ -1,44 +1,32 @@
|
||||
//! The tests for running resolc with yul option.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use crate::tests::cli::utils;
|
||||
|
||||
pub const YUL_OPTION: &str = "--yul";
|
||||
/// The `--yul` option was deprecated in Solidity 0.8.27 in favor of `--strict-assembly`.
|
||||
/// See section `--strict-assembly vs. --yul` in https://soliditylang.org/blog/2024/09/04/solidity-0.8.27-release-announcement/
|
||||
const SOLC_YUL_OPTION: &str = "--strict-assembly";
|
||||
use crate::tests::cli::utils::{
|
||||
assert_command_success, assert_equal_exit_codes, execute_resolc, execute_solc, RESOLC_YUL_FLAG,
|
||||
SOLC_YUL_FLAG, YUL_CONTRACT_PATH,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn runs_with_valid_input_file() {
|
||||
let arguments = &[utils::YUL_CONTRACT_PATH, YUL_OPTION];
|
||||
let resolc_result = utils::execute_resolc(arguments);
|
||||
utils::assert_command_success(&resolc_result, "Providing a valid input file");
|
||||
let resolc_result = execute_resolc(&[YUL_CONTRACT_PATH, RESOLC_YUL_FLAG]);
|
||||
assert_command_success(&resolc_result, "Providing a valid input file");
|
||||
|
||||
assert!(
|
||||
resolc_result
|
||||
.stderr
|
||||
.contains("Compiler run successful. No output requested"),
|
||||
"Expected the output to contain a success message."
|
||||
);
|
||||
assert!(resolc_result
|
||||
.stderr
|
||||
.contains("Compiler run successful. No output requested"));
|
||||
|
||||
let solc_arguments = &[utils::YUL_CONTRACT_PATH, SOLC_YUL_OPTION];
|
||||
let solc_result = utils::execute_solc(solc_arguments);
|
||||
utils::assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
let solc_result = execute_solc(&[YUL_CONTRACT_PATH, SOLC_YUL_FLAG]);
|
||||
assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
}
|
||||
|
||||
/// While the `solc` Solidity mode requires output selection,
|
||||
/// the strict-assembly mode does not.
|
||||
///
|
||||
/// `resolc` exhibits consistent behavior for both modes.
|
||||
#[test]
|
||||
fn fails_without_input_file() {
|
||||
let arguments = &[YUL_OPTION];
|
||||
let resolc_result = utils::execute_resolc(arguments);
|
||||
utils::assert_command_failure(&resolc_result, "Omitting an input file");
|
||||
|
||||
assert!(
|
||||
resolc_result.stderr.contains("The input file is missing"),
|
||||
"Expected the output to contain a specific error message."
|
||||
);
|
||||
|
||||
let solc_arguments = &[SOLC_YUL_OPTION];
|
||||
let solc_result = utils::execute_solc(solc_arguments);
|
||||
utils::assert_equal_exit_codes(&solc_result, &resolc_result);
|
||||
fn runs_without_input_file() {
|
||||
let resolc_result = execute_resolc(&[RESOLC_YUL_FLAG]);
|
||||
assert_command_success(&resolc_result, "Omitting an input file");
|
||||
assert!(resolc_result
|
||||
.stderr
|
||||
.contains("Compiler run successful. No output requested"));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
|
||||
pragma solidity >=0.7.0 <0.9.0;
|
||||
|
||||
library Assert {
|
||||
function equal(uint256 a, uint256 b) public pure returns (bool result) {
|
||||
result = (a == b);
|
||||
}
|
||||
}
|
||||
|
||||
library AssertNe {
|
||||
function notEqual(uint256 a, uint256 b) public pure returns (bool result) {
|
||||
result = (a != b);
|
||||
}
|
||||
}
|
||||
|
||||
contract TestAssert {
|
||||
constructor() payable {
|
||||
new Dependency();
|
||||
}
|
||||
|
||||
function checkEquality(uint256 a, uint256 b) public pure returns (string memory) {
|
||||
Assert.equal(a, b);
|
||||
return "Values are equal";
|
||||
}
|
||||
}
|
||||
|
||||
contract Dependency {
|
||||
function checkNotEquality(uint256 a, uint256 b) public pure returns (string memory) {
|
||||
AssertNe.notEqual(a, b);
|
||||
return "Values are not equal";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"language": "Yul",
|
||||
"sources": {
|
||||
"Test": {
|
||||
"content": "object \"Return\" { code { { return(0, 0) } } object \"Return_deployed\" { code { { return(0, 0) } } } }"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true
|
||||
},
|
||||
"metadata": {
|
||||
"useLiteralContent": true
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"": [
|
||||
"ast"
|
||||
],
|
||||
"*": [
|
||||
"abi",
|
||||
"evm.methodIdentifiers",
|
||||
"evm.bytecode"
|
||||
]
|
||||
}
|
||||
},
|
||||
"libraries": {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"language": "Yul",
|
||||
"sources": {
|
||||
"Test": {
|
||||
"urls": [
|
||||
"src/tests/data/yul/Test.yul"
|
||||
]
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true
|
||||
},
|
||||
"metadata": {
|
||||
"useLiteralContent": true
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"": [
|
||||
"ast"
|
||||
],
|
||||
"*": [
|
||||
"abi",
|
||||
"evm.methodIdentifiers",
|
||||
"evm.bytecode"
|
||||
]
|
||||
}
|
||||
},
|
||||
"libraries": {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
object "Return" {
|
||||
code {
|
||||
{
|
||||
return(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
object "Return_deployed" {
|
||||
code {
|
||||
{
|
||||
mstore(0, 42)
|
||||
return(0, 32)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
//! The Solidity compiler unit tests for messages.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use revive_solc_json_interface::warning::Warning;
|
||||
|
||||
pub const ECRECOVER_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract ECRecoverExample {
|
||||
function recoverAddress(
|
||||
bytes32 messageHash,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s
|
||||
) public pure returns (address) {
|
||||
return ecrecover(messageHash, v, r, s);
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn ecrecover() {
|
||||
assert!(
|
||||
super::check_solidity_warning(
|
||||
ECRECOVER_TEST_SOURCE,
|
||||
"Warning: It looks like you are using 'ecrecover' to validate a signature of a user account.",
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
None,
|
||||
).expect("Test failure")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ecrecover_suppressed() {
|
||||
assert!(
|
||||
!super::check_solidity_warning(
|
||||
ECRECOVER_TEST_SOURCE,
|
||||
"Warning: It looks like you are using 'ecrecover' to validate a signature of a user account.",
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
Some(vec![Warning::EcRecover]),
|
||||
).expect("Test failure")
|
||||
);
|
||||
}
|
||||
|
||||
pub const SEND_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract SendExample {
|
||||
address payable public recipient;
|
||||
|
||||
constructor(address payable _recipient) {
|
||||
recipient = _recipient;
|
||||
}
|
||||
|
||||
function forwardEther() external payable {
|
||||
bool success = recipient.send(msg.value);
|
||||
require(success, "Failed to send Ether");
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
pub const BALANCE_CALLS_MESSAGE: &str =
|
||||
"Warning: It looks like you are using '<address payable>.send/transfer(<X>)'";
|
||||
|
||||
#[test]
|
||||
fn send() {
|
||||
assert!(super::check_solidity_warning(
|
||||
SEND_TEST_SOURCE,
|
||||
BALANCE_CALLS_MESSAGE,
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.expect("Test failure"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_suppressed() {
|
||||
assert!(!super::check_solidity_warning(
|
||||
SEND_TEST_SOURCE,
|
||||
BALANCE_CALLS_MESSAGE,
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
Some(vec![Warning::SendTransfer]),
|
||||
)
|
||||
.expect("Test failure"));
|
||||
}
|
||||
|
||||
pub const TRANSFER_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract TransferExample {
|
||||
address payable public recipient;
|
||||
|
||||
constructor(address payable _recipient) {
|
||||
recipient = _recipient;
|
||||
}
|
||||
|
||||
function forwardEther() external payable {
|
||||
recipient.transfer(msg.value);
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn transfer() {
|
||||
assert!(super::check_solidity_warning(
|
||||
TRANSFER_TEST_SOURCE,
|
||||
BALANCE_CALLS_MESSAGE,
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.expect("Test failure"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transfer_suppressed() {
|
||||
assert!(!super::check_solidity_warning(
|
||||
TRANSFER_TEST_SOURCE,
|
||||
BALANCE_CALLS_MESSAGE,
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
Some(vec![Warning::SendTransfer]),
|
||||
)
|
||||
.expect("Test failure"));
|
||||
}
|
||||
|
||||
pub const EXTCODESIZE_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract ExternalCodeSize {
|
||||
function getExternalCodeSize(address target) public view returns (uint256) {
|
||||
uint256 codeSize;
|
||||
assembly {
|
||||
codeSize := extcodesize(target)
|
||||
}
|
||||
return codeSize;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn extcodesize() {
|
||||
assert!(super::check_solidity_warning(
|
||||
EXTCODESIZE_TEST_SOURCE,
|
||||
"Warning: Your code or one of its dependencies uses the 'extcodesize' instruction,",
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.expect("Test failure"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extcodesize_suppressed() {
|
||||
assert!(!super::check_solidity_warning(
|
||||
EXTCODESIZE_TEST_SOURCE,
|
||||
"Warning: Your code or one of its dependencies uses the 'extcodesize' instruction,",
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
Some(vec![Warning::ExtCodeSize]),
|
||||
)
|
||||
.expect("Test failure"));
|
||||
}
|
||||
|
||||
pub const TX_ORIGIN_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract TxOriginExample {
|
||||
function isOriginSender() public view returns (bool) {
|
||||
return tx.origin == msg.sender;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn tx_origin() {
|
||||
assert!(super::check_solidity_warning(
|
||||
TX_ORIGIN_TEST_SOURCE,
|
||||
"Warning: You are checking for 'tx.origin' in your code, which might lead to",
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.expect("Test failure"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tx_origin_suppressed() {
|
||||
assert!(!super::check_solidity_warning(
|
||||
TX_ORIGIN_TEST_SOURCE,
|
||||
"Warning: You are checking for 'tx.origin' in your code, which might lead to",
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
Some(vec![Warning::TxOrigin]),
|
||||
)
|
||||
.expect("Test failure"));
|
||||
}
|
||||
|
||||
pub const TX_ORIGIN_ASSEMBLY_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract TxOriginExample {
|
||||
function isOriginSender() public view returns (bool) {
|
||||
address txOrigin;
|
||||
address sender = msg.sender;
|
||||
|
||||
assembly {
|
||||
txOrigin := origin() // Get the transaction origin using the 'origin' instruction
|
||||
}
|
||||
|
||||
return txOrigin == sender;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn tx_origin_assembly() {
|
||||
assert!(super::check_solidity_warning(
|
||||
TX_ORIGIN_ASSEMBLY_TEST_SOURCE,
|
||||
"Warning: You are checking for 'tx.origin' in your code, which might lead to",
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.expect("Test failure"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tx_origin_assembly_suppressed() {
|
||||
assert!(!super::check_solidity_warning(
|
||||
TX_ORIGIN_ASSEMBLY_TEST_SOURCE,
|
||||
"Warning: You are checking for 'tx.origin' in your code, which might lead to",
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
Some(vec![Warning::TxOrigin]),
|
||||
)
|
||||
.expect("Test failure"));
|
||||
}
|
||||
@@ -1,15 +1,6 @@
|
||||
//! The Solidity compiler unit tests.
|
||||
//! The Solidity compiler tests.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
mod cli;
|
||||
mod factory_dependency;
|
||||
mod ir_artifacts;
|
||||
mod libraries;
|
||||
mod messages;
|
||||
mod optimizer;
|
||||
mod remappings;
|
||||
mod runtime_code;
|
||||
mod unsupported_opcodes;
|
||||
|
||||
pub(crate) use super::test_utils::*;
|
||||
mod unit;
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
//! The Solidity compiler unit tests for remappings.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
pub const CALLEE_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity >=0.4.16;
|
||||
|
||||
contract Callable {
|
||||
function f(uint a) public pure returns(uint) {
|
||||
return a * 2;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
pub const CALLER_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity >=0.4.16;
|
||||
|
||||
import "libraries/default/callable.sol";
|
||||
|
||||
contract Main {
|
||||
function main(Callable callable) public returns(uint) {
|
||||
return callable.f(5);
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
let mut sources = BTreeMap::new();
|
||||
sources.insert("./test.sol".to_owned(), CALLER_TEST_SOURCE.to_owned());
|
||||
sources.insert("./callable.sol".to_owned(), CALLEE_TEST_SOURCE.to_owned());
|
||||
|
||||
let mut remappings = BTreeSet::new();
|
||||
remappings.insert("libraries/default/=./".to_owned());
|
||||
|
||||
super::build_solidity(
|
||||
sources,
|
||||
BTreeMap::new(),
|
||||
Some(remappings),
|
||||
revive_llvm_context::OptimizerSettings::cycles(),
|
||||
)
|
||||
.expect("Test failure");
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
//! The Solidity compiler unit tests for runtime code.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "runtimeCode is not supported")]
|
||||
fn default() {
|
||||
let source_code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract A {}
|
||||
|
||||
contract Test {
|
||||
function main() public pure returns(bytes memory) {
|
||||
return type(A).runtimeCode;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let mut sources = BTreeMap::new();
|
||||
sources.insert("test.sol".to_owned(), source_code.to_owned());
|
||||
|
||||
super::build_solidity(
|
||||
sources,
|
||||
BTreeMap::new(),
|
||||
None,
|
||||
revive_llvm_context::OptimizerSettings::cycles(),
|
||||
)
|
||||
.expect("Test failure");
|
||||
}
|
||||
+12
-30
@@ -1,10 +1,10 @@
|
||||
//! The Solidity compiler unit tests for factory dependencies.
|
||||
|
||||
#![cfg(test)]
|
||||
use crate::test_utils::{build_solidity, sources};
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub const MAIN_CODE: &str = r#"
|
||||
#[test]
|
||||
fn default() {
|
||||
let caller_code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity >=0.4.16;
|
||||
@@ -18,10 +18,9 @@ contract Main {
|
||||
callable.set(10);
|
||||
return callable.get();
|
||||
}
|
||||
}
|
||||
"#;
|
||||
}"#;
|
||||
|
||||
pub const CALLABLE_CODE: &str = r#"
|
||||
let callee_code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity >=0.4.16;
|
||||
@@ -36,35 +35,22 @@ contract Callable {
|
||||
function get() external view returns(uint256) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
}"#;
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
let mut sources = BTreeMap::new();
|
||||
sources.insert("main.sol".to_owned(), MAIN_CODE.to_owned());
|
||||
sources.insert("callable.sol".to_owned(), CALLABLE_CODE.to_owned());
|
||||
|
||||
let output = super::build_solidity(
|
||||
sources,
|
||||
BTreeMap::new(),
|
||||
None,
|
||||
revive_llvm_context::OptimizerSettings::cycles(),
|
||||
)
|
||||
.expect("Build failure");
|
||||
let output = build_solidity(sources(&[
|
||||
("main.sol", caller_code),
|
||||
("callable.sol", callee_code),
|
||||
]))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
output
|
||||
.contracts
|
||||
.as_ref()
|
||||
.expect("Missing field `contracts`")
|
||||
.get("main.sol")
|
||||
.expect("Missing file `main.sol`")
|
||||
.get("Main")
|
||||
.expect("Missing contract `main.sol:Main`")
|
||||
.factory_dependencies
|
||||
.as_ref()
|
||||
.expect("Missing field `factory_dependencies`")
|
||||
.len(),
|
||||
1,
|
||||
"Expected 1 factory dependency in `main.sol:Main`"
|
||||
@@ -72,15 +58,11 @@ fn default() {
|
||||
assert_eq!(
|
||||
output
|
||||
.contracts
|
||||
.as_ref()
|
||||
.expect("Missing field `contracts`")
|
||||
.get("callable.sol")
|
||||
.expect("Missing file `callable.sol`")
|
||||
.get("Callable")
|
||||
.expect("Missing contract `callable.sol:Callable`")
|
||||
.factory_dependencies
|
||||
.as_ref()
|
||||
.expect("Missing field `factory_dependencies`")
|
||||
.len(),
|
||||
0,
|
||||
"Expected 0 factory dependencies in `callable.sol:Callable`"
|
||||
+5
-18
@@ -1,13 +1,11 @@
|
||||
//! The Solidity compiler unit tests for IR artifacts.
|
||||
//! The tests check if the IR artifacts are kept in the final output.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use crate::test_utils::{build_solidity, sources};
|
||||
|
||||
#[test]
|
||||
fn yul() {
|
||||
let source_code = r#"
|
||||
let code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
@@ -18,28 +16,17 @@ contract Test {
|
||||
}
|
||||
"#;
|
||||
|
||||
let mut sources = BTreeMap::new();
|
||||
sources.insert("test.sol".to_owned(), source_code.to_owned());
|
||||
|
||||
let build = super::build_solidity(
|
||||
sources,
|
||||
BTreeMap::new(),
|
||||
None,
|
||||
revive_llvm_context::OptimizerSettings::cycles(),
|
||||
)
|
||||
.expect("Test failure");
|
||||
let build = build_solidity(sources(&[("test.sol", code)])).expect("Test failure");
|
||||
|
||||
assert!(
|
||||
build
|
||||
!build
|
||||
.contracts
|
||||
.as_ref()
|
||||
.expect("Always exists")
|
||||
.get("test.sol")
|
||||
.expect("Always exists")
|
||||
.get("Test")
|
||||
.expect("Always exists")
|
||||
.ir_optimized
|
||||
.is_some(),
|
||||
.is_empty(),
|
||||
"Yul IR is missing"
|
||||
);
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
//! The Solidity compiler unit tests for libraries.
|
||||
|
||||
#![cfg(test)]
|
||||
use revive_solc_json_interface::SolcStandardJsonInputSettingsLibraries;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use crate::test_utils::build_solidity_and_detect_missing_libraries;
|
||||
|
||||
pub const LIBRARY_TEST_SOURCE: &str = r#"
|
||||
pub const CODE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
@@ -28,29 +28,21 @@ contract SimpleContract {
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
}"#;
|
||||
|
||||
#[test]
|
||||
fn not_specified() {
|
||||
let mut sources = BTreeMap::new();
|
||||
sources.insert("test.sol".to_owned(), LIBRARY_TEST_SOURCE.to_owned());
|
||||
|
||||
let output =
|
||||
super::build_solidity_and_detect_missing_libraries(sources.clone(), BTreeMap::new())
|
||||
.expect("Test failure");
|
||||
build_solidity_and_detect_missing_libraries(&[("test.sol", CODE)], Default::default())
|
||||
.unwrap();
|
||||
assert!(
|
||||
output
|
||||
.contracts
|
||||
.as_ref()
|
||||
.expect("Always exists")
|
||||
.get("test.sol")
|
||||
.expect("Always exists")
|
||||
.get("SimpleContract")
|
||||
.expect("Always exists")
|
||||
.missing_libraries
|
||||
.as_ref()
|
||||
.expect("Always exists")
|
||||
.contains("test.sol:SimpleLibrary"),
|
||||
"Missing library not detected"
|
||||
);
|
||||
@@ -58,32 +50,25 @@ fn not_specified() {
|
||||
|
||||
#[test]
|
||||
fn specified() {
|
||||
let mut sources = BTreeMap::new();
|
||||
sources.insert("test.sol".to_owned(), LIBRARY_TEST_SOURCE.to_owned());
|
||||
|
||||
let mut libraries = BTreeMap::new();
|
||||
let mut libraries = SolcStandardJsonInputSettingsLibraries::default();
|
||||
libraries
|
||||
.as_inner_mut()
|
||||
.entry("test.sol".to_string())
|
||||
.or_insert_with(BTreeMap::new)
|
||||
.or_default()
|
||||
.entry("SimpleLibrary".to_string())
|
||||
.or_insert("0x00000000000000000000000000000000DEADBEEF".to_string());
|
||||
|
||||
let output =
|
||||
super::build_solidity_and_detect_missing_libraries(sources.clone(), libraries.clone())
|
||||
.expect("Test failure");
|
||||
build_solidity_and_detect_missing_libraries(&[("test.sol", CODE)], libraries.clone())
|
||||
.unwrap();
|
||||
assert!(
|
||||
output
|
||||
.contracts
|
||||
.as_ref()
|
||||
.expect("Always exists")
|
||||
.get("test.sol")
|
||||
.expect("Always exists")
|
||||
.get("SimpleContract")
|
||||
.expect("Always exists")
|
||||
.missing_libraries
|
||||
.as_ref()
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.is_empty(),
|
||||
"The list of missing libraries must be empty"
|
||||
);
|
||||
@@ -0,0 +1,116 @@
|
||||
//! The Solidity compiler unit tests for messages.
|
||||
|
||||
use revive_llvm_context::OptimizerSettings;
|
||||
use revive_solc_json_interface::{ResolcWarning, SolcStandardJsonOutput};
|
||||
|
||||
use crate::test_utils::{build_solidity, build_solidity_with_options, sources};
|
||||
|
||||
pub const SEND_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract SendExample {
|
||||
address payable public recipient;
|
||||
|
||||
constructor(address payable _recipient) {
|
||||
recipient = _recipient;
|
||||
}
|
||||
|
||||
function forwardEther() external payable {
|
||||
bool success = recipient.send(msg.value);
|
||||
require(success, "Failed to send Ether");
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub const TRANSFER_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract TransferExample {
|
||||
address payable public recipient;
|
||||
|
||||
constructor(address payable _recipient) {
|
||||
recipient = _recipient;
|
||||
}
|
||||
|
||||
function forwardEther() external payable {
|
||||
recipient.transfer(msg.value);
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub const TX_ORIGIN_TEST_SOURCE: &str = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract TxOriginExample {
|
||||
function isOriginSender() public view returns (bool) {
|
||||
return tx.origin == msg.sender;
|
||||
}
|
||||
}"#;
|
||||
|
||||
fn contains_warning(build: SolcStandardJsonOutput, warning: ResolcWarning) -> bool {
|
||||
build
|
||||
.errors
|
||||
.iter()
|
||||
.any(|error| error.is_warning() && error.message.contains(warning.as_message()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send() {
|
||||
let build = build_solidity(sources(&[("test.sol", SEND_TEST_SOURCE)])).unwrap();
|
||||
assert!(contains_warning(build, ResolcWarning::SendAndTransfer));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_suppressed() {
|
||||
let build = build_solidity_with_options(
|
||||
sources(&[("test.sol", SEND_TEST_SOURCE)]),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
OptimizerSettings::cycles(),
|
||||
true,
|
||||
vec![ResolcWarning::SendAndTransfer],
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!contains_warning(build, ResolcWarning::SendAndTransfer));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transfer() {
|
||||
let build = build_solidity(sources(&[("test.sol", TRANSFER_TEST_SOURCE)])).unwrap();
|
||||
assert!(contains_warning(build, ResolcWarning::SendAndTransfer));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transfer_suppressed() {
|
||||
let build = build_solidity_with_options(
|
||||
sources(&[("test.sol", TRANSFER_TEST_SOURCE)]),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
OptimizerSettings::cycles(),
|
||||
true,
|
||||
vec![ResolcWarning::SendAndTransfer],
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!contains_warning(build, ResolcWarning::SendAndTransfer))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tx_origin() {
|
||||
let build = build_solidity(sources(&[("test.sol", TX_ORIGIN_TEST_SOURCE)])).unwrap();
|
||||
assert!(contains_warning(build, ResolcWarning::TxOrigin));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tx_origin_suppressed() {
|
||||
let build = build_solidity_with_options(
|
||||
sources(&[("test.sol", TX_ORIGIN_TEST_SOURCE)]),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
OptimizerSettings::cycles(),
|
||||
true,
|
||||
vec![ResolcWarning::TxOrigin],
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!contains_warning(build, ResolcWarning::TxOrigin))
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
//! The Solidity compiler unit tests.
|
||||
|
||||
mod factory_dependency;
|
||||
mod ir_artifacts;
|
||||
mod libraries;
|
||||
mod messages;
|
||||
mod optimizer;
|
||||
mod remappings;
|
||||
mod runtime_code;
|
||||
mod standard_json;
|
||||
mod unsupported_opcodes;
|
||||
@@ -1,10 +1,12 @@
|
||||
//! The Solidity compiler unit tests for the optimizer.
|
||||
|
||||
#![cfg(test)]
|
||||
use crate::test_utils::{build_solidity, build_solidity_with_options, sources};
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub const SOURCE_CODE: &str = r#"
|
||||
#[test]
|
||||
fn optimizer() {
|
||||
let source = &[(
|
||||
"test.sol",
|
||||
r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity >=0.5.0;
|
||||
@@ -40,40 +42,31 @@ contract Test {
|
||||
}
|
||||
return h;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
}"#,
|
||||
)];
|
||||
|
||||
#[test]
|
||||
fn optimizer() {
|
||||
let mut sources = BTreeMap::new();
|
||||
sources.insert("test.sol".to_owned(), SOURCE_CODE.to_owned());
|
||||
|
||||
let build_unoptimized = super::build_solidity(
|
||||
sources.clone(),
|
||||
BTreeMap::new(),
|
||||
None,
|
||||
let build_unoptimized = build_solidity_with_options(
|
||||
sources(source),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
revive_llvm_context::OptimizerSettings::none(),
|
||||
true,
|
||||
Default::default(),
|
||||
)
|
||||
.expect("Build failure");
|
||||
let build_optimized_for_cycles = super::build_solidity(
|
||||
sources.clone(),
|
||||
BTreeMap::new(),
|
||||
None,
|
||||
revive_llvm_context::OptimizerSettings::cycles(),
|
||||
)
|
||||
.expect("Build failure");
|
||||
let build_optimized_for_size = super::build_solidity(
|
||||
sources,
|
||||
BTreeMap::new(),
|
||||
None,
|
||||
.unwrap();
|
||||
let build_optimized_for_cycles = build_solidity(sources(source)).unwrap();
|
||||
let build_optimized_for_size = build_solidity_with_options(
|
||||
sources(source),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
revive_llvm_context::OptimizerSettings::size(),
|
||||
true,
|
||||
Default::default(),
|
||||
)
|
||||
.expect("Build failure");
|
||||
.unwrap();
|
||||
|
||||
let size_when_unoptimized = build_unoptimized
|
||||
.contracts
|
||||
.as_ref()
|
||||
.expect("Missing field `contracts`")
|
||||
.get("test.sol")
|
||||
.expect("Missing file `test.sol`")
|
||||
.get("Test")
|
||||
@@ -88,8 +81,6 @@ fn optimizer() {
|
||||
.len();
|
||||
let size_when_optimized_for_cycles = build_optimized_for_cycles
|
||||
.contracts
|
||||
.as_ref()
|
||||
.expect("Missing field `contracts`")
|
||||
.get("test.sol")
|
||||
.expect("Missing file `test.sol`")
|
||||
.get("Test")
|
||||
@@ -104,8 +95,6 @@ fn optimizer() {
|
||||
.len();
|
||||
let size_when_optimized_for_size = build_optimized_for_size
|
||||
.contracts
|
||||
.as_ref()
|
||||
.expect("Missing field `contracts`")
|
||||
.get("test.sol")
|
||||
.expect("Missing file `test.sol`")
|
||||
.get("Test")
|
||||
@@ -0,0 +1,40 @@
|
||||
//! The Solidity compiler unit tests for remappings.
|
||||
|
||||
use crate::test_utils::{build_solidity_with_options, sources};
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
let callee_code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity >=0.4.16;
|
||||
|
||||
contract Callable {
|
||||
function f(uint a) public pure returns(uint) {
|
||||
return a * 2;
|
||||
}
|
||||
}"#;
|
||||
|
||||
let caller_code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity >=0.4.16;
|
||||
|
||||
import "libraries/default/callable.sol";
|
||||
|
||||
contract Main {
|
||||
function main(Callable callable) public returns(uint) {
|
||||
return callable.f(5);
|
||||
}
|
||||
}"#;
|
||||
|
||||
build_solidity_with_options(
|
||||
sources(&[("./test.sol", caller_code), ("./callable.sol", callee_code)]),
|
||||
Default::default(),
|
||||
["libraries/default/=./".to_owned()].into(),
|
||||
revive_llvm_context::OptimizerSettings::cycles(),
|
||||
true,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
//! The Solidity compiler unit tests for runtime code.
|
||||
|
||||
use crate::test_utils::{build_solidity, sources};
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
let code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract A {}
|
||||
|
||||
contract Test {
|
||||
function main() public pure returns(bytes memory) {
|
||||
return type(A).runtimeCode;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
build_solidity(sources(&[("test.sol", code)]))
|
||||
.unwrap()
|
||||
.errors
|
||||
.iter()
|
||||
.find(|error| {
|
||||
error
|
||||
.to_string()
|
||||
.contains("Error: Deploy and runtime code are merged in PVM")
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use revive_solc_json_interface::SolcStandardJsonInput;
|
||||
|
||||
use crate::test_utils::build_yul_standard_json;
|
||||
|
||||
#[test]
|
||||
fn standard_json_yul_solc() {
|
||||
let solc_input = SolcStandardJsonInput::try_from(Some(
|
||||
PathBuf::from("src/tests/data/standard_json/yul_solc.json").as_path(),
|
||||
))
|
||||
.unwrap();
|
||||
let solc_output = build_yul_standard_json(solc_input).unwrap();
|
||||
|
||||
assert!(!solc_output
|
||||
.contracts
|
||||
.get("Test")
|
||||
.expect("The `Test` contract is missing")
|
||||
.get("Return")
|
||||
.expect("The `Return` contract is missing")
|
||||
.evm
|
||||
.as_ref()
|
||||
.expect("The `evm` field is missing")
|
||||
.bytecode
|
||||
.as_ref()
|
||||
.expect("The `bytecode` field is missing")
|
||||
.object
|
||||
.is_empty())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn standard_json_yul_solc_urls() {
|
||||
let solc_input = SolcStandardJsonInput::try_from(Some(
|
||||
PathBuf::from("src/tests/data/standard_json/yul_solc_urls.json").as_path(),
|
||||
))
|
||||
.unwrap();
|
||||
let solc_output = build_yul_standard_json(solc_input).unwrap();
|
||||
|
||||
assert!(!solc_output
|
||||
.contracts
|
||||
.get("Test")
|
||||
.expect("The `Test` contract is missing")
|
||||
.get("Return")
|
||||
.expect("The `Return` contract is missing")
|
||||
.evm
|
||||
.as_ref()
|
||||
.expect("The `evm` field is missing")
|
||||
.bytecode
|
||||
.as_ref()
|
||||
.expect("The `bytecode` field is missing")
|
||||
.object
|
||||
.is_empty())
|
||||
}
|
||||
+25
-68
@@ -1,13 +1,11 @@
|
||||
//! The Solidity compiler unit tests for unsupported opcodes.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use crate::test_utils::{build_solidity, build_yul, sources};
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "The `CODECOPY` instruction is not supported")]
|
||||
fn codecopy_yul_runtime() {
|
||||
let source_code = r#"
|
||||
let code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
@@ -22,22 +20,15 @@ contract FixedCodeCopy {
|
||||
|
||||
return code;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
}"#;
|
||||
|
||||
let mut sources = BTreeMap::new();
|
||||
sources.insert("test.sol".to_owned(), source_code.to_owned());
|
||||
|
||||
super::build_solidity(
|
||||
sources,
|
||||
BTreeMap::new(),
|
||||
None,
|
||||
revive_llvm_context::OptimizerSettings::cycles(),
|
||||
)
|
||||
.expect("Test failure");
|
||||
build_solidity(sources(&[("test.sol", code)])).unwrap();
|
||||
}
|
||||
|
||||
pub const CALLCODE_TEST_SOURCE: &str = r#"
|
||||
#[test]
|
||||
#[should_panic(expected = "The `CALLCODE` instruction is not supported")]
|
||||
fn callcode_yul() {
|
||||
let solidity = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
@@ -57,28 +48,15 @@ contract CallcodeTest {
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
}"#;
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "The `CALLCODE` instruction is not supported")]
|
||||
fn callcode_yul() {
|
||||
let mut sources = BTreeMap::new();
|
||||
sources.insert("test.sol".to_owned(), CALLCODE_TEST_SOURCE.to_owned());
|
||||
|
||||
super::build_solidity(
|
||||
sources,
|
||||
BTreeMap::new(),
|
||||
None,
|
||||
revive_llvm_context::OptimizerSettings::cycles(),
|
||||
)
|
||||
.expect("Test failure");
|
||||
build_solidity(sources(&[("test.sol", solidity)])).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "The `PC` instruction is not supported")]
|
||||
fn pc_yul() {
|
||||
let source_code = r#"
|
||||
let code = r#"
|
||||
object "ProgramCounter" {
|
||||
code {
|
||||
datacopy(0, dataoffset("ProgramCounter_deployed"), datasize("ProgramCounter_deployed"))
|
||||
@@ -94,13 +72,15 @@ object "ProgramCounter" {
|
||||
sstore(0, pcValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
"#;
|
||||
}"#;
|
||||
|
||||
super::build_yul(source_code).expect("Test failure");
|
||||
build_yul(&[("test.sol", code)]).unwrap();
|
||||
}
|
||||
|
||||
pub const EXTCODECOPY_TEST_SOURCE: &str = r#"
|
||||
#[test]
|
||||
#[should_panic(expected = "The `EXTCODECOPY` instruction is not supported")]
|
||||
fn extcodecopy_yul() {
|
||||
let code = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
@@ -114,25 +94,15 @@ contract ExternalCodeCopy {
|
||||
|
||||
return code;
|
||||
}
|
||||
}"#;
|
||||
|
||||
build_solidity(sources(&[("test.sol", code)])).unwrap();
|
||||
}
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "The `EXTCODECOPY` instruction is not supported")]
|
||||
fn extcodecopy_yul() {
|
||||
let mut sources = BTreeMap::new();
|
||||
sources.insert("test.sol".to_owned(), EXTCODECOPY_TEST_SOURCE.to_owned());
|
||||
|
||||
super::build_solidity(
|
||||
sources,
|
||||
BTreeMap::new(),
|
||||
None,
|
||||
revive_llvm_context::OptimizerSettings::cycles(),
|
||||
)
|
||||
.expect("Test failure");
|
||||
}
|
||||
|
||||
pub const SELFDESTRUCT_TEST_SOURCE: &str = r#"
|
||||
#[should_panic(expected = "The `SELFDESTRUCT` instruction is not supported")]
|
||||
fn selfdestruct_yul() {
|
||||
let solidity = r#"
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
@@ -147,20 +117,7 @@ contract MinimalDestructible {
|
||||
require(msg.sender == owner, "Only the owner can call this function.");
|
||||
selfdestruct(owner);
|
||||
}
|
||||
}
|
||||
"#;
|
||||
}"#;
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "The `SELFDESTRUCT` instruction is not supported")]
|
||||
fn selfdestruct_yul() {
|
||||
let mut sources = BTreeMap::new();
|
||||
sources.insert("test.sol".to_owned(), SELFDESTRUCT_TEST_SOURCE.to_owned());
|
||||
|
||||
super::build_solidity(
|
||||
sources,
|
||||
BTreeMap::new(),
|
||||
None,
|
||||
revive_llvm_context::OptimizerSettings::cycles(),
|
||||
)
|
||||
.expect("Test failure");
|
||||
build_solidity(sources(&[("test.sol", solidity)])).unwrap();
|
||||
}
|
||||
Reference in New Issue
Block a user