mirror of
https://github.com/ars3niy/tdlib-purple
synced 2025-08-30 13:37:45 +00:00
Added a real test case with login sequence
This commit is contained in:
@@ -44,6 +44,14 @@ Copy the .so to libpurple plugins directory.
|
||||
|
||||
It's good to have telegram-purple installed as well since its icon is used at the moment.
|
||||
|
||||
## Regression test
|
||||
|
||||
Build google test library and `make install` it somewhere
|
||||
|
||||
Run cmake with '-DGTEST_PATH=/path/to/gtest'
|
||||
|
||||
`make run-tests` or `test/tests` or `valgrind test/tests`
|
||||
|
||||
## GPL compatibility: building tdlib with OpenSSL 3.0
|
||||
|
||||
OpenSSL versions prior to 3.0 branch have license with advertisement clause, making it incompatible with GPL. If this is a concern, a possible solution is to build with OpenSSL 3.0 which uses Apache 2.0 license.
|
||||
|
@@ -275,8 +275,9 @@ void PurpleTdClient::setPurpleConnectionInProgress()
|
||||
purple_debug_misc(config::pluginId, "Connection in progress\n");
|
||||
PurpleConnection *gc = purple_account_get_connection(m_account);
|
||||
|
||||
if (PURPLE_CONNECTION_IS_CONNECTED(gc))
|
||||
purple_blist_remove_account(m_account);
|
||||
purple_connection_set_state (gc, PURPLE_CONNECTING);
|
||||
purple_blist_remove_account(m_account);
|
||||
purple_connection_update_progress(gc, "Connecting", 1, 3);
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,7 @@ add_executable(tests EXCLUDE_FROM_ALL
|
||||
testsuite.cpp
|
||||
test-transceiver.cpp
|
||||
libpurple-mock.cpp
|
||||
printout.cpp
|
||||
|
||||
../tdlib-purple.cpp
|
||||
../td-client.cpp
|
||||
|
@@ -64,7 +64,7 @@ void purple_account_destroy(PurpleAccount *account)
|
||||
{
|
||||
free(account->username);
|
||||
free(account->alias);
|
||||
free(account);
|
||||
delete account;
|
||||
}
|
||||
|
||||
void purple_blist_add_account(PurpleAccount *account)
|
||||
@@ -89,7 +89,7 @@ void purple_blist_remove_buddy(PurpleBuddy *buddy)
|
||||
// TODO add event
|
||||
free(buddy->name);
|
||||
free(buddy->alias);
|
||||
free(buddy);
|
||||
delete buddy;
|
||||
}
|
||||
|
||||
const char *purple_buddy_get_alias_only(PurpleBuddy *buddy)
|
||||
@@ -176,7 +176,7 @@ PurpleConversation *purple_conversation_new(PurpleConversationType type,
|
||||
void purple_conversation_destroy(PurpleConversation *conv)
|
||||
{
|
||||
free(conv->name);
|
||||
free(conv);
|
||||
delete conv;
|
||||
}
|
||||
|
||||
void purple_conversation_write(PurpleConversation *conv, const char *who,
|
||||
@@ -309,7 +309,7 @@ void purple_xfer_unref(PurpleXfer *xfer)
|
||||
{
|
||||
if (--xfer->ref == 0) {
|
||||
free(xfer->who);
|
||||
free(xfer);
|
||||
delete xfer;
|
||||
}
|
||||
}
|
||||
|
||||
|
1219
test/printout.cpp
Normal file
1219
test/printout.cpp
Normal file
File diff suppressed because it is too large
Load Diff
9
test/printout.h
Normal file
9
test/printout.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef _PRINTOUT_H
|
||||
#define _PRINTOUT_H
|
||||
|
||||
#include <td/telegram/td_api.hpp>
|
||||
|
||||
std::string requestToString(const td::td_api::Function &req);
|
||||
std::string responseToString(const td::td_api::Object &object);
|
||||
|
||||
#endif
|
@@ -1,17 +1,15 @@
|
||||
#include "test-transceiver.h"
|
||||
#include "printout.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
static std::string requestToString(const td::td_api::Function &req)
|
||||
{
|
||||
return "whatever";
|
||||
}
|
||||
using namespace td::td_api;
|
||||
|
||||
void TestTransceiver::send(td::Client::Request &&request)
|
||||
{
|
||||
m_requests.push(std::move(request));
|
||||
}
|
||||
|
||||
void TestTransceiver::verifyRequest(const td::td_api::Function &request)
|
||||
void TestTransceiver::verifyRequest(const Function &request)
|
||||
{
|
||||
m_lastRequestIds.clear();
|
||||
verifyRequestImpl(request);
|
||||
@@ -20,10 +18,10 @@ void TestTransceiver::verifyRequest(const td::td_api::Function &request)
|
||||
verifyNoRequests();
|
||||
}
|
||||
|
||||
void TestTransceiver::verifyRequests(const std::vector<td::td_api::Function> &requests)
|
||||
void TestTransceiver::verifyRequests(const std::vector<Function> &requests)
|
||||
{
|
||||
m_lastRequestIds.clear();
|
||||
for (const td::td_api::Function &req: requests) {
|
||||
for (const Function &req: requests) {
|
||||
verifyRequestImpl(req);
|
||||
m_lastRequestIds.push_back(m_requests.front().id);
|
||||
m_requests.pop();
|
||||
@@ -31,12 +29,67 @@ void TestTransceiver::verifyRequests(const std::vector<td::td_api::Function> &re
|
||||
verifyNoRequests();
|
||||
}
|
||||
|
||||
void TestTransceiver::verifyRequestImpl(const td::td_api::Function &request)
|
||||
static void compare(const Function &actual, const Function &expected)
|
||||
{
|
||||
}
|
||||
|
||||
static void compare(const setTdlibParameters &actual, const setTdlibParameters &expected)
|
||||
{
|
||||
EXPECT_EQ(expected.parameters_->database_directory_, actual.parameters_->database_directory_);
|
||||
}
|
||||
|
||||
static void compare(const checkDatabaseEncryptionKey &actual, const checkDatabaseEncryptionKey &expected)
|
||||
{
|
||||
EXPECT_EQ(expected.encryption_key_, actual.encryption_key_);
|
||||
}
|
||||
|
||||
static void compare(const setAuthenticationPhoneNumber &actual, const setAuthenticationPhoneNumber &expected)
|
||||
{
|
||||
EXPECT_EQ(expected.phone_number_, actual.phone_number_);
|
||||
EXPECT_TRUE((expected.settings_ != nullptr) == (actual.settings_ != nullptr));
|
||||
}
|
||||
|
||||
static void compareRequests(const Function &actual, const Function &expected)
|
||||
{
|
||||
EXPECT_EQ(expected.get_id(), actual.get_id()) << "Wrong request type: expected " << requestToString(expected);
|
||||
|
||||
#define C(class) case class::ID: \
|
||||
compare(static_cast<const class &>(actual), static_cast<const class &>(expected)); \
|
||||
break;
|
||||
|
||||
switch (actual.get_id()) {
|
||||
C(setTdlibParameters)
|
||||
C(checkDatabaseEncryptionKey)
|
||||
C(setAuthenticationPhoneNumber)
|
||||
default:
|
||||
compare(actual, expected);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TestTransceiver::verifyRequestImpl(const Function &request)
|
||||
{
|
||||
EXPECT_FALSE(m_requests.empty()) << "Missing request: expected " << requestToString(request);
|
||||
|
||||
std::cout << "Received request " << m_requests.front().id << ": " << requestToString(*m_requests.front().function) << "\n";
|
||||
compareRequests(*m_requests.front().function, request);
|
||||
}
|
||||
|
||||
void TestTransceiver::verifyNoRequests()
|
||||
{
|
||||
EXPECT_TRUE(m_requests.empty()) << "Unexpected request: " << requestToString(*m_requests.front().function);
|
||||
}
|
||||
|
||||
void TestTransceiver::update(object_ptr<Object> object)
|
||||
{
|
||||
std::cout << "Sending update: " << responseToString(*object) << "\n";
|
||||
receive({0, std::move(object)});
|
||||
}
|
||||
|
||||
void TestTransceiver::reply(object_ptr<Object> object)
|
||||
{
|
||||
EXPECT_GE(1u, m_lastRequestIds.size()) << "No requests to reply to";
|
||||
std::cout << "Replying to request " << m_lastRequestIds.front() << ": " << responseToString(*object) << "\n";
|
||||
receive({m_lastRequestIds.front(), std::move(object)});
|
||||
m_lastRequestIds.erase(m_lastRequestIds.begin());
|
||||
}
|
||||
|
@@ -11,6 +11,8 @@ public:
|
||||
void verifyRequest(const td::td_api::Function &request);
|
||||
void verifyRequests(const std::vector<td::td_api::Function> &requests);
|
||||
void verifyNoRequests();
|
||||
void update(td::td_api::object_ptr<td::td_api::Object> object);
|
||||
void reply(td::td_api::object_ptr<td::td_api::Object> object);
|
||||
private:
|
||||
std::queue<td::Client::Request> m_requests;
|
||||
std::vector<uint64_t> m_lastRequestIds;
|
||||
|
@@ -2,32 +2,128 @@
|
||||
#include "tdlib-purple.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace td::td_api;
|
||||
|
||||
class CommTest: public testing::Test {
|
||||
public:
|
||||
CommTest();
|
||||
~CommTest();
|
||||
|
||||
private:
|
||||
const std::string phoneNumber = "1234567";
|
||||
const std::string phoneNumber = "1234567";
|
||||
const int selfId = 1;
|
||||
const std::string selfFirstName = "Isaac";
|
||||
const std::string selfLastName = "Newton";
|
||||
|
||||
TestTransceiver tgl;
|
||||
PurplePlugin purplePlugin;
|
||||
PurpleAccount *account;
|
||||
PurpleConnection *connection;
|
||||
|
||||
protected:
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
void login();
|
||||
};
|
||||
|
||||
CommTest::CommTest()
|
||||
{
|
||||
tgprpl_set_test_backend(&tgl);
|
||||
purple_init_plugin(&purplePlugin);
|
||||
account = purple_account_new(phoneNumber.c_str(), NULL);
|
||||
((PurplePluginProtocolInfo *)purplePlugin.info->extra_info)->login(account);
|
||||
}
|
||||
|
||||
CommTest::~CommTest()
|
||||
void CommTest::SetUp()
|
||||
{
|
||||
account = purple_account_new(phoneNumber.c_str(), NULL);
|
||||
connection = new PurpleConnection;
|
||||
account->gc = connection;
|
||||
}
|
||||
|
||||
void CommTest::TearDown()
|
||||
{
|
||||
tgl.verifyNoRequests();
|
||||
if (purple_connection_get_protocol_data(connection))
|
||||
((PurplePluginProtocolInfo *)purplePlugin.info->extra_info)->close(connection);
|
||||
delete connection;
|
||||
purple_account_destroy(account);
|
||||
}
|
||||
|
||||
TEST_F(CommTest, dummy)
|
||||
void CommTest::login()
|
||||
{
|
||||
EXPECT_EQ(4, 2*2);
|
||||
((PurplePluginProtocolInfo *)purplePlugin.info->extra_info)->login(account);
|
||||
|
||||
tgl.update(make_object<updateAuthorizationState>(make_object<authorizationStateWaitTdlibParameters>()));
|
||||
tgl.verifyRequest(setTdlibParameters(make_object<tdlibParameters>(
|
||||
false,
|
||||
std::string(purple_user_dir()) + G_DIR_SEPARATOR_S +
|
||||
"tdlib" + G_DIR_SEPARATOR_S + phoneNumber,
|
||||
"",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
false,
|
||||
false
|
||||
)));
|
||||
tgl.reply(make_object<ok>());
|
||||
|
||||
// TODO: what if is_encrypted = false?
|
||||
tgl.update(make_object<updateAuthorizationState>(make_object<authorizationStateWaitEncryptionKey>(true)));
|
||||
tgl.verifyRequest(checkDatabaseEncryptionKey(""));
|
||||
tgl.reply(make_object<ok>());
|
||||
|
||||
tgl.update(make_object<updateAuthorizationState>(make_object<authorizationStateWaitPhoneNumber>()));
|
||||
tgl.verifyRequest(setAuthenticationPhoneNumber(phoneNumber, nullptr));
|
||||
tgl.reply(make_object<ok>());
|
||||
|
||||
tgl.update(make_object<updateAuthorizationState>(make_object<authorizationStateReady>()));
|
||||
tgl.verifyNoRequests();
|
||||
|
||||
tgl.update(make_object<updateConnectionState>(make_object<connectionStateConnecting>()));
|
||||
tgl.verifyNoRequests();
|
||||
// TODO: verify purple_connection_set_state and purple_connection_update_progress
|
||||
|
||||
tgl.update(make_object<updateConnectionState>(make_object<connectionStateUpdating>()));
|
||||
tgl.verifyNoRequests();
|
||||
// TODO: verify purple_connection_update_progress
|
||||
|
||||
tgl.update(make_object<updateConnectionState>(make_object<connectionStateReady>()));
|
||||
tgl.verifyRequest(getContacts());
|
||||
|
||||
tgl.update(make_object<updateUser>(make_object<user>(
|
||||
selfId,
|
||||
selfFirstName,
|
||||
selfLastName,
|
||||
"",
|
||||
phoneNumber,
|
||||
make_object<userStatusOffline>(),
|
||||
nullptr,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
"",
|
||||
false,
|
||||
true,
|
||||
make_object<userTypeRegular>(),
|
||||
""
|
||||
)));
|
||||
tgl.verifyNoRequests();
|
||||
// TODO: test sending some users and chats
|
||||
tgl.reply(make_object<users>());
|
||||
|
||||
tgl.verifyRequest(getChats());
|
||||
// TODO: test sending some chats
|
||||
tgl.reply(make_object<chats>());
|
||||
// TODO: verfy purple_account_set_alias
|
||||
}
|
||||
|
||||
TEST_F(CommTest, login)
|
||||
{
|
||||
login();
|
||||
}
|
||||
|
@@ -65,8 +65,10 @@ TdTransceiver::TdTransceiver(PurpleTdClient *owner, UpdateCb updateCb, ITranscei
|
||||
TdTransceiver::~TdTransceiver()
|
||||
{
|
||||
m_stopThread = true;
|
||||
m_impl->m_client->send({UINT64_MAX, td::td_api::make_object<td::td_api::close>()});
|
||||
m_pollThread.join();
|
||||
if (!m_testBackend) {
|
||||
m_impl->m_client->send({UINT64_MAX, td::td_api::make_object<td::td_api::close>()});
|
||||
m_pollThread.join();
|
||||
}
|
||||
|
||||
// Orphan m_impl - if the background thread generated idle callbacks while we were waiting for
|
||||
// it to quit, those callbacks will be called after this destructor return (doing nothing, as
|
||||
|
Reference in New Issue
Block a user