summaryrefslogtreecommitdiff
path: root/protocols/Telegram/tdlib/td/tdutils/test
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Telegram/tdlib/td/tdutils/test')
-rw-r--r--protocols/Telegram/tdlib/td/tdutils/test/ChainScheduler.cpp8
-rw-r--r--protocols/Telegram/tdlib/td/tdutils/test/ConcurrentHashMap.cpp38
-rw-r--r--protocols/Telegram/tdlib/td/tdutils/test/MpmcWaiter.cpp3
-rw-r--r--protocols/Telegram/tdlib/td/tdutils/test/StealingQueue.cpp12
-rw-r--r--protocols/Telegram/tdlib/td/tdutils/test/hashset_benchmark.cpp4
-rw-r--r--protocols/Telegram/tdlib/td/tdutils/test/json.cpp211
-rw-r--r--protocols/Telegram/tdlib/td/tdutils/test/misc.cpp110
-rw-r--r--protocols/Telegram/tdlib/td/tdutils/test/pq.cpp6
8 files changed, 350 insertions, 42 deletions
diff --git a/protocols/Telegram/tdlib/td/tdutils/test/ChainScheduler.cpp b/protocols/Telegram/tdlib/td/tdutils/test/ChainScheduler.cpp
index 029a4ff366..f93a718138 100644
--- a/protocols/Telegram/tdlib/td/tdutils/test/ChainScheduler.cpp
+++ b/protocols/Telegram/tdlib/td/tdutils/test/ChainScheduler.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)
@@ -116,7 +116,7 @@ TEST(ChainScheduler, Stress) {
td::vector<QueryWithParents> active_queries;
td::ChainScheduler<QueryPtr> scheduler;
- td::vector<td::vector<QueryPtr>> chains(ChainsN);
+ td::vector<td::vector<QueryPtr>> chains(ChainsN + 1);
int inflight_queries{};
int current_query_id{};
int sent_cnt{};
@@ -138,7 +138,7 @@ TEST(ChainScheduler, Stress) {
query->id = query_id;
int chain_n = rnd.fast(1, ChainsN);
td::vector<ChainId> chain_ids(ChainsN);
- std::iota(chain_ids.begin(), chain_ids.end(), 0);
+ std::iota(chain_ids.begin(), chain_ids.end(), 1);
td::rand_shuffle(td::as_mutable_span(chain_ids), rnd);
chain_ids.resize(chain_n);
for (auto chain_id : chain_ids) {
@@ -151,7 +151,7 @@ TEST(ChainScheduler, Stress) {
};
auto check_parents_ok = [&](const QueryWithParents &query_with_parents) -> bool {
- return td::all_of(query_with_parents.parents, [](auto &parent) { return parent->is_ok; });
+ return td::all_of(query_with_parents.parents, [](const auto &parent) { return parent->is_ok; });
};
auto to_query_ptr = [&](TaskId task_id) {
diff --git a/protocols/Telegram/tdlib/td/tdutils/test/ConcurrentHashMap.cpp b/protocols/Telegram/tdlib/td/tdutils/test/ConcurrentHashMap.cpp
index 5ab1f85ad2..7fbe25d0d7 100644
--- a/protocols/Telegram/tdlib/td/tdutils/test/ConcurrentHashMap.cpp
+++ b/protocols/Telegram/tdlib/td/tdutils/test/ConcurrentHashMap.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)
@@ -40,10 +40,6 @@ class ArrayHashMap {
public:
explicit ArrayHashMap(std::size_t n) : array_(n) {
}
- struct Node {
- std::atomic<KeyT> key{KeyT{}};
- std::atomic<ValueT> value{ValueT{}};
- };
static td::string get_name() {
return "ArrayHashMap";
}
@@ -201,21 +197,23 @@ class HashMapBenchmark final : public td::Benchmark {
void run(int n) final {
n = n_;
- td::vector<td::thread> threads;
-
- for (std::size_t i = 0; i < threads_n; i++) {
- std::size_t l = n * i / threads_n;
- std::size_t r = n * (i + 1) / threads_n;
- threads.emplace_back([l, r, this] {
- for (size_t i = l; i < r; i++) {
- auto x = td::narrow_cast<int>((i + 1) * MUL % n_) + 3;
- auto y = td::narrow_cast<int>(i + 2);
- hash_map->insert(x, y);
- }
- });
- }
- for (auto &thread : threads) {
- thread.join();
+ for (int count = 0; count < 1000; count++) {
+ td::vector<td::thread> threads;
+
+ for (std::size_t i = 0; i < threads_n; i++) {
+ std::size_t l = n * i / threads_n;
+ std::size_t r = n * (i + 1) / threads_n;
+ threads.emplace_back([l, r, this] {
+ for (size_t i = l; i < r; i++) {
+ auto x = td::narrow_cast<int>((i + 1) * MUL % n_) + 3;
+ auto y = td::narrow_cast<int>(i + 2);
+ hash_map->insert(x, y);
+ }
+ });
+ }
+ for (auto &thread : threads) {
+ thread.join();
+ }
}
}
diff --git a/protocols/Telegram/tdlib/td/tdutils/test/MpmcWaiter.cpp b/protocols/Telegram/tdlib/td/tdutils/test/MpmcWaiter.cpp
index 9bdabfac57..2040b85225 100644
--- a/protocols/Telegram/tdlib/td/tdutils/test/MpmcWaiter.cpp
+++ b/protocols/Telegram/tdlib/td/tdutils/test/MpmcWaiter.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)
@@ -66,6 +66,7 @@ TEST(MpmcEagerWaiter, stress_one_one) {
}
TEST(MpmcSleepyWaiter, stress_one_one) {
+ return; // the test hangs sometimes; run with --filter MpmcSleepyWaiter_stress_one_one --stress to reproduce
test_waiter_stress_one_one<td::MpmcSleepyWaiter>();
}
diff --git a/protocols/Telegram/tdlib/td/tdutils/test/StealingQueue.cpp b/protocols/Telegram/tdlib/td/tdutils/test/StealingQueue.cpp
index c0ccabf793..0a2f0d083a 100644
--- a/protocols/Telegram/tdlib/td/tdutils/test/StealingQueue.cpp
+++ b/protocols/Telegram/tdlib/td/tdutils/test/StealingQueue.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)
@@ -108,7 +108,7 @@ TEST(AtomicRead, simple2) {
TEST(StealingQueue, simple) {
td::uint64 sum = 0;
- std::atomic<td::uint64> got_sum{0};
+ std::atomic<td::uint64> check_sum{0};
td::Stage run;
td::Stage check;
@@ -138,10 +138,10 @@ TEST(StealingQueue, simple) {
sum += x_sum[x];
gq.push(x, id);
}
- got_sum = 0;
+ check_sum = 0;
}
run.wait(round * threads_n);
- while (got_sum.load() != sum) {
+ while (check_sum.load() != sum) {
auto x = [&] {
int res;
if (lq[id].local_pop(res)) {
@@ -159,8 +159,8 @@ TEST(StealingQueue, simple) {
if (x == 0) {
continue;
}
- //LOG(ERROR) << x << " " << got_sum.load() << " " << sum;
- got_sum.fetch_add(x, std::memory_order_relaxed);
+ //LOG(ERROR) << x << " " << check_sum.load() << " " << sum;
+ check_sum.fetch_add(x, std::memory_order_relaxed);
lq[id].local_push(x - 1, [&](auto y) {
//LOG(ERROR) << "OVERFLOW";
gq.push(y, id);
diff --git a/protocols/Telegram/tdlib/td/tdutils/test/hashset_benchmark.cpp b/protocols/Telegram/tdlib/td/tdutils/test/hashset_benchmark.cpp
index dbfcaa992b..35e1ae5a5e 100644
--- a/protocols/Telegram/tdlib/td/tdutils/test/hashset_benchmark.cpp
+++ b/protocols/Telegram/tdlib/td/tdutils/test/hashset_benchmark.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)
@@ -590,7 +590,7 @@ BENCHMARK_TEMPLATE(BM_mask, td::MaskSse2);
#endif
template <class KeyT, class ValueT, class HashT = td::Hash<KeyT>, class EqT = std::equal_to<KeyT>>
-using FlatHashMapImpl = td::FlatHashTable<td::MapNode<KeyT, ValueT>, HashT, EqT>;
+using FlatHashMapImpl = td::FlatHashTable<td::MapNode<KeyT, ValueT, EqT>, HashT, EqT>;
#define FOR_EACH_TABLE(F) \
F(FlatHashMapImpl) \
diff --git a/protocols/Telegram/tdlib/td/tdutils/test/json.cpp b/protocols/Telegram/tdlib/td/tdutils/test/json.cpp
index 8b42751a3d..928dea80eb 100644
--- a/protocols/Telegram/tdlib/td/tdutils/test/json.cpp
+++ b/protocols/Telegram/tdlib/td/tdutils/test/json.cpp
@@ -1,12 +1,14 @@
//
-// 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/utils/benchmark.h"
#include "td/utils/common.h"
#include "td/utils/JsonBuilder.h"
#include "td/utils/logging.h"
+#include "td/utils/Parser.h"
#include "td/utils/Slice.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/tests.h"
@@ -89,3 +91,210 @@ TEST(JSON, kphp) {
"{\"keyboard\":[[\"\\u2022 abcdefg\"],[\"\\u2022 hijklmnop\"],[\"\\u2022 "
"qrstuvwxyz\"]],\"one_time_keyboard\":true}");
}
+
+TEST(JSON, json_object_get_field) {
+ const td::string encoded_object =
+ "{\"null\":null,\"bool\":true,\"int\":\"1\",\"int2\":2,\"long\":\"123456789012\",\"long2\":2123456789012,"
+ "\"double\":12345678901.1,\"string\":\"string\",\"string2\":12345e+1,\"array\":[],\"object\":{}}";
+ {
+ td::string encoded_object_copy = encoded_object;
+ auto value = td::json_decode(encoded_object_copy).move_as_ok();
+ auto &object = value.get_object();
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("null")), "null");
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("bool")), "true");
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("bool")), "null");
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("int")), "\"1\"");
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("int2")), "2");
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("int3")), "null");
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("long")), "\"123456789012\"");
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("long2")), "2123456789012");
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("double")), "12345678901.1");
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("string")), "\"string\"");
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("string2")), "12345e+1");
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("array")), "[]");
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("object")), "{}");
+ ASSERT_EQ(td::json_encode<td::string>(object.extract_field("")), "null");
+ }
+
+ {
+ td::string encoded_object_copy = encoded_object;
+ auto value = td::json_decode(encoded_object_copy).move_as_ok();
+ auto &object = value.get_object();
+ ASSERT_TRUE(object.extract_optional_field("int", td::JsonValue::Type::Number).is_error());
+ ASSERT_TRUE(object.extract_optional_field("int", td::JsonValue::Type::Number).is_error());
+ ASSERT_TRUE(object.extract_optional_field("int2", td::JsonValue::Type::Number).is_ok());
+ ASSERT_TRUE(object.extract_optional_field("int2", td::JsonValue::Type::Number).is_error());
+ ASSERT_TRUE(object.extract_optional_field("int3", td::JsonValue::Type::Number).is_ok());
+ ASSERT_TRUE(object.extract_optional_field("int3", td::JsonValue::Type::Null).is_ok());
+ ASSERT_EQ(object.extract_optional_field("int", td::JsonValue::Type::String).ok().get_string(), "1");
+ ASSERT_TRUE(object.extract_optional_field("int", td::JsonValue::Type::Number).is_error());
+ ASSERT_EQ(object.extract_optional_field("int", td::JsonValue::Type::Null).ok().type(), td::JsonValue::Type::Null);
+
+ ASSERT_TRUE(object.extract_required_field("long", td::JsonValue::Type::Number).is_error());
+ ASSERT_TRUE(object.extract_required_field("long", td::JsonValue::Type::Number).is_error());
+ ASSERT_TRUE(object.extract_required_field("long2", td::JsonValue::Type::Number).is_ok());
+ ASSERT_TRUE(object.extract_required_field("long2", td::JsonValue::Type::Number).is_error());
+ ASSERT_TRUE(object.extract_required_field("long3", td::JsonValue::Type::Number).is_error());
+ ASSERT_TRUE(object.extract_required_field("long3", td::JsonValue::Type::Null).is_error());
+ ASSERT_EQ(object.extract_required_field("long", td::JsonValue::Type::String).ok().get_string(), "123456789012");
+ ASSERT_TRUE(object.extract_required_field("long", td::JsonValue::Type::Number).is_error());
+ ASSERT_EQ(object.extract_required_field("long", td::JsonValue::Type::Null).ok().type(), td::JsonValue::Type::Null);
+ }
+
+ td::string encoded_object_copy = encoded_object;
+ auto value = td::json_decode(encoded_object_copy).move_as_ok();
+ const auto &object = value.get_object();
+ ASSERT_TRUE(object.has_field("null"));
+ ASSERT_TRUE(object.has_field("object"));
+ ASSERT_TRUE(!object.has_field(""));
+ ASSERT_TRUE(!object.has_field("objec"));
+ ASSERT_TRUE(!object.has_field("object2"));
+
+ ASSERT_TRUE(object.get_optional_bool_field("int").is_error());
+ ASSERT_EQ(object.get_optional_bool_field("bool").ok(), true);
+ ASSERT_EQ(object.get_optional_bool_field("bool", false).ok(), true);
+ ASSERT_EQ(object.get_required_bool_field("bool").ok(), true);
+ ASSERT_EQ(object.get_optional_bool_field("bool3").ok(), false);
+ ASSERT_EQ(object.get_optional_bool_field("bool4", true).ok(), true);
+ ASSERT_TRUE(object.get_required_bool_field("bool5").is_error());
+
+ ASSERT_TRUE(object.get_optional_int_field("null").is_error());
+ ASSERT_EQ(object.get_optional_int_field("int").ok(), 1);
+ ASSERT_EQ(object.get_optional_int_field("int").ok(), 1);
+ ASSERT_EQ(object.get_required_int_field("int").ok(), 1);
+ ASSERT_EQ(object.get_optional_int_field("int2").ok(), 2);
+ ASSERT_EQ(object.get_optional_int_field("int2").ok(), 2);
+ ASSERT_EQ(object.get_required_int_field("int2").ok(), 2);
+ ASSERT_EQ(object.get_optional_int_field("int3").ok(), 0);
+ ASSERT_EQ(object.get_optional_int_field("int4", 5).ok(), 5);
+ ASSERT_TRUE(object.get_required_int_field("int5").is_error());
+ ASSERT_EQ(object.get_optional_int_field("long").is_error(), true);
+ ASSERT_EQ(object.get_optional_int_field("long2").is_error(), true);
+
+ ASSERT_TRUE(object.get_optional_long_field("null").is_error());
+ ASSERT_EQ(object.get_optional_long_field("long").ok(), 123456789012);
+ ASSERT_EQ(object.get_optional_long_field("long").ok(), 123456789012);
+ ASSERT_EQ(object.get_required_long_field("long").ok(), 123456789012);
+ ASSERT_EQ(object.get_optional_long_field("long2").ok(), 2123456789012);
+ ASSERT_EQ(object.get_optional_long_field("long2").ok(), 2123456789012);
+ ASSERT_EQ(object.get_required_long_field("long2").ok(), 2123456789012);
+ ASSERT_EQ(object.get_optional_long_field("long3").ok(), 0);
+ ASSERT_EQ(object.get_optional_long_field("long4", 5).ok(), 5);
+ ASSERT_TRUE(object.get_required_long_field("long5").is_error());
+ ASSERT_EQ(object.get_optional_long_field("int").ok(), 1);
+ ASSERT_EQ(object.get_optional_long_field("int2").ok(), 2);
+
+ auto are_equal_double = [](double lhs, double rhs) {
+ return rhs - 1e-3 < lhs && lhs < rhs + 1e-3;
+ };
+
+ ASSERT_TRUE(object.get_optional_double_field("null").is_error());
+ ASSERT_TRUE(are_equal_double(object.get_optional_double_field("double").ok(), 12345678901.1));
+ ASSERT_TRUE(are_equal_double(object.get_optional_double_field("double").ok(), 12345678901.1));
+ ASSERT_TRUE(are_equal_double(object.get_required_double_field("double").ok(), 12345678901.1));
+ ASSERT_TRUE(are_equal_double(object.get_optional_double_field("long2").ok(), 2123456789012.0));
+ ASSERT_TRUE(are_equal_double(object.get_optional_double_field("long2").ok(), 2123456789012.0));
+ ASSERT_TRUE(are_equal_double(object.get_required_double_field("long2").ok(), 2123456789012.0));
+ ASSERT_TRUE(are_equal_double(object.get_optional_double_field("double3").ok(), 0.0));
+ ASSERT_TRUE(are_equal_double(object.get_optional_double_field("double4", -5.23).ok(), -5.23));
+ ASSERT_TRUE(object.get_required_double_field("double5").is_error());
+ ASSERT_TRUE(object.get_optional_double_field("int").is_error());
+ ASSERT_TRUE(are_equal_double(object.get_optional_double_field("int2").ok(), 2));
+
+ ASSERT_TRUE(object.get_optional_string_field("null").is_error());
+ ASSERT_EQ(object.get_optional_string_field("string").ok(), "string");
+ ASSERT_EQ(object.get_optional_string_field("string").ok(), "string");
+ ASSERT_EQ(object.get_required_string_field("string").ok(), "string");
+ ASSERT_EQ(object.get_optional_string_field("string2").ok(), "12345e+1");
+ ASSERT_EQ(object.get_optional_string_field("string2").ok(), "12345e+1");
+ ASSERT_EQ(object.get_required_string_field("string2").ok(), "12345e+1");
+ ASSERT_EQ(object.get_optional_string_field("string3").ok(), td::string());
+ ASSERT_EQ(object.get_optional_string_field("string4", "abacaba").ok(), "abacaba");
+ ASSERT_TRUE(object.get_required_string_field("string5").is_error());
+ ASSERT_EQ(object.get_optional_string_field("int").ok(), "1");
+ ASSERT_EQ(object.get_optional_string_field("int2").ok(), "2");
+}
+
+class JsonStringDecodeBenchmark final : public td::Benchmark {
+ td::string str_;
+
+ public:
+ explicit JsonStringDecodeBenchmark(td::string str) : str_('"' + str + '"') {
+ }
+
+ td::string get_description() const final {
+ return td::string("JsonStringDecodeBenchmark") + str_.substr(1, 6);
+ }
+
+ void run(int n) final {
+ for (int i = 0; i < n; i++) {
+ auto str = str_;
+ td::Parser parser(str);
+ td::json_string_decode(parser).ensure();
+ }
+ }
+};
+
+TEST(JSON, bench_json_string_decode) {
+ td::bench(JsonStringDecodeBenchmark(td::string(1000, 'a')));
+ td::bench(JsonStringDecodeBenchmark(td::string(1000, '\\')));
+ td::string str;
+ for (int i = 32; i < 128; i++) {
+ if (i == 'u') {
+ continue;
+ }
+ str += "a\\";
+ str += static_cast<char>(i);
+ }
+ td::bench(JsonStringDecodeBenchmark(str));
+}
+
+static void test_string_decode(td::string str, const td::string &result) {
+ auto str_copy = str;
+ td::Parser skip_parser(str_copy);
+ auto status = td::json_string_skip(skip_parser);
+ ASSERT_TRUE(status.is_ok());
+ ASSERT_TRUE(skip_parser.empty());
+
+ td::Parser parser(str);
+ auto r_value = td::json_string_decode(parser);
+ ASSERT_TRUE(r_value.is_ok());
+ ASSERT_TRUE(parser.empty());
+ ASSERT_EQ(result, r_value.ok());
+}
+
+static void test_string_decode_error(td::string str) {
+ auto str_copy = str;
+ td::Parser skip_parser(str_copy);
+ auto status = td::json_string_skip(skip_parser);
+ ASSERT_TRUE(status.is_error());
+
+ td::Parser parser(str);
+ auto r_value = td::json_string_decode(parser);
+ ASSERT_TRUE(r_value.is_error());
+}
+
+TEST(JSON, string_decode) {
+ test_string_decode("\"\"", "");
+ test_string_decode("\"abacaba\"", "abacaba");
+ test_string_decode(
+ "\"\\1\\a\\b\\c\\d\\e\\f\\g\\h\\i\\j\\k\\l\\m\\n\\o\\p\\q\\r\\s\\t\\u00201\\v\\w\\x\\y\\z\\U\\\"\\\\\\/\\+\\-\"",
+ "1a\bcde\fghijklm\nopq\rs\t 1vwxyzU\"\\/+-");
+ test_string_decode("\"\\u0373\\ud7FB\\uD840\\uDC04\\uD840a\\uD840\\u0373\"",
+ "\xCD\xB3\xED\x9F\xBB\xF0\xA0\x80\x84\xed\xa1\x80\x61\xed\xa1\x80\xCD\xB3");
+
+ test_string_decode_error(" \"\"");
+ test_string_decode_error("\"");
+ test_string_decode_error("\"\\");
+ test_string_decode_error("\"\\b'");
+ test_string_decode_error("\"\\u\"");
+ test_string_decode_error("\"\\u123\"");
+ test_string_decode_error("\"\\u123g\"");
+ test_string_decode_error("\"\\u123G\"");
+ test_string_decode_error("\"\\u123 \"");
+ test_string_decode_error("\"\\ug123\"");
+ test_string_decode_error("\"\\uG123\"");
+ test_string_decode_error("\"\\u 123\"");
+ test_string_decode_error("\"\\uD800\\ug123\"");
+ test_string_decode_error("\"\\uD800\\u123\"");
+}
diff --git a/protocols/Telegram/tdlib/td/tdutils/test/misc.cpp b/protocols/Telegram/tdlib/td/tdutils/test/misc.cpp
index e1612a9924..cabd4e6efb 100644
--- a/protocols/Telegram/tdlib/td/tdutils/test/misc.cpp
+++ b/protocols/Telegram/tdlib/td/tdutils/test/misc.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)
@@ -7,6 +7,7 @@
#include "td/utils/algorithm.h"
#include "td/utils/as.h"
#include "td/utils/base64.h"
+#include "td/utils/benchmark.h"
#include "td/utils/BigNum.h"
#include "td/utils/bits.h"
#include "td/utils/CancellationToken.h"
@@ -82,14 +83,11 @@ TEST(Misc, update_atime_saves_mtime) {
r_file.move_as_ok().close();
auto info = td::stat(name).ok();
- td::int32 tests_ok = 0;
td::int32 tests_wa = 0;
for (int i = 0; i < 10000; i++) {
td::update_atime(name).ensure();
auto new_info = td::stat(name).ok();
- if (info.mtime_nsec_ == new_info.mtime_nsec_) {
- tests_ok++;
- } else {
+ if (info.mtime_nsec_ != new_info.mtime_nsec_) {
tests_wa++;
info.mtime_nsec_ = new_info.mtime_nsec_;
}
@@ -265,6 +263,65 @@ TEST(Misc, base64) {
ASSERT_TRUE(td::base64url_encode("ab><cd") == "YWI-PGNk");
}
+static void test_zero_encode(td::Slice str, td::Slice expected_zero = td::Slice(),
+ td::Slice expected_zero_one = td::Slice()) {
+ auto encoded = td::zero_encode(str);
+ if (!expected_zero.empty()) {
+ ASSERT_EQ(encoded, expected_zero);
+ }
+ ASSERT_EQ(td::zero_decode(encoded), str);
+
+ encoded = td::zero_one_encode(str);
+ if (!expected_zero_one.empty()) {
+ ASSERT_EQ(encoded, expected_zero_one);
+ }
+ ASSERT_EQ(td::zero_one_decode(encoded), str);
+}
+
+TEST(Misc, zero_encode) {
+ td::string str;
+ for (unsigned char i = 1; i < 255; i++) {
+ str += static_cast<char>(i);
+ }
+ test_zero_encode(str, str, str);
+
+ test_zero_encode("");
+ test_zero_encode(td::Slice("\0"), td::Slice("\0\1"), td::Slice("\0\1"));
+ test_zero_encode(td::Slice("\0\xff\0\xff\0\xff\0\xff\0\xff\0\xff\0\xff"),
+ td::Slice("\0\1\xff\0\1\xff\0\1\xff\0\1\xff\0\1\xff\0\1\xff\0\1\xff"),
+ td::Slice("\0\1\xff\1\0\1\xff\1\0\1\xff\1\0\1\xff\1\0\1\xff\1\0\1\xff\1\0\1\xff\1"));
+ test_zero_encode(td::Slice("\0\0\xff\xff\0\0\xff\xff\0\0\xff\xff\0\0\xff\xff\0\0\xff\xff\0\0\xff\xff"),
+ td::Slice("\0\2\xff\xff\0\2\xff\xff\0\2\xff\xff\0\2\xff\xff\0\2\xff\xff\0\2\xff\xff"),
+ td::Slice("\0\2\xff\2\0\2\xff\2\0\2\xff\2\0\2\xff\2\0\2\xff\2\0\2\xff\2"));
+ test_zero_encode(td::Slice("\0\0\0\0\0\xff\xff\xff\xff\xff"), td::Slice("\0\5\xff\xff\xff\xff\xff"),
+ td::Slice("\0\5\xff\5"));
+ test_zero_encode(td::Slice(
+ "\0\0\0\0\0\xff\xff\xff\xff\xff\0\0\0\0\0\xff\xff\xff\xff\xff\0\0\0\0\0\xff\xff\xff\xff\xff\0\0\0\0\0\xff\xff\xff"
+ "\xff\xff\0\0\0\0\0\xff\xff\xff\xff\xff\0\0\0\0\0\xff\xff\xff\xff\xff\0\0\0\0\0\xff\xff\xff\xff\xff"));
+ test_zero_encode(td::string(1000, '\0'));
+ test_zero_encode(str + td::string(1000, '\0') + str + td::string(1000, '\xff') + str);
+}
+
+class ZeroEncodeBenchmark final : public td::Benchmark {
+ public:
+ td::string get_description() const final {
+ return "ZeroEncodeBenchmark";
+ }
+
+ void run(int n) final {
+ for (int i = 0; i < n; i++) {
+ zero_encode(
+ td::Slice("\x02\x00\x00\x02\x01\x00\x00\x00\x19\x01\x00\x00\x7c\xc8\x64\xc1\x04\xec\x82\xb8\x20\x9e\xa0\x8d"
+ "\x1e\xbe\xb2\x79\xc4\x5a\x4c\x1e\x49\x1e\x00\x00\xa9\xa7\x31\x1b\x80\x9f\x11\x46\xfc\x97\xde\x6a"
+ "\x18\x6e\xc0\x73\x01\x00\x00\x00\x02\x00\x00\x00\x6d\x00\x00\x00\x30\x04"));
+ }
+ }
+};
+
+TEST(Misc, bench_zero_encode) {
+ td::bench(ZeroEncodeBenchmark());
+}
+
template <class T>
static void test_remove_if(td::vector<int> v, const T &func, const td::vector<int> &expected) {
td::remove_if(v, func);
@@ -349,6 +406,49 @@ TEST(Misc, remove) {
test_remove(v, 1, v);
}
+static void test_add_to_top(td::vector<int> v, size_t max_size, int new_value, const td::vector<int> &expected) {
+ auto u = v;
+ td::add_to_top(v, max_size, new_value);
+ ASSERT_EQ(expected, v);
+
+ td::add_to_top_if(u, max_size, new_value, [new_value](int value) { return value == new_value; });
+ ASSERT_EQ(expected, u);
+}
+
+static void test_add_to_top_if(td::vector<int> v, int max_size, int new_value, const td::vector<int> &expected) {
+ td::add_to_top_if(v, max_size, new_value, [new_value](int value) { return value % 10 == new_value % 10; });
+ ASSERT_EQ(expected, v);
+}
+
+TEST(Misc, add_to_top) {
+ test_add_to_top({}, 0, 1, {1});
+ test_add_to_top({}, 1, 1, {1});
+ test_add_to_top({}, 6, 1, {1});
+
+ test_add_to_top({1, 2, 3, 4, 5, 6}, 3, 2, {2, 1, 3, 4, 5, 6});
+ test_add_to_top({1, 2, 3, 4, 5, 6}, 6, 1, {1, 2, 3, 4, 5, 6});
+ test_add_to_top({1, 2, 3, 4, 5, 6}, 7, 1, {1, 2, 3, 4, 5, 6});
+ test_add_to_top({1, 2, 3, 4, 5, 6}, 6, 2, {2, 1, 3, 4, 5, 6});
+ test_add_to_top({1, 2, 3, 4, 5, 6}, 7, 2, {2, 1, 3, 4, 5, 6});
+ test_add_to_top({1, 2, 3, 4, 5, 6}, 6, 4, {4, 1, 2, 3, 5, 6});
+ test_add_to_top({1, 2, 3, 4, 5, 6}, 7, 4, {4, 1, 2, 3, 5, 6});
+ test_add_to_top({1, 2, 3, 4, 5, 6}, 6, 6, {6, 1, 2, 3, 4, 5});
+ test_add_to_top({1, 2, 3, 4, 5, 6}, 7, 6, {6, 1, 2, 3, 4, 5});
+ test_add_to_top({1, 2, 3, 4, 5, 6}, 6, 7, {7, 1, 2, 3, 4, 5});
+ test_add_to_top({1, 2, 3, 4, 5, 6}, 7, 7, {7, 1, 2, 3, 4, 5, 6});
+
+ test_add_to_top_if({1, 2, 3, 4, 5, 6}, 6, 11, {1, 2, 3, 4, 5, 6});
+ test_add_to_top_if({1, 2, 3, 4, 5, 6}, 7, 21, {1, 2, 3, 4, 5, 6});
+ test_add_to_top_if({1, 2, 3, 4, 5, 6}, 6, 32, {2, 1, 3, 4, 5, 6});
+ test_add_to_top_if({1, 2, 3, 4, 5, 6}, 7, 42, {2, 1, 3, 4, 5, 6});
+ test_add_to_top_if({1, 2, 3, 4, 5, 6}, 6, 54, {4, 1, 2, 3, 5, 6});
+ test_add_to_top_if({1, 2, 3, 4, 5, 6}, 7, 64, {4, 1, 2, 3, 5, 6});
+ test_add_to_top_if({1, 2, 3, 4, 5, 6}, 6, 76, {6, 1, 2, 3, 4, 5});
+ test_add_to_top_if({1, 2, 3, 4, 5, 6}, 7, 86, {6, 1, 2, 3, 4, 5});
+ test_add_to_top_if({1, 2, 3, 4, 5, 6}, 6, 97, {97, 1, 2, 3, 4, 5});
+ test_add_to_top_if({1, 2, 3, 4, 5, 6}, 7, 87, {87, 1, 2, 3, 4, 5, 6});
+}
+
static void test_unique(td::vector<int> v, const td::vector<int> &expected) {
auto v_str = td::transform(v, &td::to_string<int>);
auto expected_str = td::transform(expected, &td::to_string<int>);
diff --git a/protocols/Telegram/tdlib/td/tdutils/test/pq.cpp b/protocols/Telegram/tdlib/td/tdutils/test/pq.cpp
index 0983ea814c..b499b31e0f 100644
--- a/protocols/Telegram/tdlib/td/tdutils/test/pq.cpp
+++ b/protocols/Telegram/tdlib/td/tdutils/test/pq.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,8 +112,8 @@ static void test_pq_slow(td::uint64 first, td::uint64 second) {
td::BigNum p_res = td::BigNum::from_binary(p_str);
td::BigNum q_res = td::BigNum::from_binary(q_str);
- LOG_CHECK(p_str == p.to_binary()) << td::tag("got", p_res.to_decimal()) << td::tag("expected", first);
- LOG_CHECK(q_str == q.to_binary()) << td::tag("got", q_res.to_decimal()) << td::tag("expected", second);
+ LOG_CHECK(p_str == p.to_binary()) << td::tag("receive", p_res.to_decimal()) << td::tag("expected", first);
+ LOG_CHECK(q_str == q.to_binary()) << td::tag("receive", q_res.to_decimal()) << td::tag("expected", second);
}
#endif