From 3599b130c0bf8ebbee49c5a68d079af9ddb28b67 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 24 Feb 2013 10:02:26 +0000 Subject: [PATCH] expand unit tests --- include/libtorrent/escape_string.hpp | 2 + include/libtorrent/torrent_info.hpp | 1 + src/escape_string.cpp | 2 +- src/storage.cpp | 14 +- src/torrent_info.cpp | 9 +- test/Makefile.am | 4 +- test/setup_transfer.cpp | 2 +- test/test.hpp | 2 +- test/test_primitives.cpp | 144 +++++++++++++++++++++ test/test_torrent_parse.cpp | 38 ++++++ test/test_torrents/duplicate_files.torrent | 1 + test/test_torrents/whitespace_url.torrent | 1 + 12 files changed, 205 insertions(+), 15 deletions(-) create mode 100644 test/test_torrents/duplicate_files.torrent create mode 100644 test/test_torrents/whitespace_url.torrent diff --git a/include/libtorrent/escape_string.hpp b/include/libtorrent/escape_string.hpp index f3a918c1a..2c7175878 100644 --- a/include/libtorrent/escape_string.hpp +++ b/include/libtorrent/escape_string.hpp @@ -68,6 +68,8 @@ namespace libtorrent TORRENT_EXTRA_EXPORT void convert_path_to_posix(std::string& path); TORRENT_EXTRA_EXPORT std::string read_until(char const*& str, char delim, char const* end); + TORRENT_EXTRA_EXPORT int hex_to_int(char in); + TORRENT_EXPORT std::string to_hex(std::string const& s); TORRENT_EXPORT bool is_hex(char const *in, int len); TORRENT_EXPORT void to_hex(char const *in, int len, char* out); diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index 25d7cf04a..9ee774065 100644 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -78,6 +78,7 @@ namespace libtorrent TORRENT_EXTRA_EXPORT int merkle_num_nodes(int); TORRENT_EXTRA_EXPORT int merkle_get_parent(int); TORRENT_EXTRA_EXPORT int merkle_get_sibling(int); + TORRENT_EXTRA_EXPORT void trim_path_element(std::string& path_element); struct TORRENT_EXPORT announce_entry { diff --git a/src/escape_string.cpp b/src/escape_string.cpp index a7803c452..236f11c63 100644 --- a/src/escape_string.cpp +++ b/src/escape_string.cpp @@ -450,7 +450,7 @@ namespace libtorrent *out = '\0'; } - int hex_to_int(char in) + TORRENT_EXTRA_EXPORT int hex_to_int(char in) { if (in >= '0' && in <= '9') return int(in) - '0'; if (in >= 'A' && in <= 'F') return int(in) - 'A' + 10; diff --git a/src/storage.cpp b/src/storage.cpp index f746ab205..4e8c59112 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -1248,7 +1248,7 @@ ret: // allocate a temporary, aligned, buffer aligned_holder aligned_buf(aligned_size); - file::iovec_t b = {aligned_buf.get(), aligned_size}; + file::iovec_t b = {aligned_buf.get(), size_t(aligned_size) }; size_type ret = file_handle->readv(aligned_start, &b, 1, ec); if (ret < 0) { @@ -1289,7 +1289,7 @@ ret: // allocate a temporary, aligned, buffer aligned_holder aligned_buf(aligned_size); - file::iovec_t b = {aligned_buf.get(), aligned_size}; + file::iovec_t b = {aligned_buf.get(), size_t(aligned_size) }; // we have something to read if (aligned_start < actual_file_size && !ec) { @@ -1331,7 +1331,7 @@ ret: , int offset , int size) { - file::iovec_t b = { (file::iovec_base_t)buf, size }; + file::iovec_t b = { (file::iovec_base_t)buf, size_t(size) }; return writev(&b, slot, offset, 1); } @@ -1341,7 +1341,7 @@ ret: , int offset , int size) { - file::iovec_t b = { (file::iovec_base_t)buf, size }; + file::iovec_t b = { (file::iovec_base_t)buf, size_t(size) }; return readv(&b, slot, offset, 1); } @@ -2263,7 +2263,7 @@ ret: m_scratch_buffer2.reset(page_aligned_allocator::malloc(m_files.piece_length())); int piece_size = m_files.piece_size(other_piece); - file::iovec_t b = {m_scratch_buffer2.get(), piece_size}; + file::iovec_t b = {m_scratch_buffer2.get(), size_t(piece_size) }; if (m_storage->readv(&b, piece, 0, 1) != piece_size) { error = m_storage->error(); @@ -2277,7 +2277,7 @@ ret: // the slot where this piece belongs is // free. Just move the piece there. int piece_size = m_files.piece_size(piece); - file::iovec_t b = {m_scratch_buffer.get(), piece_size}; + file::iovec_t b = {m_scratch_buffer.get(), size_t(piece_size) }; if (m_storage->writev(&b, piece, 0, 1) != piece_size) { error = m_storage->error(); @@ -2319,7 +2319,7 @@ ret: m_scratch_buffer.reset(page_aligned_allocator::malloc(m_files.piece_length())); int piece_size = m_files.piece_size(other_piece); - file::iovec_t b = {m_scratch_buffer.get(), piece_size}; + file::iovec_t b = {m_scratch_buffer.get(), size_t(piece_size) }; if (m_storage->readv(&b, piece, 0, 1) != piece_size) { error = m_storage->error(); diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 0aa640fc8..dda06eea4 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -120,7 +120,7 @@ namespace libtorrent { convert_to_utf8(tmp_path, *i); valid_encoding = false; - continue; + break; } // valid 2-byte utf-8 character @@ -137,7 +137,7 @@ namespace libtorrent { convert_to_utf8(tmp_path, *i); valid_encoding = false; - continue; + break; } // valid 3-byte utf-8 character @@ -156,7 +156,7 @@ namespace libtorrent { convert_to_utf8(tmp_path, *i); valid_encoding = false; - continue; + break; } // valid 4-byte utf-8 character @@ -195,7 +195,7 @@ namespace libtorrent return true; } - void trim_path_element(std::string& path_element) + TORRENT_EXTRA_EXPORT void trim_path_element(std::string& path_element) { const int max_path_len = TORRENT_MAX_PATH; if (int(path_element.size()) > max_path_len) @@ -372,6 +372,7 @@ namespace libtorrent // as long as this file already exists // increase the counter + fprintf(stderr, "adding file: %s\n", e.path.c_str()); while (!files.insert(e.path).second) { ++cnt; diff --git a/test/Makefile.am b/test/Makefile.am index 230fa2570..99697fd29 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -51,7 +51,9 @@ EXTRA_DIST = Jamfile \ test_torrents/url_list3.torrent \ test_torrents/httpseed.torrent \ test_torrents/empty_httpseed.torrent \ - test_torrents/long_name.torrent + test_torrents/long_name.torrent \ + test_torrents/whitespace_url.torrent \ + test_torrents/duplicate_files.torrent EXTRA_PROGRAMS = $(test_programs) diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index 918f4b4ce..50fd35535 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -239,7 +239,7 @@ void create_random_files(std::string const& path, const int file_sizes[], int nu while (to_write > 0) { int s = (std::min)(to_write, 300000); - file::iovec_t b = { random_data, s}; + file::iovec_t b = { random_data, size_t(s)}; f.writev(offset, &b, 1, ec); if (ec) fprintf(stderr, "failed to write file \"%s\": (%d) %s\n" , full_path.c_str(), ec.value(), ec.message().c_str()); diff --git a/test/test.hpp b/test/test.hpp index a100ce2c9..697e351fc 100644 --- a/test/test.hpp +++ b/test/test.hpp @@ -62,7 +62,7 @@ void report_failure(char const* str, char const* file, int line); #define TEST_EQUAL(x, y) \ if (x != y) { \ std::stringstream s__; \ - s__ << "TEST_EQUAL_ERROR: " #x ": " << x << " expected: " << y << std::endl; \ + s__ << "TEST_EQUAL_ERROR:\n" #x ": " << x << "\nexpected: " << y << std::endl; \ TEST_REPORT_AUX(s__.str().c_str(), __FILE__, __LINE__); \ } #else diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index d84c35f48..b690f68bd 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -627,6 +627,10 @@ int test_main() // test that wrapping of the timestamp is properly handled h.add_sample(0xfffffff3, false); TEST_EQUAL(h.base(), 0xfffffff3); + + + // TODO: test the case where we have > 120 samples (and have the base delay actually be updated) + // TODO: test the case where a sample is lower than the history entry but not lower than the base } // test packet_buffer @@ -728,6 +732,28 @@ int test_main() TEST_CHECK(pb.at(new_index) == (void*)2); } + { + // test wrapping the indices backwards + packet_buffer pb; + + TEST_EQUAL(pb.size(), 0); + + pb.insert(0xfff3, (void*)1); + TEST_CHECK(pb.at(0xfff3) == (void*)1); + + int new_index = (0xfff3 + pb.capacity()) & 0xffff; + pb.insert(new_index, (void*)2); + TEST_CHECK(pb.at(new_index) == (void*)2); + + void* old = pb.remove(0xfff3); + TEST_CHECK(old == (void*)1); + TEST_CHECK(pb.at(0xfff3) == (void*)0); + TEST_CHECK(pb.at(new_index) == (void*)2); + + pb.insert(0xffff, (void*)0xffff); + } + + // test error codes TEST_CHECK(error_code(errors::http_error).message() == "HTTP error"); TEST_CHECK(error_code(errors::missing_file_sizes).message() == "missing or invalid 'file sizes' entry"); TEST_CHECK(error_code(errors::unsupported_protocol_version).message() == "unsupported protocol version"); @@ -739,6 +765,9 @@ int test_main() TEST_CHECK(errors::reserved159 == 159); TEST_CHECK(errors::reserved114 == 114); + TEST_CHECK(error_code(errors::unauthorized, get_http_category()).message() == "401 Unauthorized"); + TEST_CHECK(error_code(errors::service_unavailable, get_http_category()).message() == "503 Service Unavailable"); + { // test session state load/restore session* s = new session(fingerprint("LT",0,0,0,0), 0); @@ -858,6 +887,24 @@ int test_main() fprintf(stderr, "session_state\n%s\n", print_entry(session_state2).c_str()); + // parse_magnet_uri + parse_magnet_uri("magnet:?dn=foo&dht=127.0.0.1:43", p, ec); + TEST_CHECK(ec == error_code(errors::missing_info_hash_in_uri)); + ec.clear(); + + parse_magnet_uri("magnet:?xt=blah&dn=foo&dht=127.0.0.1:43", p, ec); + TEST_CHECK(ec == error_code(errors::missing_info_hash_in_uri)); + ec.clear(); + + parse_magnet_uri("magnet:?xt=urn:btih:cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd&dn=foo&dht=127.0.0.1:43", p, ec); + TEST_CHECK(!ec); + if (ec) fprintf(stderr, "%s\n", ec.message().c_str()); + ec.clear(); + + TEST_CHECK(p.dht_nodes.size() == 1); + TEST_CHECK(p.dht_nodes[0].first == "127.0.0.1"); + TEST_CHECK(p.dht_nodes[0].second == 43); + // make sure settings that haven't been changed from their defaults are not saved TEST_CHECK(session_state2.dict_find("settings")->dict_find("optimistic_disk_retry") == 0); @@ -1226,6 +1273,22 @@ int test_main() TEST_CHECK(ec == error_code(errors::invalid_escaped_string)); ec.clear(); + char hex_chars[] = "0123456789abcdefABCDEF"; + + for (int i = 1; i < 255; ++i) + { + bool hex = strchr(hex_chars, i) != NULL; + TEST_EQUAL(is_hex((char const*)&i, 1), hex); + } + + TEST_EQUAL(hex_to_int('0'), 0); + TEST_EQUAL(hex_to_int('7'), 7); + TEST_EQUAL(hex_to_int('a'), 10); + TEST_EQUAL(hex_to_int('f'), 15); + TEST_EQUAL(hex_to_int('b'), 11); + TEST_EQUAL(hex_to_int('t'), -1); + TEST_EQUAL(hex_to_int('g'), -1); + std::string path = "a\\b\\c"; convert_path_to_posix(path); TEST_EQUAL(path, "a/b/c"); @@ -1248,6 +1311,87 @@ int test_main() TEST_CHECK(verify_encoding(test)); TEST_CHECK(test == "filename=4"); + // valid 2-byte sequence + test = "filename\xc2\xa1"; + TEST_CHECK(verify_encoding(test)); + fprintf(stderr, "%s %x %x\n", test.c_str(), test[test.size()-2], test[test.size()-1]); + TEST_CHECK(test == "filename\xc2\xa1"); + + // truncated 2-byte sequence + test = "filename\xc2"; + TEST_CHECK(!verify_encoding(test)); + fprintf(stderr, "%s %x %x\n", test.c_str(), test[test.size()-2], test[test.size()-1]); + TEST_CHECK(test == "filename\xc3\x82"); + + // valid 3-byte sequence + test = "filename\xe2\x9f\xb9"; + TEST_CHECK(verify_encoding(test)); + fprintf(stderr, "%s\n", test.c_str()); + TEST_CHECK(test == "filename\xe2\x9f\xb9"); + + // truncated 3-byte sequence + test = "filename\xe2\x9f"; + TEST_CHECK(!verify_encoding(test)); + fprintf(stderr, "%s %x %x\n", test.c_str(), test[test.size()-2], test[test.size()-1]); + TEST_CHECK(test == "filename\xc3\xa2"); + + // truncated 3-byte sequence + test = "filename\xe2"; + TEST_CHECK(!verify_encoding(test)); + fprintf(stderr, "%s %x %x\n", test.c_str(), test[test.size()-2], test[test.size()-1]); + TEST_CHECK(test == "filename\xc3\xa2"); + + // valid 4-byte sequence + test = "filename\xf0\x9f\x92\x88"; + TEST_CHECK(verify_encoding(test)); + fprintf(stderr, "%s %x %x\n", test.c_str(), test[test.size()-2], test[test.size()-1]); + TEST_CHECK(test == "filename\xf0\x9f\x92\x88"); + + // truncated 4-byte sequence + test = "filename\xf0\x9f\x92"; + TEST_CHECK(!verify_encoding(test)); + fprintf(stderr, "%s %x %x\n", test.c_str(), test[test.size()-2], test[test.size()-1]); + TEST_CHECK(test == "filename\xc3\xb0"); + + // trim_path_element + + fprintf(stderr, "TORRENT_MAX_PATH: %d\n", TORRENT_MAX_PATH); + + // 1100 characters + test = "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij012345.txt"; + std::string comparison = test; + trim_path_element(test); + comparison.resize(TORRENT_MAX_PATH - 4); + comparison += ".txt"; // the extension is supposed to be preserved + TEST_EQUAL(test, comparison); + + // extensions > 15 characters are ignored + test = "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789" + "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij.123456789abcdefghij0123456789"; + comparison = test; + trim_path_element(test); + comparison.resize(TORRENT_MAX_PATH); + TEST_EQUAL(test, comparison); + // file class file f; #if TORRENT_USE_UNC_PATHS || !defined WIN32 diff --git a/test/test_torrent_parse.cpp b/test/test_torrent_parse.cpp index 209e72b62..00c449f0c 100644 --- a/test/test_torrent_parse.cpp +++ b/test/test_torrent_parse.cpp @@ -56,9 +56,33 @@ test_torrent_t test_torrents[] = { "httpseed.torrent" }, { "empty_httpseed.torrent" }, { "long_name.torrent" }, + { "whitespace_url.torrent" }, + { "duplicate_files.torrent" }, // { "" }, }; +// TODO: create a separate list of all torrents that should +// fail to parse, and include the expected error code in that list + +// TODO: merkle torrents. specifically torrent_info::add_merkle_nodes and torrent with "root hash" +// TODO: torrent where info-section is not a dict +// TODO: torrent with "piece length" <= 0 +// TODO: torrent with no "name" nor "name.utf8" +// TODO: torrent with "name" refering to an invalid path +// TODO: torrent with 'p' (padfile) attribute +// TODO: torrent with 'h' (hidden) attribute +// TODO: torrent with 'x' (executable) attribute +// TODO: torrent with 'l' (symlink) attribute +// TODO: torrent with bitcomet style padfiles (name convention) +// TODO: torrent with a negative file size +// TODO: torrent with a negative total size +// TODO: torrent with a pieces field that's not a string +// TODO: torrent with a pieces field whose length is not divisible by 20 +// TODO: creating a merkle torrent (torrent_info::build_merkle_list) +// TODO: torrent with multiple trackers in multiple tiers, making sure we shuffle them (how do you test shuffling?, load it multiple times and make sure it's in different order at least once) +// TODO: torrent with web seed. make sure we append '/' for multifile torrents +// TODO: test that creation date is parsed correctly + int test_main() { for (int i = 0; i < sizeof(test_torrents)/sizeof(test_torrents[0]); ++i) @@ -69,6 +93,19 @@ int test_main() TEST_CHECK(!ec); if (ec) fprintf(stderr, " -> failed %s\n", ec.message().c_str()); + if (std::string(test_torrents[i].file) == "whitespace_url.torrent") + { + // make sure we trimmed the url + TEST_CHECK(ti->trackers()[0].url == "udp://test.com/announce"); + } + else if (std::string(test_torrents[i].file) == "duplicate_files.torrent") + { + // make sure we disambiguated the files + TEST_EQUAL(ti->num_files(), 2); + TEST_CHECK(ti->file_at(0).path == "temp/foo/bar.txt"); + TEST_CHECK(ti->file_at(1).path == "temp/foo/bar.1.txt"); + } + int index = 0; for (torrent_info::file_iterator i = ti->begin_files(); i != ti->end_files(); ++i, ++index) @@ -88,6 +125,7 @@ int test_main() , i->symlink_attribute ? "-> ": "" , i->symlink_attribute && i->symlink_index != -1 ? ti->files().symlink(*i).c_str() : ""); } + } return 0; } diff --git a/test/test_torrents/duplicate_files.torrent b/test/test_torrents/duplicate_files.torrent new file mode 100644 index 000000000..17e9de3b7 --- /dev/null +++ b/test/test_torrents/duplicate_files.torrent @@ -0,0 +1 @@ +d10:created by10:libtorrent13:creation datei1359599503e4:infod5:filesld6:lengthi425e4:pathl3:foo7:bar.txteed6:lengthi425e4:pathl3:foo7:bar.txteee4:name4:temp12:piece lengthi16384e6:pieces20:‚ž¼Œ&¾ÇJW›}ÜA4u,·¼‘‡ee diff --git a/test/test_torrents/whitespace_url.torrent b/test/test_torrents/whitespace_url.torrent new file mode 100644 index 000000000..2c2cdbe33 --- /dev/null +++ b/test/test_torrents/whitespace_url.torrent @@ -0,0 +1 @@ +d8:announce25: udp://test.com/announce10:created by10:libtorrent13:creation datei1359599503e4:infod6:lengthi425e4:name4:temp12:piece lengthi16384e6:pieces20:‚ž¼Œ&¾ÇJW›}ÜA4u,·¼‘‡ee