use crate::build_solidity;
use parity_scale_codec::{Decode, Encode};
#[derive(Debug, PartialEq, Eq, Encode, Decode)]
struct RevertReturn(u32, String);
#[test]
fn external_call() {
#[derive(Debug, PartialEq, Eq, Encode, Decode)]
struct Ret(u32);
let mut runtime = build_solidity(
r##"
contract c {
b x;
constructor() public {
x = new b(102);
}
function test() public returns (int32) {
return x.get_x({ t: 10 });
}
}
contract b {
int32 x;
constructor(int32 a) public {
x = a;
}
function get_x(int32 t) public returns (int32) {
return x * t;
}
}"##,
);
runtime.constructor(0, Vec::new());
runtime.function("test", Vec::new());
assert_eq!(runtime.vm.output, Ret(1020).encode());
}
#[test]
fn revert_external_call() {
let mut runtime = build_solidity(
r##"
contract c {
b x;
constructor() public {
x = new b(102);
}
function test() public returns (int32) {
return x.get_x({ t: 10 });
}
}
contract b {
int32 x;
constructor(int32 a) public {
x = a;
}
function get_x(int32 t) public returns (int32) {
revert("The reason why");
}
}"##,
);
runtime.constructor(0, Vec::new());
runtime.function_expect_failure("test", Vec::new());
}
#[test]
fn revert_constructor() {
let mut runtime = build_solidity(
r##"
contract c {
b x;
constructor() public {
}
function test() public returns (int32) {
x = new b(102);
return x.get_x({ t: 10 });
}
}
contract b {
int32 x;
constructor(int32 a) public {
require(a == 0, "Hello,\
World!");
}
function get_x(int32 t) public returns (int32) {
return x * t;
}
}"##,
);
runtime.constructor(0, Vec::new());
runtime.function_expect_failure("test", Vec::new());
assert_eq!(runtime.vm.output.len(), 0);
}
#[test]
fn external_datatypes() {
#[derive(Debug, PartialEq, Eq, Encode, Decode)]
struct Ret(u64);
let mut runtime = build_solidity(
r##"
contract c {
b x;
constructor() public {
x = new b(102);
}
function test() public returns (int64) {
strukt k = x.get_x(10, "foobar", true, strukt({ f1: "abcd", f2: address(555555), f3: -1 }));
assert(k.f1 == "1234");
assert(k.f2 == address(102));
return int64(k.f3);
}
}
contract b {
int x;
constructor(int a) public {
x = a;
}
function get_x(int t, string s, bool y, strukt k) public returns (strukt) {
assert(y == true);
assert(t == 10);
assert(s == "foobar");
assert(k.f1 == "abcd");
return strukt({ f1: "1234", f2: address(102), f3: x * t });
}
}
struct strukt {
bytes4 f1;
address f2;
int f3;
}"##,
);
runtime.constructor(0, Vec::new());
runtime.function("test", Vec::new());
assert_eq!(runtime.vm.output, Ret(1020).encode());
}
#[test]
fn creation_code() {
let mut runtime = build_solidity(
r##"
contract c {
function test() public returns (bytes) {
bytes runtime = type(b).runtimeCode;
assert(runtime[0] == 0);
assert(runtime[1] == 0x61); // a
assert(runtime[2] == 0x73); // s
assert(runtime[3] == 0x6d); // m
bytes creation = type(b).creationCode;
// on Substrate, they are the same
assert(creation == runtime);
return creation;
}
}
contract b {
int public x;
constructor(int a) public {
x = a;
}
}"##,
);
runtime.constructor(0, Vec::new());
runtime.function("test", Vec::new());
#[derive(Debug, PartialEq, Eq, Encode, Decode)]
struct Ret(Vec<u8>);
assert_eq!(
runtime.vm.output,
Ret(runtime.programs[1].code.clone()).encode()
);
}
#[test]
fn issue666() {
let mut runtime = build_solidity(
r##"
contract Flipper {
function flip () pure public {
print("flip");
}
}
contract Inc {
Flipper _flipper;
constructor (Flipper _flipperContract) {
_flipper = _flipperContract;
}
function superFlip () pure public {
_flipper.flip();
}
}"##,
);
runtime.constructor(0, Vec::new());
let flipper_address = runtime.vm.account;
println!("flipper_address={}", hex::encode(flipper_address));
runtime.set_program(1);
runtime.constructor(0, flipper_address.to_vec());
runtime.function("superFlip", Vec::new());
assert!(runtime.vm.output.is_empty());
}
#[test]
fn mangle_function_names_in_abi() {
let runtime = build_solidity(
r##"
enum E { v1, v2 }
struct S { int256 i; bool b; address a; }
contract C {
// foo_
function foo() public pure {}
// foo_uint256_addressArray2Array
function foo(uint256 i, address[2][] memory a) public pure {}
// foo_uint8Array2__int256_bool_address
function foo(E[2] memory e, S memory s) public pure {}
}"##,
);
let messages: Vec<String> = runtime
.programs
.get(0)
.unwrap()
.abi
.spec()
.messages()
.iter()
.map(|m| m.label().clone())
.collect();
assert!(!messages.contains(&"foo".to_string()));
assert!(messages.contains(&"foo_".to_string()));
assert!(messages.contains(&"foo_uint256_addressArray2Array".to_string()));
assert!(messages.contains(&"foo_uint8Array2__int256_bool_address".to_string()));
}
#[test]
fn mangle_overloaded_function_names_in_abi() {
let runtime = build_solidity(
r##"
contract A {
function foo(bool x) public {}
}
contract B is A {
function foo(int x) public {}
}"##,
);
let messages_a: Vec<String> = runtime
.programs
.get(0)
.unwrap()
.abi
.spec()
.messages()
.iter()
.map(|m| m.label().clone())
.collect();
assert!(messages_a.contains(&"foo".to_string()));
assert!(!messages_a.contains(&"foo_bool".to_string()));
let messages_b: Vec<String> = runtime
.programs
.get(1)
.unwrap()
.abi
.spec()
.messages()
.iter()
.map(|m| m.label().clone())
.collect();
assert!(!messages_b.contains(&"foo".to_string()));
assert!(messages_b.contains(&"foo_bool".to_string()));
}