diff --git a/libsolutil/FixedHash.h b/libsolutil/FixedHash.h index f2c2cbcc5..dffeb7a17 100644 --- a/libsolutil/FixedHash.h +++ b/libsolutil/FixedHash.h @@ -48,6 +48,7 @@ public: /// The size of the container. enum { size = N }; + static_assert(N != 0); /// Method to convert from a string. enum ConstructFromStringType { FromHex, FromBinary }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index caa587415..f7adf16a9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -29,6 +29,7 @@ detect_stray_source_files("${contracts_sources}" "contracts/") set(libsolutil_sources libsolutil/Checksum.cpp libsolutil/CommonData.cpp + libsolutil/FixedHash.cpp libsolutil/IndentedWriter.cpp libsolutil/IpfsHash.cpp libsolutil/IterateReplacing.cpp diff --git a/test/libsolutil/FixedHash.cpp b/test/libsolutil/FixedHash.cpp new file mode 100644 index 000000000..4efe0a9e1 --- /dev/null +++ b/test/libsolutil/FixedHash.cpp @@ -0,0 +1,272 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** + * Unit tests for FixedHash. + */ + +#include + +#include + +#include +#include + +using namespace std; + +namespace solidity::util::test +{ + +static_assert(std::is_same>()); +static_assert(std::is_same>()); + +BOOST_AUTO_TEST_SUITE(FixedHashTest) + +BOOST_AUTO_TEST_CASE(default_constructor) +{ + BOOST_CHECK_EQUAL( + FixedHash<1>{}.hex(), + "00" + ); + BOOST_CHECK_EQUAL( + FixedHash<1>{}.size, + 1 + ); + BOOST_CHECK_EQUAL( + FixedHash<8>{}.hex(), + "0000000000000000" + ); + BOOST_CHECK_EQUAL( + FixedHash<8>{}.size, + 8 + ); + BOOST_CHECK_EQUAL( + FixedHash<20>{}.hex(), + "0000000000000000000000000000000000000000" + ); + BOOST_CHECK_EQUAL( + FixedHash<20>{}.size, + 20 + ); + BOOST_CHECK_EQUAL( + FixedHash<32>{}.hex(), + "0000000000000000000000000000000000000000000000000000000000000000" + ); + BOOST_CHECK_EQUAL( + FixedHash<32>{}.size, + 32 + ); +} + +BOOST_AUTO_TEST_CASE(bytes_constructor) +{ + FixedHash<8> a(bytes{}); + BOOST_CHECK_EQUAL(a.size, 8); + BOOST_CHECK_EQUAL(a.hex(), "0000000000000000"); + + FixedHash<8> b(bytes{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}); + BOOST_CHECK_EQUAL(b.size, 8); + BOOST_CHECK_EQUAL(b.hex(), "1122334455667788"); + + // TODO: short input, this should fail + FixedHash<8> c(bytes{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); + BOOST_CHECK_EQUAL(c.size, 8); + BOOST_CHECK_EQUAL(c.hex(), "0000000000000000"); + + // TODO: oversized input, this should fail + FixedHash<8> d(bytes{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}); + BOOST_CHECK_EQUAL(d.size, 8); + BOOST_CHECK_EQUAL(d.hex(), "0000000000000000"); +} + +// TODO: add FixedHash(bytesConstRef) constructor + +BOOST_AUTO_TEST_CASE(string_constructor_fromhex) +{ + // TODO: this tests the default settings ConstructFromStringType::fromHex, ConstructFromHashType::FailIfDifferent + // should test other options too + + FixedHash<8> a(""); + BOOST_CHECK_EQUAL(a.size, 8); + BOOST_CHECK_EQUAL(a.hex(), "0000000000000000"); + + FixedHash<8> b("1122334455667788"); + BOOST_CHECK_EQUAL(b.size, 8); + BOOST_CHECK_EQUAL(b.hex(), "1122334455667788"); + + FixedHash<8> c("0x1122334455667788"); + BOOST_CHECK_EQUAL(c.size, 8); + BOOST_CHECK_EQUAL(c.hex(), "1122334455667788"); + + // TODO: short input, this should fail + FixedHash<8> d("112233445566"); + BOOST_CHECK_EQUAL(d.size, 8); + BOOST_CHECK_EQUAL(d.hex(), "0000000000000000"); + + // TODO: oversized input, this should fail + FixedHash<8> e("112233445566778899"); + BOOST_CHECK_EQUAL(e.size, 8); + BOOST_CHECK_EQUAL(e.hex(), "0000000000000000"); +} + +BOOST_AUTO_TEST_CASE(string_constructor_frombytes) +{ + + FixedHash<8> b("", FixedHash<8>::FromBinary); + BOOST_CHECK_EQUAL(b.size, 8); + BOOST_CHECK_EQUAL(b.hex(), "0000000000000000"); + + FixedHash<8> c("abcdefgh", FixedHash<8>::FromBinary); + BOOST_CHECK_EQUAL(c.size, 8); + BOOST_CHECK_EQUAL(c.hex(), "6162636465666768"); + + // TODO: short input, this should fail + FixedHash<8> d("abcdefg", FixedHash<8>::FromBinary); + BOOST_CHECK_EQUAL(d.size, 8); + BOOST_CHECK_EQUAL(d.hex(), "0000000000000000"); + + // TODO: oversized input, this should fail + FixedHash<8> e("abcdefghi", FixedHash<8>::FromBinary); + BOOST_CHECK_EQUAL(e.size, 8); + BOOST_CHECK_EQUAL(e.hex(), "0000000000000000"); +} + +BOOST_AUTO_TEST_CASE(converting_constructor) +{ + // Truncation + FixedHash<8> a = FixedHash<8>(FixedHash<12>("112233445566778899001122")); + BOOST_CHECK_EQUAL(a.size, 8); + BOOST_CHECK_EQUAL(a.hex(), "1122334455667788"); + + // Left-aligned extension + FixedHash<12> b = FixedHash<12>(FixedHash<8>("1122334455667788"), FixedHash<12>::AlignLeft); + BOOST_CHECK_EQUAL(b.size, 12); + BOOST_CHECK_EQUAL(b.hex(), "112233445566778800000000"); + + // Right-aligned extension + FixedHash<12> c = FixedHash<12>(FixedHash<8>("1122334455667788"), FixedHash<12>::AlignRight); + BOOST_CHECK_EQUAL(c.size, 12); + BOOST_CHECK_EQUAL(c.hex(), "000000001122334455667788"); + + // Default setting + FixedHash<12> d = FixedHash<12>(FixedHash<8>("1122334455667788")); + BOOST_CHECK_EQUAL(d, b); + + // FailIfDifferent setting + // TODO: Shouldn't this throw? + FixedHash<12> e = FixedHash<12>(FixedHash<8>("1122334455667788"), FixedHash<12>::FailIfDifferent); + BOOST_CHECK_EQUAL(e, b); +} + +BOOST_AUTO_TEST_CASE(arith_constructor) +{ + FixedHash<20> a(u160(0x1234)); + BOOST_CHECK_EQUAL( + a.hex(), + "0000000000000000000000000000000000001234" + ); + + FixedHash<32> b(u256(0x12340000)); + BOOST_CHECK_EQUAL( + b.hex(), + "0000000000000000000000000000000000000000000000000000000012340000" + ); + + // NOTE: size-mismatched constructor is not available +} + +BOOST_AUTO_TEST_CASE(to_arith) +{ + FixedHash<20> a{}; + BOOST_CHECK_EQUAL(u160(a), 0); + + FixedHash<32> b("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); + BOOST_CHECK_EQUAL(u256(b), u256("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")); +} + +BOOST_AUTO_TEST_CASE(comparison) +{ + FixedHash<32> a("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); + FixedHash<32> b("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); + FixedHash<32> c("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a471"); + FixedHash<32> d("233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470c5d2460186f7"); + + BOOST_CHECK(a == a); + BOOST_CHECK(b == b); + BOOST_CHECK(a == b); + BOOST_CHECK(b == a); + BOOST_CHECK(a != c); + BOOST_CHECK(c != a); + BOOST_CHECK(a != d); + BOOST_CHECK(d != a); + + // Only equal size comparison is supported. + BOOST_CHECK(FixedHash<8>{} == FixedHash<8>{}); + BOOST_CHECK(FixedHash<32>{} != b); + + // Only equal size less than comparison is supported. + BOOST_CHECK(!(a < b)); + BOOST_CHECK(d < c); + BOOST_CHECK(FixedHash<32>{} < a); +} + +BOOST_AUTO_TEST_CASE(indexing) +{ + // NOTE: uses std::array, so "Accessing a nonexistent element through this operator is undefined behavior." + + FixedHash<32> a("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); + BOOST_CHECK_EQUAL(a[0], 0xc5); + BOOST_CHECK_EQUAL(a[1], 0xd2); + BOOST_CHECK_EQUAL(a[31], 0x70); + a[0] = 0xff; + a[31] = 0x54; + BOOST_CHECK_EQUAL(a[0], 0xff); + BOOST_CHECK_EQUAL(a[1], 0xd2); + BOOST_CHECK_EQUAL(a[31], 0x54); +} + +BOOST_AUTO_TEST_CASE(misc) +{ + FixedHash<32> a("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); + + uint8_t* mut_a = a.data(); + uint8_t const* const_a = a.data(); + BOOST_CHECK_EQUAL(mut_a, const_a); + BOOST_CHECK_EQUAL(memcmp(mut_a, const_a, a.size), 0); + + bytes bytes_a = a.asBytes(); + bytesRef bytesref_a = a.ref(); + bytesConstRef bytesconstref_a = a.ref(); + + // There's no printing for bytesRef/bytesConstRef + BOOST_CHECK(bytes(a.data(), a.data() + a.size) == bytes_a); + BOOST_CHECK(bytesRef(a.data(), a.size) == bytesref_a); + BOOST_CHECK(bytesConstRef(a.data(), a.size) == bytesconstref_a); +} + +BOOST_AUTO_TEST_CASE(tostream) +{ + std::ostringstream out; + out << FixedHash<4>("44114411"); + out << FixedHash<32>{}; + out << FixedHash<2>("f77f"); + out << FixedHash<1>("1"); + BOOST_CHECK_EQUAL(out.str(), "441144110000000000000000000000000000000000000000000000000000000000000000f77f01"); +} + +BOOST_AUTO_TEST_SUITE_END() + +}