diff --git a/Makefile.am b/Makefile.am index 2f20a875..8d021287 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS = \ doc \ - src + src \ + test EXTRA_DIST= \ autogen.sh \ diff --git a/configure.ac b/configure.ac index c21d183d..e85de989 100644 --- a/configure.ac +++ b/configure.ac @@ -2,6 +2,7 @@ AC_INIT(rtorrent, 0.8.6, jaris@ifi.uio.no) AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) +AM_PATH_CPPUNIT(1.9.6) AC_PROG_CXX AC_PROG_LIBTOOL @@ -63,4 +64,5 @@ AC_OUTPUT([ src/rpc/Makefile src/ui/Makefile src/utils/Makefile + test/Makefile ]) diff --git a/src/Makefile.am b/src/Makefile.am index 9ffe9517..e5af6fa8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,17 +6,9 @@ SUBDIRS = \ ui \ utils -bin_PROGRAMS = rtorrent +noinst_LIBRARIES = libsub_root.a -rtorrent_LDADD = \ - ui/libsub_ui.a \ - core/libsub_core.a \ - display/libsub_display.a \ - input/libsub_input.a \ - rpc/libsub_rpc.a \ - utils/libsub_utils.a - -rtorrent_SOURCES = \ +libsub_root_a_SOURCES = \ command_download.cc \ command_dynamic.cc \ command_events.cc \ @@ -34,7 +26,6 @@ rtorrent_SOURCES = \ control.h \ globals.cc \ globals.h \ - main.cc \ option_parser.cc \ option_parser.h \ signal_handler.cc \ @@ -46,4 +37,18 @@ rtorrent_SOURCES = \ thread_worker.cc \ thread_worker.h +bin_PROGRAMS = rtorrent + +rtorrent_LDADD = \ + ui/libsub_ui.a \ + core/libsub_core.a \ + display/libsub_display.a \ + input/libsub_input.a \ + rpc/libsub_rpc.a \ + utils/libsub_utils.a \ + libsub_root.a + +rtorrent_SOURCES = \ + main.cc + INCLUDES = -I$(srcdir) -I$(top_srcdir) diff --git a/src/command_download.cc b/src/command_download.cc index ca845c94..415b1fdb 100644 --- a/src/command_download.cc +++ b/src/command_download.cc @@ -157,6 +157,11 @@ apply_d_change_link(int changeType, core::Download* download, const torrent::Obj return torrent::Object(); } +template torrent::Object +cmd_d_change_link(core::Download* download, const torrent::Object& rawArgs) { + return apply_d_change_link(type, download, rawArgs); +} + void apply_d_delete_tied(core::Download* download) { const std::string& tie = rpc::call_command_string("d.get_tied_to_file", rpc::make_target(download)); diff --git a/src/command_helpers.cc b/src/command_helpers.cc index adbb93d1..c977f5fb 100644 --- a/src/command_helpers.cc +++ b/src/command_helpers.cc @@ -64,6 +64,9 @@ rpc::CommandSlot* commandTrackerSlotsItr = commandTr rpc::CommandSlot commandAnySlots[COMMAND_ANY_SLOTS_SIZE]; rpc::CommandSlot* commandAnySlotsItr = commandAnySlots; +rpc::command_base commandNewSlots[COMMAND_NEW_SLOTS_SIZE]; +rpc::command_base* commandNewSlotItr = commandNewSlots; + void initialize_command_object(); void initialize_command_dynamic(); void initialize_command_download(); @@ -99,7 +102,8 @@ initialize_commands() { commandFileItrSlotsItr > commandFileItrSlots + COMMAND_FILE_ITR_SLOTS_SIZE || commandPeerSlotsItr > commandPeerSlots + COMMAND_PEER_SLOTS_SIZE || commandTrackerSlotsItr > commandTrackerSlots + COMMAND_TRACKER_SLOTS_SIZE || - commandAnySlotsItr > commandAnySlots + COMMAND_ANY_SLOTS_SIZE) + commandAnySlotsItr > commandAnySlots + COMMAND_ANY_SLOTS_SIZE || + commandNewSlotItr > commandNewSlots + COMMAND_NEW_SLOTS_SIZE) #else if (commandSlotsItr != commandSlots + COMMAND_SLOTS_SIZE || commandVariablesItr != commandVariables + COMMAND_VARIABLES_SIZE || @@ -109,7 +113,8 @@ initialize_commands() { commandFileItrSlotsItr != commandFileItrSlots + COMMAND_FILE_ITR_SLOTS_SIZE || commandPeerSlotsItr != commandPeerSlots + COMMAND_PEER_SLOTS_SIZE || commandTrackerSlotsItr != commandTrackerSlots + COMMAND_TRACKER_SLOTS_SIZE || - commandAnySlotsItr != commandAnySlots + COMMAND_ANY_SLOTS_SIZE) + commandAnySlotsItr != commandAnySlots + COMMAND_ANY_SLOTS_SIZE || + commandNewSlotItr != commandNewSlots + COMMAND_NEW_SLOTS_SIZE) #endif throw torrent::internal_error("initialize_commands() static command array size mismatch."); } diff --git a/src/command_helpers.h b/src/command_helpers.h index 0c7cdfdb..ed2a1793 100644 --- a/src/command_helpers.h +++ b/src/command_helpers.h @@ -38,6 +38,7 @@ #define RTORRENT_UTILS_COMMAND_HELPERS_H #include "rpc/command_slot.h" +#include "rpc/command_new_slot.h" #include "rpc/command_function.h" #include "rpc/parse_commands.h" @@ -58,6 +59,8 @@ namespace rpc { #define COMMAND_TRACKER_SLOTS_SIZE 15 #define COMMAND_ANY_SLOTS_SIZE 50 +#define COMMAND_NEW_SLOTS_SIZE 100 + #define ADDING_COMMANDS extern rpc::CommandSlot commandSlots[COMMAND_SLOTS_SIZE]; @@ -79,6 +82,9 @@ extern rpc::CommandSlot* commandTrackerSlotsItr; extern rpc::CommandSlot commandAnySlots[COMMAND_ANY_SLOTS_SIZE]; extern rpc::CommandSlot* commandAnySlotsItr; +extern rpc::command_base commandNewSlots[COMMAND_NEW_SLOTS_SIZE]; +extern rpc::command_base* commandNewSlotItr; + void initialize_commands(); void @@ -238,4 +244,20 @@ add_variable(key, NULL, NULL, &rpc::CommandVariable::get_string, NULL, std::stri commandObjectPtrsItr->set_object(target); \ rpc::commands.insert_type(key, commandObjectPtrsItr++, &rpc::CommandObjectPtr::function, rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, NULL, NULL); +// +// New std::function based command_base helper functions: +// + +#define CMD2_A_FUNCTION(key, function, func_type, slot, parm, doc) \ + commandNewSlotItr->set_function(slot); \ + m_map.insert_type(key, commandNewSlotItr++, &rpc::function, \ + rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, NULL, NULL); + +#define CMD2_A(key, slot) \ + CMD2_A_FUNCTION(key, command_base_call_any, any_function, slot, "i:", "") + +#define CMD2_A_STRING(key, slot) \ + CMD2_A_FUNCTION(key, command_base_call_any_string, any_string_function, slot, "i:s", "") + + #endif diff --git a/src/rpc/Makefile.am b/src/rpc/Makefile.am index e875ba29..1318fb7f 100644 --- a/src/rpc/Makefile.am +++ b/src/rpc/Makefile.am @@ -12,8 +12,12 @@ libsub_rpc_a_SOURCES = \ command_scheduler_item.h \ command_slot.cc \ command_slot.h \ + command_new_slot.cc \ + command_new_slot.h \ command_variable.cc \ command_variable.h \ + command_new_slot.cc \ + command_new_slot.h \ exec_file.cc \ exec_file.h \ parse.cc \ diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 00000000..e050d619 --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,22 @@ +TESTS = rtorrentTest +check_PROGRAMS = $(TESTS) +rtorrentTest_LDADD = \ + ../src/ui/libsub_ui.a \ + ../src/core/libsub_core.a \ + ../src/display/libsub_display.a \ + ../src/input/libsub_input.a \ + ../src/rpc/libsub_rpc.a \ + ../src/utils/libsub_utils.a \ + ../src/libsub_root.a + +rtorrentTest_SOURCES = \ + rpc/command_map_test.cc \ + rpc/command_map_test.h \ + rpc/command_slot_test.cc \ + rpc/command_slot_test.h \ + main.cc + +rtorrentTest_CXXFLAGS = $(CPPUNIT_CFLAGS) +rtorrentTest_LDFLAGS = $(CPPUNIT_LIBS) -ldl + +INCLUDES = -I$(srcdir) -I$(top_srcdir) -I$(top_srcdir)/src diff --git a/test/main.cc b/test/main.cc new file mode 100644 index 00000000..171a5788 --- /dev/null +++ b/test/main.cc @@ -0,0 +1,22 @@ +#include +#include +#include + +int main(int argc, char* argv[]) +{ + // Get the top level suite from the registry + CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); + + // Adds the test to the list of test to run + CppUnit::TextUi::TestRunner runner; + runner.addTest( suite ); + + // Change the default outputter to a compiler error format outputter + runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(), + std::cerr ) ); + // Run the tests. + bool wasSucessful = runner.run(); + + // Return error code 1 if the one of test failed. + return wasSucessful ? 0 : 1; +} diff --git a/test/rpc/command_map_test.cc b/test/rpc/command_map_test.cc new file mode 100644 index 00000000..89c2ea84 --- /dev/null +++ b/test/rpc/command_map_test.cc @@ -0,0 +1,24 @@ +#include "config.h" + +#include "command_helpers.h" +#include "rpc/command_map.h" + +#import "command_map_test.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(CommandMapTest); + +torrent::Object cmd_test_map_a(rpc::target_type t, const torrent::Object& obj) { return obj; } +torrent::Object cmd_test_map_b(rpc::target_type t, const torrent::Object& obj, uint64_t c) { return torrent::Object(c); } + +torrent::Object cmd_test_any_string(__UNUSED rpc::target_type target, const std::string& rawArgs) { return (int64_t)3; } + +void +CommandMapTest::test_basics() { + CMD2_A("test_a", &cmd_test_map_a); + CMD2_A("test_b", std::tr1::bind(&cmd_test_map_b, std::tr1::placeholders::_1, std::tr1::placeholders::_2, (uint64_t)2)); + CMD2_A_STRING("any_string", &cmd_test_any_string); + + CPPUNIT_ASSERT(m_map.call_command("test_a", (int64_t)1).as_value() == 1); + CPPUNIT_ASSERT(m_map.call_command("test_b", (int64_t)1).as_value() == 2); + CPPUNIT_ASSERT(m_map.call_command("any_string", "").as_value() == 3); +} diff --git a/test/rpc/command_map_test.h b/test/rpc/command_map_test.h new file mode 100644 index 00000000..5648e6a3 --- /dev/null +++ b/test/rpc/command_map_test.h @@ -0,0 +1,24 @@ +#include + +#include "rpc/command_map.h" +#include "rpc/command_new_slot.h" + +class CommandMapTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(CommandMapTest); + CPPUNIT_TEST(test_basics); + CPPUNIT_TEST_SUITE_END(); + +public: + static const int cmd_size = 256; + + void setUp() { m_commandItr = m_commands; } + void tearDown() {} + + void test_basics(); + +private: + rpc::CommandMap m_map; + + rpc::command_base m_commands[cmd_size]; + rpc::command_base* m_commandItr; +}; diff --git a/test/rpc/command_slot_test.cc b/test/rpc/command_slot_test.cc new file mode 100644 index 00000000..13f2565a --- /dev/null +++ b/test/rpc/command_slot_test.cc @@ -0,0 +1,28 @@ +#include "config.h" + +#include +#include +#include "rpc/command_map.h" + +#import "command_slot_test.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(CommandSlotTest); + +torrent::Object cmd_test_a(rpc::target_type t, const torrent::Object& obj) { return obj; } +torrent::Object cmd_test_b(rpc::target_type t, const torrent::Object& obj, uint64_t c) { return torrent::Object(c); } + +void +CommandSlotTest::test_basics() { + rpc::command_base test_any; + test_any.set_function(&cmd_test_a); + CPPUNIT_ASSERT(rpc::command_base_call_any(&test_any, rpc::make_target(), (int64_t)1).as_value() == 1); + + test_any.set_function(std::tr1::bind(&cmd_test_b, std::tr1::placeholders::_1, std::tr1::placeholders::_2, (uint64_t)2)); + CPPUNIT_ASSERT(rpc::command_base_call_any(&test_any, rpc::make_target(), (int64_t)1).as_value() == 2); +} + +void +CommandSlotTest::test_type_validity() { + CPPUNIT_ASSERT((rpc::command_base_is_type::value)); + CPPUNIT_ASSERT((rpc::command_base_is_type::value)); +} diff --git a/test/rpc/command_slot_test.h b/test/rpc/command_slot_test.h new file mode 100644 index 00000000..d8bfd3e6 --- /dev/null +++ b/test/rpc/command_slot_test.h @@ -0,0 +1,17 @@ +#include + +#include "rpc/command_new_slot.h" + +class CommandSlotTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(CommandSlotTest); + CPPUNIT_TEST(test_basics); + CPPUNIT_TEST(test_type_validity); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp() {} + void tearDown() {} + + void test_basics(); + void test_type_validity(); +};