Changeset View
Changeset View
Standalone View
Standalone View
src/test/op_reversebytes_tests.cpp
Show First 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | static void CheckPassReverse(const uint32_t flags, | ||||
CheckPassIfEnabled(flags, {reverse_case.item}, CScript() << OP_REVERSEBYTES, | CheckPassIfEnabled(flags, {reverse_case.item}, CScript() << OP_REVERSEBYTES, | ||||
{reverse_case.reversed_item}); | {reverse_case.reversed_item}); | ||||
CheckPassIfEnabled(flags, {reverse_case.item}, | CheckPassIfEnabled(flags, {reverse_case.item}, | ||||
CScript() << OP_DUP << OP_REVERSEBYTES << OP_REVERSEBYTES | CScript() << OP_DUP << OP_REVERSEBYTES << OP_REVERSEBYTES | ||||
<< OP_EQUALVERIFY, | << OP_EQUALVERIFY, | ||||
{}); | {}); | ||||
} | } | ||||
static void RunTestsForFlags(const uint32_t flags, | |||||
const std::vector<ReverseTestCase> &test_cases, | |||||
const std::vector<valtype> &palindromes) { | |||||
// Empty stack. | |||||
CheckErrorIfEnabled(flags, {}, CScript() << OP_REVERSEBYTES, | |||||
ScriptError::INVALID_STACK_OPERATION); | |||||
for (const ReverseTestCase &test_case : test_cases) { | |||||
CheckPassReverse(flags, test_case); | |||||
} | |||||
for (const valtype &palindrome : palindromes) { | |||||
// Verify palindrome. | |||||
CheckPassIfEnabled( | |||||
flags, {palindrome}, | |||||
CScript() << OP_DUP << OP_REVERSEBYTES << OP_EQUALVERIFY, {}); | |||||
} | |||||
// Verify non-palindrome fails. | |||||
CheckErrorIfEnabled(flags, {{0x01, 0x02, 0x03, 0x02, 0x02}}, | |||||
CScript() | |||||
<< OP_DUP << OP_REVERSEBYTES << OP_EQUALVERIFY, | |||||
ScriptError::EQUALVERIFY); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(op_reversebytes_tests) { | BOOST_AUTO_TEST_CASE(op_reversebytes_tests) { | ||||
MMIXLinearCongruentialGenerator lcg; | MMIXLinearCongruentialGenerator lcg; | ||||
// Manual tests. | // Manual tests. | ||||
std::vector<ReverseTestCase> test_cases({ | std::vector<ReverseTestCase> exhaustive_test_cases({ | ||||
{{}, {}}, | {{}, {}}, | ||||
{{99}, {99}}, | {{99}, {99}}, | ||||
{{0xde, 0xad}, {0xad, 0xde}}, | {{0xde, 0xad}, {0xad, 0xde}}, | ||||
{{0xde, 0xad, 0xa1}, {0xa1, 0xad, 0xde}}, | {{0xde, 0xad, 0xa1}, {0xa1, 0xad, 0xde}}, | ||||
{{0xde, 0xad, 0xbe, 0xef}, {0xef, 0xbe, 0xad, 0xde}}, | {{0xde, 0xad, 0xbe, 0xef}, {0xef, 0xbe, 0xad, 0xde}}, | ||||
{{0x12, 0x34, 0x56}, {0x56, 0x34, 0x12}}, | {{0x12, 0x34, 0x56}, {0x56, 0x34, 0x12}}, | ||||
}); | }); | ||||
std::vector<ReverseTestCase> curated_test_cases(exhaustive_test_cases); | |||||
// Test cases for a few interesting script flag combinations. | |||||
std::vector<uint32_t> curated_flags({0}); | |||||
for (uint32_t flagindex = 0; flagindex < 32; ++flagindex) { | |||||
curated_flags.push_back(1 << flagindex); | |||||
} | |||||
// Test cases for a few interesting stack item sizes. | |||||
std::set<uint32_t> curated_datasizes( | |||||
{0, 1, 2, 10, 16, 32, 50, 128, 300, 400, 512, 519, 520}); | |||||
// Palindrome tests, they are their own reverse. | // Palindrome tests, they are their own reverse. | ||||
std::vector<valtype> palindromes; | std::vector<valtype> exhaustive_palindromes; | ||||
palindromes.reserve(MAX_SCRIPT_ELEMENT_SIZE); | std::vector<valtype> curated_palindromes; | ||||
// Generated tests: | // Generated tests: | ||||
// - for iota(n) mod 256, n = 0,..,520. | // - for iota(n) mod 256, n = 0,..,520. | ||||
// - for random bitstrings, n = 0,..,520. | // - for random bitstrings, n = 0,..,520. | ||||
// - for palindromes 0,..,n,..,0. | // - for palindromes 0,..,n,..,0. | ||||
for (size_t datasize = 0; datasize <= MAX_SCRIPT_ELEMENT_SIZE; ++datasize) { | for (size_t datasize = 0; datasize <= MAX_SCRIPT_ELEMENT_SIZE; ++datasize) { | ||||
valtype iota_data, random_data, palindrome; | valtype iota_data, random_data, palindrome; | ||||
iota_data.reserve(datasize); | iota_data.reserve(datasize); | ||||
random_data.reserve(datasize); | random_data.reserve(datasize); | ||||
palindrome.reserve(datasize); | palindrome.reserve(datasize); | ||||
for (size_t item = 0; item < datasize; ++item) { | for (size_t item = 0; item < datasize; ++item) { | ||||
iota_data.emplace_back(item % 256); | iota_data.emplace_back(item % 256); | ||||
random_data.emplace_back(lcg.next() % 256); | random_data.emplace_back(lcg.next() % 256); | ||||
palindrome.emplace_back( | palindrome.emplace_back( | ||||
(item < (datasize + 1) / 2 ? item : datasize - item - 1) % 256); | (item < (datasize + 1) / 2 ? item : datasize - item - 1) % 256); | ||||
} | } | ||||
test_cases.push_back( | std::vector<ReverseTestCase> new_cases({ | ||||
{iota_data, {iota_data.rbegin(), iota_data.rend()}}); | {iota_data, {iota_data.rbegin(), iota_data.rend()}}, | ||||
test_cases.push_back( | {random_data, {random_data.rbegin(), random_data.rend()}}, | ||||
{random_data, {random_data.rbegin(), random_data.rend()}}); | }); | ||||
palindromes.push_back(palindrome); | std::copy(new_cases.begin(), new_cases.end(), | ||||
std::back_inserter(exhaustive_test_cases)); | |||||
exhaustive_palindromes.push_back(palindrome); | |||||
// Check if datasize is curated. | |||||
if (curated_datasizes.find(datasize) != curated_datasizes.end()) { | |||||
std::copy(new_cases.begin(), new_cases.end(), | |||||
std::back_inserter(curated_test_cases)); | |||||
curated_palindromes.push_back(palindrome); | |||||
} | |||||
} | } | ||||
// Run flags exhaustively (somewhat), with curated set of test cases. | |||||
for (int i = 0; i < 4096; i++) { | for (int i = 0; i < 4096; i++) { | ||||
// Generate random flags. | // Generate random flags. | ||||
uint32_t flags = lcg.next(); | uint32_t flags = lcg.next(); | ||||
RunTestsForFlags(flags, curated_test_cases, curated_palindromes); | |||||
// Empty stack. | |||||
CheckErrorIfEnabled(flags, {}, CScript() << OP_REVERSEBYTES, | |||||
ScriptError::INVALID_STACK_OPERATION); | |||||
for (const ReverseTestCase &test_case : test_cases) { | |||||
CheckPassReverse(flags, test_case); | |||||
} | |||||
for (const valtype &palindrome : palindromes) { | |||||
// Verify palindrome. | |||||
CheckPassIfEnabled( | |||||
flags, {palindrome}, | |||||
CScript() << OP_DUP << OP_REVERSEBYTES << OP_EQUALVERIFY, {}); | |||||
} | } | ||||
// Verify non-palindrome fails. | // Run curated set of flags with exhaustive test cases. | ||||
CheckErrorIfEnabled(flags, {{0x01, 0x02, 0x03, 0x02, 0x02}}, | for (uint32_t flags : curated_flags) { | ||||
CScript() | RunTestsForFlags(flags, curated_test_cases, curated_palindromes); | ||||
<< OP_DUP << OP_REVERSEBYTES << OP_EQUALVERIFY, | |||||
ScriptError::EQUALVERIFY); | |||||
} | } | ||||
} | } | ||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |