Related refactoring to updated of ThrottleList to use new Scheduler.

This commit is contained in:
Jari Sundell
2025-05-12 10:38:07 +02:00
committed by GitHub
parent 6d888c008d
commit 9ff373fe58
33 changed files with 1005 additions and 230 deletions
+24 -17
View File
@@ -14,33 +14,40 @@ rtorrent_Test_Common = \
main.cc \
\
helpers/assert.h \
helpers/mock_compare.h \
helpers/mock_function.cc \
helpers/mock_function.h \
helpers/progress_listener.cc \
helpers/progress_listener.h \
helpers/protectors.cc \
helpers/protectors.h \
helpers/test_fixture.cc \
helpers/test_fixture.h \
helpers/test_main_thread.cc \
helpers/test_main_thread.h \
helpers/test_thread.cc \
helpers/test_thread.h \
helpers/utils.h
rtorrent_Test_Rpc_SOURCES = $(rtorrent_Test_Common) \
rpc/command_test.cc \
rpc/command_test.h \
rpc/command_map_test.cc \
rpc/command_map_test.h \
rpc/jsonrpc_test.cc \
rpc/jsonrpc_test.h \
rpc/xmlrpc_test.cc \
rpc/xmlrpc_test.h \
rpc/command_slot_test.cc \
rpc/command_slot_test.h \
rpc/object_storage_test.cc \
rpc/object_storage_test.h \
rpc/test_command.cc \
rpc/test_command.h \
rpc/test_command_map.cc \
rpc/test_command_map.h \
rpc/test_jsonrpc.cc \
rpc/test_jsonrpc.h \
rpc/test_xmlrpc.cc \
rpc/test_xmlrpc.h \
rpc/test_command_slot.cc \
rpc/test_command_slot.h \
rpc/test_object_storage.cc \
rpc/test_object_storage.h \
rpc/test_parse_options.cc \
rpc/test_parse_options.h \
src/command_dynamic_test.cc \
src/command_dynamic_test.h
rpc/test_parse_options.h
rtorrent_Test_Src_SOURCES = $(rtorrent_Test_Common) \
src/command_dynamic_test.cc \
src/command_dynamic_test.h
src/test_command_dynamic.cc \
src/test_command_dynamic.h
rtorrent_Test_Rpc_CXXFLAGS = $(CPPUNIT_CFLAGS)
rtorrent_Test_Rpc_LDFLAGS = $(CPPUNIT_LIBS) -ldl
+96
View File
@@ -0,0 +1,96 @@
#ifndef LIBTORRENT_HELPERS_MOCK_COMPARE_H
#define LIBTORRENT_HELPERS_MOCK_COMPARE_H
#include <algorithm>
#include <type_traits>
#include <torrent/event.h>
#include <torrent/net/socket_address.h>
// Compare arguments to mock functions with what is expected. The lhs
// are the expected arguments, rhs are the ones called with.
template <typename Arg>
inline bool mock_compare_arg(Arg lhs, Arg rhs) { return lhs == rhs; }
template <int I, typename A, typename... Args>
typename std::enable_if<I == 1, int>::type
mock_compare_tuple(const std::tuple<A, Args...>& lhs, const std::tuple<Args...>& rhs) {
return mock_compare_arg(std::get<I>(lhs), std::get<I - 1>(rhs)) ? 0 : 1;
}
template <int I, typename A, typename... Args>
typename std::enable_if<1 < I, int>::type
mock_compare_tuple(const std::tuple<A, Args...>& lhs, const std::tuple<Args...>& rhs) {
auto res = mock_compare_tuple<I - 1>(lhs, rhs);
if (res != 0)
return res;
return mock_compare_arg(std::get<I>(lhs), std::get<I - 1>(rhs)) ? 0 : I;
}
//template <typename T, typename std::enable_if<!std::is_const<T>::value, int>::type = 0>
template <typename T>
struct mock_compare_map {
typedef std::map<const T*, const T*> values_type;
static T* begin_pointer() { return reinterpret_cast<T*>(0x1000); }
static T* end_pointer() { return reinterpret_cast<T*>(0x2000); }
static bool is_key(const T* k) {
return k >= begin_pointer() && k < end_pointer();
}
static bool has_key(const T* k) {
return values.find(k) != values.end();
}
static bool has_value(const T* v) {
return std::find_if(values.begin(), values.end(), [v](typename values_type::value_type& kv) { return v == kv.second; }) != values.end();
}
static const T* get(const T* k) {
auto itr = values.find(k);
CPPUNIT_ASSERT_MESSAGE("mock_compare_map get failed, not inserted", itr != values.end());
return itr->second;
}
static values_type values;
};
template<typename T>
typename mock_compare_map<T>::values_type mock_compare_map<T>::values;
template<typename T>
void mock_compare_add(T* v) {
mock_compare_map<T>::add_value(v);
}
//
// Specialize:
//
template <>
inline bool mock_compare_arg<sockaddr*>(sockaddr* lhs, sockaddr* rhs) {
return lhs != nullptr && rhs != nullptr && torrent::sa_equal(lhs, rhs);
}
template <>
inline bool mock_compare_arg<const sockaddr*>(const sockaddr* lhs, const sockaddr* rhs) {
return lhs != nullptr && rhs != nullptr && torrent::sa_equal(lhs, rhs);
}
template <>
inline bool mock_compare_arg<torrent::Event*>(torrent::Event* lhs, torrent::Event* rhs) {
if (mock_compare_map<torrent::Event>::is_key(lhs)) {
if (!mock_compare_map<torrent::Event>::has_value(rhs)) {
mock_compare_map<torrent::Event>::values[lhs] = rhs;
return true;
}
return mock_compare_map<torrent::Event>::has_key(lhs) && mock_compare_map<torrent::Event>::get(lhs) == rhs;
}
return lhs == rhs;
}
#endif
+182
View File
@@ -0,0 +1,182 @@
#include "config.h"
#include "test/helpers/mock_function.h"
#include <fcntl.h>
#include <iostream>
#include <unistd.h>
#include <torrent/event.h>
#include <torrent/net/socket_address.h>
#include <torrent/net/fd.h>
#include <torrent/utils/log.h>
#include <torrent/utils/random.h>
#define MOCK_CLEANUP_MAP(MOCK_FUNC) \
CPPUNIT_ASSERT_MESSAGE("expected mock function calls not completed for '" #MOCK_FUNC "'", mock_cleanup_map(&MOCK_FUNC) || ignore_assert);
#define MOCK_LOG(log_fmt, ...) \
lt_log_print(torrent::LOG_MOCK_CALLS, "%s: " log_fmt, __func__, __VA_ARGS__);
void
mock_clear(bool ignore_assert) {
MOCK_CLEANUP_MAP(torrent::fd__accept);
MOCK_CLEANUP_MAP(torrent::fd__bind);
MOCK_CLEANUP_MAP(torrent::fd__close);
MOCK_CLEANUP_MAP(torrent::fd__connect);
MOCK_CLEANUP_MAP(torrent::fd__fcntl_int);
MOCK_CLEANUP_MAP(torrent::fd__listen);
MOCK_CLEANUP_MAP(torrent::fd__setsockopt_int);
MOCK_CLEANUP_MAP(torrent::fd__socket);
MOCK_CLEANUP_MAP(torrent::poll_event_open);
MOCK_CLEANUP_MAP(torrent::poll_event_close);
MOCK_CLEANUP_MAP(torrent::poll_event_closed);
MOCK_CLEANUP_MAP(torrent::poll_event_insert_read);
MOCK_CLEANUP_MAP(torrent::poll_event_insert_write);
MOCK_CLEANUP_MAP(torrent::poll_event_insert_error);
MOCK_CLEANUP_MAP(torrent::poll_event_remove_read);
MOCK_CLEANUP_MAP(torrent::poll_event_remove_write);
MOCK_CLEANUP_MAP(torrent::poll_event_remove_error);
MOCK_CLEANUP_MAP(torrent::random_uniform_uint16);
MOCK_CLEANUP_MAP(torrent::random_uniform_uint32);
mock_compare_map<torrent::Event>::values.clear();
};
void
mock_init() {
log_add_group_output(torrent::LOG_MOCK_CALLS, "test_output");
mock_clear(true);
}
void
mock_cleanup() {
mock_clear(false);
}
void
mock_redirect_defaults([[maybe_unused]] mock_redirect_flags flags) {
mock_redirect(torrent::fd__close, std::function<int(int fildes)>([](int fildes) { return ::close(fildes); }));
mock_redirect(torrent::fd__fcntl_int, std::function<int(int fildes, int cmd, int arg)>([](int fildes, int cmd, int arg) { return ::fcntl(fildes, cmd, arg); }));
mock_redirect(torrent::fd__setsockopt_int, std::function<int(int socket, int level, int option_name, int option_value)>([](int socket, int level, int option_name, int option_value) { return ::setsockopt(socket, level, option_name, &option_value, sizeof(int)); }));
mock_redirect(torrent::fd__socket, std::function<int(int domain, int type, int protocol)>([](int domain, int type, int protocol) { return ::socket(domain, type, protocol); }));
}
namespace torrent {
//
// Mock functions for 'torrent/net/fd.h':
//
int fd__accept(int socket, sockaddr *address, socklen_t *address_len) {
MOCK_LOG("entry socket:%i address:%s address_len:%u",
socket, torrent::sa_pretty_str(address).c_str(), (unsigned int)(*address_len));
auto ret = mock_call<int>(__func__, &torrent::fd__accept, socket, address, address_len);
MOCK_LOG("exit socket:%i address:%s address_len:%u",
socket, torrent::sa_pretty_str(address).c_str(), (unsigned int)(*address_len));
return ret;
}
int fd__bind(int socket, const sockaddr *address, socklen_t address_len) {
MOCK_LOG("socket:%i address:%s address_len:%u",
socket, torrent::sa_pretty_str(address).c_str(), (unsigned int)address_len);
return mock_call<int>(__func__, &torrent::fd__bind, socket, address, address_len);
}
int fd__close(int fildes) {
MOCK_LOG("filedes:%i", fildes);
return mock_call<int>(__func__, &torrent::fd__close, fildes);
}
int fd__connect(int socket, const sockaddr *address, socklen_t address_len) {
MOCK_LOG("socket:%i address:%s address_len:%u",
socket, torrent::sa_pretty_str(address).c_str(), (unsigned int)address_len);
return mock_call<int>(__func__, &torrent::fd__connect, socket, address, address_len);
}
int fd__fcntl_int(int fildes, int cmd, int arg) {
MOCK_LOG("filedes:%i cmd:%i arg:%i", fildes, cmd, arg);
return mock_call<int>(__func__, &torrent::fd__fcntl_int, fildes, cmd, arg);
}
int fd__listen(int socket, int backlog) {
MOCK_LOG("socket:%i backlog:%i", socket, backlog);
return mock_call<int>(__func__, &torrent::fd__listen, socket, backlog);
}
int fd__setsockopt_int(int socket, int level, int option_name, int option_value) {
MOCK_LOG("socket:%i level:%i option_name:%i option_value:%i",
socket, level, option_name, option_value);
return mock_call<int>(__func__, &torrent::fd__setsockopt_int, socket, level, option_name, option_value);
}
int fd__socket(int domain, int type, int protocol) {
MOCK_LOG("domain:%i type:%i protocol:%i", domain, type, protocol);
return mock_call<int>(__func__, &torrent::fd__socket, domain, type, protocol);
}
//
// Mock functions for 'torrent/event.h':
//
void poll_event_open(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::poll_event_open, event);
}
void poll_event_close(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::poll_event_close, event);
}
void poll_event_closed(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::poll_event_closed, event);
}
void poll_event_insert_read(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::poll_event_insert_read, event);
}
void poll_event_insert_write(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::poll_event_insert_write, event);
}
void poll_event_insert_error(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::poll_event_insert_error, event);
}
void poll_event_remove_read(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::poll_event_remove_read, event);
}
void poll_event_remove_write(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::poll_event_remove_write, event);
}
void poll_event_remove_error(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::poll_event_remove_error, event);
}
//
// Mock functions for 'torrent/utils/random.h':
//
uint16_t random_uniform_uint16(uint16_t min, uint16_t max) {
MOCK_LOG("min:%" PRIu16 " max:%" PRIu16, min, max);
return mock_call<uint16_t>(__func__, &torrent::random_uniform_uint16, min, max);
}
uint32_t random_uniform_uint32(uint32_t min, uint32_t max) {
MOCK_LOG("min:%" PRIu32 " max:%" PRIu32, min, max);
return mock_call<uint32_t>(__func__, &torrent::random_uniform_uint32, min, max);
}
}
+176
View File
@@ -0,0 +1,176 @@
#ifndef LIBTORRENT_HELPERS_MOCK_FUNCTION_H
#define LIBTORRENT_HELPERS_MOCK_FUNCTION_H
#include <functional>
#include <map>
#include <mutex>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <cppunit/extensions/HelperMacros.h>
#include "test/helpers/mock_compare.h"
namespace torrent {
extern int fd__accept(int socket, sockaddr *address, socklen_t *address_len);
extern int fd__bind(int socket, const sockaddr *address, socklen_t address_len);
extern int fd__close(int fildes);
extern int fd__connect(int socket, const sockaddr *address, socklen_t address_len);
extern int fd__fcntl_int(int fildes, int cmd, int arg);
extern int fd__listen(int socket, int backlog);
extern int fd__setsockopt_int(int socket, int level, int option_name, int option_value);
extern int fd__socket(int domain, int type, int protocol);
}
enum mock_redirect_flags {
mock_redirect_all = ~0,
};
void mock_init();
void mock_cleanup();
void mock_redirect_defaults(mock_redirect_flags flags = mock_redirect_all);
template<typename R, typename... Args>
struct mock_function_map {
typedef std::tuple<R, Args...> call_type;
typedef std::vector<call_type> call_list_type;
typedef std::map<void*, call_list_type> func_map_type;
typedef std::function<R (Args...)> function_type;
typedef std::map<void*, function_type> redirect_map_type;
static std::mutex mutex;
static func_map_type functions;
static redirect_map_type redirects;
static bool cleanup(void* fn) {
std::lock_guard<std::mutex> lock(mutex);
redirects.erase(fn);
return functions.erase(fn) == 0;
}
static R ret_erase(void* fn) {
auto itr = functions.find(fn);
auto ret = std::get<0>(itr->second.front());
itr->second.erase(itr->second.begin());
if (itr->second.empty())
functions.erase(itr);
return ret;
}
};
template<typename R, typename... Args>
std::mutex mock_function_map<R, Args...>::mutex;
template<typename R, typename... Args>
typename mock_function_map<R, Args...>::func_map_type mock_function_map<R, Args...>::functions;
template<typename R, typename... Args>
typename mock_function_map<R, Args...>::redirect_map_type mock_function_map<R, Args...>::redirects;
struct mock_void {};
template<typename R, typename... Args>
struct mock_function_type {
typedef mock_function_map<R, Args...> type;
static int compare_expected(typename type::call_type lhs, Args... rhs) {
return mock_compare_tuple<sizeof...(Args)>(lhs, std::make_tuple(rhs...));
}
static R ret_erase(void* fn) { return type::ret_erase(fn); }
static bool has_redirect(void* fn) {
std::lock_guard<std::mutex> lock(type::mutex);
return type::redirects.find(fn) != type::redirects.end();
}
static R call_redirect(void* fn, Args... args) {
std::lock_guard<std::mutex> lock(type::mutex);
return type::redirects.find(fn)->second(args...);
}
};
template<typename... Args>
struct mock_function_type<void, Args...> {
typedef mock_function_map<mock_void, Args...> type;
static int compare_expected(typename type::call_type lhs, Args... rhs) {
return mock_compare_tuple<sizeof...(Args)>(lhs, std::make_tuple(rhs...));
}
static void ret_erase(void* fn) { type::ret_erase(fn); }
static bool has_redirect(void* fn) {
std::lock_guard<std::mutex> lock(type::mutex);
return type::redirects.find(fn) != type::redirects.end();
}
static void call_redirect(void* fn, Args... args) {
std::lock_guard<std::mutex> lock(type::mutex);
type::redirects.find(fn)->second(args...);
}
};
template<typename R, typename... Args>
bool
mock_cleanup_map(R fn[[gnu::unused]](Args...)) {
return mock_function_type<R, Args...>::type::cleanup(reinterpret_cast<void*>(fn));
}
template<typename R, typename... Args>
void
mock_expect(R fn(Args...), R ret, Args... args) {
typedef mock_function_map<R, Args...> mock_map;
std::lock_guard<std::mutex> lock(mock_map::mutex);
mock_map::functions[reinterpret_cast<void*>(fn)].push_back(std::tuple<R, Args...>(ret, args...));
}
template<typename... Args>
void
mock_expect(void fn(Args...), Args... args) {
typedef mock_function_map<mock_void, Args...> mock_map;
std::lock_guard<std::mutex> lock(mock_map::mutex);
mock_map::functions[reinterpret_cast<void*>(fn)].push_back(std::tuple<mock_void, Args...>(mock_void(), args...));
}
template<typename R, typename... Args>
void
mock_redirect(R fn(Args...), std::function<R (Args...)> func) {
typedef mock_function_map<R, Args...> mock_map;
std::lock_guard<std::mutex> lock(mock_map::mutex);
mock_map::redirects[reinterpret_cast<void*>(fn)] = func;
}
template<typename R, typename... Args>
auto
mock_call_direct(std::string name, R fn(Args...), Args... args) -> decltype(fn(args...)) {
typedef mock_function_type<R, Args...> mock_type;
std::lock_guard<std::mutex> lock(mock_type::type::mutex);
auto itr = mock_type::type::functions.find(reinterpret_cast<void*>(fn));
CPPUNIT_ASSERT_MESSAGE(("mock_call expected function calls exhausted by '" + name + "'").c_str(),
itr != mock_type::type::functions.end());
auto mismatch_arg = mock_type::compare_expected(itr->second.front(), args...);
CPPUNIT_ASSERT_MESSAGE(("mock_call expected function call argument " + std::to_string(mismatch_arg) + " mismatch for '" + name + "'").c_str(),
mismatch_arg == 0);
return mock_type::ret_erase(reinterpret_cast<void*>(fn));
}
template<typename R, typename... Args>
auto
mock_call(std::string name, R fn(Args...), Args... args) -> decltype(fn(args...)) {
typedef mock_function_type<R, Args...> mock_type;
if (mock_type::has_redirect(reinterpret_cast<void*>(fn)))
return mock_type::call_redirect(reinterpret_cast<void*>(fn), args...);
return mock_call_direct(name, fn, args...);
}
#endif
+20
View File
@@ -0,0 +1,20 @@
#include "config.h"
#include "test_fixture.h"
#include "torrent/utils/log.h"
#include <iostream>
void
test_fixture::setUp() {
mock_init();
log_add_group_output(torrent::LOG_CONNECTION_BIND, "test_output");
log_add_group_output(torrent::LOG_CONNECTION_FD, "test_output");
}
void
test_fixture::tearDown() {
mock_cleanup();
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef LIBTORRENT_HELPER_TEST_FIXTURE_H
#define LIBTORRENT_HELPER_TEST_FIXTURE_H
#include <cppunit/TestFixture.h>
#include "test/helpers/mock_function.h"
class test_fixture : public CppUnit::TestFixture {
public:
void setUp();
void tearDown();
};
#endif
+52
View File
@@ -0,0 +1,52 @@
#include "config.h"
#include "test_main_thread.h"
#include "globals.h"
#include "test/helpers/mock_function.h"
#include "torrent/exceptions.h"
#include "torrent/poll.h"
#include "torrent/net/resolver.h"
#include "torrent/utils/scheduler.h"
std::unique_ptr<TestMainThread>
TestMainThread::create() {
if (torrent::Poll::slot_create_poll() == nullptr)
set_create_poll();
// Needs to be called before Thread is created.
mock_redirect_defaults();
auto thread = new TestMainThread();
return std::unique_ptr<TestMainThread>(thread);
}
TestMainThread::TestMainThread() {}
TestMainThread::~TestMainThread() {
m_self = nullptr;
}
void
TestMainThread::init_thread() {
if (!torrent::Poll::slot_create_poll())
throw torrent::internal_error("ThreadMain::init_thread(): Poll::slot_create_poll() not valid.");
m_poll = std::unique_ptr<torrent::Poll>(torrent::Poll::slot_create_poll()());
m_resolver = std::make_unique<torrent::net::Resolver>();
m_state = STATE_INITIALIZED;
//m_instrumentation_index = INSTRUMENTATION_POLLING_DO_POLL_MAIN - INSTRUMENTATION_POLLING_DO_POLL;
init_thread_local();
}
void
TestMainThread::call_events() {
process_callbacks();
}
std::chrono::microseconds
TestMainThread::next_timeout() {
return std::chrono::microseconds(10min);
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef TEST_HELPERS_TEST_MAIN_THREAD_H
#define TEST_HELPERS_TEST_MAIN_THREAD_H
#include <memory>
#include <torrent/common.h>
#include <torrent/utils/thread.h>
#include "test/helpers/test_thread.h"
class TestMainThread : public torrent::utils::Thread {
public:
static std::unique_ptr<TestMainThread> create();
~TestMainThread() override;
const char* name() const override { return "rtorrent test main"; }
void init_thread() override;
void test_set_cached_time(std::chrono::microseconds t) { set_cached_time(365 * 24h + t); }
void test_process_events_without_cached_time() { process_events_without_cached_time(); }
private:
TestMainThread();
void call_events() override;
std::chrono::microseconds next_timeout() override;
};
#endif // TEST_HELPERS_TEST_MAIN_THREAD_H
+102
View File
@@ -0,0 +1,102 @@
#include "config.h"
#include "test_thread.h"
#include <unistd.h>
#include <cppunit/extensions/HelperMacros.h>
#include <torrent/exceptions.h>
#include <torrent/poll.h>
#include "test/helpers/mock_function.h"
const int test_thread::test_flag_pre_stop;
const int test_thread::test_flag_long_timeout;
const int test_thread::test_flag_do_work;
const int test_thread::test_flag_pre_poke;
const int test_thread::test_flag_post_poke;
// TODO: Remove PollSelect.
torrent::Poll*
create_poll() {
torrent::Poll* poll = torrent::Poll::create(256);
if (poll == nullptr)
throw torrent::internal_error("Unable to create poll object");
return poll;
}
void
set_create_poll() {
torrent::Poll::slot_create_poll() = []() {
return create_poll();
};
}
std::unique_ptr<test_thread>
test_thread::create() {
// Needs to be called before Thread is created.
mock_redirect_defaults();
auto thread = new test_thread();
return std::unique_ptr<test_thread>(thread);
}
test_thread::test_thread() :
m_test_state(TEST_NONE),
m_test_flags(0) {
}
test_thread::~test_thread() {
if (is_active())
stop_thread_wait();
m_self = nullptr;
}
void
test_thread::init_thread() {
m_state = STATE_INITIALIZED;
m_test_state = TEST_PRE_START;
m_poll = std::unique_ptr<torrent::Poll>(create_poll());
}
void
test_thread::call_events() {
m_loop_count++;
if ((m_test_flags & test_flag_pre_stop) && m_test_state == TEST_PRE_START && m_state == STATE_ACTIVE)
m_test_state = TEST_PRE_STOP;
if ((m_flags & flag_do_shutdown)) {
if ((m_flags & flag_did_shutdown))
throw torrent::internal_error("Already trigged shutdown.");
m_flags |= flag_did_shutdown;
throw torrent::shutdown_exception();
}
if ((m_test_flags & test_flag_pre_poke)) {
}
if ((m_test_flags & test_flag_do_work)) {
usleep(10 * 1000); // TODO: Don't just sleep, as that give up core.
m_test_flags &= ~test_flag_do_work;
}
if ((m_test_flags & test_flag_post_poke)) {
}
process_callbacks();
}
std::chrono::microseconds
test_thread::next_timeout() {
if ((m_test_flags & test_flag_long_timeout))
return std::chrono::microseconds(10s);
else
return std::chrono::microseconds(100ms);
}
+73
View File
@@ -0,0 +1,73 @@
#ifndef TEST_HELPERS_TEST_THREAD_H
#define TEST_HELPERS_TEST_THREAD_H
#include <atomic>
#include <memory>
#include "torrent/common.h"
#include "torrent/utils/thread.h"
class test_thread : public torrent::utils::Thread {
public:
enum test_state {
TEST_NONE,
TEST_PRE_START,
TEST_PRE_STOP,
TEST_STOP
};
static const int test_flag_pre_stop = 0x1;
static const int test_flag_long_timeout = 0x2;
static const int test_flag_do_work = 0x100;
static const int test_flag_pre_poke = 0x200;
static const int test_flag_post_poke = 0x400;
static std::unique_ptr<test_thread> create();
~test_thread() override;
int test_state() const { return m_test_state; }
bool is_state(int state) const { return m_state == state; }
bool is_test_state(int state) const { return m_test_state == state; }
bool is_test_flags(int flags) const { return (m_test_flags & flags) == flags; }
bool is_not_test_flags(int flags) const { return !(m_test_flags & flags); }
// Loop count increments twice each loop.
int loop_count() const { return m_loop_count; }
const char* name() const override { return "test_thread"; }
void init_thread() override;
void set_pre_stop() { m_test_flags |= test_flag_pre_stop; }
void set_test_flag(int flags) { m_test_flags |= flags; }
private:
test_thread();
void call_events() override;
std::chrono::microseconds next_timeout() override;
std::atomic_int m_test_state;
std::atomic_int m_test_flags;
std::atomic_int m_loop_count{0};
};
void set_create_poll();
// TODO: Need better cleanup here.
// TODO: Replace these with class that holds the threads and cleans them up on destruction.
#define SETUP_THREAD_DISK() \
auto thread_test = test_thread::create(); \
thread_test->init_thread(); \
torrent::ThreadDisk::create_thread(); \
torrent::thread_disk()->init_thread(); \
torrent::thread_disk()->start_thread();
#define CLEANUP_THREAD_DISK() \
torrent::ThreadDisk::destroy_thread();
#endif
-19
View File
@@ -1,19 +0,0 @@
#include <cppunit/extensions/HelperMacros.h>
#include "rpc/command.h"
class CommandTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(CommandTest);
CPPUNIT_TEST(test_stack);
CPPUNIT_TEST(test_stack_double);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() { }
void tearDown() {}
void test_stack();
void test_stack_double();
private:
};
-19
View File
@@ -1,19 +0,0 @@
#include <cppunit/extensions/HelperMacros.h>
#include "rpc/command_map.h"
#include "rpc/jsonrpc.h"
class JsonrpcTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(JsonrpcTest);
CPPUNIT_TEST(test_basics);
CPPUNIT_TEST_SUITE_END();
public:
void setUp();
void tearDown() {}
void test_basics();
private:
rpc::JsonRpc m_jsonrpc;
};
@@ -1,8 +1,10 @@
#include "config.h"
#include "command_test.h"
#include "test/rpc/test_command.h"
CPPUNIT_TEST_SUITE_REGISTRATION(CommandTest);
#include "rpc/command.h"
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommand);
bool
command_stack_all_empty() {
@@ -11,7 +13,7 @@ command_stack_all_empty() {
}
void
CommandTest::test_stack() {
TestCommand::test_stack() {
torrent::Object::list_type args;
rpc::command_base::stack_type stack;
torrent::Object* last_stack;
@@ -50,7 +52,7 @@ CommandTest::test_stack() {
}
void
CommandTest::test_stack_double() {
TestCommand::test_stack_double() {
torrent::Object::list_type args;
rpc::command_base::stack_type stack_first;
rpc::command_base::stack_type stack_second;
+14
View File
@@ -0,0 +1,14 @@
#include "test/helpers/test_fixture.h"
class TestCommand : public test_fixture {
CPPUNIT_TEST_SUITE(TestCommand);
CPPUNIT_TEST(test_stack);
CPPUNIT_TEST(test_stack_double);
CPPUNIT_TEST_SUITE_END();
public:
void test_stack();
void test_stack_double();
};
@@ -1,11 +1,11 @@
#include "config.h"
#include "test/rpc/test_command_map.h"
#include "command_helpers.h"
#include "rpc/command_map.h"
#include "command_map_test.h"
CPPUNIT_TEST_SUITE_REGISTRATION(CommandMapTest);
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandMap);
#undef CMD2_A_FUNCTION
@@ -13,13 +13,13 @@ CPPUNIT_TEST_SUITE_REGISTRATION(CommandMapTest);
m_map.insert_slot<rpc::command_base_is_type<rpc::function>::type>(key, slot, &rpc::function, \
rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_rpc, NULL, NULL);
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_map_a([[maybe_unused]] rpc::target_type t, const torrent::Object& obj) { return obj; }
torrent::Object cmd_test_map_b([[maybe_unused]] rpc::target_type t, [[maybe_unused]] 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; }
torrent::Object cmd_test_any_string([[maybe_unused]] rpc::target_type target, [[maybe_unused]] const std::string& rawArgs) { return (int64_t)3; }
void
CommandMapTest::test_basics() {
TestCommandMap::test_basics() {
CMD2_ANY("test_a", &cmd_test_map_a);
CMD2_ANY("test_b", std::bind(&cmd_test_map_b, std::placeholders::_1, std::placeholders::_2, (uint64_t)2));
CMD2_ANY_STRING("any_string", &cmd_test_any_string);
@@ -1,17 +1,18 @@
#include <cppunit/extensions/HelperMacros.h>
#include "test/helpers/test_fixture.h"
#include "rpc/command_map.h"
class CommandMapTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(CommandMapTest);
class TestCommandMap : public test_fixture {
CPPUNIT_TEST_SUITE(TestCommandMap);
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();
@@ -1,26 +1,27 @@
#include "config.h"
#include "test/rpc/test_command_slot.h"
#include <sstream>
#include <torrent/object.h>
#include "rpc/command_map.h"
#include "command_slot_test.h"
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandSlot);
CPPUNIT_TEST_SUITE_REGISTRATION(CommandSlotTest);
torrent::Object cmd_test_a([[maybe_unused]] rpc::target_type t, const torrent::Object& obj) { return obj; }
torrent::Object cmd_test_b([[maybe_unused]] rpc::target_type t, [[maybe_unused]] const torrent::Object& obj, uint64_t c) { return torrent::Object(c); }
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); }
torrent::Object cmd_test_list([[maybe_unused]] rpc::target_type t, const torrent::Object::list_type& obj) { return torrent::Object(obj.front()); }
torrent::Object cmd_test_list(rpc::target_type t, const torrent::Object::list_type& obj) { return torrent::Object(obj.front()); }
void cmd_test_convert_void(rpc::target_type t, const torrent::Object& obj) {}
int32_t cmd_test_convert_int32_t(rpc::target_type t, const torrent::Object& obj) { return 9; }
int64_t cmd_test_convert_int64_t(rpc::target_type t, const torrent::Object& obj) { return 10; }
std::string cmd_test_convert_string(rpc::target_type t, const torrent::Object& obj) { return "test_1"; }
const std::string& cmd_test_convert_const_string(rpc::target_type t, const torrent::Object& obj) { static const std::string ret = "test_2"; return ret; }
void cmd_test_convert_void([[maybe_unused]] rpc::target_type t, [[maybe_unused]] const torrent::Object& obj) {}
int32_t cmd_test_convert_int32_t([[maybe_unused]] rpc::target_type t, [[maybe_unused]] const torrent::Object& obj) { return 9; }
int64_t cmd_test_convert_int64_t([[maybe_unused]] rpc::target_type t, [[maybe_unused]] const torrent::Object& obj) { return 10; }
std::string cmd_test_convert_string([[maybe_unused]] rpc::target_type t, [[maybe_unused]] const torrent::Object& obj) { return "test_1"; }
const std::string& cmd_test_convert_const_string([[maybe_unused]] rpc::target_type t, [[maybe_unused]] const torrent::Object& obj) { static const std::string ret = "test_2"; return ret; }
void
CommandSlotTest::test_basics() {
TestCommandSlot::test_basics() {
// rpc::command_base test_any;
// test_any.set_function<rpc::any_function>(&cmd_test_a);
// CPPUNIT_ASSERT(rpc::command_base_call_any(&test_any, rpc::make_target(), (int64_t)1).as_value() == 1);
@@ -33,13 +34,13 @@ CommandSlotTest::test_basics() {
}
void
CommandSlotTest::test_type_validity() {
TestCommandSlot::test_type_validity() {
// CPPUNIT_ASSERT((rpc::command_base_is_type<rpc::any_function, &rpc::command_base_call_any>::value));
// CPPUNIT_ASSERT((rpc::command_base_is_type<rpc::any_string_function, &rpc::command_base_call_any_string>::value));
}
void
CommandSlotTest::test_convert_return() {
TestCommandSlot::test_convert_return() {
// rpc::command_base test_any;
// test_any.set_function<rpc::any_function>(&cmd_test_convert_string);
@@ -1,18 +1,15 @@
#include <cppunit/extensions/HelperMacros.h>
#include "test/helpers/test_fixture.h"
#include "rpc/command.h"
class TestCommandSlot : public test_fixture {
CPPUNIT_TEST_SUITE(TestCommandSlot);
class CommandSlotTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(CommandSlotTest);
CPPUNIT_TEST(test_basics);
CPPUNIT_TEST(test_type_validity);
CPPUNIT_TEST(test_convert_return);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {}
void tearDown() {}
void test_basics();
void test_type_validity();
void test_convert_return();
@@ -1,14 +1,15 @@
#include "config.h"
#include <string>
#include "command_helpers.h"
#include "rpc/command_map.h"
#include "test/rpc/test_jsonrpc.h"
#include <string>
#include "control.h"
#include "globals.h"
#include "jsonrpc_test.h"
#include "command_helpers.h"
#include "rpc/command_map.h"
CPPUNIT_TEST_SUITE_REGISTRATION(JsonrpcTest);
CPPUNIT_TEST_SUITE_REGISTRATION(TestJsonrpc);
torrent::Object
jsonrpc_cmd_test_reflect([[maybe_unused]] rpc::target_type t, const torrent::Object& obj) { return obj; }
@@ -117,19 +118,27 @@ std::vector<std::tuple<std::string, std::string, std::string>> basic_jsonrpc_req
};
void
JsonrpcTest::setUp() {
TestJsonrpc::setUp() {
m_test_main_thread = TestMainThread::create();
m_test_main_thread->init_thread();
m_jsonrpc = rpc::JsonRpc();
m_jsonrpc.initialize();
setlocale(LC_ALL, "");
// cachedTime = rak::timer::current();
control = new Control;
control = new Control;
if (rpc::commands.find("jsonrpc_reflect") == rpc::commands.end()) {
CMD2_ANY("jsonrpc_reflect", &jsonrpc_cmd_test_reflect);
}
}
void
JsonrpcTest::test_basics() {
TestJsonrpc::tearDown() {
m_test_main_thread.reset();
}
void
TestJsonrpc::test_basics() {
for (auto& test : basic_jsonrpc_requests) {
std::string output;
m_jsonrpc.process(std::get<1>(test).c_str(), std::get<1>(test).size(), [&output](const char* c, uint32_t l) { output.append(c, l); return true; });
+24
View File
@@ -0,0 +1,24 @@
#include "test/helpers/test_fixture.h"
#include "test/helpers/test_main_thread.h"
#include "rpc/command_map.h"
#include "rpc/jsonrpc.h"
class TestJsonrpc : public test_fixture {
CPPUNIT_TEST_SUITE(TestJsonrpc);
CPPUNIT_TEST(test_basics);
CPPUNIT_TEST_SUITE_END();
public:
void setUp();
void tearDown();
void test_basics();
private:
std::unique_ptr<TestMainThread> m_test_main_thread;
rpc::JsonRpc m_jsonrpc;
};
@@ -1,16 +1,17 @@
#include "config.h"
#include "object_storage_test.h"
#include "test/rpc/test_object_storage.h"
#include "helpers/assert.h"
CPPUNIT_TEST_SUITE_REGISTRATION(ObjectStorageTest);
CPPUNIT_TEST_SUITE_REGISTRATION(TestObjectStorage);
void
ObjectStorageTest::test_basics() {
TestObjectStorage::test_basics() {
rpc::object_storage::iterator itr;
CPPUNIT_ASSERT(m_storage.empty());
itr = m_storage.insert("test_1", torrent::Object("a"), rpc::object_storage::flag_string_type);
CPPUNIT_ASSERT(itr != m_storage.end());
@@ -32,7 +33,7 @@ ObjectStorageTest::test_basics() {
}
void
ObjectStorageTest::test_conversions() {
TestObjectStorage::test_conversions() {
CPPUNIT_ASSERT(m_storage.insert("test_1", torrent::Object("a"), rpc::object_storage::flag_string_type) != m_storage.end());
CPPUNIT_ASSERT(m_storage.insert_str(std::string("test_2"), torrent::Object("a"), rpc::object_storage::flag_string_type) != m_storage.end());
@@ -44,7 +45,7 @@ ObjectStorageTest::test_conversions() {
}
void
ObjectStorageTest::test_validate_keys() {
TestObjectStorage::test_validate_keys() {
torrent::raw_string raw_string_4("test_4\0foo", 10);
ASSERT_CATCH_INPUT_ERROR( { m_storage.insert(raw_string_4, torrent::Object("a"), rpc::object_storage::flag_string_type); } );
@@ -55,7 +56,7 @@ ObjectStorageTest::test_validate_keys() {
// Test for various conversions of fixed_key_type.
void
ObjectStorageTest::test_access() {
TestObjectStorage::test_access() {
m_storage.insert("string_1", torrent::Object("gen_a"), rpc::object_storage::flag_string_type);
m_storage.insert("value_1", int64_t(1), rpc::object_storage::flag_value_type);
@@ -68,7 +69,7 @@ ObjectStorageTest::test_access() {
// CPPUNIT_ASSERT(m_storage.set_c_str_value("value_1", "123").as_value() == 123);
// CPPUNIT_ASSERT(m_storage.set_c_str_value("value_1", torrent::raw_string::from_c_str("321")).as_value() == 321);
// CPPUNIT_ASSERT(m_storage.set_c_str_value("value_1", torrent::raw_bencode::from_c_str("i567e")).as_value() == 567);
// ASSERT_CATCH_INPUT_ERROR( { m_storage.set_c_str_value("value_1", "e123"); } );
// Test string from raw and normal, list, etc.
@@ -1,19 +1,18 @@
#include <cppunit/extensions/HelperMacros.h>
#include "test/helpers/test_fixture.h"
#include "rpc/object_storage.h"
class ObjectStorageTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ObjectStorageTest);
class TestObjectStorage : public test_fixture {
CPPUNIT_TEST_SUITE(TestObjectStorage);
CPPUNIT_TEST(test_basics);
CPPUNIT_TEST(test_conversions);
CPPUNIT_TEST(test_validate_keys);
CPPUNIT_TEST(test_access);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() { }
void tearDown() {}
void test_basics();
void test_conversions();
+4 -5
View File
@@ -1,8 +1,6 @@
#include "config.h"
#include "test_parse_options.h"
#include "helpers/assert.h"
#include "test/rpc/test_parse_options.h"
#include <array>
#include <torrent/connection_manager.h>
@@ -10,6 +8,7 @@
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include "test/helpers/assert.h"
#include "rpc/parse_options.h"
CPPUNIT_TEST_SUITE_REGISTRATION(TestParseOptions);
@@ -37,7 +36,7 @@ flag_to_int(const std::string& flag) {
for (auto f : flag_list)
if (f.first == flag)
return f.second;
throw torrent::input_error("unknown flag");
}
@@ -86,7 +85,7 @@ TestParseOptions::test_flag_error() {
FLAG_ASSERT_ERROR("");
FLAG_ASSERT_ERROR("foo|bar");
FLAG_ASSERT_ERROR("foo|bar|baz");
FLAG_ASSERT_ERROR("foo |bar");
FLAG_ASSERT_ERROR("foo | bar| baz");
}
+4 -5
View File
@@ -1,7 +1,8 @@
#include <cppunit/extensions/HelperMacros.h>
#include "test/helpers/test_fixture.h"
class TestParseOptions : public CppUnit::TestFixture {
class TestParseOptions : public test_fixture {
CPPUNIT_TEST_SUITE(TestParseOptions);
CPPUNIT_TEST(test_flag_basic);
CPPUNIT_TEST(test_flag_error);
@@ -14,12 +15,10 @@ class TestParseOptions : public CppUnit::TestFixture {
CPPUNIT_TEST(test_flag_libtorrent);
CPPUNIT_TEST(test_flags_libtorrent);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() { }
void tearDown() {}
void test_flag_basic();
void test_flag_error();
@@ -1,14 +1,15 @@
#include "config.h"
#include "test/rpc/test_xmlrpc.h"
#include <string>
#include "control.h"
#include "globals.h"
#include "command_helpers.h"
#include "rpc/command_map.h"
#include "xmlrpc_test.h"
#include "control.h"
#include "globals.h"
CPPUNIT_TEST_SUITE_REGISTRATION(XmlrpcTest);
CPPUNIT_TEST_SUITE_REGISTRATION(TestXmlrpc);
torrent::Object xmlrpc_cmd_test_reflect([[maybe_unused]] rpc::target_type t, const torrent::Object& obj) { return obj; }
@@ -99,19 +100,27 @@ std::vector<std::tuple<std::string, std::string, std::string>> basic_requests =
};
void
XmlrpcTest::setUp() {
TestXmlrpc::setUp() {
m_test_main_thread = TestMainThread::create();
m_test_main_thread->init_thread();
m_xmlrpc = rpc::XmlRpc();
m_xmlrpc.initialize();
setlocale(LC_ALL, "");
// cachedTime = rak::timer::current();
control = new Control;
if (rpc::commands.find("xmlrpc_reflect") == rpc::commands.end()) {
CMD2_ANY("xmlrpc_reflect", &xmlrpc_cmd_test_reflect);
}
}
void
XmlrpcTest::test_basics() {
TestXmlrpc::tearDown() {
m_test_main_thread.reset();
}
void
TestXmlrpc::test_basics() {
for (auto& test : basic_requests) {
std::string output;
m_xmlrpc.process(std::get<1>(test).c_str(), std::get<1>(test).size(), [&output](const char* c, uint32_t l){ output.append(c, l); return true;});
@@ -120,7 +129,7 @@ XmlrpcTest::test_basics() {
}
void
XmlrpcTest::test_invalid_utf8() {
TestXmlrpc::test_invalid_utf8() {
// Surprisingly, this call doesn't fail. TinyXML-2 technically expects
// valid UTF-8, but doesn't check strings, and Object strings are
// just a series of bytes so it reflects just fine.
@@ -132,7 +141,7 @@ XmlrpcTest::test_invalid_utf8() {
}
void
XmlrpcTest::test_size_limit() {
TestXmlrpc::test_size_limit() {
std::string input = "<?xml version=\"1.0\"?><methodCall><methodName>xmlrpc_reflect</methodName><params><param><value><string></string></value></param><param><value><string>\xc3\x28</string></value></param></params></methodCall>";
std::string expected = "<?xml version=\"1.0\"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><i8>-509</i8></value></member><member><name>faultString</name><value><string>Content size exceeds maximum XML-RPC limit</string></value></member></struct></value></fault></methodResponse>";
std::string output;
@@ -140,9 +149,13 @@ XmlrpcTest::test_size_limit() {
m_xmlrpc.process(input.c_str(), input.size(), [&output](const char* c, uint32_t l){ output.append(c, l); return true;});
CPPUNIT_ASSERT_EQUAL(expected, output);
}
#else
void XmlrpcTest::test_invalid_utf8() {}
void XmlrpcTest::test_basics() {}
void XmlrpcTest::test_size_limit() {}
void XmlrpcTest::setUp() {}
void TestXmlrpc::test_invalid_utf8() {}
void TestXmlrpc::test_basics() {}
void TestXmlrpc::test_size_limit() {}
void TestXmlrpc::setUp() {}
void TestXmlrpc::tearDown() {}
#endif
@@ -1,29 +1,32 @@
#include <cppunit/extensions/HelperMacros.h>
#include "test/helpers/test_fixture.h"
#include "test/helpers/test_main_thread.h"
#include "rpc/command_map.h"
#include "rpc/xmlrpc.h"
class XmlrpcTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(XmlrpcTest);
class TestXmlrpc : public test_fixture {
CPPUNIT_TEST_SUITE(TestXmlrpc);
CPPUNIT_TEST(test_basics);
CPPUNIT_TEST(test_invalid_utf8);
CPPUNIT_TEST(test_size_limit);
CPPUNIT_TEST_SUITE_END();
public:
static const int cmd_size = 256;
void setUp();
void tearDown() {}
void tearDown();
void test_basics();
void test_invalid_utf8();
void test_size_limit();
private:
rpc::XmlRpc m_xmlrpc;
rpc::CommandMap m_map;
std::unique_ptr<TestMainThread> m_test_main_thread;
rpc::XmlRpc m_xmlrpc;
rpc::CommandMap m_map;
rpc::command_base m_commands[cmd_size];
};
-20
View File
@@ -1,20 +0,0 @@
#include <cppunit/extensions/HelperMacros.h>
class CommandDynamicTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(CommandDynamicTest);
CPPUNIT_TEST(test_basics);
CPPUNIT_TEST(test_get_set);
CPPUNIT_TEST(test_old_style);
CPPUNIT_TEST_SUITE_END();
public:
void setUp();
void tearDown() {}
void test_basics();
void test_get_set();
void test_old_style();
private:
};
@@ -1,22 +1,21 @@
#include "config.h"
#include <iostream>
#include "test/src/test_command_dynamic.h"
#include "command_dynamic_test.h"
#include "helpers/assert.h"
#include "rpc/parse_commands.h"
#include "control.h"
#include "globals.h"
#include "rpc/parse_commands.h"
CPPUNIT_TEST_SUITE_REGISTRATION(CommandDynamicTest);
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandDynamic);
void initialize_command_dynamic();
void initialize_command_ui();
void
CommandDynamicTest::setUp() {
TestCommandDynamic::setUp() {
m_test_main_thread = TestMainThread::create();
m_test_main_thread->init_thread();
if (rpc::commands.find("method.insert") == rpc::commands.end()) {
setlocale(LC_ALL, "");
// cachedTime = rak::timer::current();
@@ -28,13 +27,18 @@ CommandDynamicTest::setUp() {
}
void
CommandDynamicTest::test_basics() {
TestCommandDynamic::tearDown() {
m_test_main_thread.reset();
}
void
TestCommandDynamic::test_basics() {
rpc::commands.call_command("method.insert.value", rpc::create_object_list("test_basics.1", int64_t(1)));
CPPUNIT_ASSERT(rpc::commands.call_command("test_basics.1", torrent::Object()).as_value() == 1);
}
void
CommandDynamicTest::test_get_set() {
TestCommandDynamic::test_get_set() {
rpc::commands.call_command("method.insert.simple", rpc::create_object_list("test_get_set.1", "cat=1"));
CPPUNIT_ASSERT(rpc::commands.call_command("test_get_set.1", torrent::Object()).as_string() == "1");
CPPUNIT_ASSERT(rpc::commands.call_command("method.get", "test_get_set.1").as_string() == "cat=1");
@@ -44,7 +48,7 @@ CommandDynamicTest::test_get_set() {
}
void
CommandDynamicTest::test_old_style() {
TestCommandDynamic::test_old_style() {
rpc::commands.call_command("method.insert", rpc::create_object_list("test_old_style.1", "value", int64_t(1)));
CPPUNIT_ASSERT(rpc::commands.call_command("test_old_style.1", torrent::Object()).as_value() == 1);
+24
View File
@@ -0,0 +1,24 @@
#include "test/helpers/test_fixture.h"
#include "test/helpers/test_main_thread.h"
class TestCommandDynamic : public test_fixture {
CPPUNIT_TEST_SUITE(TestCommandDynamic);
CPPUNIT_TEST(test_basics);
CPPUNIT_TEST(test_get_set);
CPPUNIT_TEST(test_old_style);
CPPUNIT_TEST_SUITE_END();
public:
void setUp();
void tearDown();
void test_basics();
void test_get_set();
void test_old_style();
private:
std::unique_ptr<TestMainThread> m_test_main_thread;
};