From 8e36edeef44005c24fa574fbb90556442a6a516f Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sun, 29 Sep 2024 14:24:23 +0300 Subject: TDLIB: copyright updates & code cleaning --- protocols/Telegram/tdlib/td/test/CMakeLists.txt | 4 +- protocols/Telegram/tdlib/td/test/country_info.cpp | 2 +- protocols/Telegram/tdlib/td/test/crypto.cpp | 2 +- protocols/Telegram/tdlib/td/test/data.cpp | 2 +- protocols/Telegram/tdlib/td/test/data.h | 2 +- protocols/Telegram/tdlib/td/test/db.cpp | 2 +- protocols/Telegram/tdlib/td/test/fuzz_url.cpp | 2 +- protocols/Telegram/tdlib/td/test/http.cpp | 87 ++++++- protocols/Telegram/tdlib/td/test/link.cpp | 265 +++++++++++++++++--- protocols/Telegram/tdlib/td/test/main.cpp | 2 +- .../Telegram/tdlib/td/test/message_entities.cpp | 269 +++++++++++++++------ protocols/Telegram/tdlib/td/test/mtproto.cpp | 36 +-- protocols/Telegram/tdlib/td/test/online.cpp | 26 +- protocols/Telegram/tdlib/td/test/poll.cpp | 2 +- protocols/Telegram/tdlib/td/test/query_merger.cpp | 5 +- protocols/Telegram/tdlib/td/test/secret.cpp | 39 +-- .../Telegram/tdlib/td/test/secure_storage.cpp | 2 +- .../Telegram/tdlib/td/test/set_with_position.cpp | 2 +- .../Telegram/tdlib/td/test/string_cleaning.cpp | 6 +- protocols/Telegram/tdlib/td/test/tdclient.cpp | 25 +- protocols/Telegram/tdlib/td/test/tqueue.cpp | 4 +- 21 files changed, 596 insertions(+), 190 deletions(-) (limited to 'protocols/Telegram/tdlib/td/test') diff --git a/protocols/Telegram/tdlib/td/test/CMakeLists.txt b/protocols/Telegram/tdlib/td/test/CMakeLists.txt index 2a140a3af7..da7d45c3f2 100644 --- a/protocols/Telegram/tdlib/td/test/CMakeLists.txt +++ b/protocols/Telegram/tdlib/td/test/CMakeLists.txt @@ -2,7 +2,6 @@ if ((CMAKE_MAJOR_VERSION LESS 3) OR (CMAKE_VERSION VERSION_LESS "3.0.2")) message(FATAL_ERROR "CMake >= 3.0.2 is required") endif() -#SOURCE SETS set(TD_TEST_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/country_info.cpp ${CMAKE_CURRENT_SOURCE_DIR}/db.cpp @@ -36,11 +35,10 @@ set(TESTS_MAIN #target_link_libraries(all_tests PRIVATE tdcore tdclient) if (NOT CMAKE_CROSSCOMPILING OR EMSCRIPTEN) - #Tests if (OPENSSL_FOUND) add_executable(test-crypto EXCLUDE_FROM_ALL crypto.cpp) target_include_directories(test-crypto SYSTEM PRIVATE ${OPENSSL_INCLUDE_DIR}) - target_link_libraries(test-crypto PRIVATE ${OPENSSL_CRYPTO_LIBRARY} ${CMAKE_DL_LIBS} ${ZLIB_LIBRARIES} tdutils tdcore) + target_link_libraries(test-crypto PRIVATE ${OPENSSL_CRYPTO_LIBRARY} ${CMAKE_DL_LIBS} ${ZLIB_LIBRARIES} tdutils tdmtproto) if (WIN32) if (MINGW) diff --git a/protocols/Telegram/tdlib/td/test/country_info.cpp b/protocols/Telegram/tdlib/td/test/country_info.cpp index 0a9e3c26b6..2fe59de245 100644 --- a/protocols/Telegram/tdlib/td/test/country_info.cpp +++ b/protocols/Telegram/tdlib/td/test/country_info.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/protocols/Telegram/tdlib/td/test/crypto.cpp b/protocols/Telegram/tdlib/td/test/crypto.cpp index f6657747f1..0de3d464c3 100644 --- a/protocols/Telegram/tdlib/td/test/crypto.cpp +++ b/protocols/Telegram/tdlib/td/test/crypto.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/protocols/Telegram/tdlib/td/test/data.cpp b/protocols/Telegram/tdlib/td/test/data.cpp index c53658d243..e0516dd16d 100644 --- a/protocols/Telegram/tdlib/td/test/data.cpp +++ b/protocols/Telegram/tdlib/td/test/data.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/protocols/Telegram/tdlib/td/test/data.h b/protocols/Telegram/tdlib/td/test/data.h index 79093e1996..99e1936227 100644 --- a/protocols/Telegram/tdlib/td/test/data.h +++ b/protocols/Telegram/tdlib/td/test/data.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/protocols/Telegram/tdlib/td/test/db.cpp b/protocols/Telegram/tdlib/td/test/db.cpp index 9e56e331f4..4fe75c15f8 100644 --- a/protocols/Telegram/tdlib/td/test/db.cpp +++ b/protocols/Telegram/tdlib/td/test/db.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/protocols/Telegram/tdlib/td/test/fuzz_url.cpp b/protocols/Telegram/tdlib/td/test/fuzz_url.cpp index cd7af58a77..f29e7c1295 100644 --- a/protocols/Telegram/tdlib/td/test/fuzz_url.cpp +++ b/protocols/Telegram/tdlib/td/test/fuzz_url.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/protocols/Telegram/tdlib/td/test/http.cpp b/protocols/Telegram/tdlib/td/test/http.cpp index e3d2301f6e..5deca6d0c9 100644 --- a/protocols/Telegram/tdlib/td/test/http.cpp +++ b/protocols/Telegram/tdlib/td/test/http.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -71,13 +71,13 @@ static td::string gen_http_content() { return td::rand_string(std::numeric_limits::min(), std::numeric_limits::max(), len); } -static td::string make_http_query(td::string content, bool is_json, bool is_chunked, bool is_gzip, double gzip_k = 5, - td::string zip_override = td::string()) { +static td::string make_http_query(td::string content, td::string content_type, bool is_chunked, bool is_gzip, + double gzip_k = 5, td::string zip_override = td::string()) { td::HttpHeaderCreator hc; hc.init_post("/"); hc.add_header("jfkdlsahhjk", td::rand_string('a', 'z', td::Random::fast(1, 2000))); - if (is_json) { - hc.add_header("content-type", "application/json"); + if (!content_type.empty()) { + hc.add_header("content-type", content_type); } if (is_gzip) { td::BufferSlice zip; @@ -105,7 +105,7 @@ static td::string make_http_query(td::string content, bool is_json, bool is_chun static td::string rand_http_query(td::string content) { bool is_chunked = td::Random::fast_bool(); bool is_gzip = td::Random::fast_bool(); - return make_http_query(std::move(content), false, is_chunked, is_gzip); + return make_http_query(std::move(content), td::string(), is_chunked, is_gzip); } static td::string join(const td::vector &v) { @@ -144,9 +144,17 @@ TEST(Http, reader) { #pragma clang diagnostic ignored "-Wunknown-pragmas" #pragma clang diagnostic ignored "-Wunknown-warning-option" #pragma clang diagnostic ignored "-Wself-move" +#endif +#if TD_GCC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wself-move" #endif a = std::move(a); b = std::move(b); +#if TD_GCC +#pragma GCC diagnostic pop +#endif #if TD_CLANG #pragma clang diagnostic pop #endif @@ -220,7 +228,7 @@ TEST(Http, gzip_bomb) { .as_slice() .str(); - auto query = make_http_query("", false, false, true, 0.01, gzip_bomb_str); + auto query = make_http_query(td::string(), td::string(), false, true, 0.01, gzip_bomb_str); auto parts = td::rand_split(query); td::ChainBufferWriter input_writer; auto input = input_writer.extract_reader(); @@ -248,7 +256,7 @@ TEST(Http, gzip) { td::HttpReader reader; reader.init(&input, 0, 0); - auto query = make_http_query("", true, false, true, 0.01, gzip_str); + auto query = make_http_query(td::string(), "application/json", false, true, 0.01, gzip_str); input_writer.append(query); input.sync_with_writer(); @@ -442,7 +450,7 @@ TEST(Http, gzip_bomb_with_limit) { gzip_bomb_str = sink.result()->move_as_buffer_slice().as_slice().str(); } - auto query = make_http_query("", false, false, true, 0.01, gzip_bomb_str); + auto query = make_http_query(td::string(), td::string(), false, true, 0.01, gzip_bomb_str); auto parts = td::rand_split(query); td::ChainBufferWriter input_writer; auto input = input_writer.extract_reader(); @@ -464,6 +472,67 @@ TEST(Http, gzip_bomb_with_limit) { ASSERT_TRUE(ok); } +TEST(Http, partial_form_data) { + td::ChainBufferWriter input_writer; + auto input = input_writer.extract_reader(); + + td::HttpReader reader; + reader.init(&input, 0, 0); + + auto query = + make_http_query("------abcd\r\nCo", "Content-Type: multipart/form-data; boundary=----abcd", false, false); + input_writer.append(query); + input.sync_with_writer(); + + td::HttpQuery q; + auto r_state = reader.read_next(&q); + ASSERT_TRUE(r_state.is_error()); + ASSERT_EQ(400, r_state.error().code()); +} + +TEST(Http, form_data) { + td::ChainBufferWriter input_writer; + auto input = input_writer.extract_reader(); + + td::HttpReader reader; + reader.init(&input, 0, 1); + + auto query = make_http_query( + "------abcd\r\n" + "Content-Disposition: form-data; name=\"text\"\r\n" + "\r\n" + "some text\r\n" + "------abcd\r\n" + "Content-Disposition: form-data; name=\"text2\"\r\n" + "\r\n" + "some text\r\n" + "more text\r\n" + "------abcd\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"file.txt\"\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "File content\r\n" + "------abcd--", + "Content-Type: multipart/form-data; boundary=----abcd", false, false); + input_writer.append(query); + input.sync_with_writer(); + + td::HttpQuery q; + auto r_state = reader.read_next(&q); + ASSERT_TRUE(r_state.is_ok()); + ASSERT_EQ(2u, q.args_.size()); + ASSERT_EQ("text", q.args_[0].first); + ASSERT_EQ("some text", q.args_[0].second); + ASSERT_EQ("text2", q.args_[1].first); + ASSERT_EQ("some text\r\nmore text", q.args_[1].second); + ASSERT_EQ(1u, q.files_.size()); + ASSERT_EQ("file.txt", q.files_[0].name); + ASSERT_EQ("file", q.files_[0].field_name); + ASSERT_EQ("text/plain", q.files_[0].content_type); + ASSERT_EQ(12, q.files_[0].size); + ASSERT_TRUE(!q.files_[0].temp_file_name.empty()); +} + #if TD_DARWIN_WATCH_OS struct Baton { std::mutex mutex; diff --git a/protocols/Telegram/tdlib/td/test/link.cpp b/protocols/Telegram/tdlib/td/test/link.cpp index 67b81c1354..6403b98962 100644 --- a/protocols/Telegram/tdlib/td/test/link.cpp +++ b/protocols/Telegram/tdlib/td/test/link.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -79,6 +79,8 @@ TEST(Link, check_link) { check_link("http://..", "http://../"); check_link("..", "http://../"); check_link("https://.", ""); + check_link("tOnSiTe://google", "tonsite://google/"); + check_link("tOnSiTe://google.ton?t=1#we", "tonsite://google.ton?t=1#we"); } static td::td_api::object_ptr get_internal_link_type_object( @@ -97,6 +99,10 @@ static void parse_internal_link(const td::string &url, td::td_api::object_ptrget_id() == td::td_api::internalLinkTypeChatBoost::ID) { + // external chat boost links must be generated with getChatBoostLink + continue; + } if (!is_internal && expected->get_id() == td::td_api::internalLinkTypeMessage::ID) { // external message links must be generated with getMessageLink continue; @@ -160,11 +166,12 @@ static void parse_internal_link(const td::string &url, td::td_api::object_ptr( can_manage_chat, can_change_info, can_post_messages, can_edit_messages, can_delete_messages, can_invite_users, can_restrict_members, can_pin_messages, can_manage_topics, can_promote_members, can_manage_video_chats, - is_anonymous); + can_post_stories, can_edit_stories, can_delete_stories, is_anonymous); } static auto target_chat_chosen(bool allow_users, bool allow_bots, bool allow_groups, bool allow_channels) { @@ -214,10 +221,22 @@ static auto bot_start_in_group(const td::string &bot_username, const td::string std::move(administrator_rights)); } +static auto business_chat(const td::string &link_name) { + return td::td_api::make_object(link_name); +} + +static auto buy_stars(td::int64 star_count, const td::string &purpose) { + return td::td_api::make_object(star_count, purpose); +} + static auto change_phone_number() { return td::td_api::make_object(); } +static auto chat_boost(const td::string &url) { + return td::td_api::make_object(url); +} + static auto chat_folder_invite(const td::string &slug) { return td::td_api::make_object("tg:addlist?slug=" + slug); } @@ -258,6 +277,10 @@ static auto language_settings() { return td::td_api::make_object(); } +static auto main_web_app(const td::string &bot_username, const td::string &start_parameter, bool is_compact) { + return td::td_api::make_object(bot_username, start_parameter, is_compact); +} + static auto message(const td::string &url) { return td::td_api::make_object(url); } @@ -282,6 +305,14 @@ static auto premium_features(const td::string &referrer) { return td::td_api::make_object(referrer); } +static auto premium_gift(const td::string &referrer) { + return td::td_api::make_object(referrer); +} + +static auto premium_gift_code(const td::string &code) { + return td::td_api::make_object(code); +} + static auto privacy_and_security_settings() { return td::td_api::make_object(); } @@ -297,8 +328,9 @@ static auto proxy_socks(const td::string &server, td::int32 port, const td::stri server, port, td::td_api::make_object(username, password)); } -static auto public_chat(const td::string &chat_username) { - return td::td_api::make_object(chat_username); +static auto public_chat(const td::string &chat_username, const td::string &draft_text = td::string(), + bool open_profile = false) { + return td::td_api::make_object(chat_username, draft_text, open_profile); } static auto qr_code_authentication() { @@ -317,6 +349,10 @@ static auto sticker_set(const td::string &sticker_set_name, bool expect_custom_e return td::td_api::make_object(sticker_set_name, expect_custom_emoji); } +static auto story(const td::string &sender_username, td::int32 story_id) { + return td::td_api::make_object(sender_username, story_id); +} + static auto theme(const td::string &theme_name) { return td::td_api::make_object(theme_name); } @@ -333,8 +369,10 @@ static auto unsupported_proxy() { return td::td_api::make_object(); } -static auto user_phone_number(const td::string &phone_number) { - return td::td_api::make_object(phone_number); +static auto user_phone_number(const td::string &phone_number, const td::string &draft_text = td::string(), + bool open_profile = false) { + return td::td_api::make_object('+' + phone_number, draft_text, + open_profile); } static auto user_token(const td::string &token) { @@ -346,8 +384,9 @@ static auto video_chat(const td::string &chat_username, const td::string &invite } static auto web_app(const td::string &bot_username, const td::string &web_app_short_name, - const td::string &start_parameter) { - return td::td_api::make_object(bot_username, web_app_short_name, start_parameter); + const td::string &start_parameter, bool is_compact) { + return td::td_api::make_object(bot_username, web_app_short_name, start_parameter, + is_compact); } TEST(Link, parse_internal_link_part1) { @@ -372,6 +411,29 @@ TEST(Link, parse_internal_link_part1) { parse_internal_link("t.m/levlam/1", nullptr); parse_internal_link("t.men/levlam/1", nullptr); + parse_internal_link("t.me/levlam?boos", public_chat("levlam")); + parse_internal_link("telegram.me/levlam?booster", public_chat("levlam")); + parse_internal_link("telegram.dog/levlam?boost", chat_boost("tg://boost?domain=levlam")); + parse_internal_link("www.t.me/levlam?boost", chat_boost("tg://boost?domain=levlam")); + parse_internal_link("t.me/c/l12345?boost", nullptr); + parse_internal_link("t.me/c/12345l5431?boost", chat_boost("tg://boost?channel=12345")); + parse_internal_link("t.me/c/12345?boost", chat_boost("tg://boost?channel=12345")); + parse_internal_link("t.me/c/123456789012?boost", chat_boost("tg://boost?channel=123456789012")); + parse_internal_link("t.me/c/123456789012?boost=12312&domain=123", chat_boost("tg://boost?channel=123456789012")); + + parse_internal_link("t.me/boost/s/12345", story("boost", 12345)); + parse_internal_link("t.me/boost/s", chat_boost("tg://boost?domain=s")); + parse_internal_link("t.me/boost/12", message("tg://resolve?domain=boost&post=12")); + parse_internal_link("t.me/boost?cc=1#c=1", public_chat("boost")); + parse_internal_link("t.me/boost?c=-1", public_chat("boost")); + parse_internal_link("t.me/boost?c=12telegram", chat_boost("tg://boost?channel=12")); + parse_internal_link("t.me/bOoSt?c=12telegram", chat_boost("tg://boost?channel=12")); + + parse_internal_link("tg:boost?domain=username/12345&single", chat_boost("tg://boost?domain=username%2F12345")); + parse_internal_link("tg:boost?domain=username&channel=12345", chat_boost("tg://boost?domain=username")); + parse_internal_link("tg:boost?channel=12345&domain=username", chat_boost("tg://boost?domain=username")); + parse_internal_link("tg:boost?channel=12345", chat_boost("tg://boost?channel=12345")); + parse_internal_link("tg:resolve?domain=username&post=12345&single", message("tg://resolve?domain=username&post=12345&single")); parse_internal_link("tg:resolve?domain=username&post=12345&single&startattach=1&attach=test", @@ -412,8 +474,11 @@ TEST(Link, parse_internal_link_part1) { attachment_menu_bot(nullptr, public_chat("telegram"), "test", "")); parse_internal_link("tg:resolve?domain=telegram&attach=test&startattach=1", attachment_menu_bot(nullptr, public_chat("telegram"), "test", "1")); + parse_internal_link("tg:resolve?domain=username&profile=12&asd", public_chat("username", "", true)); + parse_internal_link("tg:resolve?domain=username&profile&text=@asd", public_chat("username", " @asd", true)); parse_internal_link("tg:resolve?phone=1", user_phone_number("1")); + parse_internal_link("tg:resolve?phone=+1", user_phone_number("1")); parse_internal_link("tg:resolve?phone=123456", user_phone_number("123456")); parse_internal_link("tg:resolve?phone=123456&startattach", user_phone_number("123456")); parse_internal_link("tg:resolve?phone=123456&startattach=123", user_phone_number("123456")); @@ -422,6 +487,10 @@ TEST(Link, parse_internal_link_part1) { parse_internal_link("tg:resolve?phone=123456&attach=&startattach=123", user_phone_number("123456")); parse_internal_link("tg:resolve?phone=123456&attach=test", attachment_menu_bot(nullptr, user_phone_number("123456"), "test", "")); + parse_internal_link("tg:resolve?phone=+123456&attach=test", + attachment_menu_bot(nullptr, user_phone_number("123456"), "test", "")); + parse_internal_link("tg:resolve?phone=++123456&attach=test", + unknown_deep_link("tg://resolve?phone=++123456&attach=test")); parse_internal_link("tg:resolve?phone=123456&attach=test&startattach&choose=users", attachment_menu_bot(nullptr, user_phone_number("123456"), "test", "")); parse_internal_link("tg:resolve?phone=123456&attach=test&startattach=123", @@ -431,8 +500,16 @@ TEST(Link, parse_internal_link_part1) { parse_internal_link("tg:resolve?phone=012345678901234567890123456789123", unknown_deep_link("tg://resolve?phone=012345678901234567890123456789123")); parse_internal_link("tg:resolve?phone=", unknown_deep_link("tg://resolve?phone=")); - parse_internal_link("tg:resolve?phone=+123", unknown_deep_link("tg://resolve?phone=+123")); + parse_internal_link("tg:resolve?phone=+123", user_phone_number("123")); parse_internal_link("tg:resolve?phone=123456 ", unknown_deep_link("tg://resolve?phone=123456 ")); + parse_internal_link("tg:resolve?domain=telegram&text=asd", public_chat("telegram", "asd")); + parse_internal_link("tg:resolve?phone=12345678901&text=asd", user_phone_number("12345678901", "asd")); + parse_internal_link("tg:resolve?domain=telegram&text=@asd", public_chat("telegram", " @asd")); + parse_internal_link("tg:resolve?phone=12345678901&text=@asd", user_phone_number("12345678901", " @asd")); + parse_internal_link("tg:resolve?domain=telegram&text=1%A02", public_chat("telegram")); + parse_internal_link("tg:resolve?phone=12345678901&text=1%A02", user_phone_number("12345678901")); + parse_internal_link("tg:resolve?phone=123456&profile", user_phone_number("123456", "", true)); + parse_internal_link("tg:resolve?phone=123456&profile&text=@asd", user_phone_number("123456", " @asd", true)); parse_internal_link("tg:contact?token=1", user_token("1")); parse_internal_link("tg:contact?token=123456", user_token("123456")); @@ -487,6 +564,8 @@ TEST(Link, parse_internal_link_part1) { attachment_menu_bot(nullptr, public_chat("username"), "bot", "")); parse_internal_link("t.me/username?attach=bot&startattach=1&choose=users", attachment_menu_bot(nullptr, public_chat("username"), "bot", "1")); + parse_internal_link("t.me/username?asd&profile=12", public_chat("username", "", true)); + parse_internal_link("t.me/username?profile&text=@asd", public_chat("username", " @asd", true)); parse_internal_link("tg:privatepost?domain=username/12345&single", unknown_deep_link("tg://privatepost?domain=username/12345&single")); @@ -552,7 +631,7 @@ TEST(Link, parse_internal_link_part1) { parse_internal_link("t.me/bg/111111-222222%20?rotation=180%20", background("111111-222222%20?rotation=180%20")); parse_internal_link("t.me/bg/111111~222222", background("111111~222222")); parse_internal_link("t.me/bg/abacaba", background("abacaba")); - parse_internal_link("t.me/Bg/abacaba", web_app("Bg", "abacaba", "")); + parse_internal_link("t.me/Bg/abacaba", web_app("Bg", "abacaba", "", false)); parse_internal_link("t.me/bg/111111~222222#asdasd", background("111111~222222")); parse_internal_link("t.me/bg/111111~222222?mode=blur", background("111111~222222")); parse_internal_link("t.me/bg/111111~222222?mode=blur&text=1", background("111111~222222")); @@ -599,6 +678,42 @@ TEST(Link, parse_internal_link_part2) { parse_internal_link("tg:invoice?slug=abc%30ef", invoice("abc0ef")); parse_internal_link("tg://invoice?slug=", unknown_deep_link("tg://invoice?slug=")); + parse_internal_link("t.me/giftcode?slug=abcdef", nullptr); + parse_internal_link("t.me/giftcode", nullptr); + parse_internal_link("t.me/giftcode/", nullptr); + parse_internal_link("t.me/giftcode//abcdef", nullptr); + parse_internal_link("t.me/giftcode?/abcdef", nullptr); + parse_internal_link("t.me/giftcode/?abcdef", nullptr); + parse_internal_link("t.me/giftcode/#abcdef", nullptr); + parse_internal_link("t.me/giftcode/abacaba", premium_gift_code("abacaba")); + parse_internal_link("t.me/giftcode/aba%20aba", premium_gift_code("aba aba")); + parse_internal_link("t.me/giftcode/123456a", premium_gift_code("123456a")); + parse_internal_link("t.me/giftcode/12345678901", premium_gift_code("12345678901")); + parse_internal_link("t.me/giftcode/123456", premium_gift_code("123456")); + parse_internal_link("t.me/giftcode/123456/123123/12/31/a/s//21w/?asdas#test", premium_gift_code("123456")); + + parse_internal_link("tg:giftcode?slug=abcdef", premium_gift_code("abcdef")); + parse_internal_link("tg:giftcode?slug=abc%30ef", premium_gift_code("abc0ef")); + parse_internal_link("tg://giftcode?slug=", unknown_deep_link("tg://giftcode?slug=")); + + parse_internal_link("t.me/m?slug=abcdef", nullptr); + parse_internal_link("t.me/m", nullptr); + parse_internal_link("t.me/m/", nullptr); + parse_internal_link("t.me/m//abcdef", nullptr); + parse_internal_link("t.me/m?/abcdef", nullptr); + parse_internal_link("t.me/m/?abcdef", nullptr); + parse_internal_link("t.me/m/#abcdef", nullptr); + parse_internal_link("t.me/m/abacaba", business_chat("abacaba")); + parse_internal_link("t.me/m/aba%20aba", business_chat("aba aba")); + parse_internal_link("t.me/m/123456a", business_chat("123456a")); + parse_internal_link("t.me/m/12345678901", business_chat("12345678901")); + parse_internal_link("t.me/m/123456", business_chat("123456")); + parse_internal_link("t.me/m/123456/123123/12/31/a/s//21w/?asdas#test", business_chat("123456")); + + parse_internal_link("tg:message?slug=abcdef", business_chat("abcdef")); + parse_internal_link("tg:message?slug=abc%30ef", business_chat("abc0ef")); + parse_internal_link("tg://message?slug=", unknown_deep_link("tg://message?slug=")); + parse_internal_link("tg:share?url=google.com&text=text#asdasd", message_draft("google.com\ntext", true)); parse_internal_link("tg:share?url=google.com&text=", message_draft("google.com", false)); parse_internal_link("tg:share?url=&text=google.com", message_draft("google.com", false)); @@ -702,10 +817,19 @@ TEST(Link, parse_internal_link_part2) { parse_internal_link("t.me/+123456?attach=&startattach", user_phone_number("123456")); parse_internal_link("t.me/+123456?attach=&startattach=1", user_phone_number("123456")); parse_internal_link("t.me/+123456?attach=bot", attachment_menu_bot(nullptr, user_phone_number("123456"), "bot", "")); - parse_internal_link("t.me/+123456?attach=bot&startattach", + parse_internal_link("t.me/+123456?attach=bot&startattach&profile", attachment_menu_bot(nullptr, user_phone_number("123456"), "bot", "")); parse_internal_link("t.me/+123456?attach=bot&startattach=1", attachment_menu_bot(nullptr, user_phone_number("123456"), "bot", "1")); + parse_internal_link("t.me/+123456?profile", user_phone_number("123456", "", true)); + parse_internal_link("t.me/+123456?profile&text=@asd", user_phone_number("123456", " @asd", true)); + + parse_internal_link("telegram.t.me?text=asd", public_chat("telegram", "asd")); + parse_internal_link("t.me/%2012345678901?text=asd", user_phone_number("12345678901", "asd")); + parse_internal_link("t.me/telegram?text=@asd", public_chat("telegram", " @asd")); + parse_internal_link("t.me/%2012345678901?text=@asd", user_phone_number("12345678901", " @asd")); + parse_internal_link("t.me/telegram?text=1%A02", public_chat("telegram")); + parse_internal_link("t.me/%2012345678901?text=1%A02", user_phone_number("12345678901")); parse_internal_link("t.me/addlist?invite=abcdef", nullptr); parse_internal_link("t.me/addlist", nullptr); @@ -965,25 +1089,26 @@ TEST(Link, parse_internal_link_part3) { parse_internal_link("tg:resolve?domain=username&startgroup=1&admin=delete_messages+anonymous", bot_start_in_group("username", "1", chat_administrator_rights(true, false, false, false, true, false, false, false, - false, false, false, true))); + false, false, false, false, false, false, true))); parse_internal_link( "tg:resolve?domain=username&startgroup&admin=manage_chat+change_info+post_messages+edit_messages+delete_messages+" - "invite_users+restrict_members+pin_messages+manage_topics+promote_members+manage_video_chats+anonymous", - bot_start_in_group( - "username", "", - chat_administrator_rights(true, true, false, false, true, true, true, true, true, true, true, true))); + "invite_users+restrict_members+pin_messages+manage_topics+promote_members+manage_video_chats+post_stories+edit_" + "stories+delete_stories+anonymous", + bot_start_in_group("username", "", + chat_administrator_rights(true, true, false, false, true, true, true, true, true, true, true, + true, true, true, true))); parse_internal_link("tg:resolve?domain=username&startchannel", public_chat("username")); parse_internal_link("tg:resolve?domain=username&startchannel&admin=", public_chat("username")); parse_internal_link( "tg:resolve?domain=username&startchannel&admin=post_messages", bot_add_to_channel("username", chat_administrator_rights(true, false, true, false, false, false, true, false, - false, false, false, false))); + false, false, false, false, false, false, false))); parse_internal_link( "tg:resolve?domain=username&startchannel&admin=manage_chat+change_info+post_messages+edit_messages+delete_" "messages+invite_users+restrict_members+pin_messages+manage_topics+promote_members+manage_video_chats+anonymous", bot_add_to_channel("username", chat_administrator_rights(true, true, true, true, true, true, true, false, false, - true, true, false))); + true, true, false, false, false, false))); parse_internal_link("t.me/username/0/a//s/as?startgroup=", bot_start_in_group("username", "", nullptr)); parse_internal_link("t.me/username/aasdas/2?test=1&startgroup=#12312", bot_start_in_group("username", "", nullptr)); @@ -1001,27 +1126,29 @@ TEST(Link, parse_internal_link_part3) { parse_internal_link("t.me/username?startgroup=1&admin=delete_messages+anonymous", bot_start_in_group("username", "1", chat_administrator_rights(true, false, false, false, true, false, false, false, - false, false, false, true))); + false, false, false, false, false, false, true))); parse_internal_link( "t.me/" "username?startgroup&admin=manage_chat+change_info+post_messages+edit_messages+delete_messages+invite_users+" - "restrict_members+pin_messages+manage_topics+promote_members+manage_video_chats+anonymous", - bot_start_in_group( - "username", "", - chat_administrator_rights(true, true, false, false, true, true, true, true, true, true, true, true))); + "restrict_members+pin_messages+manage_topics+promote_members+manage_video_chats+post_stories+edit_stories+delete_" + "stories+anonymous", + bot_start_in_group("username", "", + chat_administrator_rights(true, true, false, false, true, true, true, true, true, true, true, + true, true, true, true))); parse_internal_link("t.me/username?startchannel", public_chat("username")); parse_internal_link("t.me/username?startchannel&admin=", public_chat("username")); parse_internal_link( "t.me/username?startchannel&admin=post_messages", bot_add_to_channel("username", chat_administrator_rights(true, false, true, false, false, false, true, false, - false, false, false, false))); + false, false, false, false, false, false, false))); parse_internal_link( "t.me/" "username?startchannel&admin=manage_chat+change_info+post_messages+edit_messages+delete_messages+invite_users+" - "restrict_members+pin_messages+manage_topics+promote_members+manage_video_chats+anonymous", + "restrict_members+pin_messages+manage_topics+promote_members+manage_video_chats+post_stories+edit_stories+delete_" + "stories+anonymous", bot_add_to_channel("username", chat_administrator_rights(true, true, true, true, true, true, true, false, false, - true, true, false))); + true, true, true, true, true, false))); } TEST(Link, parse_internal_link_part4) { @@ -1046,8 +1173,33 @@ TEST(Link, parse_internal_link_part4) { parse_internal_link("t.me//username?game=asd", nullptr); parse_internal_link("https://telegram.dog/tele%63ram?game=t%63st", game("telecram", "tcst")); + parse_internal_link("tg:resolve?domain=username&story=123", story("username", 123)); + parse_internal_link("TG://resolve?domain=username&story=", public_chat("username")); + parse_internal_link("TG://resolve?domain=username&story=0", public_chat("username")); + parse_internal_link("TG://resolve?domain=username&story=-1", public_chat("username")); + parse_internal_link("TG://test@resolve?domain=username&story=1", nullptr); + parse_internal_link("tg:resolve:80?domain=username&story=1", nullptr); + parse_internal_link("tg:http://resolve?domain=username&story=1", nullptr); + parse_internal_link("tg:https://resolve?domain=username&story=1", nullptr); + parse_internal_link("tg:resolve?domain=&story=1", unknown_deep_link("tg://resolve?domain=&story=1")); + parse_internal_link("tg:resolve?domain=telegram&&&&&&&story=%30", public_chat("telegram")); + parse_internal_link("tg:resolve?domain=telegram&&&&&&&story=%31", story("telegram", 1)); + parse_internal_link("tg:resolve?domain=telegram&&&&&&&story=%31ab", public_chat("telegram")); + parse_internal_link("tg:resolve?domain=telegram&&&&&&&story=%31%39", story("telegram", 19)); + parse_internal_link("tg:resolve?domain=telegram&&&&&&&story=2222222222", public_chat("telegram")); + + parse_internal_link("t.me/username/s/1234", story("username", 1234)); + parse_internal_link("t.me/username/s/3?qwe=12312#12312", story("username", 3)); + parse_internal_link("t.me/username/s/1", story("username", 1)); + parse_internal_link("t.me/username/s/2", story("username", 2)); + parse_internal_link("t.me/username/s/5", story("username", 5)); + parse_internal_link("t.me/username/s/", public_chat("username")); + parse_internal_link("t.me/username#/s/123", public_chat("username")); + parse_internal_link("t.me/username?story=123", public_chat("username")); + parse_internal_link("https://telegram.dog/tele%63ram/s/%31%39", story("telecram", 19)); + parse_internal_link("tg:resolve?domain=username&appname=aasdasd&startapp=123asd", - web_app("username", "aasdasd", "123asd")); + web_app("username", "aasdasd", "123asd", false)); parse_internal_link("TG://resolve?domain=username&appname=&startapp=123asd", public_chat("username")); parse_internal_link("TG://test@resolve?domain=username&appname=asd", nullptr); parse_internal_link("tg:resolve:80?domain=username&appname=asd", nullptr); @@ -1056,7 +1208,10 @@ TEST(Link, parse_internal_link_part4) { parse_internal_link("tg:resolve?domain=&appname=asd", unknown_deep_link("tg://resolve?domain=&appname=asd")); parse_internal_link("tg:resolve?domain=telegram&&&&&&&appname=%41&startapp=", public_chat("telegram")); parse_internal_link("tg:resolve?domain=telegram&&&&&&&appname=%41b&startapp=", public_chat("telegram")); - parse_internal_link("tg:resolve?domain=telegram&&&&&&&appname=%41bc&startapp=", web_app("telegram", "Abc", "")); + parse_internal_link("tg:resolve?domain=telegram&&&&&&&appname=%41bc&startapp=", + web_app("telegram", "Abc", "", false)); + parse_internal_link("tg:resolve?domain=telegram&&&&&&&appname=%41bc&startapp=&mode=compact", + web_app("telegram", "Abc", "", true)); parse_internal_link("t.me/username/0/a//s/as?appname=asd", public_chat("username")); parse_internal_link("t.me/username/aasdas/2?test=1&appname=asd#12312", public_chat("username")); @@ -1068,12 +1223,35 @@ TEST(Link, parse_internal_link_part4) { parse_internal_link("t.me//username?appname=asd", nullptr); parse_internal_link("https://telegram.dog/tele%63ram?appname=t%63st", public_chat("telecram")); parse_internal_link("t.me/username/def/asd", public_chat("username")); - parse_internal_link("t.me/username/asd#12312&startapp=qwe", web_app("username", "asd", "")); - parse_internal_link("t.me/username/asd?12312&startapp=qwe", web_app("username", "asd", "qwe")); - parse_internal_link("t.me/username/asdasd?startapp=0", web_app("username", "asdasd", "0")); - parse_internal_link("t.me/username/asd", web_app("username", "asd", "")); + parse_internal_link("t.me/username/asd#12312&startapp=qwe", web_app("username", "asd", "", false)); + parse_internal_link("t.me/username/asd?12312&startapp=qwe&mode=compac", web_app("username", "asd", "qwe", false)); + parse_internal_link("t.me/username/asd?12312&startapp=qwe&mode=compact", web_app("username", "asd", "qwe", true)); + parse_internal_link("t.me/username/asdasd?startapp=0", web_app("username", "asdasd", "0", false)); + parse_internal_link("t.me/username/asd", web_app("username", "asd", "", false)); parse_internal_link("t.me/username/", public_chat("username")); - parse_internal_link("https://telegram.dog/tele%63ram/t%63st", web_app("telecram", "tcst", "")); + parse_internal_link("https://telegram.dog/tele%63ram/t%63st", web_app("telecram", "tcst", "", false)); + parse_internal_link("https://telegram.dog/tele%63ram/t%63st?mode=compact", web_app("telecram", "tcst", "", true)); + + parse_internal_link("tg:resolve?domain=username&startapp=aasdasd", main_web_app("username", "aasdasd", false)); + parse_internal_link("TG://resolve?domain=username&startapp=&startapp=123asd", main_web_app("username", "", false)); + parse_internal_link("TG://test@resolve?domain=username&startapp=asd", nullptr); + parse_internal_link("tg:resolve:80?domain=username&startapp=asd", nullptr); + parse_internal_link("tg:http://resolve?domain=username&startapp=asd", nullptr); + parse_internal_link("tg:https://resolve?domain=username&startapp=asd", nullptr); + parse_internal_link("tg:resolve?domain=&startapp=asd", unknown_deep_link("tg://resolve?domain=&startapp=asd")); + parse_internal_link("tg:resolve?domain=telegram&&&&&&&startapp=%41", main_web_app("telegram", "A", false)); + parse_internal_link("tg:resolve?domain=telegram&&&&&&&startapp=%41b", main_web_app("telegram", "Ab", false)); + parse_internal_link("tg:resolve?domain=telegram&&&&&&&startapp=%41bc", main_web_app("telegram", "Abc", false)); + parse_internal_link("tg:resolve?domain=telegram&&mode=compact&&&&&&startapp=%41bc", + main_web_app("telegram", "Abc", true)); + + parse_internal_link("t.me/username?startapp=qwe", main_web_app("username", "qwe", false)); + parse_internal_link("t.me/username?12312&startapp=qwe", main_web_app("username", "qwe", false)); + parse_internal_link("t.me/username?startapp=0", main_web_app("username", "0", false)); + parse_internal_link("https://telegram.dog/tele%63ram?startapp=t%63st", main_web_app("telecram", "tcst", false)); + parse_internal_link("https://telegram.dog/tele%63ram?startapp=t%63st&mode=%63ompact", + main_web_app("telecram", "tcst", true)); + parse_internal_link("https://telegram.dog?startapp=t%63st", nullptr); parse_internal_link("tg:resolve?domain=username&Game=asd", public_chat("username")); parse_internal_link("TG://test@resolve?domain=username", nullptr); @@ -1129,6 +1307,10 @@ TEST(Link, parse_internal_link_part4) { parse_internal_link("tg:premium_offer?ref=abc%30ef", premium_features("abc0ef")); parse_internal_link("tg://premium_offer?ref=", premium_features("")); + parse_internal_link("tg:premium_multigift?ref=abcdef", premium_gift("abcdef")); + parse_internal_link("tg:premium_multigift?ref=abc%30ef", premium_gift("abc0ef")); + parse_internal_link("tg://premium_multigift?ref=", premium_gift("")); + parse_internal_link("tg://settings", settings()); parse_internal_link("tg://setting", unknown_deep_link("tg://setting")); parse_internal_link("tg://settings?asdsa?D?SADasD?asD", settings()); @@ -1150,6 +1332,12 @@ TEST(Link, parse_internal_link_part4) { parse_internal_link("tg://settings/language", language_settings()); parse_internal_link("tg://settings/privacy", privacy_and_security_settings()); + parse_internal_link("tg://stars_topup", unknown_deep_link("tg://stars_topup")); + parse_internal_link("tg://stars_topup?balance=", unknown_deep_link("tg://stars_topup?balance=")); + parse_internal_link("tg://stars_topup?balance=test", buy_stars(1, "")); + parse_internal_link("tg://stars_topup?balance=10&purpose=%30test", buy_stars(10, "0test")); + parse_internal_link("tg://stars_topup?balance=100000000000&purpose=subs", buy_stars(100000000000, "subs")); + parse_internal_link("username.t.me////0/a//s/as?start=", bot_start("username", "")); parse_internal_link("username.t.me?start=as", bot_start("username", "as")); parse_internal_link("username.t.me", public_chat("username")); @@ -1162,15 +1350,24 @@ TEST(Link, parse_internal_link_part4) { parse_internal_link("aaa_.t.me/12345?single", nullptr); parse_internal_link("0aaa.t.me/12345?single", nullptr); parse_internal_link("_aaa.t.me/12345?single", nullptr); + parse_internal_link("a.t.me", nullptr); + parse_internal_link("b.t.me", nullptr); + parse_internal_link("k.t.me", nullptr); + parse_internal_link("z.t.me", nullptr); + parse_internal_link("web.t.me", nullptr); parse_internal_link("addemoji.t.me", nullptr); parse_internal_link("addlist.t.me", nullptr); parse_internal_link("addstickers.t.me", nullptr); parse_internal_link("addtheme.t.me", nullptr); parse_internal_link("auth.t.me", nullptr); + parse_internal_link("boost.t.me", nullptr); parse_internal_link("confirmphone.t.me", nullptr); + parse_internal_link("contact.t.me", nullptr); + parse_internal_link("giftcode.t.me", nullptr); parse_internal_link("invoice.t.me", nullptr); parse_internal_link("joinchat.t.me", nullptr); parse_internal_link("login.t.me", nullptr); + parse_internal_link("m.t.me", nullptr); parse_internal_link("proxy.t.me", nullptr); parse_internal_link("setlanguage.t.me", nullptr); parse_internal_link("share.t.me", nullptr); diff --git a/protocols/Telegram/tdlib/td/test/main.cpp b/protocols/Telegram/tdlib/td/test/main.cpp index 9a774b37db..6cd81fd421 100644 --- a/protocols/Telegram/tdlib/td/test/main.cpp +++ b/protocols/Telegram/tdlib/td/test/main.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/protocols/Telegram/tdlib/td/test/message_entities.cpp b/protocols/Telegram/tdlib/td/test/message_entities.cpp index 378e76b23a..64cd7dcca9 100644 --- a/protocols/Telegram/tdlib/td/test/message_entities.cpp +++ b/protocols/Telegram/tdlib/td/test/message_entities.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -29,7 +29,7 @@ static void check_mention(const td::string &str, const td::vector &e result.push_back(it.str()); } if (result != expected) { - LOG(FATAL) << td::tag("text", str) << td::tag("got", td::format::as_array(result)) + LOG(FATAL) << td::tag("text", str) << td::tag("receive", td::format::as_array(result)) << td::tag("expected", td::format::as_array(expected)); } } @@ -60,7 +60,7 @@ static void check_bot_command(const td::string &str, const td::vector &e result.push_back(it.str()); } if (result != expected) { - LOG(FATAL) << td::tag("text", str) << td::tag("got", td::format::as_array(result)) + LOG(FATAL) << td::tag("text", str) << td::tag("receive", td::format::as_array(result)) << td::tag("expected", td::format::as_array(expected)); } } @@ -128,7 +128,7 @@ static void check_cashtag(const td::string &str, const td::vector &e result.push_back(it.str()); } if (result != expected) { - LOG(FATAL) << td::tag("text", str) << td::tag("got", td::format::as_array(result)) + LOG(FATAL) << td::tag("text", str) << td::tag("receive", td::format::as_array(result)) << td::tag("expected", td::format::as_array(expected)); } } @@ -190,7 +190,7 @@ static void check_media_timestamp(const td::string &str, const td::vector &ex result.push_back(it.str()); } if (result != expected) { - LOG(FATAL) << td::tag("text", str) << td::tag("got", td::format::as_array(result)) + LOG(FATAL) << td::tag("text", str) << td::tag("receive", td::format::as_array(result)) << td::tag("expected", td::format::as_array(expected)); } } @@ -464,11 +464,11 @@ static void check_url(const td::string &str, const td::vector &expec } } if (result_urls != expected_urls) { - LOG(FATAL) << td::tag("text", str) << td::tag("got", td::format::as_array(result_urls)) + LOG(FATAL) << td::tag("text", str) << td::tag("receive", td::format::as_array(result_urls)) << td::tag("expected", td::format::as_array(expected_urls)); } if (result_email_addresses != expected_email_addresses) { - LOG(FATAL) << td::tag("text", str) << td::tag("got", td::format::as_array(result_email_addresses)) + LOG(FATAL) << td::tag("text", str) << td::tag("receive", td::format::as_array(result_email_addresses)) << td::tag("expected", td::format::as_array(expected_email_addresses)); } } @@ -501,6 +501,10 @@ TEST(MessageEntities, url) { check_url("ftp://telegram.org", {"ftp://telegram.org"}); check_url("ftps://telegram.org", {}); check_url("sftp://telegram.org", {}); + check_url("tonsite://telegram.ton", {"tonsite://telegram.ton"}); + check_url("telegram.ton", {"telegram.ton"}); + check_url("telegram.onion", {"telegram.onion"}); + check_url("telegram.tonsite", {}); check_url("hTtPs://telegram.org", {"hTtPs://telegram.org"}); check_url("HTTP://telegram.org", {"HTTP://telegram.org"}); check_url("аHTTP://telegram.org", {"HTTP://telegram.org"}); @@ -787,17 +791,13 @@ TEST(MessageEntities, fix_formatted_text) { entities.emplace_back(td::MessageEntity::Type::Bold, 0, i); td::vector fixed_entities; - if (i != 33) { - fixed_entities.emplace_back(td::MessageEntity::Type::Bold, 32, i - 33); - } + fixed_entities.emplace_back(td::MessageEntity::Type::Bold, 0, i - 1 /* deleted \r */); check_fix_formatted_text(str, entities, fixed_str, fixed_entities, true, false, false, true); - td::string expected_str; + td::string expected_str = fixed_str.substr(0, 33); if (i != 33) { - fixed_entities.back().offset = 0; - fixed_entities.back().length = 1; + fixed_entities.back().length = 33; } - expected_str = "a"; check_fix_formatted_text(str, entities, expected_str, fixed_entities, false, false, false, false); } @@ -809,8 +809,13 @@ TEST(MessageEntities, fix_formatted_text) { check_fix_formatted_text(str, entities, true, true, true, true); check_fix_formatted_text(str, entities, false, false, false, false); } else { - check_fix_formatted_text(str, entities, str, {}, true, true, true, true); - check_fix_formatted_text(str, entities, str.substr(0, str.size() - 2), {}, false, false, false, false); + check_fix_formatted_text(str, entities, str, {{td::MessageEntity::Type::Bold, i, 1}}, true, true, true, true); + if (i == 2) { + check_fix_formatted_text(str, entities, str.substr(0, str.size() - 2), {{td::MessageEntity::Type::Bold, i, 1}}, + false, false, false, false); + } else { + check_fix_formatted_text(str, entities, str.substr(0, str.size() - 2), {}, false, false, false, false); + } } } @@ -850,18 +855,9 @@ TEST(MessageEntities, fix_formatted_text) { fixed_str = skip_trim ? "aba \n caba " : "aba \n caba"; auto fixed_length = offset <= 4 && offset + length >= 5 ? length - 1 : length; auto fixed_offset = offset >= 5 ? offset - 1 : offset; - if (static_cast(fixed_offset) >= fixed_str.size()) { - fixed_length = 0; - } while (static_cast(fixed_offset + fixed_length) > fixed_str.size()) { fixed_length--; } - if (type == td::MessageEntity::Type::Bold || type == td::MessageEntity::Type::Url) { - while (fixed_length > 0 && (fixed_str[fixed_offset] == ' ' || fixed_str[fixed_offset] == '\n')) { - fixed_offset++; - fixed_length--; - } - } td::vector entities; entities.emplace_back(type, offset, length); @@ -872,17 +868,11 @@ TEST(MessageEntities, fix_formatted_text) { } td::vector fixed_entities; if (fixed_length > 0) { - for (auto i = 0; i < length; i++) { - if (!td::is_space(str[offset + i]) || type == td::MessageEntity::Type::TextUrl || - type == td::MessageEntity::Type::MentionName) { - fixed_entities.emplace_back(type, fixed_offset, fixed_length); - if (type == td::MessageEntity::Type::TextUrl) { - fixed_entities.back().argument = "t.me"; - } else if (type == td::MessageEntity::Type::MentionName) { - fixed_entities.back().user_id = user_id; - } - break; - } + fixed_entities.emplace_back(type, fixed_offset, fixed_length); + if (type == td::MessageEntity::Type::TextUrl) { + fixed_entities.back().argument = "t.me"; + } else if (type == td::MessageEntity::Type::MentionName) { + fixed_entities.back().user_id = user_id; } } check_fix_formatted_text(str, entities, fixed_str, fixed_entities, true, false, false, skip_trim); @@ -904,13 +894,7 @@ TEST(MessageEntities, fix_formatted_text) { td::vector fixed_entities; if (length > 0) { - if (offset == 3) { - if (length >= 2) { - fixed_entities.emplace_back(td::MessageEntity::Type::Bold, offset + 1, length - 1); - } - } else { - fixed_entities.emplace_back(td::MessageEntity::Type::Bold, offset, length); - } + fixed_entities.emplace_back(td::MessageEntity::Type::Bold, offset, length); } check_fix_formatted_text(str, entities, str, fixed_entities, true, false, false, false); @@ -958,6 +942,9 @@ TEST(MessageEntities, fix_formatted_text) { if (i < 4) { fixed_entities.emplace_back(td::MessageEntity::Type::Bold, i * 3, 2); } + if (i < 3) { + fixed_entities.emplace_back(td::MessageEntity::Type::Italic, i * 3 + 2, 1); + } } check_fix_formatted_text(str, entities, td::utf8_utf16_substr(str, 3, 11).str(), fixed_entities, false, false, @@ -974,10 +961,10 @@ TEST(MessageEntities, fix_formatted_text) { check_fix_formatted_text("a \r", {{td::MessageEntity::Type::Bold, 0, 3}, {td::MessageEntity::Type::Underline, 2, 1}}, "a ", {{td::MessageEntity::Type::Bold, 0, 2}}, true, false, false, true); check_fix_formatted_text("a \r ", {{td::MessageEntity::Type::Bold, 0, 4}, {td::MessageEntity::Type::Underline, 2, 1}}, - "a ", {{td::MessageEntity::Type::Bold, 0, 2}}, true, false, false, true); - check_fix_formatted_text( - "a \r b", {{td::MessageEntity::Type::Bold, 0, 5}, {td::MessageEntity::Type::Underline, 2, 1}}, "a b", - {{td::MessageEntity::Type::Bold, 0, 2}, {td::MessageEntity::Type::Bold, 3, 1}}, true, false, false, true); + "a ", {{td::MessageEntity::Type::Bold, 0, 3}}, true, false, false, true); + check_fix_formatted_text("a \r b", + {{td::MessageEntity::Type::Bold, 0, 5}, {td::MessageEntity::Type::Underline, 2, 1}}, "a b", + {{td::MessageEntity::Type::Bold, 0, 4}}, true, false, false, true); check_fix_formatted_text("a\rbc\r", {{td::MessageEntity::Type::Italic, 0, 1}, @@ -1014,6 +1001,7 @@ TEST(MessageEntities, fix_formatted_text) { check_fix_formatted_text("@tests @tests", {{td::MessageEntity::Type::Italic, 0, 13}}, "@tests @tests", {{td::MessageEntity::Type::Mention, 0, 6}, {td::MessageEntity::Type::Italic, 0, 6}, + {td::MessageEntity::Type::Italic, 6, 1}, {td::MessageEntity::Type::Mention, 7, 6}, {td::MessageEntity::Type::Italic, 7, 6}}); @@ -1113,7 +1101,7 @@ TEST(MessageEntities, fix_formatted_text) { check_fix_formatted_text("example.com a", {{td::MessageEntity::Type::Italic, 0, 13}}, "example.com a", {{td::MessageEntity::Type::Url, 0, 11}, {td::MessageEntity::Type::Italic, 0, 11}, - {td::MessageEntity::Type::Italic, 12, 1}}); + {td::MessageEntity::Type::Italic, 11, 2}}); check_fix_formatted_text("a example.com", {{td::MessageEntity::Type::Italic, 0, 13}}, "a example.com", {{td::MessageEntity::Type::Italic, 0, 2}, {td::MessageEntity::Type::Url, 2, 11}, @@ -1134,7 +1122,7 @@ TEST(MessageEntities, fix_formatted_text) { auto n = td::Random::fast(1, 20); td::vector entities; for (int j = 0; j < n; j++) { - td::int32 type = td::Random::fast(4, 16); + td::int32 type = td::Random::fast(4, static_cast(td::MessageEntity::Type::Size) - 1); td::int32 offset = td::Random::fast(0, static_cast(str.size()) - 1); auto max_length = static_cast(str.size() - offset); if ((test_n & 1) != 0 && max_length > 4) { @@ -1156,7 +1144,7 @@ TEST(MessageEntities, fix_formatted_text) { auto old_type_mask = get_type_mask(str.size(), entities); ASSERT_TRUE(td::fix_formatted_text(str, entities, false, false, true, true, false).is_ok()); auto new_type_mask = get_type_mask(str.size(), entities); - auto splittable_mask = (1 << 5) | (1 << 6) | (1 << 14) | (1 << 15); + auto splittable_mask = (1 << 5) | (1 << 6) | (1 << 14) | (1 << 15) | (1 << 19); auto pre_mask = (1 << 7) | (1 << 8) | (1 << 9); for (std::size_t pos = 0; pos < str.size(); pos++) { if ((new_type_mask[pos] & pre_mask) != 0) { @@ -1176,7 +1164,9 @@ TEST(MessageEntities, fix_formatted_text) { if (keep_url && ((1 << static_cast(entity.type)) & splittable_mask) == 0 && !(end <= url_offset || url_end <= offset)) { - keep_url = (entity.type == td::MessageEntity::Type::BlockQuote && offset <= url_offset && url_end <= end); + keep_url = ((entity.type == td::MessageEntity::Type::BlockQuote || + entity.type == td::MessageEntity::Type::ExpandableBlockQuote) && + offset <= url_offset && url_end <= end); } } ASSERT_EQ(keep_url, std::count(entities.begin(), entities.end(), url_entity) == 1); @@ -1199,7 +1189,8 @@ TEST(MessageEntities, fix_formatted_text) { // pre can't contain other entities ASSERT_TRUE((type_mask & pre_mask) == 0); - if ((type_mask & splittable_mask) == 0 && entities[i].type != td::MessageEntity::Type::BlockQuote) { + if ((type_mask & splittable_mask) == 0 && entities[i].type != td::MessageEntity::Type::BlockQuote && + entities[i].type != td::MessageEntity::Type::ExpandableBlockQuote) { // continuous entities can contain only splittable entities ASSERT_TRUE(((1 << static_cast(entities[j].type)) & splittable_mask) != 0); } @@ -1217,6 +1208,24 @@ TEST(MessageEntities, fix_formatted_text) { {}); } +TEST(MessageEntities, is_visible_url) { + td::string str = "a telegram.org telegran.org telegrao.org telegram.orc telegrap.org c"; + td::vector entities; + entities.emplace_back(td::MessageEntity::Type::TextUrl, 0, 1, "telegrab.org"); + entities.emplace_back(td::MessageEntity::Type::TextUrl, static_cast(str.size()) - 1, 1, "telegrax.org"); + td::fix_formatted_text(str, entities, false, false, false, false, true).ensure(); + td::FormattedText text{std::move(str), std::move(entities)}; + ASSERT_EQ(td::get_first_url(text), "telegrab.org"); + ASSERT_TRUE(!td::is_visible_url(text, "telegrab.org")); + ASSERT_TRUE(td::is_visible_url(text, "telegram.org")); + ASSERT_TRUE(td::is_visible_url(text, "telegran.org")); + ASSERT_TRUE(td::is_visible_url(text, "telegrao.org")); + ASSERT_TRUE(!td::is_visible_url(text, "telegram.orc")); + ASSERT_TRUE(td::is_visible_url(text, "telegrap.org")); + ASSERT_TRUE(!td::is_visible_url(text, "telegraf.org")); + ASSERT_TRUE(!td::is_visible_url(text, "telegrax.org")); +} + static void check_parse_html(td::string text, const td::string &result, const td::vector &entities) { auto r_entities = td::parse_html(text); ASSERT_TRUE(r_entities.is_ok()); @@ -1241,8 +1250,7 @@ TEST(MessageEntities, parse_html) { check_parse_html("🏟 🏟<", "Unsupported start tag \"abac\" at byte offset 13"); check_parse_html("🏟 🏟<", "Unsupported start tag \"abac\" at byte offset 13"); check_parse_html("🏟 🏟<", "Empty attribute name in the tag \"i\" at byte offset 13"); - check_parse_html("🏟 🏟<", - "Expected equal sign in declaration of an attribute of the tag \"i\" at byte offset 13"); + check_parse_html("🏟 🏟<", "Can't find end tag corresponding to start tag \"i\""); check_parse_html("🏟 🏟<", "Unclosed start tag at byte offset 13"); @@ -1265,6 +1273,7 @@ TEST(MessageEntities, parse_html) { check_parse_html("➡️ ➡️➡️ ➡️", "➡️ ➡️➡️ ➡️", {{td::MessageEntity::Type::Strikethrough, 5, 5}}); check_parse_html("➡️ ➡️➡️ ➡️", "➡️ ➡️➡️ ➡️", {{td::MessageEntity::Type::Strikethrough, 5, 5}}); check_parse_html("➡️ ➡️➡️ ➡️", "➡️ ➡️➡️ ➡️", {{td::MessageEntity::Type::Strikethrough, 5, 5}}); + check_parse_html("➡️ ➡️
➡️ ➡️
", "➡️ ➡️➡️ ➡️", {{td::MessageEntity::Type::BlockQuote, 5, 5}}); check_parse_html("➡️ ➡️➡️ ➡️➡️ ➡️", "➡️ ➡️➡️ ➡️➡️ ➡️", {{td::MessageEntity::Type::Italic, 5, 5}, {td::MessageEntity::Type::Bold, 10, 5}}); check_parse_html("🏟 🏟🏟 <🏟", "🏟 🏟🏟 <🏟", {{td::MessageEntity::Type::Italic, 5, 6}}); @@ -1349,11 +1358,22 @@ TEST(MessageEntities, parse_html) { check_parse_html("🏟 🏟🏟1", "🏟 🏟🏟1", {{td::MessageEntity::Type::Bold, 5, 3}, {td::MessageEntity::Type::CustomEmoji, 5, 2, td::CustomEmojiId(static_cast(1))}}); + check_parse_html("
a<
b;", "aa<
b;", "aa<
b;", "aa<
b;", "a &entities) {
   auto r_entities = td::parse_markdown_v2(text);
+  if (r_entities.is_error()) {
+    LOG(ERROR) << r_entities.error();
+  }
   ASSERT_TRUE(r_entities.is_ok());
   ASSERT_EQ(entities, r_entities.ok());
   ASSERT_STREQ(result, text);
@@ -1368,7 +1388,7 @@ static void check_parse_markdown(td::string text, td::Slice error_message) {
 
 TEST(MessageEntities, parse_markdown) {
   td::Slice reserved_characters("]()>#+-=|{}.!");
-  td::Slice begin_characters("_*[~`");
+  td::Slice begin_characters("_*[~`>");
   for (char c = 1; c < 126; c++) {
     if (begin_characters.find(c) != td::Slice::npos) {
       continue;
@@ -1405,6 +1425,7 @@ TEST(MessageEntities, parse_markdown) {
   check_parse_markdown("🏟 🏟__", "Can't find end of Underline entity at byte offset 9");
   check_parse_markdown("🏟 🏟||test\\|", "Can't find end of Spoiler entity at byte offset 9");
   check_parse_markdown("🏟 🏟!", "Character '!' is reserved and must be escaped with the preceding '\\'");
+  check_parse_markdown("🏟 🏟>", "Character '>' is reserved and must be escaped with the preceding '\\'");
   check_parse_markdown("🏟 🏟![", "Can't find end of CustomEmoji entity at byte offset 9");
   check_parse_markdown("🏟 🏟![👍", "Can't find end of CustomEmoji entity at byte offset 9");
   check_parse_markdown("🏟 🏟![👍]", "Custom emoji entity must contain a tg://emoji URL");
@@ -1414,6 +1435,12 @@ TEST(MessageEntities, parse_markdown) {
   check_parse_markdown("🏟 🏟![👍](tg://emoji#test)", "Custom emoji URL must have an emoji identifier");
   check_parse_markdown("🏟 🏟![👍](tg://emoji?test=1#&id=25)", "Custom emoji URL must have an emoji identifier");
   check_parse_markdown("🏟 🏟![👍](tg://emoji?test=1231&id=025)", "Invalid custom emoji identifier specified");
+  check_parse_markdown(">*b\n>ld \n>bo\nld*\nasd\ndef", "Can't find end of Bold entity at byte offset 1");
+  check_parse_markdown(">\n*a*>2", "Character '>' is reserved and must be escaped with the preceding '\\'");
+  check_parse_markdown(">asd\n>q||e||w||\n||asdad", "Can't find end of Spoiler entity at byte offset 16");
+  check_parse_markdown(">asd\n>q||ew\n||asdad", "Can't find end of Spoiler entity at byte offset 7");
+  check_parse_markdown(">asd\n>q||e||w__\n||asdad", "Can't find end of Underline entity at byte offset 13");
+  check_parse_markdown(">asd\n>q||e||w||a\n||asdad", "Can't find end of Spoiler entity at byte offset 13");
 
   check_parse_markdown("", "", {});
   check_parse_markdown("\\\\", "\\", {});
@@ -1478,6 +1505,71 @@ TEST(MessageEntities, parse_markdown) {
                        {{0, 12, td::UserId(static_cast(123456))}});
   check_parse_markdown("🏟 🏟![👍](TG://EMoJI/?test=1231&id=25#id=32)a", "🏟 🏟👍a",
                        {{td::MessageEntity::Type::CustomEmoji, 5, 2, td::CustomEmojiId(static_cast(25))}});
+  check_parse_markdown("> \n> \n>", " \n \n", {{td::MessageEntity::Type::BlockQuote, 0, 4}});
+  check_parse_markdown("> \\>\n \\> \n>", " >\n > \n", {{td::MessageEntity::Type::BlockQuote, 0, 3}});
+  check_parse_markdown("abc\n> \n> \n>\ndef", "abc\n \n \n\ndef", {{td::MessageEntity::Type::BlockQuote, 4, 5}});
+  check_parse_markdown(">", "", {});
+  check_parse_markdown(">a", "a", {{td::MessageEntity::Type::BlockQuote, 0, 1}});
+  check_parse_markdown("\r>a", "\ra", {{td::MessageEntity::Type::BlockQuote, 1, 1}});
+  check_parse_markdown("\r\r>\r\ra\r\n\r", "\r\r\r\ra\r\n\r", {{td::MessageEntity::Type::BlockQuote, 2, 5}});
+  check_parse_markdown(
+      ">*bold _italic bold ~italic bold strikethrough ||italic bold strikethrough spoiler||~ __underline italic "
+      "bold___ bold*",
+      "bold italic bold italic bold strikethrough italic bold strikethrough spoiler underline italic bold bold",
+      {{td::MessageEntity::Type::BlockQuote, 0, 103},
+       {td::MessageEntity::Type::Bold, 0, 103},
+       {td::MessageEntity::Type::Italic, 5, 93},
+       {td::MessageEntity::Type::Strikethrough, 17, 59},
+       {td::MessageEntity::Type::Spoiler, 43, 33},
+       {td::MessageEntity::Type::Underline, 77, 21}});
+  check_parse_markdown(">*b\n>ld \n>bo\n>ld*\nasd\ndef", "b\nld \nbo\nld\nasd\ndef",
+                       {{td::MessageEntity::Type::BlockQuote, 0, 12}, {td::MessageEntity::Type::Bold, 0, 11}});
+  check_parse_markdown("*a\n>b\n>ld \n>bo\n>ld\nasd*\ndef", "a\nb\nld \nbo\nld\nasd\ndef",
+                       {{td::MessageEntity::Type::Bold, 0, 17}, {td::MessageEntity::Type::BlockQuote, 2, 12}});
+  check_parse_markdown(">`b\n>ld \n>bo\nld`\n>asd\ndef", "b\n>ld \n>bo\nld\nasd\ndef",
+                       {{td::MessageEntity::Type::BlockQuote, 0, 18}, {td::MessageEntity::Type::Code, 0, 13}});
+  check_parse_markdown("`>b\n>ld \n>bo\nld`\n>asd\ndef", ">b\n>ld \n>bo\nld\nasd\ndef",
+                       {{td::MessageEntity::Type::Code, 0, 14}, {td::MessageEntity::Type::BlockQuote, 15, 4}});
+  check_parse_markdown(">1", "1", {{td::MessageEntity::Type::BlockQuote, 0, 1}});
+  check_parse_markdown(">\n1", "\n1", {{td::MessageEntity::Type::BlockQuote, 0, 1}});
+  check_parse_markdown(">\n\r>2", "\n\r2",
+                       {{td::MessageEntity::Type::BlockQuote, 0, 1}, {td::MessageEntity::Type::BlockQuote, 2, 1}});
+  check_parse_markdown(">\n**>2", "\n2",
+                       {{td::MessageEntity::Type::BlockQuote, 0, 1}, {td::MessageEntity::Type::BlockQuote, 1, 1}});
+  check_parse_markdown(">**\n>2", "\n2", {{td::MessageEntity::Type::BlockQuote, 0, 2}});
+  // check_parse_markdown("*>abcd*", "abcd",
+  //                      {{td::MessageEntity::Type::BlockQuote, 0, 4}, {td::MessageEntity::Type::Bold, 0, 4}});
+  check_parse_markdown(">*abcd*", "abcd",
+                       {{td::MessageEntity::Type::BlockQuote, 0, 4}, {td::MessageEntity::Type::Bold, 0, 4}});
+  // check_parse_markdown(">*abcd\n*", "abcd\n",
+  //                      {{td::MessageEntity::Type::BlockQuote, 0, 5}, {td::MessageEntity::Type::Bold, 0, 5}});
+  check_parse_markdown(">*abcd*\n", "abcd\n",
+                       {{td::MessageEntity::Type::BlockQuote, 0, 5}, {td::MessageEntity::Type::Bold, 0, 4}});
+  check_parse_markdown("*>abcd\n*", "abcd\n",
+                       {{td::MessageEntity::Type::BlockQuote, 0, 5}, {td::MessageEntity::Type::Bold, 0, 5}});
+  check_parse_markdown("abc\n>def\n>def\n\r>ghi2\njkl", "abc\ndef\ndef\n\rghi2\njkl",
+                       {{td::MessageEntity::Type::BlockQuote, 4, 8}, {td::MessageEntity::Type::BlockQuote, 13, 5}});
+  check_parse_markdown(
+      ">asd\n>q||e||w||\nasdad", "asd\nqew\nasdad",
+      {{td::MessageEntity::Type::ExpandableBlockQuote, 0, 8}, {td::MessageEntity::Type::Spoiler, 5, 1}});
+  check_parse_markdown(">asd\n>q||ew||\nasdad", "asd\nqew\nasdad",
+                       {{td::MessageEntity::Type::BlockQuote, 0, 8}, {td::MessageEntity::Type::Spoiler, 5, 2}});
+  check_parse_markdown(
+      ">asd\r\n>q||e||w||\r\nasdad", "asd\r\nqew\r\nasdad",
+      {{td::MessageEntity::Type::ExpandableBlockQuote, 0, 10}, {td::MessageEntity::Type::Spoiler, 6, 1}});
+  check_parse_markdown(">asd\r\n>q||ew||\r\nasdad", "asd\r\nqew\r\nasdad",
+                       {{td::MessageEntity::Type::BlockQuote, 0, 10}, {td::MessageEntity::Type::Spoiler, 6, 2}});
+  check_parse_markdown(
+      ">asd\r\n>q||e||w||\r\n", "asd\r\nqew\r\n",
+      {{td::MessageEntity::Type::ExpandableBlockQuote, 0, 10}, {td::MessageEntity::Type::Spoiler, 6, 1}});
+  check_parse_markdown(">asd\r\n>q||ew||\r\n", "asd\r\nqew\r\n",
+                       {{td::MessageEntity::Type::BlockQuote, 0, 10}, {td::MessageEntity::Type::Spoiler, 6, 2}});
+  check_parse_markdown(
+      ">asd\r\n>q||e||w||", "asd\r\nqew",
+      {{td::MessageEntity::Type::ExpandableBlockQuote, 0, 8}, {td::MessageEntity::Type::Spoiler, 6, 1}});
+  check_parse_markdown(">asd\r\n>q||ew||", "asd\r\nqew",
+                       {{td::MessageEntity::Type::BlockQuote, 0, 8}, {td::MessageEntity::Type::Spoiler, 6, 2}});
+  check_parse_markdown(">||", "", {});
 }
 
 static void check_parse_markdown_v3(td::string text, td::vector entities,
@@ -1628,8 +1720,8 @@ TEST(MessageEntities, parse_markdown_v3) {
 
   check_parse_markdown_v3("__ __", " ", {{td::MessageEntity::Type::Italic, 0, 1}});
   check_parse_markdown_v3("__\n__", "\n", {{td::MessageEntity::Type::Italic, 0, 1}});
-  check_parse_markdown_v3("__ __a", " a", {}, true);
-  check_parse_markdown_v3("__\n__a", "\na", {}, true);
+  check_parse_markdown_v3("__ __a", " a", {{td::MessageEntity::Type::Italic, 0, 1}}, true);
+  check_parse_markdown_v3("__\n__a", "\na", {{td::MessageEntity::Type::Italic, 0, 1}}, true);
   check_parse_markdown_v3("**** __a__ **b** ~~c~~ ||d||", "**** a b c d",
                           {{td::MessageEntity::Type::Italic, 5, 1},
                            {td::MessageEntity::Type::Bold, 7, 1},
@@ -1764,9 +1856,10 @@ TEST(MessageEntities, parse_markdown_v3) {
   check_parse_markdown_v3(
       "__italic__ ~~strikethrough~~ **bold** `code` ```pre``` __[italic__ text_url](telegram.org) __italic**bold "
       "italic__bold**__italic__ ~~strikethrough~~ **bold** `code` ```pre``` __[italic__ text_url](telegram.org) "
-      "__italic**bold italic__bold** ||spoiler||",
+      "__italic**bold italic__bold** ||spoiler|| ```pre\nprecode``` init",
+      {{td::MessageEntity::Type::Italic, 271, 4}},
       "italic strikethrough bold code pre italic text_url italicbold italicbolditalic strikethrough bold code pre "
-      "italic text_url italicbold italicbold spoiler",
+      "italic text_url italicbold italicbold spoiler precode init",
       {{td::MessageEntity::Type::Italic, 0, 6},
        {td::MessageEntity::Type::Strikethrough, 7, 13},
        {td::MessageEntity::Type::Bold, 21, 4},
@@ -1785,14 +1878,31 @@ TEST(MessageEntities, parse_markdown_v3) {
        {td::MessageEntity::Type::Italic, 107, 6},
        {td::MessageEntity::Type::Italic, 123, 17},
        {td::MessageEntity::Type::Bold, 129, 15},
-       {td::MessageEntity::Type::Spoiler, 145, 7}});
+       {td::MessageEntity::Type::Spoiler, 145, 7},
+       {td::MessageEntity::Type::PreCode, 153, 7, "pre"},
+       {td::MessageEntity::Type::Italic, 161, 4}});
+  check_parse_markdown_v3("```\nsome code\n```", "some code\n", {{td::MessageEntity::Type::Pre, 0, 10}});
+  check_parse_markdown_v3("asd\n```\nsome code\n```cabab", "asd\nsome code\ncabab",
+                          {{td::MessageEntity::Type::Pre, 4, 10}});
+  check_parse_markdown_v3("asd\naba```\nsome code\n```cabab", "asd\nabasome code\ncabab",
+                          {{td::MessageEntity::Type::Pre, 7, 10}});
+  check_parse_markdown_v3("asd\naba```\nsome code\n```\ncabab", "asd\nabasome code\n\ncabab",
+                          {{td::MessageEntity::Type::Pre, 7, 10}});
+  check_parse_markdown_v3("asd\naba```a b\nsome code\n```\ncabab", "asd\nabaa b\nsome code\n\ncabab",
+                          {{td::MessageEntity::Type::Pre, 7, 14}});
+  check_parse_markdown_v3("asd\naba```a!@#$%^&*(b\nsome code\n```\ncabab", "asd\nabasome code\n\ncabab",
+                          {{td::MessageEntity::Type::PreCode, 7, 10, "a!@#$%^&*(b"}});
+  check_parse_markdown_v3("```aba\n```", "aba\n", {{td::MessageEntity::Type::Pre, 0, 4}});
+  check_parse_markdown_v3("```\n```", "\n", {{td::MessageEntity::Type::Pre, 0, 1}});
+  check_parse_markdown_v3("```\n```", {{td::MessageEntity::Type::BlockQuote, 0, 7}}, "\n",
+                          {{td::MessageEntity::Type::BlockQuote, 0, 1}, {td::MessageEntity::Type::Pre, 0, 1}});
 
   td::vector parts{"a", " #test__a", "__", "**", "~~", "||", "[", "](t.me)", "`"};
   td::vector types{
       td::MessageEntity::Type::Bold,          td::MessageEntity::Type::Italic,  td::MessageEntity::Type::Underline,
       td::MessageEntity::Type::Strikethrough, td::MessageEntity::Type::Spoiler, td::MessageEntity::Type::Code,
       td::MessageEntity::Type::Pre,           td::MessageEntity::Type::PreCode, td::MessageEntity::Type::TextUrl,
-      td::MessageEntity::Type::MentionName,   td::MessageEntity::Type::Cashtag};
+      td::MessageEntity::Type::MentionName,   td::MessageEntity::Type::Cashtag, td::MessageEntity::Type::BlockQuote};
   for (size_t test_n = 0; test_n < 1000; test_n++) {
     td::string str;
     int part_n = td::Random::fast(1, 200);
@@ -1836,7 +1946,7 @@ static void check_get_markdown_v3(const td::string &result_text, const td::vecto
 }
 
 TEST(MessageEntities, get_markdown_v3) {
-  check_get_markdown_v3("``` ```", {}, " ", {{td::MessageEntity::Type::Pre, 0, 1}});
+  check_get_markdown_v3("```\n ```", {}, " ", {{td::MessageEntity::Type::Pre, 0, 1}});
   check_get_markdown_v3("` `", {}, " ", {{td::MessageEntity::Type::Code, 0, 1}});
   check_get_markdown_v3("`\n`", {}, "\n", {{td::MessageEntity::Type::Code, 0, 1}});
   check_get_markdown_v3("ab", {{td::MessageEntity::Type::Code, 0, 1}, {td::MessageEntity::Type::Pre, 1, 1}}, "ab",
@@ -1851,16 +1961,18 @@ TEST(MessageEntities, get_markdown_v3) {
   check_get_markdown_v3("** **", {}, " ", {{td::MessageEntity::Type::Bold, 0, 1}});
   check_get_markdown_v3("~~ ~~", {}, " ", {{td::MessageEntity::Type::Strikethrough, 0, 1}});
   check_get_markdown_v3("|| ||", {}, " ", {{td::MessageEntity::Type::Spoiler, 0, 1}});
-  check_get_markdown_v3("__a__ **b** ~~c~~ ||d|| e", {{td::MessageEntity::Type::PreCode, 24, 1, "C++"}}, "a b c d e",
+  check_get_markdown_v3("__a__ **b** ~~c~~ ||d|| e", {{td::MessageEntity::Type::PreCode, 24, 1, " C++"}}, "a b c d e",
                         {{td::MessageEntity::Type::Italic, 0, 1},
                          {td::MessageEntity::Type::Bold, 2, 1},
                          {td::MessageEntity::Type::Strikethrough, 4, 1},
                          {td::MessageEntity::Type::Spoiler, 6, 1},
-                         {td::MessageEntity::Type::PreCode, 8, 1, "C++"}});
-  check_get_markdown_v3("`ab` ```cd``` ef", {{td::MessageEntity::Type::PreCode, 14, 2, "C++"}}, "ab cd ef",
-                        {{td::MessageEntity::Type::Code, 0, 2},
-                         {td::MessageEntity::Type::Pre, 3, 2},
-                         {td::MessageEntity::Type::PreCode, 6, 2, "C++"}});
+                         {td::MessageEntity::Type::PreCode, 8, 1, " C++"}});
+  check_get_markdown_v3("```cpp\ngh```\n`ab`\n```\ncd```\nef", {{td::MessageEntity::Type::PreCode, 28, 2, " C++"}},
+                        "gh\nab\ncd\nef",
+                        {{td::MessageEntity::Type::PreCode, 0, 2, "cpp"},
+                         {td::MessageEntity::Type::Code, 3, 2},
+                         {td::MessageEntity::Type::Pre, 6, 2},
+                         {td::MessageEntity::Type::PreCode, 9, 2, " C++"}});
   check_get_markdown_v3("__asd__[__ab__cd](http://t.me/)", {}, "asdabcd",
                         {{td::MessageEntity::Type::Italic, 0, 3},
                          {td::MessageEntity::Type::TextUrl, 3, 4, "http://t.me/"},
@@ -1879,4 +1991,19 @@ TEST(MessageEntities, get_markdown_v3) {
                         {{td::MessageEntity::Type::TextUrl, 0, 16, "http://example.com/"},
                          {td::MessageEntity::Type::Bold, 0, 16},
                          {td::MessageEntity::Type::Italic, 0, 16}});
+  check_get_markdown_v3("```\nsome code\n```", {}, "some code\n", {{td::MessageEntity::Type::Pre, 0, 10}});
+  check_get_markdown_v3("asd\n```\nsome code\n```cabab", {}, "asd\nsome code\ncabab",
+                        {{td::MessageEntity::Type::Pre, 4, 10}});
+  check_get_markdown_v3("asd\naba```\nsome code\n```cabab", {}, "asd\nabasome code\ncabab",
+                        {{td::MessageEntity::Type::Pre, 7, 10}});
+  check_get_markdown_v3("asd\naba```\nsome code\n```\ncabab", {}, "asd\nabasome code\n\ncabab",
+                        {{td::MessageEntity::Type::Pre, 7, 10}});
+  check_get_markdown_v3("asd\naba```\na b\nsome code\n```\ncabab", {}, "asd\nabaa b\nsome code\n\ncabab",
+                        {{td::MessageEntity::Type::Pre, 7, 14}});
+  check_get_markdown_v3("asd\n```\na b\nsome code\n```\ncabab", {}, "asd\na b\nsome code\n\ncabab",
+                        {{td::MessageEntity::Type::Pre, 4, 14}});
+  check_get_markdown_v3("asd\naba```a!@#$%^&*(b\nsome code\n```\ncabab", {}, "asd\nabasome code\n\ncabab",
+                        {{td::MessageEntity::Type::PreCode, 7, 10, "a!@#$%^&*(b"}});
+  check_get_markdown_v3("```\naba\n```", {}, "aba\n", {{td::MessageEntity::Type::Pre, 0, 4}});
+  check_get_markdown_v3("```\n```", {}, "\n", {{td::MessageEntity::Type::Pre, 0, 1}});
 }
diff --git a/protocols/Telegram/tdlib/td/test/mtproto.cpp b/protocols/Telegram/tdlib/td/test/mtproto.cpp
index 614e153e6f..72d1af5d73 100644
--- a/protocols/Telegram/tdlib/td/test/mtproto.cpp
+++ b/protocols/Telegram/tdlib/td/test/mtproto.cpp
@@ -1,14 +1,13 @@
 //
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 //
 #include "td/telegram/ConfigManager.h"
-#include "td/telegram/net/DcId.h"
-#include "td/telegram/net/PublicRsaKeyShared.h"
-#include "td/telegram/net/Session.h"
+#include "td/telegram/net/PublicRsaKeySharedMain.h"
 #include "td/telegram/NotificationManager.h"
+#include "td/telegram/telegram_api.h"
 
 #include "td/mtproto/AuthData.h"
 #include "td/mtproto/DhCallback.h"
@@ -34,6 +33,7 @@
 #include "td/utils/BufferedFd.h"
 #include "td/utils/common.h"
 #include "td/utils/crypto.h"
+#include "td/utils/HttpDate.h"
 #include "td/utils/logging.h"
 #include "td/utils/port/Clocks.h"
 #include "td/utils/port/IPAddress.h"
@@ -46,6 +46,8 @@
 #include "td/utils/tests.h"
 #include "td/utils/Time.h"
 
+#include 
+
 TEST(Mtproto, GetHostByNameActor) {
   int threads_n = 1;
   td::ConcurrentScheduler sched(threads_n, 0);
@@ -194,7 +196,7 @@ TEST(Mtproto, encrypted_config) {
       "FnWWdEV+BPJeOTk+ARHcNkuJBt0CqnfcVCoDOpKqGyq0U31s2MOpQvHgAG+Tlpg02syuH0E4dCGRw5CbJPARiynteb9y5fT5x/"
       "kmdp6BMR5tWQSQF0liH16zLh8BDSIdiMsikdcwnAvBwdNhRqQBqGx9MTh62MDmlebjtczE9Gz0z5cscUO2yhzGdphgIy6SP+"
       "bwaqLWYF0XdPGjKLMUEJW+rou6fbL1t/EUXPtU0XmQAnO0Fh86h+AqDMOe30N4qKrPQ==   ";
-  auto config = td::decode_config(data).move_as_ok();
+  td::telegram_api::object_ptr config = td::decode_config(data).move_as_ok();
 }
 
 class TestPingActor final : public td::Actor {
@@ -300,11 +302,11 @@ class HandshakeContext final : public td::mtproto::AuthKeyHandshakeContext {
     return nullptr;
   }
   td::mtproto::PublicRsaKeyInterface *get_public_rsa_key_interface() final {
-    return &public_rsa_key;
+    return public_rsa_key_.get();
   }
 
  private:
-  td::PublicRsaKeyShared public_rsa_key{td::DcId::empty(), true};
+  std::shared_ptr public_rsa_key_ = td::PublicRsaKeySharedMain::create(true);
 };
 
 class HandshakeTestActor final : public td::Actor {
@@ -365,11 +367,11 @@ class HandshakeTestActor final : public td::Actor {
           10.0,
           td::PromiseCreator::lambda(
               [actor_id = actor_id(this)](td::Result> raw_connection) {
-                td::send_closure(actor_id, &HandshakeTestActor::got_connection, std::move(raw_connection), 1);
+                td::send_closure(actor_id, &HandshakeTestActor::on_connection, std::move(raw_connection), 1);
               }),
           td::PromiseCreator::lambda(
               [actor_id = actor_id(this)](td::Result> handshake) {
-                td::send_closure(actor_id, &HandshakeTestActor::got_handshake, std::move(handshake), 1);
+                td::send_closure(actor_id, &HandshakeTestActor::on_handshake, std::move(handshake), 1);
               }))
           .release();
       wait_for_raw_connection_ = true;
@@ -377,7 +379,7 @@ class HandshakeTestActor final : public td::Actor {
     }
   }
 
-  void got_connection(td::Result> r_raw_connection, bool dummy) {
+  void on_connection(td::Result> r_raw_connection, bool dummy) {
     CHECK(wait_for_raw_connection_);
     wait_for_raw_connection_ = false;
     if (r_raw_connection.is_ok()) {
@@ -390,7 +392,7 @@ class HandshakeTestActor final : public td::Actor {
     loop();
   }
 
-  void got_handshake(td::Result> r_handshake, bool dummy) {
+  void on_handshake(td::Result> r_handshake, bool dummy) {
     CHECK(wait_for_handshake_);
     wait_for_handshake_ = false;
     CHECK(r_handshake.is_ok());
@@ -553,16 +555,16 @@ class FastPingTestActor final : public td::Actor {
         "HandshakeActor", std::move(handshake), std::move(raw_connection), td::make_unique(), 10.0,
         td::PromiseCreator::lambda(
             [actor_id = actor_id(this)](td::Result> raw_connection) {
-              td::send_closure(actor_id, &FastPingTestActor::got_connection, std::move(raw_connection), 1);
+              td::send_closure(actor_id, &FastPingTestActor::on_connection, std::move(raw_connection), 1);
             }),
         td::PromiseCreator::lambda(
             [actor_id = actor_id(this)](td::Result> handshake) {
-              td::send_closure(actor_id, &FastPingTestActor::got_handshake, std::move(handshake), 1);
+              td::send_closure(actor_id, &FastPingTestActor::on_handshake, std::move(handshake), 1);
             }))
         .release();
   }
 
-  void got_connection(td::Result> r_raw_connection, bool dummy) {
+  void on_connection(td::Result> r_raw_connection, bool dummy) {
     if (r_raw_connection.is_error()) {
       *result_ = r_raw_connection.move_as_error();
       LOG(INFO) << "Receive " << *result_ << " instead of a connection";
@@ -572,7 +574,7 @@ class FastPingTestActor final : public td::Actor {
     loop();
   }
 
-  void got_handshake(td::Result> r_handshake, bool dummy) {
+  void on_handshake(td::Result> r_handshake, bool dummy) {
     if (r_handshake.is_error()) {
       *result_ = r_handshake.move_as_error();
       LOG(INFO) << "Receive " << *result_ << " instead of a handshake";
@@ -582,7 +584,7 @@ class FastPingTestActor final : public td::Actor {
     loop();
   }
 
-  void got_raw_connection(td::Result> r_connection) {
+  void on_raw_connection(td::Result> r_connection) {
     if (r_connection.is_error()) {
       *result_ = r_connection.move_as_error();
       LOG(INFO) << "Receive " << *result_ << " instead of a handshake";
@@ -619,7 +621,7 @@ class FastPingTestActor final : public td::Actor {
           td::Slice(), std::move(connection_), std::move(auth_data),
           td::PromiseCreator::lambda(
               [actor_id = actor_id(this)](td::Result> r_raw_connection) {
-                td::send_closure(actor_id, &FastPingTestActor::got_raw_connection, std::move(r_raw_connection));
+                td::send_closure(actor_id, &FastPingTestActor::on_raw_connection, std::move(r_raw_connection));
               }),
           td::ActorShared<>());
     }
diff --git a/protocols/Telegram/tdlib/td/test/online.cpp b/protocols/Telegram/tdlib/td/test/online.cpp
index de7afa8a66..db5faa8771 100644
--- a/protocols/Telegram/tdlib/td/test/online.cpp
+++ b/protocols/Telegram/tdlib/td/test/online.cpp
@@ -1,5 +1,5 @@
 //
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -224,7 +224,9 @@ class InitTask : public Task {
 
   void start_up() override {
     send_query(td::make_tl_object("version"),
-               [](auto res) { LOG(INFO) << td::td_api::to_string(res.ok()); });
+               [](td::Result> res) {
+                 LOG(INFO) << td::td_api::to_string(res.ok());
+               });
   }
   void process_authorization_state(td::tl_object_ptr authorization_state) {
     td::tl_object_ptr function;
@@ -244,7 +246,6 @@ class InitTask : public Task {
         request->system_language_code_ = "en";
         request->device_model_ = "Desktop";
         request->application_version_ = "tdclient-test";
-        request->enable_storage_optimizer_ = true;
         send(std::move(request));
         break;
       }
@@ -258,7 +259,7 @@ class InitTask : public Task {
   }
   template 
   void send(T &&query) {
-    send_query(std::move(query), [this](auto res) {
+    send_query(std::move(query), [this](td::Result res) {
       if (is_alive()) {
         res.ensure();
       }
@@ -284,7 +285,9 @@ class GetMe : public Task {
   explicit GetMe(Promise promise) : promise_(std::move(promise)) {
   }
   void start_up() override {
-    send_query(td::make_tl_object(), [this](auto res) { with_user_id(res.move_as_ok()->id_); });
+    send_query(
+        td::make_tl_object(),
+        [this](td::Result> res) { with_user_id(res.move_as_ok()->id_); });
   }
 
  private:
@@ -293,8 +296,9 @@ class GetMe : public Task {
 
   void with_user_id(int64 user_id) {
     result_.user_id = user_id;
-    send_query(td::make_tl_object(user_id, false),
-               [this](auto res) { with_chat_id(res.move_as_ok()->id_); });
+    send_query(
+        td::make_tl_object(user_id, false),
+        [this](td::Result> res) { with_chat_id(res.move_as_ok()->id_); });
   }
 
   void with_chat_id(int64 chat_id) {
@@ -333,11 +337,11 @@ class UploadFile : public Task {
     write_file(content_path_, content_).ensure();
 
     send_query(td::make_tl_object(
-                   chat_id_, 0, 0, nullptr, nullptr,
+                   chat_id_, 0, nullptr, nullptr, nullptr,
                    td::make_tl_object(
                        td::make_tl_object(content_path_), nullptr, true,
                        td::make_tl_object("tag", td::Auto()))),
-               [this](auto res) { with_message(res.move_as_ok()); });
+               [this](td::Result> res) { with_message(res.move_as_ok()); });
   }
 
  private:
@@ -393,7 +397,7 @@ class TestDownloadFile : public Task {
   }
   void start_up() override {
     send_query(td::make_tl_object(remote_id_, nullptr),
-               [this](auto res) { start_file(*res.ok()); });
+               [this](td::Result> res) { start_file(*res.ok()); });
   }
 
  private:
@@ -455,7 +459,7 @@ class TestDownloadFile : public Task {
     send_query(td::make_tl_object(
                    file_id_, 1, static_cast(ranges_.back().begin),
                    static_cast(ranges_.back().end - ranges_.back().begin), true),
-               [this](auto res) { on_get_chunk(*res.ok()); });
+               [this](td::Result> res) { on_get_chunk(*res.ok()); });
   }
 };
 
diff --git a/protocols/Telegram/tdlib/td/test/poll.cpp b/protocols/Telegram/tdlib/td/test/poll.cpp
index 3629c3c136..757d9c0eda 100644
--- a/protocols/Telegram/tdlib/td/test/poll.cpp
+++ b/protocols/Telegram/tdlib/td/test/poll.cpp
@@ -1,5 +1,5 @@
 //
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
diff --git a/protocols/Telegram/tdlib/td/test/query_merger.cpp b/protocols/Telegram/tdlib/td/test/query_merger.cpp
index becac44e65..1211407082 100644
--- a/protocols/Telegram/tdlib/td/test/query_merger.cpp
+++ b/protocols/Telegram/tdlib/td/test/query_merger.cpp
@@ -1,5 +1,5 @@
 //
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -70,7 +70,8 @@ class TestQueryMerger final : public td::Actor {
                                 } else {
                                   yield();
                                 }
-                              }));
+                              }),
+                              "TestQueryMerger::loop");
     }
   }
 
diff --git a/protocols/Telegram/tdlib/td/test/secret.cpp b/protocols/Telegram/tdlib/td/test/secret.cpp
index bd54705695..48523ec27b 100644
--- a/protocols/Telegram/tdlib/td/test/secret.cpp
+++ b/protocols/Telegram/tdlib/td/test/secret.cpp
@@ -1,5 +1,5 @@
 //
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -9,8 +9,11 @@
 #include "td/telegram/Global.h"
 #include "td/telegram/logevent/LogEvent.h"
 #include "td/telegram/MessageId.h"
+#include "td/telegram/net/NetQuery.h"
+#include "td/telegram/net/NetQueryCreator.h"
 #include "td/telegram/secret_api.h"
 #include "td/telegram/SecretChatActor.h"
+#include "td/telegram/SecretChatDb.h"
 #include "td/telegram/SecretChatId.h"
 #include "td/telegram/telegram_api.h"
 #include "td/telegram/UserId.h"
@@ -66,7 +69,7 @@ class messages_getDhConfig {
 
   messages_getDhConfig() = default;
 
-  messages_getDhConfig(int32 version_, int32 random_length_);
+  messages_getDhConfig(int32 version, int32 random_length);
 
   static const int32 ID = 651135312;
 
@@ -225,8 +228,8 @@ class messages_dhConfig final {
 
   messages_dhConfig() = default;
 
-  messages_dhConfig(int32 g_, BufferSlice &&p_, int32 version_, BufferSlice &&random_)
-      : g_(g_), p_(std::move(p_)), version_(version_), random_(std::move(random_)) {
+  messages_dhConfig(int32 g, BufferSlice &&p, int32 version, BufferSlice &&random)
+      : g_(g), p_(std::move(p)), version_(version), random_(std::move(random)) {
   }
 
   static const int32 ID = 740433629;
@@ -249,6 +252,7 @@ class messages_dhConfig final {
     TlStoreString::store(random_, s);
   }
 };
+const int32 messages_dhConfig::ID;
 
 class encryptedChat final {
  public:
@@ -262,15 +266,15 @@ class encryptedChat final {
 
   encryptedChat() = default;
 
-  encryptedChat(int32 id_, int64 access_hash_, int32 date_, int64 admin_id_, int64 participant_id_,
-                BufferSlice &&g_a_or_b_, int64 key_fingerprint_)
-      : id_(id_)
-      , access_hash_(access_hash_)
-      , date_(date_)
-      , admin_id_(admin_id_)
-      , participant_id_(participant_id_)
-      , g_a_or_b_(std::move(g_a_or_b_))
-      , key_fingerprint_(key_fingerprint_) {
+  encryptedChat(int32 id, int64 access_hash, int32 date, int64 admin_id, int64 participant_id, BufferSlice &&g_a_or_b,
+                int64 key_fingerprint)
+      : id_(id)
+      , access_hash_(access_hash)
+      , date_(date)
+      , admin_id_(admin_id)
+      , participant_id_(participant_id)
+      , g_a_or_b_(std::move(g_a_or_b))
+      , key_fingerprint_(key_fingerprint) {
   }
 
   static const int32 ID = -94974410;
@@ -300,6 +304,7 @@ class encryptedChat final {
     TlStoreBinary::store(key_fingerprint_, s);
   }
 };
+const int32 encryptedChat::ID;
 
 class messages_sentEncryptedMessage final {
  public:
@@ -307,7 +312,7 @@ class messages_sentEncryptedMessage final {
 
   messages_sentEncryptedMessage() = default;
 
-  explicit messages_sentEncryptedMessage(int32 date_) : date_(date_) {
+  explicit messages_sentEncryptedMessage(int32 date) : date_(date) {
   }
 
   static const int32 ID = 1443858741;
@@ -361,7 +366,7 @@ class FakeBinlog final
   FakeBinlog() {
     register_actor("FakeBinlog", this).release();
   }
-  void force_sync(Promise<> promise) final {
+  void force_sync(Promise<> promise, const char *source) final {
     if (pending_events_.empty()) {
       pending_events_.emplace_back();
     }
@@ -527,7 +532,7 @@ class FakeSecretChatContext final : public SecretChatActor::Context {
     return false;
   }
 
-  // We don't want to expose the whole NetQueryDispatcher, MessagesManager and ContactsManager.
+  // We don't want to expose the whole NetQueryDispatcher, MessagesManager and UserManager.
   // So it is more clear which parts of MessagesManager is really used. And it is much easier to create tests.
   void send_net_query(NetQueryPtr query, ActorShared callback, bool ordered) final;
 
@@ -636,7 +641,7 @@ class Master final : public Actor {
       if (binlog_generation != binlog_generation_) {
         return promise.set_error(Status::Error("Binlog generation mismatch"));
       }
-      binlog_->force_sync(std::move(promise));
+      binlog_->force_sync(std::move(promise), "sync_binlog");
     }
     void on_closed() {
       LOG(INFO) << "CLOSED";
diff --git a/protocols/Telegram/tdlib/td/test/secure_storage.cpp b/protocols/Telegram/tdlib/td/test/secure_storage.cpp
index 714e92f77a..e115e751b8 100644
--- a/protocols/Telegram/tdlib/td/test/secure_storage.cpp
+++ b/protocols/Telegram/tdlib/td/test/secure_storage.cpp
@@ -1,5 +1,5 @@
 //
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
diff --git a/protocols/Telegram/tdlib/td/test/set_with_position.cpp b/protocols/Telegram/tdlib/td/test/set_with_position.cpp
index f8494b392b..ca2742f8ce 100644
--- a/protocols/Telegram/tdlib/td/test/set_with_position.cpp
+++ b/protocols/Telegram/tdlib/td/test/set_with_position.cpp
@@ -1,5 +1,5 @@
 //
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
diff --git a/protocols/Telegram/tdlib/td/test/string_cleaning.cpp b/protocols/Telegram/tdlib/td/test/string_cleaning.cpp
index c597d7616c..a1bb9e989b 100644
--- a/protocols/Telegram/tdlib/td/test/string_cleaning.cpp
+++ b/protocols/Telegram/tdlib/td/test/string_cleaning.cpp
@@ -1,5 +1,5 @@
 //
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -112,4 +112,8 @@ TEST(StringCleaning, strip_empty_characters) {
   check_strip_empty_characters(
       "\xe2\x80\xa7\xe2\x80\xa8\xe2\x80\xa9\xe2\x80\xaa\xe2\x80\xab\xe2\x80\xac\xe2\x80\xad\xe2\x80\xae", 3,
       "\xe2\x80\xa7\xe2\x80\xa8\xe2\x80\xa9");
+  check_strip_empty_characters(
+      "\xF3\x9F\xBF\xBF\xF3\xA0\x80\x80\xF3\xA0\x80\x81\xF3\xA0\x80\xBF\xF3\xA0\x81\x80\xF3\xA0\x81\x81\xF3\xA0\x81\xBF"
+      "\xF3\xA0\x82\x80",
+      9, "\xF3\x9F\xBF\xBF      \xF3\xA0\x82\x80");
 }
diff --git a/protocols/Telegram/tdlib/td/test/tdclient.cpp b/protocols/Telegram/tdlib/td/test/tdclient.cpp
index a608c75593..66f0ae6154 100644
--- a/protocols/Telegram/tdlib/td/test/tdclient.cpp
+++ b/protocols/Telegram/tdlib/td/test/tdclient.cpp
@@ -1,5 +1,5 @@
 //
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -224,7 +224,7 @@ class DoAuthentication final : public TestClinetTask {
         function = td::make_tl_object(code_);
         break;
       case td::td_api::authorizationStateWaitRegistration::ID:
-        function = td::make_tl_object(name_, "");
+        function = td::make_tl_object(name_, "", false);
         break;
       case td::td_api::authorizationStateWaitTdlibParameters::ID: {
         auto request = td::td_api::make_object();
@@ -237,7 +237,6 @@ class DoAuthentication final : public TestClinetTask {
         request->system_language_code_ = "en";
         request->device_model_ = "Desktop";
         request->application_version_ = "tdclient-test";
-        request->enable_storage_optimizer_ = true;
         function = std::move(request);
         break;
       }
@@ -311,10 +310,10 @@ class SetUsername final : public TestClinetTask {
       CHECK(res->get_id() == td::td_api::chat::ID);
       auto chat = td::move_tl_object_as(res);
       this->send_query(td::make_tl_object(
-                           chat->id_, 0, 0, nullptr, nullptr,
+                           chat->id_, 0, nullptr, nullptr, nullptr,
                            td::make_tl_object(
                                td::make_tl_object(PSTRING() << tag_ << " INIT", td::Auto()),
-                               false, false)),
+                               nullptr, false)),
                        [](auto res) {});
     });
   }
@@ -382,10 +381,10 @@ class TestA final : public TestClinetTask {
       for (int i = 0; i < 20; i++) {
         this->send_query(
             td::make_tl_object(
-                chat->id_, 0, 0, nullptr, nullptr,
+                chat->id_, 0, nullptr, nullptr, nullptr,
                 td::make_tl_object(
                     td::make_tl_object(PSTRING() << tag_ << " " << (1000 + i), td::Auto()),
-                    false, false)),
+                    nullptr, false)),
             [&](auto res) { this->stop(); });
       }
     });
@@ -431,10 +430,10 @@ class TestSecretChat final : public TestClinetTask {
       for (int i = 0; i < 20; i++) {
         send_query(
             td::make_tl_object(
-                chat_id_, 0, 0, nullptr, nullptr,
+                chat_id_, 0, nullptr, nullptr, nullptr,
                 td::make_tl_object(
                     td::make_tl_object(PSTRING() << tag_ << " " << (1000 + i), td::Auto()),
-                    false, false)),
+                    nullptr, false)),
             [](auto res) {});
       }
     }
@@ -495,7 +494,7 @@ class TestFileGenerated final : public TestClinetTask {
     file.flush_write().ensure();  // important
     file.close();
     send_query(td::make_tl_object(
-                   chat_id_, 0, 0, nullptr, nullptr,
+                   chat_id_, 0, nullptr, nullptr, nullptr,
                    td::make_tl_object(
                        td::make_tl_object(file_path, "square", 0),
                        td::make_tl_object(
@@ -504,7 +503,7 @@ class TestFileGenerated final : public TestClinetTask {
                [](auto res) { check_td_error(res); });
 
     send_query(td::make_tl_object(
-                   chat_id_, 0, 0, nullptr, nullptr,
+                   chat_id_, 0, nullptr, nullptr, nullptr,
                    td::make_tl_object(
                        td::make_tl_object(file_path, "square", 0), nullptr, true,
                        td::make_tl_object(tag_, td::Auto()))),
@@ -612,10 +611,10 @@ class CheckTestC final : public TestClinetTask {
 
   void one_file() {
     send_query(td::make_tl_object(
-                   chat_id_, 0, 0, nullptr, nullptr,
+                   chat_id_, 0, nullptr, nullptr, nullptr,
                    td::make_tl_object(
                        td::make_tl_object(PSTRING() << tag_ << " ONE_FILE", td::Auto()),
-                       false, false)),
+                       nullptr, false)),
                [](auto res) { check_td_error(res); });
   }
 
diff --git a/protocols/Telegram/tdlib/td/test/tqueue.cpp b/protocols/Telegram/tdlib/td/test/tqueue.cpp
index 9c3da0034c..50f58e4dbe 100644
--- a/protocols/Telegram/tdlib/td/test/tqueue.cpp
+++ b/protocols/Telegram/tdlib/td/test/tqueue.cpp
@@ -1,5 +1,5 @@
 //
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -31,7 +31,7 @@ TEST(TQueue, hands) {
   auto qid = 12;
   ASSERT_EQ(true, tqueue->get_head(qid).empty());
   ASSERT_EQ(true, tqueue->get_tail(qid).empty());
-  tqueue->push(qid, "hello", 1, 0, td::TQueue::EventId());
+  tqueue->push(qid, "hello", 1, 0, td::TQueue::EventId()).ignore();
   auto head = tqueue->get_head(qid);
   auto tail = tqueue->get_tail(qid);
   ASSERT_EQ(head.next().ok(), tail);
-- 
cgit v1.2.3