From 8a90767be8821e9661f8be73853f7064535e4d9e Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 11 Aug 2005 11:06:52 +0000 Subject: [PATCH] added some tests --- include/libtorrent/entry.hpp | 19 ++-- include/libtorrent/peer_id.hpp | 12 ++- src/entry.cpp | 19 ++++ test/Jamfile | 18 ++++ test/main.cpp | 31 +++++++ test/test.hpp | 40 +++++++++ test/test_bencoding.cpp | 74 +++++++++++++++ test/test_hasher.cpp | 46 ++++++++++ test/test_ip_filter.cpp | 158 +++++++++++++++++++++++++++++++++ 9 files changed, 404 insertions(+), 13 deletions(-) create mode 100644 test/Jamfile create mode 100644 test/main.cpp create mode 100644 test/test.hpp create mode 100644 test/test_bencoding.cpp create mode 100644 test/test_hasher.cpp create mode 100644 test/test_ip_filter.cpp diff --git a/include/libtorrent/entry.hpp b/include/libtorrent/entry.hpp index 398c37873..662c66bf6 100755 --- a/include/libtorrent/entry.hpp +++ b/include/libtorrent/entry.hpp @@ -108,10 +108,9 @@ namespace libtorrent { public: - // we need a list here instead of a map, to maintain - // the order of elements. Since the info-hash is - // reconstructed from an entry, it's important that - // the order is preserved. + // the key is always a string. If a generic entry would be allowed + // as a key, sorting would become a problem (e.g. to compare a string + // to a list). The definition doesn't mention such a limit though. typedef std::list > dictionary_type; typedef std::string string_type; typedef std::list list_type; @@ -138,11 +137,13 @@ namespace libtorrent entry(const entry& e); ~entry(); - void operator=(const entry& e); - void operator=(const dictionary_type&); - void operator=(const string_type&); - void operator=(const list_type&); - void operator=(const integer_type&); + bool operator==(entry const& e) const; + + void operator=(entry const&); + void operator=(dictionary_type const&); + void operator=(string_type const&); + void operator=(list_type const&); + void operator=(integer_type const&); void sort(); diff --git a/include/libtorrent/peer_id.hpp b/include/libtorrent/peer_id.hpp index 0f23aaa5b..19e09d831 100755 --- a/include/libtorrent/peer_id.hpp +++ b/include/libtorrent/peer_id.hpp @@ -112,8 +112,7 @@ namespace libtorrent inline std::ostream& operator<<(std::ostream& os, big_number const& peer) { for (big_number::const_iterator i = peer.begin(); - i != peer.end(); - ++i) + i != peer.end(); ++i) { os << std::hex << std::setw(2) << std::setfill('0') << static_cast(*i); @@ -131,8 +130,12 @@ namespace libtorrent { char c[2]; is >> c[0] >> c[1]; - if (c[0] < 0 || c[1] < 0 - || c[0] > 'f' || c[1] > 'f' + c[0] = tolower(c[0]); + c[1] = tolower(c[1]); + std::cerr << c[0] << " " << c[1] << "\n"; + if ( + ((c[0] < '0' || c[0] > '9') && (c[0] < 'a' || c[0] > 'f')) + || ((c[1] < '0' || c[1] > '9') && (c[1] < 'a' || c[1] > 'f')) || is.fail()) { is.setstate(ios_base::failbit); @@ -147,3 +150,4 @@ namespace libtorrent } #endif // TORRENT_PEER_ID_HPP_INCLUDED + diff --git a/src/entry.cpp b/src/entry.cpp index 0c73c4a74..81f6aa8fb 100755 --- a/src/entry.cpp +++ b/src/entry.cpp @@ -198,6 +198,25 @@ namespace libtorrent m_type = int_t; } + bool entry::operator==(entry const& e) const + { + if (m_type != e.m_type) return false; + + switch(m_type) + { + case int_t: + return integer() == e.integer(); + case string_t: + return string() == e.string(); + case list_t: + return list() == e.list(); + case dictionary_t: + return dict() == e.dict(); + default: + assert(m_type == undefined_t); + return true; + } + } void entry::construct(data_type t) { diff --git a/test/Jamfile b/test/Jamfile new file mode 100644 index 000000000..e53a5f4b9 --- /dev/null +++ b/test/Jamfile @@ -0,0 +1,18 @@ +use-project /torrent : .. ; + +project + : + requirements multi + /torrent + main.cpp + ; + +test-suite libtorrent : +# [ run test_storage.cpp ] +# [ run test_piece_picker.cpp ] +# [ run test_entry.cpp ] + [ run test_bencoding.cpp ] + [ run test_ip_filter.cpp ] + [ run test_hasher.cpp ] + ; + diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 000000000..4d146a4a3 --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,31 @@ +#include + +int test_main(); + +bool tests_failure = false; + +void report_failure(char const* err, char const* file, int line) +{ + std::cerr << file << ":" << line << "\"" << err << "\"\n"; + tests_failure = true; +} + +int main() +{ + try + { + test_main(); + return tests_failure ? 1 : 0; + } + catch (std::exception const& e) + { + std::cerr << "Terminated with exception: \"" << e.what() << "\"\n"; + return 1; + } + catch (...) + { + std::cerr << "Terminated with unknown exception\n"; + return 1; + } +} + diff --git a/test/test.hpp b/test/test.hpp new file mode 100644 index 000000000..90efb07c0 --- /dev/null +++ b/test/test.hpp @@ -0,0 +1,40 @@ +#ifndef TEST_HPP +#define TEST_HPP + +void report_failure(char const* str, char const* file, int line); + +#if defined(_MSC_VER) +#define COUNTER_GUARD(x) +#else +#define COUNTER_GUARD(type) \ + struct BOOST_PP_CAT(type, _counter_guard) \ + { \ + ~BOOST_PP_CAT(type, _counter_guard()) \ + { \ + TEST_CHECK(counted_type::count == 0); \ + } \ + } BOOST_PP_CAT(type, _guard) +#endif + +#define TEST_REPORT_AUX(x, line, file) \ + report_failure(x, line, file) + +#define TEST_CHECK(x) \ + if (!(x)) \ + TEST_REPORT_AUX("TEST_CHECK failed: \"" #x "\"", __FILE__, __LINE__) + +#define TEST_ERROR(x) \ + TEST_REPORT_AUX((std::string("ERROR: \"") + x + "\"").c_str(), __FILE__, __LINE__) + +#define TEST_NOTHROW(x) \ + try \ + { \ + x; \ + } \ + catch (...) \ + { \ + TEST_ERROR("Exception thrown: " #x); \ + } + +#endif // TEST_HPP + diff --git a/test/test_bencoding.cpp b/test/test_bencoding.cpp new file mode 100644 index 000000000..592a1751e --- /dev/null +++ b/test/test_bencoding.cpp @@ -0,0 +1,74 @@ +#include "libtorrent/bencode.hpp" +#include + +#include "test.hpp" + +using namespace libtorrent; + +// test vectors from bittorrent protocol description +// http://www.bittorrent.com/protocol.html + +std::string encode(entry const& e) +{ + std::string ret; + bencode(std::back_inserter(ret), e); + return ret; +} + +entry decode(std::string const& str) +{ + return bdecode(str.begin(), str.end()); +} + +int test_main() +{ + using namespace libtorrent; + + // ** strings ** + { + entry e("spam"); + TEST_CHECK(encode(e) == "4:spam"); + TEST_CHECK(decode(encode(e)) == e); + } + + // ** integers ** + { + entry e(3); + TEST_CHECK(encode(e) == "i3e"); + TEST_CHECK(decode(encode(e)) == e); + } + + { + entry e(-3); + TEST_CHECK(encode(e) == "i-3e"); + TEST_CHECK(decode(encode(e)) == e); + } + + { + entry e(int(0)); + TEST_CHECK(encode(e) == "i0e"); + TEST_CHECK(decode(encode(e)) == e); + } + + // ** lists ** + { + entry::list_type l; + l.push_back(entry("spam")); + l.push_back(entry("eggs")); + entry e(l); + TEST_CHECK(encode(e) == "l4:spam4:eggse"); + TEST_CHECK(decode(encode(e)) == e); + } + + // ** dictionaries ** + { + entry e(entry::dictionary_t); + e["cow"] = entry("moo"); + e["spam"] = entry("eggs"); + TEST_CHECK(encode(e) == "d3:cow3:moo4:spam4:eggse"); + TEST_CHECK(decode(encode(e)) == e); + } + + return 0; +} + diff --git a/test/test_hasher.cpp b/test/test_hasher.cpp new file mode 100644 index 000000000..33a78256c --- /dev/null +++ b/test/test_hasher.cpp @@ -0,0 +1,46 @@ +#include "libtorrent/hasher.hpp" +#include + +#include "test.hpp" + +using namespace libtorrent; + +// test vectors from RFC 3174 +// http://www.faqs.org/rfcs/rfc3174.html + +char const* test_array[4] = +{ + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "a", + "0123456701234567012345670123456701234567012345670123456701234567" +}; + +long int repeat_count[4] = { 1, 1, 1000000, 10 }; + +char const* result_array[4] = +{ + "A9993E364706816ABA3E25717850C26C9CD0D89D", + "84983E441C3BD26EBAAE4AA1F95129E5E54670F1", + "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F", + "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452" +}; + + +int test_main() +{ + using namespace libtorrent; + + for (int test = 0; test < 4; ++test) + { + hasher h; + for (int i = 0; i < repeat_count[test]; ++i) + h.update(test_array[test], std::strlen(test_array[test])); + + sha1_hash result = boost::lexical_cast(result_array[test]); + TEST_CHECK(result == h.final()); + } + + return 0; +} + diff --git a/test/test_ip_filter.cpp b/test/test_ip_filter.cpp new file mode 100644 index 000000000..d7afd2a10 --- /dev/null +++ b/test/test_ip_filter.cpp @@ -0,0 +1,158 @@ +#include "libtorrent/ip_filter.hpp" +#include + +#include "test.hpp" + +using namespace libtorrent; + +bool compare(ip_filter::ip_range const& lhs + , ip_filter::ip_range const& rhs) +{ + return lhs.first == rhs.first + && lhs.last == rhs.last + && lhs.flags == rhs.flags; +} + +void test_rules_invariant(std::vector const& r, ip_filter const& f) +{ + typedef std::vector::const_iterator iterator; + TEST_CHECK(!r.empty()); + if (r.empty()) return; + + TEST_CHECK(r.front().first == address(0,0,0,0,0)); + TEST_CHECK(r.back().last == address(255,255,255,255,0)); + + iterator i = r.begin(); + iterator j = boost::next(i); + for (iterator i(r.begin()), j(boost::next(r.begin())) + , end(r.end()); j != end; ++j, ++i) + { + TEST_CHECK(f.access(i->last) == i->flags); + TEST_CHECK(f.access(j->first) == j->flags); + TEST_CHECK(i->last.ip() + 1 == j->first.ip()); + } +} + +int test_main() +{ + using namespace libtorrent; + std::vector range; + + // **** test joining of ranges at the end **** + ip_filter::ip_range expected1[] = + { + {address(0,0,0,0,0), address(0,255,255,255,0), 0} + , {address(1,0,0,0,0), address(3,0,0,0,0), ip_filter::blocked} + , {address(3,0,0,1,0), address(255,255,255,255,0), 0} + }; + + { + ip_filter f; + f.add_rule(address(1,0,0,0,0), address(2,0,0,0,0), ip_filter::blocked); + f.add_rule(address(2,0,0,1,0), address(3,0,0,0,0), ip_filter::blocked); + + range = f.export_filter(); + test_rules_invariant(range, f); + + TEST_CHECK(range.size() == 3); + TEST_CHECK(std::equal(range.begin(), range.end(), expected1, &compare)); + } + + // **** test joining of ranges at the start **** + + { + ip_filter f; + f.add_rule(address(2,0,0,1,0), address(3,0,0,0,0), ip_filter::blocked); + f.add_rule(address(1,0,0,0,0), address(2,0,0,0,0), ip_filter::blocked); + + range = f.export_filter(); + test_rules_invariant(range, f); + + TEST_CHECK(range.size() == 3); + TEST_CHECK(std::equal(range.begin(), range.end(), expected1, &compare)); + } + + + // **** test joining of overlapping ranges at the start **** + + { + ip_filter f; + f.add_rule(address(2,0,0,1,0), address(3,0,0,0,0), ip_filter::blocked); + f.add_rule(address(1,0,0,0,0), address(2,4,0,0,0), ip_filter::blocked); + + range = f.export_filter(); + test_rules_invariant(range, f); + + TEST_CHECK(range.size() == 3); + TEST_CHECK(std::equal(range.begin(), range.end(), expected1, &compare)); + } + + + // **** test joining of overlapping ranges at the end **** + + { + ip_filter f; + f.add_rule(address(1,0,0,0,0), address(2,4,0,0,0), ip_filter::blocked); + f.add_rule(address(2,0,0,1,0), address(3,0,0,0,0), ip_filter::blocked); + + range = f.export_filter(); + test_rules_invariant(range, f); + + TEST_CHECK(range.size() == 3); + TEST_CHECK(std::equal(range.begin(), range.end(), expected1, &compare)); + } + + + // **** test joining of multiple overlapping ranges 1 **** + + { + ip_filter f; + f.add_rule(address(1,0,0,0,0), address(2,0,0,0,0), ip_filter::blocked); + f.add_rule(address(3,0,0,0,0), address(4,0,0,0,0), ip_filter::blocked); + f.add_rule(address(5,0,0,0,0), address(6,0,0,0,0), ip_filter::blocked); + f.add_rule(address(7,0,0,0,0), address(8,0,0,0,0), ip_filter::blocked); + + f.add_rule(address(1,0,1,0,0), address(9,0,0,0,0), ip_filter::blocked); + + range = f.export_filter(); + test_rules_invariant(range, f); + + TEST_CHECK(range.size() == 3); + ip_filter::ip_range expected[] = + { + {address(0,0,0,0,0), address(0,255,255,255,0), 0} + , {address(1,0,0,0,0), address(9,0,0,0,0), ip_filter::blocked} + , {address(9,0,0,1,0), address(255,255,255,255,0), 0} + }; + + TEST_CHECK(std::equal(range.begin(), range.end(), expected, &compare)); + } + + // **** test joining of multiple overlapping ranges 2 **** + + { + ip_filter f; + f.add_rule(address(1,0,0,0,0), address(2,0,0,0,0), ip_filter::blocked); + f.add_rule(address(3,0,0,0,0), address(4,0,0,0,0), ip_filter::blocked); + f.add_rule(address(5,0,0,0,0), address(6,0,0,0,0), ip_filter::blocked); + f.add_rule(address(7,0,0,0,0), address(8,0,0,0,0), ip_filter::blocked); + + f.add_rule(address(0,0,1,0,0), address(7,0,4,0,0), ip_filter::blocked); + + range = f.export_filter(); + test_rules_invariant(range, f); + + TEST_CHECK(range.size() == 3); + ip_filter::ip_range expected[] = + { + {address(0,0,0,0,0), address(0,0,0,255,0), 0} + , {address(0,0,1,0,0), address(8,0,0,0,0), ip_filter::blocked} + , {address(8,0,0,1,0), address(255,255,255,255,0), 0} + }; + + TEST_CHECK(std::equal(range.begin(), range.end(), expected, &compare)); + } + + return 0; +} +