From a86ca47db8c4baeb466c9362657d08d9b60a1692 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Fri, 27 Sep 2019 19:59:38 -0400 Subject: [PATCH 1/5] unit tests --- CMakeLists.txt | 22 ++- .../include/eosio.token/eosio.token.hpp | 2 +- integration-tests/.clang-format | 76 ++++++++++ integration-tests/CMakeLists.txt | 25 ++++ integration-tests/eosio.token-tests.cpp | 132 ++++++++++++++++++ 5 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 integration-tests/.clang-format create mode 100644 integration-tests/CMakeLists.txt create mode 100644 integration-tests/eosio.token-tests.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ef311a3b..39adfe9e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,9 @@ string(REPLACE ";" "|" TEST_PREFIX_PATH "${CMAKE_PREFIX_PATH}") string(REPLACE ";" "|" TEST_FRAMEWORK_PATH "${CMAKE_FRAMEWORK_PATH}") string(REPLACE ";" "|" TEST_MODULE_PATH "${CMAKE_MODULE_PATH}") -set(BUILD_TESTS FALSE CACHE BOOL "Build unit tests") +set(BUILD_TESTS FALSE CACHE BOOL "Build unit tests, which should have been integration tests, + but are left here named unit tests, so that the newer correctly-named integration tests, + don't have a name conflict") if(BUILD_TESTS) message(STATUS "Building unit tests.") @@ -92,3 +94,21 @@ if(BUILD_TESTS) else() message(STATUS "Unit tests will not be built. To build unit tests, set BUILD_TESTS to true.") endif() + +set(BUILD_INTEGRATION_TESTS FALSE CACHE BOOL "Build integration tests") + +if(BUILD_INTEGRATION_TESTS) + ExternalProject_Add( + integration-tests + SOURCE_DIR ${CMAKE_SOURCE_DIR}/integration-tests + BINARY_DIR ${CMAKE_BINARY_DIR}/integration-tests + CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${EOSIO_CDT_ROOT}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake + UPDATE_COMMAND "" + PATCH_COMMAND "" + TEST_COMMAND "" + INSTALL_COMMAND "" + BUILD_ALWAYS 1 + ) +else() + message(STATUS "Integration tests will not be built. To build integration tests, set BUILD_INTEGRATION_TESTS to true.") +endif() diff --git a/contracts/eosio.token/include/eosio.token/eosio.token.hpp b/contracts/eosio.token/include/eosio.token/eosio.token.hpp index bb08ca409..3222b5708 100644 --- a/contracts/eosio.token/include/eosio.token/eosio.token.hpp +++ b/contracts/eosio.token/include/eosio.token/eosio.token.hpp @@ -153,7 +153,7 @@ namespace eosio { using transfer_action = eosio::action_wrapper<"transfer"_n, &token::transfer>; using open_action = eosio::action_wrapper<"open"_n, &token::open>; using close_action = eosio::action_wrapper<"close"_n, &token::close>; - private: + struct [[eosio::table]] account { asset balance; diff --git a/integration-tests/.clang-format b/integration-tests/.clang-format new file mode 100644 index 000000000..b55bfd792 --- /dev/null +++ b/integration-tests/.clang-format @@ -0,0 +1,76 @@ +BasedOnStyle: LLVM +IndentWidth: 3 +UseTab: Never +ColumnLimit: 120 + +--- +Language: Cpp +# always align * and & to the type +DerivePointerAlignment: false +PointerAlignment: Left + +# regroup includes to these classes +IncludeCategories: + - Regex: '(<|"(eosio)/)' + Priority: 4 + - Regex: '(<|"(boost)/)' + Priority: 3 + - Regex: '(<|"(llvm|llvm-c|clang|clang-c)/' + Priority: 3 + - Regex: '<[[:alnum:]]+>' + Priority: 2 + - Regex: '.*' + Priority: 1 + +#IncludeBlocks: Regroup + +# set indent for public, private and protected +#AccessModifierOffset: 3 + +# make line continuations twice the normal indent +ContinuationIndentWidth: 6 + +# add missing namespace comments +FixNamespaceComments: true + +# add spaces to braced list i.e. int* foo = { 0, 1, 2 }; instead of int* foo = {0,1,2}; +Cpp11BracedListStyle: false +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +AlignOperands: true +AlignTrailingComments: true +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortBlocksOnASingleLine: true +#AllowShortIfStatementsOnASingleLine: WithoutElse +#AllowShortIfStatementsOnASingleLine: true +#AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AlwaysBreakTemplateDeclarations: true + +BinPackParameters: true +### use this with clang9 +BreakBeforeBraces: Custom +BraceWrapping: + #AfterCaseLabel: true + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + +BreakConstructorInitializers: BeforeColon +CompactNamespaces: true +IndentCaseLabels: true +IndentPPDirectives: AfterHash +NamespaceIndentation: Inner +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +--- diff --git a/integration-tests/CMakeLists.txt b/integration-tests/CMakeLists.txt new file mode 100644 index 000000000..f9d5c8bbd --- /dev/null +++ b/integration-tests/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.10) + +project(integration-tests) + +set(EOSIO_WASM_OLD_BEHAVIOR "off") +find_package(eosio.cdt) + +function(add_test TARGET SRC) + add_executable(${TARGET} ${SRC}) + target_link_libraries(${TARGET} -ftester -stack-size=65536) + target_compile_options(${TARGET} PUBLIC -ftester -Os) + target_include_directories(${TARGET} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../contracts/eosio.bios/include + ${CMAKE_CURRENT_SOURCE_DIR}/../contracts/eosio.msig/include + ${CMAKE_CURRENT_SOURCE_DIR}/../contracts/eosio.system/include + ${CMAKE_CURRENT_SOURCE_DIR}/../contracts/eosio.token/include + ${CMAKE_CURRENT_SOURCE_DIR}/../contracts/eosio.wrap/include + ) + set_target_properties(${TARGET} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) +endfunction() + +add_test(eosio.token-tests eosio.token-tests.cpp) diff --git a/integration-tests/eosio.token-tests.cpp b/integration-tests/eosio.token-tests.cpp new file mode 100644 index 000000000..798a316c1 --- /dev/null +++ b/integration-tests/eosio.token-tests.cpp @@ -0,0 +1,132 @@ +#include +#include + +using namespace eosio; + +namespace eosio { + +inline bool operator!=(const token::currency_stats& a, const token::currency_stats& b) { + return a.supply != b.supply || a.max_supply != b.max_supply || a.issuer != b.issuer; +} + +} // namespace eosio + +struct token_tester { + test_chain chain; + + token_tester() { + chain.create_account("alice"_n); + chain.create_account("bob"_n); + chain.create_account("carol"_n); + chain.create_code_account("eosio.token"_n); + chain.set_code("eosio.token"_n, "contracts/eosio.token/eosio.token.wasm"); + } + + chain_types::transaction_trace create(name issuer, const asset& maximum_supply, + const char* expected_except = nullptr) { + return chain.transact({ token::create_action{ "eosio.token"_n, { "eosio.token"_n, "active"_n } }.to_action( + issuer, maximum_supply) }, + expected_except); + } + + chain_types::transaction_trace issue(name issuer, name to, const asset& quantity, const string& memo, + const char* expected_except = nullptr) { + return chain.transact( + { token::issue_action{ "eosio.token"_n, { issuer, "active"_n } }.to_action(to, quantity, memo) }, + expected_except); + } + + chain_types::transaction_trace retire(name issuer, const asset& quantity, const string& memo, + const char* expected_except = nullptr) { + return chain.transact( + { token::retire_action{ "eosio.token"_n, { issuer, "active"_n } }.to_action(quantity, memo) }, + expected_except); + } + + chain_types::transaction_trace transfer(name from, name to, const asset& quantity, const string& memo, + const char* expected_except = nullptr) { + return chain.transact( + { token::transfer_action{ "eosio.token"_n, { from, "active"_n } }.to_action(from, to, quantity, memo) }, + expected_except); + } + + chain_types::transaction_trace open(name owner, const symbol& symbol, name ram_payer, + const char* expected_except = nullptr) { + return chain.transact( + { token::open_action{ "eosio.token"_n, { ram_payer, "active"_n } }.to_action(owner, symbol, ram_payer) }, + expected_except); + } + + chain_types::transaction_trace close(name owner, const symbol& symbol, const char* expected_except = nullptr) { + return chain.transact({ token::close_action{ "eosio.token"_n, { owner, "active"_n } }.to_action(owner, symbol) }, + expected_except); + } + + auto get_stats(symbol_code sym_code) { + token::stats statstable("eosio.token"_n, sym_code.raw()); + return statstable.get(sym_code.raw()); + } +}; // token_tester + +TEST_CASE(create_tests, [] { + token_tester t; + + t.create("alice"_n, s2a("1000.000 TKN")); + TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + (token::currency_stats{ + .supply = s2a("0.000 TKN"), + .max_supply = s2a("1000.000 TKN"), + .issuer = "alice"_n, + })); +}) + +TEST_CASE(create_negative_max_supply, [] { + token_tester t; + t.create("alice"_n, s2a("-1000.000 TKN"), "max-supply must be positive"); +}) + +TEST_CASE(symbol_already_exists, [] { + token_tester t; + + t.create("alice"_n, s2a("1000 TKN")); + TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + (token::currency_stats{ + .supply = s2a("0 TKN"), + .max_supply = s2a("1000 TKN"), + .issuer = "alice"_n, + })); + t.create("alice"_n, s2a("100 TKN"), "token with symbol already exists"); +}) + +TEST_CASE(create_max_supply, [] { + token_tester t; + + t.create("alice"_n, s2a("4611686018427387903 TKN")); + TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + (token::currency_stats{ + .supply = s2a("0 TKN"), + .max_supply = s2a("4611686018427387903 TKN"), + .issuer = "alice"_n, + })); + + auto too_big = s2a("4611686018427387903 NKT"); + ++too_big.amount; + t.create("alice"_n, too_big, "invalid supply"); +}) + +TEST_CASE(precision_too_high, [] { + token_tester t; + + t.create("alice"_n, asset{ 1, symbol{ "TKN", 18 } }); + TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + (token::currency_stats{ + .supply = s2a("0.000000000000000000 TKN"), + .max_supply = s2a("0.000000000000000001 TKN"), + .issuer = "alice"_n, + })); + + // eosio.token fails to check precision. Verify this broken behavior is still broken. + t.create("alice"_n, asset{ 1, symbol{ "NKT", 50 } }); +}) + +TEST_ENTRY From 8162dd6cff92623e45c2eb6094b472eafe0fb17c Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Mon, 30 Sep 2019 11:51:11 -0400 Subject: [PATCH 2/5] token tests --- integration-tests/eosio.token-tests.cpp | 135 +++++++++++++++++++++++- 1 file changed, 134 insertions(+), 1 deletion(-) diff --git a/integration-tests/eosio.token-tests.cpp b/integration-tests/eosio.token-tests.cpp index 798a316c1..471f4a860 100644 --- a/integration-tests/eosio.token-tests.cpp +++ b/integration-tests/eosio.token-tests.cpp @@ -66,6 +66,15 @@ struct token_tester { token::stats statstable("eosio.token"_n, sym_code.raw()); return statstable.get(sym_code.raw()); } + + std::optional get_account_optional(name owner, symbol_code sym_code) { + token::accounts accountstable("eosio.token"_n, owner.value); + auto it = accountstable.find(sym_code.raw()); + if (it != accountstable.end()) + return *it; + else + return {}; + } }; // token_tester TEST_CASE(create_tests, [] { @@ -125,8 +134,132 @@ TEST_CASE(precision_too_high, [] { .issuer = "alice"_n, })); - // eosio.token fails to check precision. Verify this broken behavior is still broken. + // eosio.token fails to check precision. Verify this broken behavior is still present. t.create("alice"_n, asset{ 1, symbol{ "NKT", 50 } }); }) +TEST_CASE(issue_tests, [] { + token_tester t; + + t.create("alice"_n, s2a("1000.000 TKN")); + t.issue("alice"_n, "alice"_n, s2a("500.000 TKN"), "hola"); + TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + (token::currency_stats{ + .supply = s2a("500.000 TKN"), + .max_supply = s2a("1000.000 TKN"), + .issuer = "alice"_n, + })); + TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "TKN" }), s2a("500.000 TKN")); + t.issue("alice"_n, "alice"_n, s2a("500.001 TKN"), "hola", "quantity exceeds available supply"); + t.issue("alice"_n, "alice"_n, s2a("-1.000 TKN"), "hola", "must issue positive quantity"); + t.issue("alice"_n, "alice"_n, s2a("1.000 TKN"), "hola"); +}) + +TEST_CASE(retire_tests, [] { + token_tester t; + + t.create("alice"_n, s2a("1000.000 TKN")); + t.issue("alice"_n, "alice"_n, s2a("500.000 TKN"), "hola"); + TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + (token::currency_stats{ + .supply = s2a("500.000 TKN"), + .max_supply = s2a("1000.000 TKN"), + .issuer = "alice"_n, + })); + + TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "TKN" }), s2a("500.000 TKN")); + t.retire("alice"_n, s2a("200.000 TKN"), "hola"); + + TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + (token::currency_stats{ + .supply = s2a("300.000 TKN"), + .max_supply = s2a("1000.000 TKN"), + .issuer = "alice"_n, + })); + TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "TKN" }), s2a("300.000 TKN")); + + // should fail to retire more than current balance + t.retire("alice"_n, s2a("500.000 TKN"), "hola", "overdrawn balance"); + + t.transfer("alice"_n, "bob"_n, s2a("200.000 TKN"), "hola"); + // should fail to retire since tokens are not on the issuer's balance + t.retire("alice"_n, s2a("300.000 TKN"), "hola", "overdrawn balance"); + // transfer tokens back + t.transfer("bob"_n, "alice"_n, s2a("200.000 TKN"), "hola"); + + t.retire("alice"_n, s2a("300.000 TKN"), "hola"); + TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + (token::currency_stats{ + .supply = s2a("0.000 TKN"), + .max_supply = s2a("1000.000 TKN"), + .issuer = "alice"_n, + })); + + TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "TKN" }), s2a("0.000 TKN")); + + // trying to retire tokens with zero balance + t.retire("alice"_n, s2a("1.000 TKN"), "hola", "overdrawn balance"); +}) + +TEST_CASE(transfer_tests, [] { + token_tester t; + + t.create("alice"_n, s2a("1000 CERO")); + t.issue("alice"_n, "alice"_n, s2a("1000 CERO"), "hola"); + + TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "CERO" }), // + (token::currency_stats{ + .supply = s2a("1000 CERO"), + .max_supply = s2a("1000 CERO"), + .issuer = "alice"_n, + })); + + TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }), s2a("1000 CERO")); + t.transfer("alice"_n, "bob"_n, s2a("300 CERO"), "hola"); + TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }), s2a("700 CERO")); + TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "bob"_n, symbol_code{ "CERO" }), s2a("300 CERO")); + + t.transfer("alice"_n, "bob"_n, s2a("701 CERO"), "hola", "overdrawn balance"); + t.transfer("alice"_n, "bob"_n, s2a("-1000 CERO"), "hola", "must transfer positive quantity"); +}) + +TEST_CASE(open_tests, [] { + token_tester t; + + t.create("alice"_n, s2a("1000 CERO")); + + TESTER_REQUIRE_EQUAL(t.get_account_optional("alice"_n, symbol_code("CERO")), std::nullopt); + t.issue("alice"_n, "bob"_n, s2a("1000 CERO"), "", "tokens can only be issued to issuer account"); + t.issue("alice"_n, "alice"_n, s2a("1000 CERO"), "issue"); + + TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }), s2a("1000 CERO")); + TESTER_REQUIRE_EQUAL(t.get_account_optional("bob"_n, symbol_code("CERO")), std::nullopt); + + t.open("nonexistent"_n, symbol{ "CERO", 0 }, "alice"_n, "owner account does not exist"); + t.open("bob"_n, symbol{ "CERO", 0 }, "alice"_n); + + TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "bob"_n, symbol_code{ "CERO" }), s2a("0 CERO")); + t.transfer("alice"_n, "bob"_n, s2a("200 CERO"), "hola"); + TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "bob"_n, symbol_code{ "CERO" }), s2a("200 CERO")); + + t.open("carol"_n, symbol{ "INVALID", 0 }, "alice"_n, "symbol does not exist"); + t.open("carol"_n, symbol{ "CERO", 1 }, "alice"_n, "symbol precision mismatch"); +}) + +TEST_CASE(close_tests, [] { + token_tester t; + + t.create("alice"_n, s2a("1000 CERO")); + TESTER_REQUIRE_EQUAL(t.get_account_optional("alice"_n, symbol_code("CERO")), std::nullopt); + + t.issue("alice"_n, "alice"_n, s2a("1000 CERO"), "hola"); + TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }), s2a("1000 CERO")); + + t.transfer("alice"_n, "bob"_n, s2a("1000 CERO"), "hola"); + TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }), s2a("0 CERO")); + + t.close("alice"_n, symbol{ "CERO", 0 }); + TESTER_REQUIRE_EQUAL(t.get_account_optional("alice"_n, symbol_code("CERO")), std::nullopt); +}) + TEST_ENTRY From d8dd63a55d9a1b4d532fd75d3cd93abcac024e24 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Tue, 1 Oct 2019 13:28:34 -0400 Subject: [PATCH 3/5] msig tests --- .gitignore | 1 + integration-tests/.clang-format | 2 + integration-tests/CMakeLists.txt | 1 + integration-tests/eosio.msig-tests.cpp | 84 ++++++++++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 integration-tests/eosio.msig-tests.cpp diff --git a/.gitignore b/.gitignore index 1f63cf480..c22535cdf 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ build/* .DS_Store +.vscode diff --git a/integration-tests/.clang-format b/integration-tests/.clang-format index b55bfd792..072e21a7b 100644 --- a/integration-tests/.clang-format +++ b/integration-tests/.clang-format @@ -73,4 +73,6 @@ NamespaceIndentation: Inner ReflowComments: true SortIncludes: true SortUsingDeclarations: true + +ReflowComments: false --- diff --git a/integration-tests/CMakeLists.txt b/integration-tests/CMakeLists.txt index f9d5c8bbd..85bf4f6a9 100644 --- a/integration-tests/CMakeLists.txt +++ b/integration-tests/CMakeLists.txt @@ -22,4 +22,5 @@ function(add_test TARGET SRC) RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endfunction() +add_test(eosio.msig-tests eosio.msig-tests.cpp) add_test(eosio.token-tests eosio.token-tests.cpp) diff --git a/integration-tests/eosio.msig-tests.cpp b/integration-tests/eosio.msig-tests.cpp new file mode 100644 index 000000000..75c38b9b0 --- /dev/null +++ b/integration-tests/eosio.msig-tests.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +using namespace eosio; +using eosiobios::bios; + +namespace eosio { + +inline bool operator!=(const token::currency_stats& a, const token::currency_stats& b) { + return a.supply != b.supply || a.max_supply != b.max_supply || a.issuer != b.issuer; +} + +} // namespace eosio + +struct approve_args { + name proposer = {}; + name proposal_name = {}; + permission_level level = {}; + + EOSLIB_SERIALIZE(approve_args, (proposer)(proposal_name)(level)) +}; + +struct msig_tester { + test_chain chain; + + msig_tester() { + chain.set_code("eosio"_n, "contracts/eosio.bios/eosio.bios.wasm"); + chain.create_code_account("eosio.msig"_n, true); + chain.create_account("eosio.stake"_n); + chain.create_account("eosio.ram"_n); + chain.create_account("eosio.ramfee"_n); + chain.create_account("alice"_n); + chain.create_account("bob"_n); + chain.create_account("carol"_n); + chain.set_code("eosio.msig"_n, "contracts/eosio.msig/eosio.msig.wasm"); + } + + chain_types::transaction_trace propose(name proposer, name proposal_name, std::vector requested, + transaction trx, const char* expected_except = nullptr) { + return chain.transact({ multisig::propose_action{ "eosio.msig"_n, { proposer, "active"_n } }.to_action( + proposer, proposal_name, std::move(requested), std::move(trx)) }, + expected_except); + } + + chain_types::transaction_trace approve(name proposer, name proposal_name, permission_level level, + const char* expected_except = nullptr) { + return chain.transact({ { level, "eosio.msig"_n, "approve"_n, approve_args{ proposer, proposal_name, level } } }, + expected_except); + } + + chain_types::transaction_trace exec(name proposer, name proposal_name, name executer, + const char* expected_except = nullptr) { + return chain.transact({ multisig::exec_action{ "eosio.msig"_n, { executer, "active"_n } }.to_action( + proposer, proposal_name, executer) }, + expected_except); + } + +}; // msig_tester + +TEST_CASE(propose_approve_execute, [] { + msig_tester t; + + t.propose("alice"_n, "first"_n, { { "alice"_n, "active"_n } }, + t.chain.make_transaction( + { bios::reqauth_action{ "eosio"_n, { "alice"_n, "active"_n } }.to_action("alice"_n) })); + + // fail to execute before approval + t.exec("alice"_n, "first"_n, "alice"_n, "transaction authorization failed"); + + // approve and execute + t.approve("alice"_n, "first"_n, { "alice"_n, "active"_n }); + TESTER_REQUIRE(!t.chain.exec_deferred()); + t.exec("alice"_n, "first"_n, "alice"_n); + + auto receipt = t.chain.exec_deferred(); + TESTER_REQUIRE(!t.chain.exec_deferred()); + TESTER_REQUIRE(receipt); + expect(*receipt); + TESTER_REQUIRE_EQUAL(std::get<0>(*receipt).action_traces.size(), 1); +}) // propose_approve_execute + +TEST_ENTRY From 7122a6154d48e6d19ad284f032aa34aaae503b78 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Wed, 15 Jan 2020 14:54:27 -0500 Subject: [PATCH 4/5] Update tester to Boost.Test/Catch2. --- integration-tests/eosio.msig-tests.cpp | 33 ++++----- integration-tests/eosio.token-tests.cpp | 98 +++++++++++++------------ 2 files changed, 67 insertions(+), 64 deletions(-) diff --git a/integration-tests/eosio.msig-tests.cpp b/integration-tests/eosio.msig-tests.cpp index 75c38b9b0..c6d01477a 100644 --- a/integration-tests/eosio.msig-tests.cpp +++ b/integration-tests/eosio.msig-tests.cpp @@ -3,6 +3,9 @@ #include #include +#define BOOST_TEST_MAIN +#include + using namespace eosio; using eosiobios::bios; @@ -59,26 +62,22 @@ struct msig_tester { }; // msig_tester -TEST_CASE(propose_approve_execute, [] { - msig_tester t; - - t.propose("alice"_n, "first"_n, { { "alice"_n, "active"_n } }, - t.chain.make_transaction( - { bios::reqauth_action{ "eosio"_n, { "alice"_n, "active"_n } }.to_action("alice"_n) })); +BOOST_FIXTURE_TEST_CASE(propose_approve_execute, msig_tester) { + propose("alice"_n, "first"_n, { { "alice"_n, "active"_n } }, + chain.make_transaction( + { bios::reqauth_action{ "eosio"_n, { "alice"_n, "active"_n } }.to_action("alice"_n) })); // fail to execute before approval - t.exec("alice"_n, "first"_n, "alice"_n, "transaction authorization failed"); + exec("alice"_n, "first"_n, "alice"_n, "transaction authorization failed"); // approve and execute - t.approve("alice"_n, "first"_n, { "alice"_n, "active"_n }); - TESTER_REQUIRE(!t.chain.exec_deferred()); - t.exec("alice"_n, "first"_n, "alice"_n); + approve("alice"_n, "first"_n, { "alice"_n, "active"_n }); + BOOST_TEST(!chain.exec_deferred()); + exec("alice"_n, "first"_n, "alice"_n); - auto receipt = t.chain.exec_deferred(); - TESTER_REQUIRE(!t.chain.exec_deferred()); - TESTER_REQUIRE(receipt); + auto receipt = chain.exec_deferred(); + BOOST_TEST(!chain.exec_deferred()); + BOOST_TEST(receipt.has_value()); expect(*receipt); - TESTER_REQUIRE_EQUAL(std::get<0>(*receipt).action_traces.size(), 1); -}) // propose_approve_execute - -TEST_ENTRY + BOOST_TEST(std::get<0>(*receipt).action_traces.size() == 1); +} // propose_approve_execute diff --git a/integration-tests/eosio.token-tests.cpp b/integration-tests/eosio.token-tests.cpp index 471f4a860..c4669eda3 100644 --- a/integration-tests/eosio.token-tests.cpp +++ b/integration-tests/eosio.token-tests.cpp @@ -1,6 +1,9 @@ #include #include +#define CATCH_CONFIG_MAIN +#include + using namespace eosio; namespace eosio { @@ -8,6 +11,9 @@ namespace eosio { inline bool operator!=(const token::currency_stats& a, const token::currency_stats& b) { return a.supply != b.supply || a.max_supply != b.max_supply || a.issuer != b.issuer; } +inline bool operator==(const token::currency_stats& a, const token::currency_stats& b) { + return !(a != b); +} } // namespace eosio @@ -77,41 +83,41 @@ struct token_tester { } }; // token_tester -TEST_CASE(create_tests, [] { +TEST_CASE("Create a token", "[create]") { token_tester t; t.create("alice"_n, s2a("1000.000 TKN")); - TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + REQUIRE(t.get_stats(symbol_code{ "TKN" }) == (token::currency_stats{ .supply = s2a("0.000 TKN"), .max_supply = s2a("1000.000 TKN"), .issuer = "alice"_n, })); -}) +} -TEST_CASE(create_negative_max_supply, [] { +TEST_CASE("Create a token with negative max supply", "[create_negative_max_supply]") { token_tester t; t.create("alice"_n, s2a("-1000.000 TKN"), "max-supply must be positive"); -}) +} -TEST_CASE(symbol_already_exists, [] { +TEST_CASE("Create token with a symbol that already exists", "[symbol_already_exists]") { token_tester t; t.create("alice"_n, s2a("1000 TKN")); - TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + REQUIRE(t.get_stats(symbol_code{ "TKN" }) == (token::currency_stats{ .supply = s2a("0 TKN"), .max_supply = s2a("1000 TKN"), .issuer = "alice"_n, })); t.create("alice"_n, s2a("100 TKN"), "token with symbol already exists"); -}) +} -TEST_CASE(create_max_supply, [] { +TEST_CASE("Create a token whose max supply is to large", "[create_max_supply]") { token_tester t; t.create("alice"_n, s2a("4611686018427387903 TKN")); - TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + REQUIRE(t.get_stats(symbol_code{ "TKN" }) == (token::currency_stats{ .supply = s2a("0 TKN"), .max_supply = s2a("4611686018427387903 TKN"), @@ -121,13 +127,13 @@ TEST_CASE(create_max_supply, [] { auto too_big = s2a("4611686018427387903 NKT"); ++too_big.amount; t.create("alice"_n, too_big, "invalid supply"); -}) +} -TEST_CASE(precision_too_high, [] { +TEST_CASE("Create a token whose precision is too high", "[precision_too_high]") { token_tester t; t.create("alice"_n, asset{ 1, symbol{ "TKN", 18 } }); - TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + REQUIRE(t.get_stats(symbol_code{ "TKN" }) == // (token::currency_stats{ .supply = s2a("0.000000000000000000 TKN"), .max_supply = s2a("0.000000000000000001 TKN"), @@ -136,47 +142,47 @@ TEST_CASE(precision_too_high, [] { // eosio.token fails to check precision. Verify this broken behavior is still present. t.create("alice"_n, asset{ 1, symbol{ "NKT", 50 } }); -}) +} -TEST_CASE(issue_tests, [] { +TEST_CASE("Test issuing a token", "[issue_tests]") { token_tester t; t.create("alice"_n, s2a("1000.000 TKN")); t.issue("alice"_n, "alice"_n, s2a("500.000 TKN"), "hola"); - TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + REQUIRE(t.get_stats(symbol_code{ "TKN" }) == // (token::currency_stats{ .supply = s2a("500.000 TKN"), .max_supply = s2a("1000.000 TKN"), .issuer = "alice"_n, })); - TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "TKN" }), s2a("500.000 TKN")); + REQUIRE(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "TKN" }) == s2a("500.000 TKN")); t.issue("alice"_n, "alice"_n, s2a("500.001 TKN"), "hola", "quantity exceeds available supply"); t.issue("alice"_n, "alice"_n, s2a("-1.000 TKN"), "hola", "must issue positive quantity"); t.issue("alice"_n, "alice"_n, s2a("1.000 TKN"), "hola"); -}) +} -TEST_CASE(retire_tests, [] { +TEST_CASE("Retire tokens", "[retire_tests]") { token_tester t; t.create("alice"_n, s2a("1000.000 TKN")); t.issue("alice"_n, "alice"_n, s2a("500.000 TKN"), "hola"); - TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + REQUIRE(t.get_stats(symbol_code{ "TKN" }) == // (token::currency_stats{ .supply = s2a("500.000 TKN"), .max_supply = s2a("1000.000 TKN"), .issuer = "alice"_n, })); - TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "TKN" }), s2a("500.000 TKN")); + REQUIRE(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "TKN" }) == s2a("500.000 TKN")); t.retire("alice"_n, s2a("200.000 TKN"), "hola"); - TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + REQUIRE(t.get_stats(symbol_code{ "TKN" }) == // (token::currency_stats{ .supply = s2a("300.000 TKN"), .max_supply = s2a("1000.000 TKN"), .issuer = "alice"_n, })); - TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "TKN" }), s2a("300.000 TKN")); + REQUIRE(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "TKN" }) == s2a("300.000 TKN")); // should fail to retire more than current balance t.retire("alice"_n, s2a("500.000 TKN"), "hola", "overdrawn balance"); @@ -188,78 +194,76 @@ TEST_CASE(retire_tests, [] { t.transfer("bob"_n, "alice"_n, s2a("200.000 TKN"), "hola"); t.retire("alice"_n, s2a("300.000 TKN"), "hola"); - TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "TKN" }), // + REQUIRE(t.get_stats(symbol_code{ "TKN" }) == // (token::currency_stats{ .supply = s2a("0.000 TKN"), .max_supply = s2a("1000.000 TKN"), .issuer = "alice"_n, })); - TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "TKN" }), s2a("0.000 TKN")); + REQUIRE(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "TKN" }) == s2a("0.000 TKN")); // trying to retire tokens with zero balance t.retire("alice"_n, s2a("1.000 TKN"), "hola", "overdrawn balance"); -}) +} -TEST_CASE(transfer_tests, [] { +TEST_CASE("Transfer tokens", "[transfer_tests]") { token_tester t; t.create("alice"_n, s2a("1000 CERO")); t.issue("alice"_n, "alice"_n, s2a("1000 CERO"), "hola"); - TESTER_REQUIRE_EQUAL(t.get_stats(symbol_code{ "CERO" }), // + REQUIRE(t.get_stats(symbol_code{ "CERO" }) == // (token::currency_stats{ .supply = s2a("1000 CERO"), .max_supply = s2a("1000 CERO"), .issuer = "alice"_n, })); - TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }), s2a("1000 CERO")); + REQUIRE(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }) == s2a("1000 CERO")); t.transfer("alice"_n, "bob"_n, s2a("300 CERO"), "hola"); - TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }), s2a("700 CERO")); - TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "bob"_n, symbol_code{ "CERO" }), s2a("300 CERO")); + REQUIRE(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }) == s2a("700 CERO")); + REQUIRE(token::get_balance("eosio.token"_n, "bob"_n, symbol_code{ "CERO" }) == s2a("300 CERO")); t.transfer("alice"_n, "bob"_n, s2a("701 CERO"), "hola", "overdrawn balance"); t.transfer("alice"_n, "bob"_n, s2a("-1000 CERO"), "hola", "must transfer positive quantity"); -}) +} -TEST_CASE(open_tests, [] { +TEST_CASE("Open token balance", "[open_tests]") { token_tester t; t.create("alice"_n, s2a("1000 CERO")); - TESTER_REQUIRE_EQUAL(t.get_account_optional("alice"_n, symbol_code("CERO")), std::nullopt); + REQUIRE(t.get_account_optional("alice"_n, symbol_code("CERO")) == std::nullopt); t.issue("alice"_n, "bob"_n, s2a("1000 CERO"), "", "tokens can only be issued to issuer account"); t.issue("alice"_n, "alice"_n, s2a("1000 CERO"), "issue"); - TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }), s2a("1000 CERO")); - TESTER_REQUIRE_EQUAL(t.get_account_optional("bob"_n, symbol_code("CERO")), std::nullopt); + REQUIRE(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }) == s2a("1000 CERO")); + REQUIRE(t.get_account_optional("bob"_n, symbol_code("CERO")) == std::nullopt); t.open("nonexistent"_n, symbol{ "CERO", 0 }, "alice"_n, "owner account does not exist"); t.open("bob"_n, symbol{ "CERO", 0 }, "alice"_n); - TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "bob"_n, symbol_code{ "CERO" }), s2a("0 CERO")); + REQUIRE(token::get_balance("eosio.token"_n, "bob"_n, symbol_code{ "CERO" }) == s2a("0 CERO")); t.transfer("alice"_n, "bob"_n, s2a("200 CERO"), "hola"); - TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "bob"_n, symbol_code{ "CERO" }), s2a("200 CERO")); + REQUIRE(token::get_balance("eosio.token"_n, "bob"_n, symbol_code{ "CERO" }) == s2a("200 CERO")); t.open("carol"_n, symbol{ "INVALID", 0 }, "alice"_n, "symbol does not exist"); t.open("carol"_n, symbol{ "CERO", 1 }, "alice"_n, "symbol precision mismatch"); -}) +} -TEST_CASE(close_tests, [] { +TEST_CASE("Close token balance", "[close_tests]") { token_tester t; t.create("alice"_n, s2a("1000 CERO")); - TESTER_REQUIRE_EQUAL(t.get_account_optional("alice"_n, symbol_code("CERO")), std::nullopt); + REQUIRE(t.get_account_optional("alice"_n, symbol_code("CERO")) == std::nullopt); t.issue("alice"_n, "alice"_n, s2a("1000 CERO"), "hola"); - TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }), s2a("1000 CERO")); + REQUIRE(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }) == s2a("1000 CERO")); t.transfer("alice"_n, "bob"_n, s2a("1000 CERO"), "hola"); - TESTER_REQUIRE_EQUAL(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }), s2a("0 CERO")); + REQUIRE(token::get_balance("eosio.token"_n, "alice"_n, symbol_code{ "CERO" }) == s2a("0 CERO")); t.close("alice"_n, symbol{ "CERO", 0 }); - TESTER_REQUIRE_EQUAL(t.get_account_optional("alice"_n, symbol_code("CERO")), std::nullopt); -}) - -TEST_ENTRY + REQUIRE(t.get_account_optional("alice"_n, symbol_code("CERO")) == std::nullopt); +} From 8eba89f315d25955d30780275a67e3ccf3d28a13 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 21 Feb 2020 15:21:32 -0500 Subject: [PATCH 5/5] Remove chain_types:: --- integration-tests/eosio.msig-tests.cpp | 14 +++++++------- integration-tests/eosio.token-tests.cpp | 22 +++++++++++----------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/integration-tests/eosio.msig-tests.cpp b/integration-tests/eosio.msig-tests.cpp index c6d01477a..48ff4fd03 100644 --- a/integration-tests/eosio.msig-tests.cpp +++ b/integration-tests/eosio.msig-tests.cpp @@ -40,21 +40,21 @@ struct msig_tester { chain.set_code("eosio.msig"_n, "contracts/eosio.msig/eosio.msig.wasm"); } - chain_types::transaction_trace propose(name proposer, name proposal_name, std::vector requested, - transaction trx, const char* expected_except = nullptr) { + transaction_trace propose(name proposer, name proposal_name, std::vector requested, + transaction trx, const char* expected_except = nullptr) { return chain.transact({ multisig::propose_action{ "eosio.msig"_n, { proposer, "active"_n } }.to_action( proposer, proposal_name, std::move(requested), std::move(trx)) }, expected_except); } - chain_types::transaction_trace approve(name proposer, name proposal_name, permission_level level, - const char* expected_except = nullptr) { + transaction_trace approve(name proposer, name proposal_name, permission_level level, + const char* expected_except = nullptr) { return chain.transact({ { level, "eosio.msig"_n, "approve"_n, approve_args{ proposer, proposal_name, level } } }, expected_except); } - chain_types::transaction_trace exec(name proposer, name proposal_name, name executer, - const char* expected_except = nullptr) { + transaction_trace exec(name proposer, name proposal_name, name executer, + const char* expected_except = nullptr) { return chain.transact({ multisig::exec_action{ "eosio.msig"_n, { executer, "active"_n } }.to_action( proposer, proposal_name, executer) }, expected_except); @@ -79,5 +79,5 @@ BOOST_FIXTURE_TEST_CASE(propose_approve_execute, msig_tester) { BOOST_TEST(!chain.exec_deferred()); BOOST_TEST(receipt.has_value()); expect(*receipt); - BOOST_TEST(std::get<0>(*receipt).action_traces.size() == 1); + BOOST_TEST(receipt->action_traces.size() == 1); } // propose_approve_execute diff --git a/integration-tests/eosio.token-tests.cpp b/integration-tests/eosio.token-tests.cpp index c4669eda3..f0ea84ca5 100644 --- a/integration-tests/eosio.token-tests.cpp +++ b/integration-tests/eosio.token-tests.cpp @@ -28,42 +28,42 @@ struct token_tester { chain.set_code("eosio.token"_n, "contracts/eosio.token/eosio.token.wasm"); } - chain_types::transaction_trace create(name issuer, const asset& maximum_supply, - const char* expected_except = nullptr) { + transaction_trace create(name issuer, const asset& maximum_supply, + const char* expected_except = nullptr) { return chain.transact({ token::create_action{ "eosio.token"_n, { "eosio.token"_n, "active"_n } }.to_action( issuer, maximum_supply) }, expected_except); } - chain_types::transaction_trace issue(name issuer, name to, const asset& quantity, const string& memo, - const char* expected_except = nullptr) { + transaction_trace issue(name issuer, name to, const asset& quantity, const string& memo, + const char* expected_except = nullptr) { return chain.transact( { token::issue_action{ "eosio.token"_n, { issuer, "active"_n } }.to_action(to, quantity, memo) }, expected_except); } - chain_types::transaction_trace retire(name issuer, const asset& quantity, const string& memo, - const char* expected_except = nullptr) { + transaction_trace retire(name issuer, const asset& quantity, const string& memo, + const char* expected_except = nullptr) { return chain.transact( { token::retire_action{ "eosio.token"_n, { issuer, "active"_n } }.to_action(quantity, memo) }, expected_except); } - chain_types::transaction_trace transfer(name from, name to, const asset& quantity, const string& memo, - const char* expected_except = nullptr) { + transaction_trace transfer(name from, name to, const asset& quantity, const string& memo, + const char* expected_except = nullptr) { return chain.transact( { token::transfer_action{ "eosio.token"_n, { from, "active"_n } }.to_action(from, to, quantity, memo) }, expected_except); } - chain_types::transaction_trace open(name owner, const symbol& symbol, name ram_payer, - const char* expected_except = nullptr) { + transaction_trace open(name owner, const symbol& symbol, name ram_payer, + const char* expected_except = nullptr) { return chain.transact( { token::open_action{ "eosio.token"_n, { ram_payer, "active"_n } }.to_action(owner, symbol, ram_payer) }, expected_except); } - chain_types::transaction_trace close(name owner, const symbol& symbol, const char* expected_except = nullptr) { + transaction_trace close(name owner, const symbol& symbol, const char* expected_except = nullptr) { return chain.transact({ token::close_action{ "eosio.token"_n, { owner, "active"_n } }.to_action(owner, symbol) }, expected_except); }