Moving some bytes and array tests to semanticTests

This commit is contained in:
Djordje Mijovic 2020-11-12 15:29:08 +01:00
parent bdf05bf8a0
commit 11033c9536
16 changed files with 297 additions and 398 deletions

View File

@ -2593,25 +2593,6 @@ BOOST_AUTO_TEST_CASE(copying_bytes_multiassign)
ABI_CHECK(callContractFunction("val()"), encodeArgs(0x80));
}
BOOST_AUTO_TEST_CASE(delete_removes_bytes_data)
{
char const* sourceCode = R"(
contract c {
fallback() external { data = msg.data; }
function del() public returns (bool) { delete data; return true; }
bytes data;
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("---", 7), bytes());
BOOST_CHECK(!storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("del()", 7), encodeArgs(true));
BOOST_CHECK(storageEmpty(m_contractAddress));
);
}
BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data)
{
char const* sourceCode = R"(
@ -2633,83 +2614,6 @@ BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data)
);
}
BOOST_AUTO_TEST_CASE(copy_removes_bytes_data)
{
char const* sourceCode = R"(
contract c {
function set() public returns (bool) { data1 = msg.data; return true; }
function reset() public returns (bool) { data1 = data2; return true; }
bytes data1;
bytes data2;
}
)";
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5), encodeArgs(true));
BOOST_CHECK(!storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("reset()"), encodeArgs(true));
BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(bytes_inside_mappings)
{
char const* sourceCode = R"(
contract c {
function set(uint key) public returns (bool) { data[key] = msg.data; return true; }
function copy(uint from, uint to) public returns (bool) { data[to] = data[from]; return true; }
mapping(uint => bytes) data;
}
)";
compileAndRun(sourceCode);
// store a short byte array at 1 and a longer one at 2
ABI_CHECK(callContractFunction("set(uint256)", 1, 2), encodeArgs(true));
ABI_CHECK(callContractFunction("set(uint256)", 2, 2, 3, 4, 5), encodeArgs(true));
BOOST_CHECK(!storageEmpty(m_contractAddress));
// copy shorter to longer
ABI_CHECK(callContractFunction("copy(uint256,uint256)", 1, 2), encodeArgs(true));
BOOST_CHECK(!storageEmpty(m_contractAddress));
// copy empty to both
ABI_CHECK(callContractFunction("copy(uint256,uint256)", 99, 1), encodeArgs(true));
BOOST_CHECK(!storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("copy(uint256,uint256)", 99, 2), encodeArgs(true));
BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete)
{
char const* sourceCode = R"(
contract c {
struct Struct { uint a; bytes data; uint b; }
Struct data1;
Struct data2;
function set(uint _a, bytes calldata _data, uint _b) external returns (bool) {
data1.a = _a;
data1.b = _b;
data1.data = _data;
return true;
}
function copy() public returns (bool) {
data1 = data2;
return true;
}
function del() public returns (bool) {
delete data1;
return true;
}
}
)";
compileAndRun(sourceCode);
string data = "123456789012345678901234567890123";
BOOST_CHECK(storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, 0x60, 13, u256(data.length()), data), encodeArgs(true));
BOOST_CHECK(!storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("copy()"), encodeArgs(true));
BOOST_CHECK(storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, 0x60, 13, u256(data.length()), data), encodeArgs(true));
BOOST_CHECK(!storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("del()"), encodeArgs(true));
BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(storing_invalid_boolean)
{
char const* sourceCode = R"(
@ -2894,197 +2798,6 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments)
);
}
BOOST_AUTO_TEST_CASE(fixed_array_cleanup)
{
char const* sourceCode = R"(
contract c {
uint spacer1;
uint spacer2;
uint[20] data;
function fill() public {
for (uint i = 0; i < data.length; ++i) data[i] = i+1;
}
function clear() public { delete data; }
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
BOOST_CHECK(storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("fill()"), bytes());
BOOST_CHECK(!storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("clear()"), bytes());
BOOST_CHECK(storageEmpty(m_contractAddress));
);
}
BOOST_AUTO_TEST_CASE(short_fixed_array_cleanup)
{
char const* sourceCode = R"(
contract c {
uint spacer1;
uint spacer2;
uint[3] data;
function fill() public {
for (uint i = 0; i < data.length; ++i) data[i] = i+1;
}
function clear() public { delete data; }
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
BOOST_CHECK(storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("fill()"), bytes());
BOOST_CHECK(!storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("clear()"), bytes());
BOOST_CHECK(storageEmpty(m_contractAddress));
);
}
BOOST_AUTO_TEST_CASE(dynamic_array_cleanup)
{
char const* sourceCode = R"(
contract c {
uint[20] spacer;
uint[] dynamic;
function fill() public {
for (uint i = 0; i < 21; ++i)
dynamic.push(i + 1);
}
function halfClear() public {
while (dynamic.length > 5)
dynamic.pop();
}
function fullClear() public { delete dynamic; }
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
BOOST_CHECK(storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("fill()"), bytes());
BOOST_CHECK(!storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("halfClear()"), bytes());
BOOST_CHECK(!storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("fullClear()"), bytes());
BOOST_CHECK(storageEmpty(m_contractAddress));
);
}
BOOST_AUTO_TEST_CASE(dynamic_multi_array_cleanup)
{
char const* sourceCode = R"(
contract c {
struct s { uint[][] d; }
s[] data;
function fill() public returns (uint) {
while (data.length < 3)
data.push();
while (data[2].d.length < 4)
data[2].d.push();
while (data[2].d[3].length < 5)
data[2].d[3].push();
data[2].d[3][4] = 8;
return data[2].d[3][4];
}
function clear() public { delete data; }
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
BOOST_CHECK(storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("fill()"), encodeArgs(8));
BOOST_CHECK(!storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("clear()"), bytes());
BOOST_CHECK(storageEmpty(m_contractAddress));
);
}
BOOST_AUTO_TEST_CASE(array_copy_storage_storage_dyn_dyn)
{
char const* sourceCode = R"(
contract c {
uint[] data1;
uint[] data2;
function setData1(uint length, uint index, uint value) public {
data1 = new uint[](length);
if (index < length)
data1[index] = value;
}
function copyStorageStorage() public { data2 = data1; }
function getData2(uint index) public returns (uint len, uint val) {
len = data2.length; if (index < len) val = data2[index];
}
}
)";
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("setData1(uint256,uint256,uint256)", 10, 5, 4), bytes());
ABI_CHECK(callContractFunction("copyStorageStorage()"), bytes());
ABI_CHECK(callContractFunction("getData2(uint256)", 5), encodeArgs(10, 4));
ABI_CHECK(callContractFunction("setData1(uint256,uint256,uint256)", 0, 0, 0), bytes());
ABI_CHECK(callContractFunction("copyStorageStorage()"), bytes());
ABI_CHECK(callContractFunction("getData2(uint256)", 0), encodeArgs(0, 0));
BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(array_copy_target_leftover)
{
// test that leftover elements in the last slot of target are correctly cleared during assignment
char const* sourceCode = R"(
contract c {
byte[10] data1;
bytes2[32] data2;
function test() public returns (uint check, uint res1, uint res2) {
uint i;
for (i = 0; i < data2.length; ++i)
data2[i] = 0xffff;
check = uint(uint16(data2[31])) * 0x10000 | uint(uint16(data2[14]));
for (i = 0; i < data1.length; ++i)
data1[i] = byte(uint8(1 + i));
data2 = data1;
for (i = 0; i < 16; ++i)
res1 |= uint(uint16(data2[i])) * 0x10000**i;
for (i = 0; i < 16; ++i)
res2 |= uint(uint16(data2[16 + i])) * 0x10000**i;
}
}
)";
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("test()"), encodeArgs(u256("0xffffffff"), asString(fromHex("0000000000000000000000000a00090008000700060005000400030002000100")), asString(fromHex("0000000000000000000000000000000000000000000000000000000000000000"))));
}
BOOST_AUTO_TEST_CASE(array_copy_storage_storage_struct)
{
char const* sourceCode = R"(
contract c {
struct Data { uint x; uint y; }
Data[] data1;
Data[] data2;
function test() public returns (uint x, uint y) {
while (data1.length < 9)
data1.push();
data1[8].x = 4;
data1[8].y = 5;
data2 = data1;
x = data2[8].x;
y = data2[8].y;
while (data1.length > 0)
data1.pop();
data2 = data1;
}
}
)";
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("test()"), encodeArgs(4, 5));
BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(array_copy_storage_abi)
{
// NOTE: This does not really test copying from storage to ABI directly,
@ -3141,117 +2854,6 @@ BOOST_AUTO_TEST_CASE(array_copy_storage_abi)
);
}
BOOST_AUTO_TEST_CASE(array_pop_uint16_transition)
{
char const* sourceCode = R"(
contract c {
uint16[] data;
function test() public returns (uint16 x, uint16 y, uint16 z) {
for (uint i = 1; i <= 48; i++)
data.push(uint16(i));
for (uint j = 1; j <= 10; j++)
data.pop();
x = data[data.length - 1];
for (uint k = 1; k <= 10; k++)
data.pop();
y = data[data.length - 1];
for (uint l = 1; l <= 10; l++)
data.pop();
z = data[data.length - 1];
for (uint m = 1; m <= 18; m++)
data.pop();
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("test()"), encodeArgs(38, 28, 18));
BOOST_CHECK(storageEmpty(m_contractAddress));
);
}
BOOST_AUTO_TEST_CASE(array_pop_uint24_transition)
{
char const* sourceCode = R"(
contract c {
uint256 a;
uint256 b;
uint256 c;
uint24[] data;
function test() public returns (uint24 x, uint24 y) {
for (uint i = 1; i <= 30; i++)
data.push(uint24(i));
for (uint j = 1; j <= 10; j++)
data.pop();
x = data[data.length - 1];
for (uint k = 1; k <= 10; k++)
data.pop();
y = data[data.length - 1];
for (uint l = 1; l <= 10; l++)
data.pop();
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("test()"), encodeArgs(20, 10));
BOOST_CHECK(storageEmpty(m_contractAddress));
);
}
BOOST_AUTO_TEST_CASE(array_pop_array_transition)
{
char const* sourceCode = R"(
contract c {
uint256 a;
uint256 b;
uint256 c;
uint16[] inner = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
uint16[][] data;
function test() public returns (uint x, uint y, uint z) {
for (uint i = 1; i <= 48; i++)
data.push(inner);
for (uint j = 1; j <= 10; j++)
data.pop();
x = data[data.length - 1][0];
for (uint k = 1; k <= 10; k++)
data.pop();
y = data[data.length - 1][1];
for (uint l = 1; l <= 10; l++)
data.pop();
z = data[data.length - 1][2];
for (uint m = 1; m <= 18; m++)
data.pop();
delete inner;
}
}
)";
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("test()"), encodeArgs(1, 2, 3));
BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(array_pop_storage_empty)
{
char const* sourceCode = R"(
contract c {
uint[] data;
function test() public {
data.push(7);
data.pop();
}
}
)";
ALSO_VIA_YUL(
DISABLE_EWASM_TESTRUN()
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("test()"), encodeArgs());
BOOST_CHECK(storageEmpty(m_contractAddress));
);
}
BOOST_AUTO_TEST_CASE(byte_array_pop_storage_empty)
{
char const* sourceCode = R"(

View File

@ -0,0 +1,26 @@
contract c {
uint256 a;
uint256 b;
uint256 c;
uint16[] inner = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
uint16[][] data;
function test() public returns (uint x, uint y, uint z) {
for (uint i = 1; i <= 48; i++)
data.push(inner);
for (uint j = 1; j <= 10; j++)
data.pop();
x = data[data.length - 1][0];
for (uint k = 1; k <= 10; k++)
data.pop();
y = data[data.length - 1][1];
for (uint l = 1; l <= 10; l++)
data.pop();
z = data[data.length - 1][2];
for (uint m = 1; m <= 18; m++)
data.pop();
delete inner;
}
}
// ----
// test() -> 1, 2, 3
// storage: empty

View File

@ -0,0 +1,12 @@
contract c {
uint[] data;
function test() public {
data.push(7);
data.pop();
}
}
// ====
// compileViaYul: also
// ----
// test() ->
// storage: empty

View File

@ -0,0 +1,23 @@
contract c {
uint16[] data;
function test() public returns (uint16 x, uint16 y, uint16 z) {
for (uint i = 1; i <= 48; i++)
data.push(uint16(i));
for (uint j = 1; j <= 10; j++)
data.pop();
x = data[data.length - 1];
for (uint k = 1; k <= 10; k++)
data.pop();
y = data[data.length - 1];
for (uint l = 1; l <= 10; l++)
data.pop();
z = data[data.length - 1];
for (uint m = 1; m <= 18; m++)
data.pop();
}
}
// ====
// compileViaYul: also
// ----
// test() -> 38, 28, 18
// storage: empty

View File

@ -0,0 +1,23 @@
contract c {
uint256 a;
uint256 b;
uint256 c;
uint24[] data;
function test() public returns (uint24 x, uint24 y) {
for (uint i = 1; i <= 30; i++)
data.push(uint24(i));
for (uint j = 1; j <= 10; j++)
data.pop();
x = data[data.length - 1];
for (uint k = 1; k <= 10; k++)
data.pop();
y = data[data.length - 1];
for (uint l = 1; l <= 10; l++)
data.pop();
}
}
// ====
// compileViaYul: also
// ----
// test() -> 20, 10
// storage: empty

View File

@ -0,0 +1,22 @@
contract c {
uint[] data1;
uint[] data2;
function setData1(uint length, uint index, uint value) public {
data1 = new uint[](length);
if (index < length)
data1[index] = value;
}
function copyStorageStorage() public { data2 = data1; }
function getData2(uint index) public returns (uint len, uint val) {
len = data2.length; if (index < len) val = data2[index];
}
}
// ----
// setData1(uint256,uint256,uint256): 10, 5, 4 ->
// copyStorageStorage() ->
// getData2(uint256): 5 -> 10, 4
// setData1(uint256,uint256,uint256): 0, 0, 0 ->
// copyStorageStorage() ->
// getData2(uint256): 0 -> 0, 0
// storage: empty

View File

@ -0,0 +1,20 @@
contract c {
struct Data { uint x; uint y; }
Data[] data1;
Data[] data2;
function test() public returns (uint x, uint y) {
while (data1.length < 9)
data1.push();
data1[8].x = 4;
data1[8].y = 5;
data2 = data1;
x = data2[8].x;
y = data2[8].y;
while (data1.length > 0)
data1.pop();
data2 = data1;
}
}
// ----
// test() -> 4, 5
// storage: empty

View File

@ -0,0 +1,19 @@
contract c {
byte[10] data1;
bytes2[32] data2;
function test() public returns (uint check, uint res1, uint res2) {
uint i;
for (i = 0; i < data2.length; ++i)
data2[i] = 0xffff;
check = uint(uint16(data2[31])) * 0x10000 | uint(uint16(data2[14]));
for (i = 0; i < data1.length; ++i)
data1[i] = byte(uint8(1 + i));
data2 = data1;
for (i = 0; i < 16; ++i)
res1 |= uint(uint16(data2[i])) * 0x10000**i;
for (i = 0; i < 16; ++i)
res2 |= uint(uint16(data2[16 + i])) * 0x10000**i;
}
}
// ----
// test() -> 0xffffffff, 0x0000000000000000000000000a00090008000700060005000400030002000100, 0x0000000000000000000000000000000000000000000000000000000000000000

View File

@ -0,0 +1,15 @@
contract c {
function set(uint key) public returns (bool) { data[key] = msg.data; return true; }
function copy(uint from, uint to) public returns (bool) { data[to] = data[from]; return true; }
mapping(uint => bytes) data;
}
// ----
// set(uint256): 1, 2 -> true
// set(uint256): 2, 2, 3, 4, 5 -> true
// storage: nonempty
// copy(uint256,uint256): 1, 2 -> true
// storage: nonempty
// copy(uint256,uint256): 99, 1 -> true
// storage: nonempty
// copy(uint256,uint256): 99, 2 -> true
// storage: empty

View File

@ -0,0 +1,12 @@
contract c {
function set() public returns (bool) { data1 = msg.data; return true; }
function reset() public returns (bool) { data1 = data2; return true; }
bytes data1;
bytes data2;
}
// ----
// set(): 1, 2, 3, 4, 5 -> true
// storage: nonempty
// reset() -> true
// storage: empty

View File

@ -0,0 +1,12 @@
contract c {
fallback() external { data = msg.data; }
function del() public returns (bool) { delete data; return true; }
bytes data;
}
// ====
// compileViaYul: also
// ----
// (): 7 ->
// storage: nonempty
// del(): 7 -> true
// storage: empty

View File

@ -0,0 +1,23 @@
contract c {
uint[20] spacer;
uint[] dynamic;
function fill() public {
for (uint i = 0; i < 21; ++i)
dynamic.push(i + 1);
}
function halfClear() public {
while (dynamic.length > 5)
dynamic.pop();
}
function fullClear() public { delete dynamic; }
}
// ====
// compileViaYul: also
// ----
// storage: empty
// fill() ->
// storage: nonempty
// halfClear() ->
// storage: nonempty
// fullClear() ->
// storage: empty

View File

@ -0,0 +1,23 @@
contract c {
struct s { uint[][] d; }
s[] data;
function fill() public returns (uint) {
while (data.length < 3)
data.push();
while (data[2].d.length < 4)
data[2].d.push();
while (data[2].d[3].length < 5)
data[2].d[3].push();
data[2].d[3][4] = 8;
return data[2].d[3][4];
}
function clear() public { delete data; }
}
// ====
// compileViaYul: also
// ----
// storage: empty
// fill() -> 8
// storage: nonempty
// clear() ->
// storage: empty

View File

@ -0,0 +1,17 @@
contract c {
uint spacer1;
uint spacer2;
uint[20] data;
function fill() public {
for (uint i = 0; i < data.length; ++i) data[i] = i+1;
}
function clear() public { delete data; }
}
// ====
// compileViaYul: also
// ----
// storage: empty
// fill() ->
// storage: nonempty
// clear() ->
// storage: empty

View File

@ -0,0 +1,17 @@
contract c {
uint spacer1;
uint spacer2;
uint[3] data;
function fill() public {
for (uint i = 0; i < data.length; ++i) data[i] = i+1;
}
function clear() public { delete data; }
}
// ====
// compileViaYul: also
// ----
// storage: empty
// fill() ->
// storage: nonempty
// clear() ->
// storage: empty

View File

@ -0,0 +1,33 @@
contract c {
struct Struct { uint a; bytes data; uint b; }
Struct data1;
Struct data2;
function set(uint _a, bytes calldata _data, uint _b) external returns (bool) {
data1.a = _a;
data1.b = _b;
data1.data = _data;
return true;
}
function copy() public returns (bool) {
data1 = data2;
return true;
}
function del() public returns (bool) {
delete data1;
return true;
}
function test(uint256 i) public returns (byte) {
return data1.data[i];
}
}
// ----
// storage: empty
// set(uint256,bytes,uint256): 12, 0x60, 13, 33, "12345678901234567890123456789012", "3" -> true
// test(uint256): 32 -> "3"
// storage: nonempty
// copy() -> true
// storage: empty
// set(uint256,bytes,uint256): 12, 0x60, 13, 33, "12345678901234567890123456789012", "3" -> true
// storage: nonempty
// del() -> true
// storage: empty