Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
59
libs/base/base_tests/CMakeLists.txt
Normal file
59
libs/base/base_tests/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
project(base_tests)
|
||||
|
||||
set(SRC
|
||||
assert_test.cpp
|
||||
beam_tests.cpp
|
||||
bidirectional_map_tests.cpp
|
||||
bits_test.cpp
|
||||
buffer_vector_test.cpp
|
||||
cache_test.cpp
|
||||
cancellable_tests.cpp
|
||||
checked_cast_tests.cpp
|
||||
clustering_map_tests.cpp
|
||||
collection_cast_test.cpp
|
||||
containers_test.cpp
|
||||
control_flow_tests.cpp
|
||||
exception_tests.cpp
|
||||
fifo_cache_test.cpp
|
||||
file_name_utils_tests.cpp
|
||||
geo_object_id_tests.cpp
|
||||
levenshtein_dfa_test.cpp
|
||||
linked_map_tests.cpp
|
||||
logging_test.cpp
|
||||
lru_cache_tests.cpp
|
||||
math_test.cpp
|
||||
matrix_test.cpp
|
||||
mem_trie_test.cpp
|
||||
message_test.cpp
|
||||
newtype_test.cpp
|
||||
non_intersecting_intervals_tests.cpp
|
||||
observer_list_test.cpp
|
||||
range_iterator_test.cpp
|
||||
ref_counted_tests.cpp
|
||||
regexp_test.cpp
|
||||
rolling_hash_test.cpp
|
||||
scope_guard_test.cpp
|
||||
small_set_test.cpp
|
||||
stl_helpers_tests.cpp
|
||||
string_utils_test.cpp
|
||||
suffix_array_tests.cpp
|
||||
sunrise_sunset_test.cpp
|
||||
thread_pool_computational_tests.cpp
|
||||
thread_pool_delayed_tests.cpp
|
||||
thread_pool_tests.cpp
|
||||
thread_safe_queue_tests.cpp
|
||||
threaded_list_test.cpp
|
||||
threads_test.cpp
|
||||
timer_test.cpp
|
||||
uni_string_dfa_test.cpp
|
||||
visitor_tests.cpp
|
||||
)
|
||||
|
||||
# Windows does not have timegm function
|
||||
if(NOT WIN32)
|
||||
list(APPEND SRC "timegm_test.cpp")
|
||||
endif()
|
||||
|
||||
omim_add_test(${PROJECT_NAME} ${SRC} NO_PLATFORM_INIT)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} base)
|
||||
37
libs/base/base_tests/assert_test.cpp
Normal file
37
libs/base/base_tests/assert_test.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/base.hpp"
|
||||
#include "base/exception.hpp"
|
||||
#include "base/logging.hpp"
|
||||
|
||||
UNIT_TEST(Assert_Smoke)
|
||||
{
|
||||
int x = 5;
|
||||
// to avoid warning in release
|
||||
#ifdef RELEASE
|
||||
UNUSED_VALUE(x);
|
||||
#endif
|
||||
ASSERT_EQUAL(x, 5, ());
|
||||
ASSERT_NOT_EQUAL(x, 6, ());
|
||||
// ASSERT_EQUAL ( x, 666, ("Skip this to continue test") );
|
||||
}
|
||||
|
||||
UNIT_TEST(Check_Smoke)
|
||||
{
|
||||
int x = 5;
|
||||
CHECK_EQUAL(x, 5, ());
|
||||
CHECK_NOT_EQUAL(x, 6, ());
|
||||
// CHECK_EQUAL ( x, 666, ("Skip this to continue test") );
|
||||
}
|
||||
|
||||
UNIT_TEST(Exception_Formatting)
|
||||
{
|
||||
try
|
||||
{
|
||||
MYTHROW(RootException, ("String1", "String2", "String3"));
|
||||
}
|
||||
catch (RootException const & e)
|
||||
{
|
||||
LOG(LINFO, ("Exception string: ", e.what()));
|
||||
}
|
||||
}
|
||||
85
libs/base/base_tests/beam_tests.cpp
Normal file
85
libs/base/base_tests/beam_tests.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/beam.hpp"
|
||||
|
||||
#include "base/scope_guard.hpp"
|
||||
#include "base/timer.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace beam_tests
|
||||
{
|
||||
using namespace base;
|
||||
using namespace std;
|
||||
|
||||
template <template <typename, typename> class Beam>
|
||||
void Smoke()
|
||||
{
|
||||
size_t const kCapacity = 10;
|
||||
size_t const kTotal = 100;
|
||||
|
||||
CHECK_LESS_OR_EQUAL(kCapacity, kTotal, ());
|
||||
|
||||
Beam<uint32_t, double> beam(kCapacity);
|
||||
|
||||
for (uint32_t i = 0; i < kTotal; ++i)
|
||||
beam.Add(i, static_cast<double>(i));
|
||||
|
||||
vector<double> expected;
|
||||
for (size_t i = 0; i < kCapacity; ++i)
|
||||
expected.emplace_back(kTotal - 1 - i);
|
||||
|
||||
vector<double> actual;
|
||||
actual.reserve(kCapacity);
|
||||
for (auto const & e : beam.GetEntries())
|
||||
actual.emplace_back(e.m_value);
|
||||
|
||||
sort(actual.rbegin(), actual.rend());
|
||||
CHECK_EQUAL(expected, actual, ());
|
||||
}
|
||||
|
||||
template <template <typename, typename> class Beam>
|
||||
void Benchmark(string const & beamType, uint64_t const numResets, size_t const capacity, uint64_t const numEvents)
|
||||
{
|
||||
base::Timer timer;
|
||||
SCOPE_GUARD(timerGuard, [&] { LOG(LINFO, ("type:", beamType, "\ttime passed:", timer.ElapsedSeconds())); });
|
||||
|
||||
CHECK_LESS_OR_EQUAL(capacity, numEvents, ());
|
||||
|
||||
mt19937 rng(0);
|
||||
uniform_real_distribution<double> dis(0.0, 1.0);
|
||||
for (uint64_t wave = 0; wave <= numResets; ++wave)
|
||||
{
|
||||
Beam<uint64_t, double> beam(capacity);
|
||||
|
||||
uint64_t const begin = wave * numEvents / (numResets + 1);
|
||||
uint64_t const end = (wave + 1) * numEvents / (numResets + 1);
|
||||
for (uint64_t i = begin; i < end; ++i)
|
||||
beam.Add(i, dis(rng));
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(Beam_Smoke)
|
||||
{
|
||||
Smoke<Beam>();
|
||||
Smoke<HeapBeam>();
|
||||
}
|
||||
|
||||
UNIT_TEST(Beam_Benchmark)
|
||||
{
|
||||
size_t const kCapacity = 100;
|
||||
uint64_t const kNumEvents = 1000000;
|
||||
|
||||
for (uint64_t numResets = 0; numResets < 1000; numResets += 200)
|
||||
{
|
||||
LOG(LINFO, ("Resets =", numResets, "Capacity =", kCapacity, "Total events =", kNumEvents));
|
||||
Benchmark<Beam>("Vector-based", numResets, kCapacity, kNumEvents);
|
||||
Benchmark<HeapBeam>("Heap-based", numResets, kCapacity, kNumEvents);
|
||||
}
|
||||
}
|
||||
} // namespace beam_tests
|
||||
96
libs/base/base_tests/bidirectional_map_tests.cpp
Normal file
96
libs/base/base_tests/bidirectional_map_tests.cpp
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/bidirectional_map.hpp"
|
||||
#include "base/macros.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace base;
|
||||
using namespace std;
|
||||
|
||||
UNIT_TEST(BidirectionalMap_Smoke)
|
||||
{
|
||||
BidirectionalMap<int, string> m;
|
||||
m.Add(1, "a");
|
||||
|
||||
{
|
||||
string value;
|
||||
TEST(m.GetValue(1, value), ());
|
||||
TEST_EQUAL(value, "a", ());
|
||||
}
|
||||
{
|
||||
int key;
|
||||
TEST(m.GetKey("a", key), ());
|
||||
TEST_EQUAL(key, 1, ());
|
||||
}
|
||||
|
||||
TEST(!m.Add(1, "b"), ());
|
||||
TEST(!m.Add(2, "a"), ());
|
||||
TEST(m.Add(2, "b"), ());
|
||||
TEST(!m.Add(2, "b"), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(BidirectionalMap_Remove)
|
||||
{
|
||||
{
|
||||
BidirectionalMap<int, string> m;
|
||||
TEST(m.Add(1, "a"), ());
|
||||
TEST(m.Add(2, "b"), ());
|
||||
|
||||
TEST_EQUAL(m.Size(), 2, ());
|
||||
|
||||
TEST(!m.RemoveKey(3), ());
|
||||
TEST_EQUAL(m.Size(), 2, ());
|
||||
|
||||
TEST(m.RemoveKey(1), ());
|
||||
TEST_EQUAL(m.Size(), 1, ());
|
||||
|
||||
TEST(!m.RemoveValue("a"), ());
|
||||
TEST_EQUAL(m.Size(), 1, ());
|
||||
|
||||
TEST(m.RemoveValue("b"), ());
|
||||
TEST(m.IsEmpty(), ());
|
||||
}
|
||||
|
||||
{
|
||||
BidirectionalMap<int, int> m;
|
||||
TEST(m.Add(1, 1), ());
|
||||
TEST(m.Add(2, 2), ());
|
||||
|
||||
TEST_EQUAL(m.Size(), 2, ());
|
||||
|
||||
TEST(!m.RemoveKey(3), ());
|
||||
TEST_EQUAL(m.Size(), 2, ());
|
||||
|
||||
TEST(m.RemoveKey(1), ());
|
||||
TEST_EQUAL(m.Size(), 1, ());
|
||||
|
||||
TEST(!m.RemoveValue(1), ());
|
||||
TEST_EQUAL(m.Size(), 1, ());
|
||||
|
||||
TEST(m.RemoveValue(2), ());
|
||||
TEST(m.IsEmpty(), ());
|
||||
}
|
||||
|
||||
{
|
||||
BidirectionalMap<int, int> m;
|
||||
TEST(m.Add(1, 2), ());
|
||||
TEST(m.Add(2, 1), ());
|
||||
|
||||
TEST_EQUAL(m.Size(), 2, ());
|
||||
|
||||
TEST(!m.RemoveKey(3), ());
|
||||
TEST_EQUAL(m.Size(), 2, ());
|
||||
|
||||
TEST(m.RemoveKey(1), ());
|
||||
TEST_EQUAL(m.Size(), 1, ());
|
||||
|
||||
TEST(!m.RemoveValue(2), ());
|
||||
TEST_EQUAL(m.Size(), 1, ());
|
||||
|
||||
TEST(m.RemoveValue(1), ());
|
||||
TEST(m.IsEmpty(), ());
|
||||
}
|
||||
}
|
||||
114
libs/base/base_tests/bits_test.cpp
Normal file
114
libs/base/base_tests/bits_test.cpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/bits.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
UNIT_TEST(Select1Test)
|
||||
{
|
||||
TEST_EQUAL(0U, bits::select1(1, 1), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(PerfectShuffle)
|
||||
{
|
||||
// 0010 0001 0100 0000
|
||||
// 0010 0001 1000 1110
|
||||
TEST_EQUAL(bits::PerfectShuffle(557851022), 288529443381657684ULL, ());
|
||||
TEST_EQUAL(bits::PerfectUnshuffle(288529443381657684ULL), 557851022, ());
|
||||
|
||||
TEST_EQUAL(bits::PerfectShuffle(0b0), 0b0, ());
|
||||
TEST_EQUAL(bits::PerfectShuffle(0b1), 0b1, ());
|
||||
|
||||
TEST_EQUAL(bits::PerfectShuffle(0b1111111111111111ULL), 0b01010101010101010101010101010101ULL, ());
|
||||
TEST_EQUAL(bits::PerfectUnshuffle(0b01010101010101010101010101010101ULL), 0b1111111111111111ULL, ());
|
||||
TEST_EQUAL(bits::PerfectShuffle(0b00000000000000001111111100000000ULL), 0b01010101010101010000000000000000ULL, ());
|
||||
TEST_EQUAL(bits::PerfectUnshuffle(0b01010101010101010000000000000000ULL), 0b00000000000000001111111100000000ULL, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(BitwiseMerge)
|
||||
{
|
||||
TEST_EQUAL(bits::BitwiseMerge(1, 1), 3, ());
|
||||
TEST_EQUAL(bits::BitwiseMerge(3, 1), 7, ());
|
||||
TEST_EQUAL(bits::BitwiseMerge(1, 3), 11, ());
|
||||
TEST_EQUAL(bits::BitwiseMerge(uint32_t{1} << 31, uint32_t{1} << 31), uint64_t{3} << 62, ());
|
||||
|
||||
auto bitwiseMergeSlow = [](uint32_t x, uint32_t y) -> uint64_t
|
||||
{
|
||||
uint64_t result = 0;
|
||||
for (uint32_t i = 0; i < 32; ++i)
|
||||
{
|
||||
uint64_t const bitX = (static_cast<uint64_t>(x) >> i) & 1;
|
||||
uint64_t const bitY = (static_cast<uint64_t>(y) >> i) & 1;
|
||||
result |= bitX << (2 * i);
|
||||
result |= bitY << (2 * i + 1);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
for (uint32_t x = 0; x < 16; ++x)
|
||||
for (uint32_t y = 0; y < 16; ++y)
|
||||
TEST_EQUAL(bits::BitwiseMerge(x, y), bitwiseMergeSlow(x, y), (x, y));
|
||||
}
|
||||
|
||||
UNIT_TEST(ZigZagEncode)
|
||||
{
|
||||
TEST_EQUAL(bits::ZigZagEncode(0), 0, ());
|
||||
TEST_EQUAL(bits::ZigZagEncode(-1), 1, ());
|
||||
TEST_EQUAL(bits::ZigZagEncode(1), 2, ());
|
||||
TEST_EQUAL(bits::ZigZagEncode(-2), 3, ());
|
||||
TEST_EQUAL(bits::ZigZagEncode(2), 4, ());
|
||||
TEST_EQUAL(bits::ZigZagEncode(127), 254, ());
|
||||
TEST_EQUAL(bits::ZigZagEncode(-128), 255, ());
|
||||
TEST_EQUAL(bits::ZigZagEncode(128), 256, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ZigZagDecode)
|
||||
{
|
||||
TEST_EQUAL(bits::ZigZagDecode(0U), 0, ());
|
||||
TEST_EQUAL(bits::ZigZagDecode(1U), -1, ());
|
||||
TEST_EQUAL(bits::ZigZagDecode(2U), 1, ());
|
||||
TEST_EQUAL(bits::ZigZagDecode(3U), -2, ());
|
||||
TEST_EQUAL(bits::ZigZagDecode(4U), 2, ());
|
||||
TEST_EQUAL(bits::ZigZagDecode(254U), 127, ());
|
||||
TEST_EQUAL(bits::ZigZagDecode(255U), -128, ());
|
||||
TEST_EQUAL(bits::ZigZagDecode(256U), 128, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(NumHiZeroBits32)
|
||||
{
|
||||
TEST_EQUAL(bits::NumHiZeroBits32(0), 32, ());
|
||||
TEST_EQUAL(bits::NumHiZeroBits32(0xFFFFFFFF), 0, ());
|
||||
TEST_EQUAL(bits::NumHiZeroBits32(0x0FABCDEF), 4, ());
|
||||
TEST_EQUAL(bits::NumHiZeroBits32(0x000000FF), 24, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(NumHiZeroBits64)
|
||||
{
|
||||
TEST_EQUAL(bits::NumHiZeroBits64(0), 64, ());
|
||||
TEST_EQUAL(bits::NumHiZeroBits64(0xFFFFFFFFFFFFFFFFULL), 0, ());
|
||||
TEST_EQUAL(bits::NumHiZeroBits64(0x0FABCDEF0FABCDEFULL), 4, ());
|
||||
TEST_EQUAL(bits::NumHiZeroBits64(0x000000000000FDEFULL), 48, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(NumUsedBits)
|
||||
{
|
||||
TEST_EQUAL(bits::NumUsedBits(0), 0, ());
|
||||
TEST_EQUAL(bits::NumUsedBits(0xFFFFFFFFFFFFFFFFULL), 64, ());
|
||||
TEST_EQUAL(bits::NumUsedBits(0x0FABCDEF0FABCDEFULL), 60, ());
|
||||
TEST_EQUAL(bits::NumUsedBits(0x000000000000FDEFULL), 16, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CeilLog)
|
||||
{
|
||||
TEST_EQUAL(0, bits::FloorLog(0x0), ());
|
||||
TEST_EQUAL(0, bits::FloorLog(0x1), ());
|
||||
TEST_EQUAL(1, bits::FloorLog(0x2), ());
|
||||
TEST_EQUAL(1, bits::FloorLog(0x3), ());
|
||||
TEST_EQUAL(2, bits::FloorLog(0x4), ());
|
||||
|
||||
TEST_EQUAL(6, bits::FloorLog(0x7f), ());
|
||||
TEST_EQUAL(7, bits::FloorLog(0x80), ());
|
||||
TEST_EQUAL(31, bits::FloorLog(0xFFFFFFFF), ());
|
||||
TEST_EQUAL(63, bits::FloorLog(0xFFFFFFFFFFFFFFFF), ());
|
||||
}
|
||||
412
libs/base/base_tests/buffer_vector_test.cpp
Normal file
412
libs/base/base_tests/buffer_vector_test.cpp
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/buffer_vector.hpp"
|
||||
#include "base/string_utils.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
|
||||
namespace buffer_vector_test
|
||||
{
|
||||
template <class TCont>
|
||||
void CheckVector(TCont & cont, size_t count)
|
||||
{
|
||||
TEST_EQUAL(cont.size(), count, ());
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
TEST_EQUAL(cont[i], i, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVector_PushBackAndRealloc)
|
||||
{
|
||||
using ElementT = std::vector<int>;
|
||||
ElementT element({1, 2, 3});
|
||||
|
||||
size_t constexpr kFixedSize = 2;
|
||||
{
|
||||
buffer_vector<ElementT, kFixedSize> v;
|
||||
v.append(kFixedSize, element);
|
||||
|
||||
v.push_back(v[0]);
|
||||
TEST_EQUAL(v.size(), kFixedSize + 1, ());
|
||||
|
||||
for (auto const & e : v)
|
||||
TEST_EQUAL(e, element, ());
|
||||
}
|
||||
|
||||
{
|
||||
buffer_vector<ElementT, kFixedSize> v;
|
||||
v.append(kFixedSize, element);
|
||||
|
||||
v.emplace_back(3, v[0][1]);
|
||||
TEST_EQUAL(v.size(), kFixedSize + 1, ());
|
||||
|
||||
for (size_t i = 0; i < kFixedSize; ++i)
|
||||
TEST_EQUAL(v[i], element, ());
|
||||
TEST_EQUAL(v[kFixedSize], ElementT({2, 2, 2}), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVector_Bounds)
|
||||
{
|
||||
buffer_vector<size_t, 2> v;
|
||||
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
{
|
||||
v.push_back(i);
|
||||
CheckVector(v, i + 1);
|
||||
}
|
||||
|
||||
v.resize(2);
|
||||
CheckVector(v, 2);
|
||||
|
||||
v.resize(3);
|
||||
v[2] = 2;
|
||||
CheckVector(v, 3);
|
||||
|
||||
v.resize(4);
|
||||
v[3] = 3;
|
||||
CheckVector(v, 4);
|
||||
|
||||
v.resize(1);
|
||||
CheckVector(v, 1);
|
||||
|
||||
v.resize(0);
|
||||
CheckVector(v, 0);
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVector_Swap)
|
||||
{
|
||||
typedef buffer_vector<size_t, 2> value_t;
|
||||
buffer_vector<value_t, 2> v1, v2;
|
||||
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
{
|
||||
v1.push_back(value_t());
|
||||
v2.push_back(value_t());
|
||||
}
|
||||
|
||||
// check swap of vectors
|
||||
value_t const * d1 = v1.data();
|
||||
value_t const * d2 = v2.data();
|
||||
|
||||
swap(v1, v2);
|
||||
TEST_EQUAL(d1, v2.data(), ());
|
||||
TEST_EQUAL(d2, v1.data(), ());
|
||||
|
||||
// check swap in resized data
|
||||
{
|
||||
v1[0].push_back(666);
|
||||
|
||||
auto const * dd1 = v1[0].data();
|
||||
|
||||
// resize from 5 to 1 => v[0] will stay at the same place
|
||||
v1.resize(1);
|
||||
TEST_EQUAL(v1[0].size(), 1, ());
|
||||
TEST_EQUAL(v1[0][0], 666, ());
|
||||
TEST_EQUAL(dd1, v1[0].data(), ());
|
||||
|
||||
v1.resize(7);
|
||||
TEST_EQUAL(v1[0].size(), 1, ());
|
||||
TEST_EQUAL(v1[0][0], 666, ());
|
||||
}
|
||||
|
||||
{
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
v2[0].push_back(i);
|
||||
|
||||
// inner dynamic buffer should be swapped during resizing
|
||||
// (??? but it's not specified by standart of std::vector ???)
|
||||
auto const * dd2 = v2[0].data();
|
||||
|
||||
v2.resize(1);
|
||||
TEST_EQUAL(v2[0].size(), 5, ());
|
||||
TEST_EQUAL(dd2, v2[0].data(), ());
|
||||
|
||||
v1.resize(7);
|
||||
TEST_EQUAL(v2[0].size(), 5, ());
|
||||
TEST_EQUAL(dd2, v2[0].data(), ());
|
||||
}
|
||||
|
||||
// check resize from static to dynamic buffer
|
||||
buffer_vector<value_t, 2> v3;
|
||||
v3.push_back(value_t());
|
||||
|
||||
{
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
v3[0].push_back(i);
|
||||
|
||||
auto const * dd3 = v3[0].data();
|
||||
|
||||
// resize from static to dynamic buffer => v3[0] will stay at the same place
|
||||
v1.resize(7);
|
||||
TEST_EQUAL(v3[0].size(), 5, ());
|
||||
TEST_EQUAL(dd3, v3[0].data(), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVector_Resize)
|
||||
{
|
||||
for (size_t size = 0; size < 20; ++size)
|
||||
{
|
||||
buffer_vector<int, 5> v;
|
||||
v.resize(size, 3);
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
TEST_EQUAL(v[i], 3, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVector_Insert)
|
||||
{
|
||||
for (size_t initialLength = 0; initialLength < 20; ++initialLength)
|
||||
{
|
||||
for (size_t insertLength = 0; insertLength < 20; ++insertLength)
|
||||
{
|
||||
for (size_t insertPos = 0; insertPos <= initialLength; ++insertPos)
|
||||
{
|
||||
buffer_vector<char, 5> b;
|
||||
std::vector<char> v;
|
||||
for (size_t i = 0; i < initialLength; ++i)
|
||||
{
|
||||
b.push_back('A' + i);
|
||||
v.push_back('A' + i);
|
||||
}
|
||||
|
||||
std::vector<int> dataToInsert(insertLength);
|
||||
std::iota(dataToInsert.begin(), dataToInsert.end(), 'a');
|
||||
|
||||
b.insert(b.begin() + insertPos, dataToInsert.begin(), dataToInsert.end());
|
||||
v.insert(v.begin() + insertPos, dataToInsert.begin(), dataToInsert.end());
|
||||
|
||||
std::vector<char> result(b.begin(), b.end());
|
||||
TEST_EQUAL(v, result, (initialLength, insertLength, insertPos));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVector_InsertSingleValue)
|
||||
{
|
||||
buffer_vector<char, 3> v;
|
||||
v.insert(v.end(), 'x');
|
||||
TEST_EQUAL(v.size(), 1, ());
|
||||
TEST_EQUAL(v[0], 'x', ());
|
||||
|
||||
v.insert(v.begin(), 'y');
|
||||
TEST_EQUAL(v.size(), 2, ());
|
||||
TEST_EQUAL(v[0], 'y', ());
|
||||
TEST_EQUAL(v[1], 'x', ());
|
||||
|
||||
v.insert(v.begin() + 1, 'z');
|
||||
TEST_EQUAL(v.size(), 3, ());
|
||||
TEST_EQUAL(v[0], 'y', ());
|
||||
TEST_EQUAL(v[1], 'z', ());
|
||||
TEST_EQUAL(v[2], 'x', ());
|
||||
// Switch to dynamic.
|
||||
v.insert(v.begin() + 1, 'q');
|
||||
TEST_EQUAL(v.size(), 4, ());
|
||||
TEST_EQUAL(v[0], 'y', ());
|
||||
TEST_EQUAL(v[1], 'q', ());
|
||||
TEST_EQUAL(v[2], 'z', ());
|
||||
TEST_EQUAL(v[3], 'x', ());
|
||||
|
||||
v.insert(v.end() - 1, 'c');
|
||||
TEST_EQUAL(v[3], 'c', ());
|
||||
TEST_EQUAL(v[4], 'x', ());
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVector_Append)
|
||||
{
|
||||
for (size_t initialLength = 0; initialLength < 20; ++initialLength)
|
||||
{
|
||||
for (size_t insertLength = 0; insertLength < 20; ++insertLength)
|
||||
{
|
||||
buffer_vector<char, 5> b;
|
||||
std::vector<char> v;
|
||||
for (size_t i = 0; i < initialLength; ++i)
|
||||
{
|
||||
b.push_back('A' + i);
|
||||
v.push_back('A' + i);
|
||||
}
|
||||
|
||||
std::vector<int> dataToInsert(insertLength);
|
||||
std::iota(dataToInsert.begin(), dataToInsert.end(), 'a');
|
||||
|
||||
b.append(dataToInsert.begin(), dataToInsert.end());
|
||||
v.insert(v.end(), dataToInsert.begin(), dataToInsert.end());
|
||||
|
||||
std::vector<char> result(b.begin(), b.end());
|
||||
TEST_EQUAL(v, result, (initialLength, insertLength));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVector_PopBack)
|
||||
{
|
||||
for (size_t len = 1; len < 6; ++len)
|
||||
{
|
||||
buffer_vector<size_t, 3> v;
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
v.push_back(i);
|
||||
for (size_t i = len; i > 0; --i)
|
||||
{
|
||||
TEST(!v.empty(), (len, i));
|
||||
TEST_EQUAL(v.size(), i, ());
|
||||
TEST_EQUAL(v.front(), 0, ());
|
||||
TEST_EQUAL(v.back(), i - 1, ());
|
||||
v.pop_back();
|
||||
TEST_EQUAL(v.size(), i - 1, ());
|
||||
}
|
||||
TEST(v.empty(), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVector_Assign)
|
||||
{
|
||||
int const arr5[] = {1, 2, 3, 4, 5};
|
||||
buffer_vector<int, 5> v(&arr5[0], &arr5[0] + ARRAY_SIZE(arr5));
|
||||
for (size_t i = 0; i < ARRAY_SIZE(arr5); ++i)
|
||||
TEST_EQUAL(arr5[i], v[i], ());
|
||||
|
||||
int const arr10[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
v.assign(&arr10[0], &arr10[0] + ARRAY_SIZE(arr10));
|
||||
for (size_t i = 0; i < ARRAY_SIZE(arr10); ++i)
|
||||
TEST_EQUAL(arr10[i], v[i], ());
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVector_Equality)
|
||||
{
|
||||
int const arr5[] = {1, 2, 3, 4, 5};
|
||||
buffer_vector<int, 5> v1(&arr5[0], &arr5[0] + ARRAY_SIZE(arr5));
|
||||
buffer_vector<int, 10> v2(&arr5[0], &arr5[0] + ARRAY_SIZE(arr5));
|
||||
buffer_vector<int, 3> v3(&arr5[0], &arr5[0] + ARRAY_SIZE(arr5));
|
||||
TEST_EQUAL(v1, v2, ());
|
||||
TEST_EQUAL(v1, v3, ());
|
||||
TEST_EQUAL(v2, v3, ());
|
||||
v1.push_back(999);
|
||||
TEST_NOT_EQUAL(v1, v2, ());
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct CopyCtorChecker
|
||||
{
|
||||
std::string m_s;
|
||||
|
||||
CopyCtorChecker() = default;
|
||||
explicit CopyCtorChecker(char const * s) : m_s(s) {}
|
||||
|
||||
CopyCtorChecker(CopyCtorChecker const & rhs)
|
||||
{
|
||||
TEST(rhs.m_s.empty(), ("Copy ctor is called only in resize with default element"));
|
||||
}
|
||||
CopyCtorChecker(CopyCtorChecker && rhs) = default;
|
||||
|
||||
CopyCtorChecker & operator=(CopyCtorChecker &&) = default;
|
||||
CopyCtorChecker & operator=(CopyCtorChecker const &)
|
||||
{
|
||||
TEST(false, ("Assigment operator should not be called"));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// void swap(CopyCtorChecker & r1, CopyCtorChecker & r2)
|
||||
// {
|
||||
// r1.m_s.swap(r2.m_s);
|
||||
// }
|
||||
|
||||
typedef buffer_vector<CopyCtorChecker, 2> VectorT;
|
||||
|
||||
VectorT GetVector()
|
||||
{
|
||||
VectorT v;
|
||||
v.emplace_back("0");
|
||||
v.emplace_back("1");
|
||||
return v;
|
||||
}
|
||||
|
||||
void TestVector(VectorT const & v, size_t sz)
|
||||
{
|
||||
TEST_EQUAL(v.size(), sz, ());
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
TEST_EQUAL(v[i].m_s, strings::to_string(i), ());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(BufferVector_Move)
|
||||
{
|
||||
VectorT v1 = GetVector();
|
||||
TestVector(v1, 2);
|
||||
|
||||
// Make intermediate array to avoid warning (moving to itself).
|
||||
std::array<VectorT *, 2> arr = {&v1, &v1};
|
||||
*arr[0] = std::move(*arr[1]);
|
||||
TestVector(v1, 2);
|
||||
|
||||
v1.emplace_back("2");
|
||||
TestVector(v1, 3);
|
||||
|
||||
VectorT v2(std::move(v1));
|
||||
TestVector(v2, 3);
|
||||
TestVector(v1, 0);
|
||||
|
||||
v1 = std::move(v2);
|
||||
TestVector(v1, 3);
|
||||
TestVector(v2, 0);
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVector_EraseIf)
|
||||
{
|
||||
buffer_vector<int, 2> v;
|
||||
v.push_back(1);
|
||||
v.push_back(2);
|
||||
v.erase_if([](int x) { return x == 1; });
|
||||
TEST_EQUAL(v.size(), 1, ());
|
||||
TEST_EQUAL(v[0], 2, ());
|
||||
|
||||
v.push_back(3);
|
||||
v.push_back(4);
|
||||
v.erase_if([](int x) { return x == 3; });
|
||||
TEST_EQUAL(v.size(), 2, ());
|
||||
TEST_EQUAL(v[0], 2, ());
|
||||
TEST_EQUAL(v[1], 4, ());
|
||||
|
||||
v.erase_if([](int) { return true; });
|
||||
TEST_EQUAL(v.size(), 0, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVector_OnlyMoveableItems)
|
||||
{
|
||||
buffer_vector<std::unique_ptr<size_t>, 4> v;
|
||||
|
||||
for (size_t i = 0; i < 10; ++i)
|
||||
v.emplace_back(std::make_unique<size_t>(i));
|
||||
|
||||
TEST_EQUAL(v.size(), 10, ());
|
||||
for (size_t i = 0; i < 10; ++i)
|
||||
TEST_EQUAL(*v[i], i, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVector_Erase)
|
||||
{
|
||||
buffer_vector<int, 32> v1;
|
||||
std::vector<int> v2;
|
||||
for (int i = 1; i < 100; ++i)
|
||||
{
|
||||
v1.push_back(i);
|
||||
v2.push_back(i);
|
||||
}
|
||||
|
||||
while (v1.size() > 1)
|
||||
{
|
||||
v1.erase(v1.begin() + v1.size() / 3, v1.begin() + 2 * v1.size() / 3);
|
||||
v2.erase(v2.begin() + v2.size() / 3, v2.begin() + 2 * v2.size() / 3);
|
||||
|
||||
TEST_EQUAL(v1.size(), v2.size(), ());
|
||||
for (size_t i = 0; i < v1.size(); ++i)
|
||||
TEST_EQUAL(v1[i], v2[i], ());
|
||||
}
|
||||
}
|
||||
} // namespace buffer_vector_test
|
||||
178
libs/base/base_tests/cache_test.cpp
Normal file
178
libs/base/base_tests/cache_test.cpp
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/cache.hpp"
|
||||
#include "base/macros.hpp"
|
||||
#include "base/math.hpp"
|
||||
#include "base/stl_helpers.hpp"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace
|
||||
{
|
||||
// This functor will be passed in Cache::ForEachValue by reference
|
||||
class SimpleFunctor
|
||||
{
|
||||
public:
|
||||
SimpleFunctor() {}
|
||||
|
||||
void operator()(char c) { m_v.push_back(c); }
|
||||
|
||||
std::vector<char> m_v;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY(SimpleFunctor);
|
||||
};
|
||||
|
||||
// This functor will be passed in Cache::ForEachValue by move ctor
|
||||
class SimpleMovableFunctor
|
||||
{
|
||||
public:
|
||||
explicit SimpleMovableFunctor(std::vector<char> * v) : m_v(v) {}
|
||||
|
||||
SimpleMovableFunctor(SimpleMovableFunctor && other)
|
||||
{
|
||||
m_v = other.m_v;
|
||||
other.m_v = nullptr;
|
||||
}
|
||||
|
||||
SimpleMovableFunctor & operator=(SimpleMovableFunctor && other)
|
||||
{
|
||||
m_v = other.m_v;
|
||||
other.m_v = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator()(char c) { m_v->push_back(c); }
|
||||
|
||||
private:
|
||||
std::vector<char> * m_v;
|
||||
|
||||
DISALLOW_COPY(SimpleMovableFunctor);
|
||||
};
|
||||
|
||||
double constexpr kEpsilon = 1e-6;
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(CacheSmoke)
|
||||
{
|
||||
char const s[] = "1123212434445";
|
||||
char const isNew[] = "1011???1??001";
|
||||
size_t const n = ARRAY_SIZE(s) - 1;
|
||||
for (int logCacheSize = 2; logCacheSize < 6; ++logCacheSize)
|
||||
{
|
||||
base::Cache<uint32_t, char> cache(logCacheSize);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
bool found = false;
|
||||
char & c = cache.Find(s[i], found);
|
||||
if (isNew[i] != '?')
|
||||
TEST_EQUAL(found, isNew[i] == '0', (i, s[i]));
|
||||
if (found)
|
||||
TEST_EQUAL(c, s[i], (i));
|
||||
else
|
||||
c = s[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(CacheSmoke_0)
|
||||
{
|
||||
base::Cache<uint32_t, char> cache(3); // it contains 2^3=8 elements
|
||||
bool found = true;
|
||||
cache.Find(0, found);
|
||||
TEST(!found, ());
|
||||
std::vector<char> v;
|
||||
cache.ForEachValue(base::MakeBackInsertFunctor(v));
|
||||
TEST_EQUAL(v, std::vector<char>(8, 0), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CacheSmoke_1)
|
||||
{
|
||||
base::Cache<uint32_t, char> cache(3); // it contains 2^3=8 elements
|
||||
SimpleFunctor f;
|
||||
cache.ForEachValue(f); // f passed by reference
|
||||
TEST_EQUAL(f.m_v, std::vector<char>(8, 0), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CacheSmoke_2)
|
||||
{
|
||||
base::Cache<uint32_t, char> cache(3); // it contains 2^3=8 elements
|
||||
SimpleFunctor f;
|
||||
cache.ForEachValue(std::ref(f)); // f passed by reference
|
||||
TEST_EQUAL(f.m_v, std::vector<char>(8, 0), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CacheSmoke_3)
|
||||
{
|
||||
base::CacheWithStat<uint32_t, char> cache(3); // it contains 2^3=8 elements
|
||||
|
||||
// 0 access, cache miss is 0
|
||||
TEST(AlmostEqualAbs(0.0, cache.GetCacheMiss(), kEpsilon), ());
|
||||
|
||||
bool found = true;
|
||||
cache.Find(1, found);
|
||||
TEST(!found, ());
|
||||
// 1 access, 1 miss, cache miss = 1/1 = 1
|
||||
TEST(AlmostEqualAbs(1.0, cache.GetCacheMiss(), kEpsilon), ());
|
||||
|
||||
found = false;
|
||||
cache.Find(1, found);
|
||||
TEST(found, ());
|
||||
// 2 access, 1 miss, cache miss = 1/2 = 0.5
|
||||
TEST(AlmostEqualAbs(0.5, cache.GetCacheMiss(), kEpsilon), ());
|
||||
|
||||
found = false;
|
||||
cache.Find(2, found);
|
||||
TEST(!found, ());
|
||||
// 3 access, 2 miss, cache miss = 2/3 = 0.6(6)
|
||||
TEST(AlmostEqualAbs(2.0 / 3.0, cache.GetCacheMiss(), kEpsilon), ());
|
||||
|
||||
cache.Reset();
|
||||
|
||||
// 0 access, cache miss is 0
|
||||
TEST(AlmostEqualAbs(0.0, cache.GetCacheMiss(), kEpsilon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CacheSmoke_4)
|
||||
{
|
||||
base::CacheWithStat<uint32_t, char> cache(3); // it contains 2^3=8 elements
|
||||
SimpleFunctor f;
|
||||
cache.ForEachValue(f); // f passed by reference
|
||||
TEST_EQUAL(f.m_v, std::vector<char>(8, 0), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CacheSmoke_5)
|
||||
{
|
||||
base::CacheWithStat<uint32_t, char> cache(3); // it contains 2^3=8 elements
|
||||
SimpleFunctor f;
|
||||
cache.ForEachValue(std::ref(f)); // f passed by reference
|
||||
TEST_EQUAL(f.m_v, std::vector<char>(8, 0), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(CacheSmoke_6)
|
||||
{
|
||||
base::CacheWithStat<uint32_t, char> cache(3); // it contains 2^3=8 elements
|
||||
std::vector<char> v;
|
||||
cache.ForEachValue(SimpleMovableFunctor(&v));
|
||||
TEST_EQUAL(v, std::vector<char>(8, 0), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Cache_Init)
|
||||
{
|
||||
base::Cache<uint32_t, char> cache;
|
||||
cache.Init(3 /* logCacheSize */);
|
||||
|
||||
bool found = true;
|
||||
cache.Find(5, found) = 'a';
|
||||
TEST(!found, ());
|
||||
|
||||
TEST_EQUAL(cache.Find(5, found), 'a', ());
|
||||
TEST(found, ());
|
||||
|
||||
cache.Init(1 /* logCacheSize */);
|
||||
cache.Find(5, found) = 'b';
|
||||
TEST(!found, ());
|
||||
|
||||
TEST_EQUAL(cache.Find(5, found), 'b', ());
|
||||
TEST(found, ());
|
||||
}
|
||||
83
libs/base/base_tests/cancellable_tests.cpp
Normal file
83
libs/base/base_tests/cancellable_tests.cpp
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/cancellable.hpp"
|
||||
#include "base/math.hpp"
|
||||
#include "base/thread.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <future>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace base
|
||||
{
|
||||
UNIT_TEST(Cancellable_Smoke)
|
||||
{
|
||||
Cancellable cancellable;
|
||||
|
||||
promise<void> syncPromise;
|
||||
auto syncFuture = syncPromise.get_future();
|
||||
|
||||
double x = 0.123;
|
||||
|
||||
auto const fn = [&]
|
||||
{
|
||||
for (size_t it = 0;; it++)
|
||||
{
|
||||
if (it > 100 && cancellable.IsCancelled())
|
||||
break;
|
||||
|
||||
x = cos(x);
|
||||
}
|
||||
|
||||
syncPromise.set_value();
|
||||
};
|
||||
|
||||
threads::SimpleThread thread(fn);
|
||||
cancellable.Cancel();
|
||||
syncFuture.wait();
|
||||
thread.join();
|
||||
|
||||
TEST(cancellable.IsCancelled(), ());
|
||||
TEST_EQUAL(cancellable.CancellationStatus(), Cancellable::Status::CancelCalled, ());
|
||||
TEST(AlmostEqualAbs(x, 0.739, 1e-3), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Cancellable_Deadline)
|
||||
{
|
||||
Cancellable cancellable;
|
||||
chrono::steady_clock::duration kTimeout = chrono::milliseconds(20);
|
||||
cancellable.SetDeadline(chrono::steady_clock::now() + kTimeout);
|
||||
|
||||
promise<void> syncPromise;
|
||||
auto syncFuture = syncPromise.get_future();
|
||||
|
||||
double x = 0.123;
|
||||
|
||||
auto const fn = [&]
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (cancellable.IsCancelled())
|
||||
break;
|
||||
|
||||
x = cos(x);
|
||||
}
|
||||
|
||||
syncPromise.set_value();
|
||||
};
|
||||
|
||||
threads::SimpleThread thread(fn);
|
||||
syncFuture.wait();
|
||||
thread.join();
|
||||
|
||||
TEST(cancellable.IsCancelled(), ());
|
||||
TEST_EQUAL(cancellable.CancellationStatus(), Cancellable::Status::DeadlineExceeded, ());
|
||||
TEST(AlmostEqualAbs(x, 0.739, 1e-3), ());
|
||||
|
||||
cancellable.Cancel();
|
||||
TEST(cancellable.IsCancelled(), ());
|
||||
TEST_EQUAL(cancellable.CancellationStatus(), Cancellable::Status::CancelCalled, ());
|
||||
}
|
||||
} // namespace base
|
||||
74
libs/base/base_tests/checked_cast_tests.cpp
Normal file
74
libs/base/base_tests/checked_cast_tests.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/checked_cast.hpp"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wimplicitly-unsigned-literal"
|
||||
#endif // #ifdef __clang__
|
||||
UNIT_TEST(IsCastValid)
|
||||
{
|
||||
{
|
||||
int8_t value = -1;
|
||||
TEST(base::IsCastValid<int8_t>(value), ());
|
||||
TEST(base::IsCastValid<int16_t>(value), ());
|
||||
TEST(base::IsCastValid<int32_t>(value), ());
|
||||
TEST(base::IsCastValid<int64_t>(value), ());
|
||||
|
||||
TEST(!base::IsCastValid<uint8_t>(value), ());
|
||||
TEST(!base::IsCastValid<uint16_t>(value), ());
|
||||
TEST(!base::IsCastValid<uint32_t>(value), ());
|
||||
TEST(!base::IsCastValid<uint64_t>(value), ());
|
||||
}
|
||||
{
|
||||
int64_t value = -1;
|
||||
TEST(base::IsCastValid<int8_t>(value), ());
|
||||
TEST(base::IsCastValid<int16_t>(value), ());
|
||||
TEST(base::IsCastValid<int32_t>(value), ());
|
||||
TEST(base::IsCastValid<int64_t>(value), ());
|
||||
|
||||
TEST(!base::IsCastValid<uint8_t>(value), ());
|
||||
TEST(!base::IsCastValid<uint16_t>(value), ());
|
||||
TEST(!base::IsCastValid<uint32_t>(value), ());
|
||||
TEST(!base::IsCastValid<uint64_t>(value), ());
|
||||
}
|
||||
{
|
||||
uint8_t value = 128;
|
||||
TEST(!base::IsCastValid<int8_t>(value), ());
|
||||
TEST(base::IsCastValid<int16_t>(value), ());
|
||||
TEST(base::IsCastValid<int32_t>(value), ());
|
||||
TEST(base::IsCastValid<int64_t>(value), ());
|
||||
|
||||
TEST(base::IsCastValid<uint8_t>(value), ());
|
||||
TEST(base::IsCastValid<uint16_t>(value), ());
|
||||
TEST(base::IsCastValid<uint32_t>(value), ());
|
||||
TEST(base::IsCastValid<uint64_t>(value), ());
|
||||
}
|
||||
{
|
||||
uint64_t value = 9223372036854775808ULL;
|
||||
TEST(!base::IsCastValid<int8_t>(value), ());
|
||||
TEST(!base::IsCastValid<int16_t>(value), ());
|
||||
TEST(!base::IsCastValid<int32_t>(value), ());
|
||||
TEST(!base::IsCastValid<int64_t>(value), ());
|
||||
|
||||
TEST(!base::IsCastValid<uint8_t>(value), ());
|
||||
TEST(!base::IsCastValid<uint16_t>(value), ());
|
||||
TEST(!base::IsCastValid<uint32_t>(value), ());
|
||||
TEST(base::IsCastValid<uint64_t>(value), ());
|
||||
}
|
||||
{
|
||||
int64_t value = -9223372036854775807LL;
|
||||
TEST(!base::IsCastValid<int8_t>(value), ());
|
||||
TEST(!base::IsCastValid<int16_t>(value), ());
|
||||
TEST(!base::IsCastValid<int32_t>(value), ());
|
||||
TEST(base::IsCastValid<int64_t>(value), ());
|
||||
|
||||
TEST(!base::IsCastValid<uint8_t>(value), ());
|
||||
TEST(!base::IsCastValid<uint16_t>(value), ());
|
||||
TEST(!base::IsCastValid<uint32_t>(value), ());
|
||||
TEST(!base::IsCastValid<uint64_t>(value), ());
|
||||
}
|
||||
}
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif // #ifdef __clang__
|
||||
177
libs/base/base_tests/clustering_map_tests.cpp
Normal file
177
libs/base/base_tests/clustering_map_tests.cpp
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/clustering_map.hpp"
|
||||
#include "base/internal/message.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace base;
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename T>
|
||||
vector<T> Sort(vector<T> vs)
|
||||
{
|
||||
sort(vs.begin(), vs.end());
|
||||
return vs;
|
||||
}
|
||||
|
||||
template <typename Key, typename Value, typename Hash = hash<Key>>
|
||||
class ClusteringMapAdapter
|
||||
{
|
||||
public:
|
||||
struct Cluster
|
||||
{
|
||||
Cluster(Key const & key, Value const & value) : m_keys({key}), m_values({value}) {}
|
||||
|
||||
Cluster(vector<Key> const & keys, vector<Value> const & values) : m_keys(keys), m_values(values)
|
||||
{
|
||||
sort(m_keys.begin(), m_keys.end());
|
||||
sort(m_values.begin(), m_values.end());
|
||||
}
|
||||
|
||||
bool operator<(Cluster const & rhs) const
|
||||
{
|
||||
if (m_keys != rhs.m_keys)
|
||||
return m_keys < rhs.m_keys;
|
||||
return m_values < rhs.m_values;
|
||||
}
|
||||
|
||||
bool operator==(Cluster const & rhs) const { return m_keys == rhs.m_keys && m_values == rhs.m_values; }
|
||||
|
||||
friend string DebugPrint(Cluster const & cluster)
|
||||
{
|
||||
ostringstream os;
|
||||
os << "Cluster [";
|
||||
os << "keys: " << ::DebugPrint(cluster.m_keys) << ", ";
|
||||
os << "values: " << ::DebugPrint(cluster.m_values);
|
||||
os << "]";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
vector<Key> m_keys;
|
||||
vector<Value> m_values;
|
||||
};
|
||||
|
||||
template <typename V>
|
||||
void Append(Key const & key, V && value)
|
||||
{
|
||||
m_m.Append(key, std::forward<V>(value));
|
||||
}
|
||||
|
||||
void Union(Key const & u, Key const & v) { m_m.Union(u, v); }
|
||||
|
||||
vector<Value> Get(Key const & key) { return Sort(m_m.Get(key)); }
|
||||
|
||||
vector<Cluster> Clusters()
|
||||
{
|
||||
vector<Cluster> clusters;
|
||||
|
||||
m_m.ForEachCluster([&](vector<Key> const & keys, vector<Value> const & values)
|
||||
{ clusters.emplace_back(keys, values); });
|
||||
sort(clusters.begin(), clusters.end());
|
||||
return clusters;
|
||||
}
|
||||
|
||||
private:
|
||||
ClusteringMap<Key, Value, Hash> m_m;
|
||||
};
|
||||
|
||||
UNIT_TEST(ClusteringMap_Smoke)
|
||||
{
|
||||
{
|
||||
ClusteringMapAdapter<int, string> m;
|
||||
TEST(m.Get(0).empty(), ());
|
||||
TEST(m.Get(1).empty(), ());
|
||||
|
||||
m.Union(0, 1);
|
||||
TEST(m.Get(0).empty(), ());
|
||||
TEST(m.Get(1).empty(), ());
|
||||
}
|
||||
|
||||
{
|
||||
ClusteringMapAdapter<int, string> m;
|
||||
m.Append(0, "Hello");
|
||||
m.Append(1, "World!");
|
||||
|
||||
TEST_EQUAL(m.Get(0), vector<string>({"Hello"}), ());
|
||||
TEST_EQUAL(m.Get(1), vector<string>({"World!"}), ());
|
||||
|
||||
m.Union(0, 1);
|
||||
TEST_EQUAL(m.Get(0), vector<string>({"Hello", "World!"}), ());
|
||||
TEST_EQUAL(m.Get(1), vector<string>({"Hello", "World!"}), ());
|
||||
|
||||
m.Append(2, "alpha");
|
||||
m.Append(3, "beta");
|
||||
m.Append(4, "gamma");
|
||||
|
||||
TEST_EQUAL(m.Get(2), vector<string>({"alpha"}), ());
|
||||
TEST_EQUAL(m.Get(3), vector<string>({"beta"}), ());
|
||||
TEST_EQUAL(m.Get(4), vector<string>({"gamma"}), ());
|
||||
|
||||
m.Union(2, 3);
|
||||
m.Union(3, 4);
|
||||
|
||||
TEST_EQUAL(m.Get(2), vector<string>({"alpha", "beta", "gamma"}), ());
|
||||
TEST_EQUAL(m.Get(3), vector<string>({"alpha", "beta", "gamma"}), ());
|
||||
TEST_EQUAL(m.Get(4), vector<string>({"alpha", "beta", "gamma"}), ());
|
||||
|
||||
TEST_EQUAL(m.Get(5), vector<string>(), ());
|
||||
m.Union(2, 5);
|
||||
TEST_EQUAL(m.Get(5), vector<string>({"alpha", "beta", "gamma"}), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(ClusteringMap_ForEach)
|
||||
{
|
||||
using Map = ClusteringMapAdapter<int, string>;
|
||||
using Cluster = Map::Cluster;
|
||||
|
||||
{
|
||||
Map m;
|
||||
auto const clusters = m.Clusters();
|
||||
TEST(clusters.empty(), (clusters));
|
||||
}
|
||||
|
||||
{
|
||||
Map m;
|
||||
m.Append(0, "Hello");
|
||||
m.Append(1, "World!");
|
||||
m.Append(2, "alpha");
|
||||
m.Append(3, "beta");
|
||||
m.Append(4, "gamma");
|
||||
|
||||
{
|
||||
vector<Cluster> const expected = {
|
||||
{Cluster{0, "Hello"}, Cluster{1, "World!"}, Cluster{2, "alpha"}, Cluster{3, "beta"}, Cluster{4, "gamma"}}};
|
||||
TEST_EQUAL(expected, m.Clusters(), ());
|
||||
}
|
||||
|
||||
m.Union(0, 1);
|
||||
{
|
||||
vector<Cluster> const expected = {
|
||||
{Cluster{{0, 1}, {"Hello", "World!"}}, Cluster{2, "alpha"}, Cluster{3, "beta"}, Cluster{4, "gamma"}}};
|
||||
TEST_EQUAL(expected, m.Clusters(), ());
|
||||
}
|
||||
|
||||
m.Union(2, 3);
|
||||
m.Union(3, 4);
|
||||
{
|
||||
vector<Cluster> const expected = {
|
||||
{Cluster{{0, 1}, {"Hello", "World!"}}, Cluster{{2, 3, 4}, {"alpha", "beta", "gamma"}}}};
|
||||
TEST_EQUAL(expected, m.Clusters(), ());
|
||||
}
|
||||
|
||||
m.Union(0, 3);
|
||||
{
|
||||
vector<Cluster> const expected = {{Cluster{{0, 1, 2, 3, 4}, {"Hello", "World!", "alpha", "beta", "gamma"}}}};
|
||||
TEST_EQUAL(expected, m.Clusters(), ());
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
17
libs/base/base_tests/collection_cast_test.cpp
Normal file
17
libs/base/base_tests/collection_cast_test.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/collection_cast.hpp"
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
UNIT_TEST(collection_cast)
|
||||
{
|
||||
TEST_EQUAL((std::list<int>{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
}),
|
||||
base::collection_cast<std::list>(std::vector<int>{1, 2, 3, 4}), ());
|
||||
}
|
||||
35
libs/base/base_tests/containers_test.cpp
Normal file
35
libs/base/base_tests/containers_test.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/limited_priority_queue.hpp"
|
||||
|
||||
using namespace base;
|
||||
|
||||
UNIT_TEST(LPQueue_Smoke)
|
||||
{
|
||||
limited_priority_queue<int> q(3);
|
||||
TEST(q.empty(), ());
|
||||
|
||||
q.push(5);
|
||||
q.push(-1);
|
||||
q.push(3);
|
||||
TEST_EQUAL(q.top(), 5, ());
|
||||
|
||||
q.push(2);
|
||||
TEST_EQUAL(q.top(), 3, ());
|
||||
TEST_EQUAL(q.size(), 3, ());
|
||||
|
||||
q.push(0);
|
||||
q.push(0);
|
||||
q.push(0);
|
||||
|
||||
TEST_EQUAL(q.top(), 0, ());
|
||||
q.pop();
|
||||
|
||||
TEST_EQUAL(q.top(), 0, ());
|
||||
q.pop();
|
||||
|
||||
TEST_EQUAL(q.top(), -1, ());
|
||||
q.pop();
|
||||
|
||||
TEST(q.empty(), ());
|
||||
}
|
||||
58
libs/base/base_tests/control_flow_tests.cpp
Normal file
58
libs/base/base_tests/control_flow_tests.cpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/control_flow.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
using namespace base;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Repeater
|
||||
{
|
||||
explicit Repeater(uint32_t repetitions) : m_repetitions(repetitions) {}
|
||||
|
||||
template <typename Fn>
|
||||
void ForEach(Fn && fn)
|
||||
{
|
||||
ControlFlowWrapper<Fn> wrapper(std::forward<Fn>(fn));
|
||||
for (uint32_t i = 0; i < m_repetitions; ++i)
|
||||
{
|
||||
++m_calls;
|
||||
if (wrapper() == ControlFlow::Break)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t m_repetitions = 0;
|
||||
uint32_t m_calls = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(ControlFlow_Smoke)
|
||||
{
|
||||
{
|
||||
Repeater repeater(10);
|
||||
uint32_t c = 0;
|
||||
repeater.ForEach([&c] { ++c; });
|
||||
|
||||
TEST_EQUAL(c, 10, ());
|
||||
TEST_EQUAL(c, repeater.m_repetitions, ());
|
||||
TEST_EQUAL(c, repeater.m_calls, ());
|
||||
}
|
||||
|
||||
{
|
||||
Repeater repeater(10);
|
||||
uint32_t c = 0;
|
||||
repeater.ForEach([&c]
|
||||
{
|
||||
++c;
|
||||
if (c == 5)
|
||||
return ControlFlow::Break;
|
||||
return ControlFlow::Continue;
|
||||
});
|
||||
|
||||
TEST_EQUAL(c, 5, ());
|
||||
TEST_EQUAL(c, repeater.m_calls, ());
|
||||
}
|
||||
}
|
||||
185
libs/base/base_tests/exception_tests.cpp
Normal file
185
libs/base/base_tests/exception_tests.cpp
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/exception.hpp"
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
int FuncDoesNotThrow() noexcept
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int FuncThrowsRootException()
|
||||
{
|
||||
throw RootException("RootException", "RootException");
|
||||
}
|
||||
int FuncThrowsException()
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
int FuncThrowsRuntimeError()
|
||||
{
|
||||
throw std::runtime_error("runtime_error");
|
||||
}
|
||||
int FuncThrowsNumber()
|
||||
{
|
||||
throw 1;
|
||||
}
|
||||
|
||||
int FuncDoesNotThrowArg(int) noexcept
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int FuncThrowsRootExceptionArg(int)
|
||||
{
|
||||
throw RootException("RootException", "RootException");
|
||||
}
|
||||
int FuncThrowsExceptionArg(int)
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
int FuncThrowsNumberArg(int)
|
||||
{
|
||||
throw 1;
|
||||
}
|
||||
|
||||
void FuncDoesNotThrowVoid(int) noexcept
|
||||
{
|
||||
return;
|
||||
}
|
||||
void FuncThrowsRootExceptionVoid(int)
|
||||
{
|
||||
throw RootException("RootException", "RootException");
|
||||
}
|
||||
void FuncThrowsExceptionVoid()
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
void FuncThrowsNumberVoid()
|
||||
{
|
||||
throw 1;
|
||||
}
|
||||
|
||||
std::string const & ReturnsByRef(std::string const & str)
|
||||
{
|
||||
bool exception = true;
|
||||
return ExceptionCatcher("ReturnsByRef().", exception,
|
||||
[](std::string const & str) -> std::string const & { return str; }, str);
|
||||
}
|
||||
|
||||
UNIT_TEST(ExceptionCatcher_FunctionsWithoutArgs)
|
||||
{
|
||||
bool exception = false;
|
||||
ExceptionCatcher("Function without arg.", exception, FuncDoesNotThrow);
|
||||
TEST(!exception, ());
|
||||
ExceptionCatcher("Function without arg.", exception, FuncThrowsRootException);
|
||||
TEST(exception, ());
|
||||
ExceptionCatcher("Function without arg.", exception, FuncThrowsException);
|
||||
TEST(exception, ());
|
||||
ExceptionCatcher("Function without arg.", exception, FuncThrowsRuntimeError);
|
||||
TEST(exception, ());
|
||||
ExceptionCatcher("Function without arg.", exception, FuncThrowsNumber);
|
||||
TEST(exception, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ExceptionCatcher_Functions)
|
||||
{
|
||||
bool exception = false;
|
||||
ExceptionCatcher("Function with arg.", exception, FuncDoesNotThrowArg, 7);
|
||||
TEST(!exception, ());
|
||||
ExceptionCatcher("Function with arg.", exception, FuncThrowsRootExceptionArg, 7);
|
||||
TEST(exception, ());
|
||||
ExceptionCatcher("Function with arg.", exception, FuncThrowsExceptionArg, 7);
|
||||
TEST(exception, ());
|
||||
ExceptionCatcher("Function with arg.", exception, FuncThrowsNumberArg, 7);
|
||||
TEST(exception, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ExceptionCatcher_LambdasReturnInt)
|
||||
{
|
||||
bool exception = false;
|
||||
size_t callCount = 0;
|
||||
ExceptionCatcher("Lambda", exception, [&callCount](int)
|
||||
{
|
||||
++callCount;
|
||||
return 1;
|
||||
}, 7);
|
||||
TEST(!exception, ());
|
||||
TEST_EQUAL(callCount, 1, ());
|
||||
|
||||
ExceptionCatcher("Lambda", exception, [&callCount](int) -> int
|
||||
{
|
||||
++callCount;
|
||||
throw RootException("RootException", "RootException");
|
||||
}, 7);
|
||||
TEST(exception, ());
|
||||
TEST_EQUAL(callCount, 2, ());
|
||||
|
||||
ExceptionCatcher("Lambda", exception, [&callCount](int) -> int
|
||||
{
|
||||
++callCount;
|
||||
throw std::exception();
|
||||
}, 7);
|
||||
TEST(exception, ());
|
||||
TEST_EQUAL(callCount, 3, ());
|
||||
|
||||
ExceptionCatcher("Lambda", exception, [&callCount](int) -> int
|
||||
{
|
||||
++callCount;
|
||||
throw 1;
|
||||
}, 7);
|
||||
TEST(exception, ());
|
||||
TEST_EQUAL(callCount, 4, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ExceptionCatcher_LambdasReturnVoid)
|
||||
{
|
||||
bool exception = false;
|
||||
size_t callCount = 0;
|
||||
ExceptionCatcher("Lambda", exception, [&callCount](int) { ++callCount; }, 7);
|
||||
TEST(!exception, ());
|
||||
TEST_EQUAL(callCount, 1, ());
|
||||
|
||||
ExceptionCatcher("Lambda", exception, [&callCount](int)
|
||||
{
|
||||
++callCount;
|
||||
throw RootException("RootException", "RootException");
|
||||
}, 7);
|
||||
TEST(exception, ());
|
||||
TEST_EQUAL(callCount, 2, ());
|
||||
|
||||
ExceptionCatcher("Lambda", exception, [&callCount](int)
|
||||
{
|
||||
++callCount;
|
||||
throw std::exception();
|
||||
}, 7);
|
||||
TEST(exception, ());
|
||||
TEST_EQUAL(callCount, 3, ());
|
||||
|
||||
ExceptionCatcher("Lambda", exception, [&callCount](int)
|
||||
{
|
||||
++callCount;
|
||||
throw 1;
|
||||
}, 7);
|
||||
TEST(exception, ());
|
||||
TEST_EQUAL(callCount, 4, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ExceptionCatcher_FunctionsReturnVoid)
|
||||
{
|
||||
bool exception = false;
|
||||
ExceptionCatcher("Function returns void.", exception, FuncDoesNotThrowVoid, 7);
|
||||
ExceptionCatcher("Function returns void.", exception, FuncThrowsRootExceptionVoid, 7);
|
||||
ExceptionCatcher("Function returns void.", exception, FuncThrowsExceptionVoid);
|
||||
ExceptionCatcher("Function returns void.", exception, FuncThrowsNumberVoid);
|
||||
}
|
||||
|
||||
UNIT_TEST(ExceptionCatcher_PreventReturningRefOnLocalTemporaryObj)
|
||||
{
|
||||
std::string const str = "A string";
|
||||
auto const returnedStr = ReturnsByRef(str);
|
||||
TEST_EQUAL(str, returnedStr, ());
|
||||
}
|
||||
} // namespace
|
||||
114
libs/base/base_tests/fifo_cache_test.cpp
Normal file
114
libs/base/base_tests/fifo_cache_test.cpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/fifo_cache.hpp"
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-copy"
|
||||
#endif
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
template <typename Key, typename Value>
|
||||
class FifoCacheTest
|
||||
{
|
||||
public:
|
||||
FifoCacheTest(size_t capacity, typename FifoCache<Key, Value>::Loader const & loader) : m_cache(capacity, loader) {}
|
||||
|
||||
Value const & GetValue(Key const & key) { return m_cache.GetValue(key); }
|
||||
unordered_map<Key, Value> const & GetMap() const { return m_cache.m_map; }
|
||||
boost::circular_buffer<Key> const & GetFifo() const { return m_cache.m_fifo; }
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
set<Key> listKeys(m_cache.m_fifo.begin(), m_cache.m_fifo.end());
|
||||
set<Key> mapKeys;
|
||||
|
||||
for (auto const & kv : m_cache.m_map)
|
||||
mapKeys.insert(kv.first);
|
||||
|
||||
return listKeys == mapKeys;
|
||||
}
|
||||
|
||||
private:
|
||||
FifoCache<Key, Value> m_cache;
|
||||
};
|
||||
|
||||
UNIT_TEST(FifoCache_Smoke)
|
||||
{
|
||||
using Key = int;
|
||||
using Value = int;
|
||||
FifoCacheTest<Key, Value> cache(3 /* capacity */, [](Key k, Value & v) { v = k; } /* loader */);
|
||||
|
||||
TEST_EQUAL(cache.GetValue(1), 1, ());
|
||||
TEST_EQUAL(cache.GetValue(2), 2, ());
|
||||
TEST_EQUAL(cache.GetValue(3), 3, ());
|
||||
TEST_EQUAL(cache.GetValue(4), 4, ());
|
||||
TEST_EQUAL(cache.GetValue(1), 1, ());
|
||||
TEST(cache.IsValid(), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(FifoCache)
|
||||
{
|
||||
using Key = int;
|
||||
using Value = int;
|
||||
FifoCacheTest<Key, Value> cache(3 /* capacity */, [](Key k, Value & v) { v = k; } /* loader */);
|
||||
|
||||
TEST_EQUAL(cache.GetValue(1), 1, ());
|
||||
TEST_EQUAL(cache.GetValue(3), 3, ());
|
||||
TEST_EQUAL(cache.GetValue(2), 2, ());
|
||||
TEST(cache.IsValid(), ());
|
||||
{
|
||||
unordered_map<Key, Value> expectedMap({{1 /* key */, 1 /* value */}, {2, 2}, {3, 3}});
|
||||
TEST_EQUAL(cache.GetMap(), expectedMap, ());
|
||||
list<Key> expectedList({2, 3, 1});
|
||||
boost::circular_buffer<Key> expectedCB(expectedList.cbegin(), expectedList.cend());
|
||||
TEST(cache.GetFifo() == expectedCB, ());
|
||||
}
|
||||
|
||||
TEST_EQUAL(cache.GetValue(7), 7, ());
|
||||
TEST(cache.IsValid(), ());
|
||||
{
|
||||
unordered_map<Key, Value> expectedMap({{7 /* key */, 7 /* value */}, {2, 2}, {3, 3}});
|
||||
TEST_EQUAL(cache.GetMap(), expectedMap, ());
|
||||
list<Key> expectedList({7, 2, 3});
|
||||
boost::circular_buffer<Key> expectedCB(expectedList.cbegin(), expectedList.cend());
|
||||
TEST(cache.GetFifo() == expectedCB, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(FifoCache_LoaderCalls)
|
||||
{
|
||||
using Key = int;
|
||||
using Value = int;
|
||||
bool shouldLoadBeCalled = true;
|
||||
auto loader = [&shouldLoadBeCalled](Key k, Value & v)
|
||||
{
|
||||
TEST(shouldLoadBeCalled, ());
|
||||
v = k;
|
||||
};
|
||||
|
||||
FifoCacheTest<Key, Value> cache(3 /* capacity */, loader);
|
||||
TEST(cache.IsValid(), ());
|
||||
cache.GetValue(1);
|
||||
cache.GetValue(2);
|
||||
cache.GetValue(3);
|
||||
TEST(cache.IsValid(), ());
|
||||
shouldLoadBeCalled = false;
|
||||
cache.GetValue(3);
|
||||
cache.GetValue(2);
|
||||
cache.GetValue(1);
|
||||
TEST(cache.IsValid(), ());
|
||||
shouldLoadBeCalled = true;
|
||||
cache.GetValue(4);
|
||||
cache.GetValue(1);
|
||||
TEST(cache.IsValid(), ());
|
||||
}
|
||||
86
libs/base/base_tests/file_name_utils_tests.cpp
Normal file
86
libs/base/base_tests/file_name_utils_tests.cpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/file_name_utils.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
UNIT_TEST(FileName_Smoke)
|
||||
{
|
||||
std::string name = "/Users/xxx/Documents/test.test";
|
||||
TEST_EQUAL(base::GetFileExtension(name), ".test", ());
|
||||
base::GetNameFromFullPath(name);
|
||||
TEST_EQUAL(name, "test.test", ());
|
||||
base::GetNameFromFullPath(name);
|
||||
TEST_EQUAL(name, "test.test", ());
|
||||
base::GetNameWithoutExt(name);
|
||||
TEST_EQUAL(name, "test", ());
|
||||
|
||||
name = "C:\\My Documents\\test.test";
|
||||
TEST_EQUAL(base::GetFileExtension(name), ".test", ());
|
||||
base::GetNameFromFullPath(name);
|
||||
TEST_EQUAL(name, "test.test", ());
|
||||
base::GetNameWithoutExt(name);
|
||||
TEST_EQUAL(name, "test", ());
|
||||
|
||||
name = "/";
|
||||
TEST_EQUAL(base::GetFileExtension(name), std::string(), ());
|
||||
base::GetNameFromFullPath(name);
|
||||
TEST(name.empty(), ());
|
||||
|
||||
name = "C:\\";
|
||||
TEST_EQUAL(base::GetFileExtension(name), std::string(), ());
|
||||
base::GetNameFromFullPath(name);
|
||||
TEST(name.empty(), ());
|
||||
|
||||
name = "../test";
|
||||
TEST_EQUAL(base::GetFileExtension(name), std::string(), ());
|
||||
base::GetNameFromFullPath(name);
|
||||
TEST_EQUAL(name, "test", ());
|
||||
base::GetNameWithoutExt(name);
|
||||
TEST_EQUAL(name, "test", ());
|
||||
}
|
||||
|
||||
// TODO (@gorshenin): implement a Clean() method to clean file path
|
||||
// (remove redundant separators, correctly collapse dots, dot-dots, etc.).
|
||||
#ifndef OMIM_OS_WINDOWS
|
||||
|
||||
UNIT_TEST(FileName_GetDirectory)
|
||||
{
|
||||
TEST_EQUAL("/tmp", base::GetDirectory("/tmp/evil\\file"), ());
|
||||
TEST_EQUAL(".", base::GetDirectory("evil\\file"), ());
|
||||
|
||||
TEST_EQUAL("/", base::GetDirectory("/somefile.txt"), ());
|
||||
|
||||
TEST_EQUAL("/", base::GetDirectory("////somefile"), ());
|
||||
TEST_EQUAL("a/b", base::GetDirectory("a/b///somefile.txt"), ());
|
||||
|
||||
TEST_EQUAL("/a/b", base::GetDirectory("/a/b/c"), ());
|
||||
TEST_EQUAL("/a/b", base::GetDirectory("/a/b/c.txt"), ());
|
||||
|
||||
TEST_EQUAL(".", base::GetDirectory("somefile.txt"), ());
|
||||
TEST_EQUAL(".", base::GetDirectory("somefile"), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(FilePath_Slash)
|
||||
{
|
||||
TEST_EQUAL("/", base::AddSlashIfNeeded(""), ());
|
||||
TEST_EQUAL("/", base::AddSlashIfNeeded("/"), ());
|
||||
TEST_EQUAL("./", base::AddSlashIfNeeded("."), ());
|
||||
TEST_EQUAL("data/", base::AddSlashIfNeeded("data"), ());
|
||||
TEST_EQUAL("data/", base::AddSlashIfNeeded("data/"), ());
|
||||
TEST_EQUAL("/data/", base::AddSlashIfNeeded("/data"), ());
|
||||
TEST_EQUAL("/data/", base::AddSlashIfNeeded("/data/"), ());
|
||||
TEST_EQUAL("../../data/", base::AddSlashIfNeeded("../../data"), ());
|
||||
TEST_EQUAL("../../data/", base::AddSlashIfNeeded("../../data/"), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(FilePath_Join)
|
||||
{
|
||||
TEST_EQUAL("/root//path//file", base::JoinPath("/root/", "/path/", "/file"), ());
|
||||
TEST_EQUAL("omim/strings.txt", base::JoinPath("omim", "strings.txt"), ());
|
||||
TEST_EQUAL("omim/strings.txt", base::JoinPath("omim/", "strings.txt"), ());
|
||||
TEST_EQUAL("../../omim/strings.txt", base::JoinPath("..", "..", "omim", "strings.txt"), ());
|
||||
TEST_EQUAL("../../omim/strings.txt", base::JoinPath("../", "..", "omim/", "strings.txt"), ());
|
||||
}
|
||||
|
||||
#endif // OMIM_OS_WINDOWS
|
||||
67
libs/base/base_tests/geo_object_id_tests.cpp
Normal file
67
libs/base/base_tests/geo_object_id_tests.cpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/geo_object_id.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace base;
|
||||
|
||||
UNIT_TEST(GeoObjectId_Smoke)
|
||||
{
|
||||
GeoObjectId const invalid(GeoObjectId::kInvalid);
|
||||
TEST_EQUAL(invalid.GetType(), GeoObjectId::Type::Invalid, ());
|
||||
TEST_EQUAL(DebugPrint(invalid), "Invalid 0", ());
|
||||
|
||||
GeoObjectId const node(GeoObjectId::Type::ObsoleteOsmNode, 12345);
|
||||
TEST_EQUAL(node.GetSerialId(), 12345ULL, ());
|
||||
TEST_EQUAL(node.GetType(), GeoObjectId::Type::ObsoleteOsmNode, ());
|
||||
TEST_EQUAL(DebugPrint(node), "Osm Node 12345", ());
|
||||
|
||||
GeoObjectId const way(GeoObjectId::Type::ObsoleteOsmWay, 93245123456332ULL);
|
||||
TEST_EQUAL(way.GetSerialId(), 93245123456332ULL, ());
|
||||
TEST_EQUAL(way.GetType(), GeoObjectId::Type::ObsoleteOsmWay, ());
|
||||
TEST_EQUAL(DebugPrint(way), "Osm Way 93245123456332", ());
|
||||
|
||||
GeoObjectId const relation(GeoObjectId::Type::ObsoleteOsmRelation, 5);
|
||||
TEST_EQUAL(relation.GetSerialId(), 5ULL, ());
|
||||
TEST_EQUAL(relation.GetType(), GeoObjectId::Type::ObsoleteOsmRelation, ());
|
||||
TEST_EQUAL(DebugPrint(relation), "Osm Relation 5", ());
|
||||
|
||||
// 2^48 - 1, maximal possible serial id.
|
||||
GeoObjectId const surrogate(GeoObjectId::Type::OsmSurrogate, 281474976710655ULL);
|
||||
TEST_EQUAL(surrogate.GetSerialId(), 281474976710655ULL, ());
|
||||
TEST_EQUAL(surrogate.GetType(), GeoObjectId::Type::OsmSurrogate, ());
|
||||
TEST_EQUAL(DebugPrint(surrogate), "Osm Surrogate 281474976710655", ());
|
||||
|
||||
// 0 is not prohibited by the encoding even though OSM ids start from 1.
|
||||
GeoObjectId const booking(GeoObjectId::Type::BookingComNode, 0);
|
||||
TEST_EQUAL(booking.GetSerialId(), 0, ());
|
||||
TEST_EQUAL(booking.GetType(), GeoObjectId::Type::BookingComNode, ());
|
||||
TEST_EQUAL(DebugPrint(booking), "Booking.com 0", ());
|
||||
|
||||
GeoObjectId const fias(GeoObjectId::Type::Fias, 0xf1a5);
|
||||
TEST_EQUAL(fias.GetSerialId(), 0xf1a5, ());
|
||||
TEST_EQUAL(fias.GetType(), GeoObjectId::Type::Fias, ());
|
||||
TEST_EQUAL(DebugPrint(fias), "FIAS 61861", ());
|
||||
}
|
||||
|
||||
UNIT_TEST(GeoObjectId_Print)
|
||||
{
|
||||
// https://www.openstreetmap.org/#map=19/54.54438/25.69932
|
||||
|
||||
// Belarus -> Lithuania B L
|
||||
LOG(LINFO, (MakeOsmWay(533044131).GetEncodedId())); // 1 3 0
|
||||
LOG(LINFO, (MakeOsmWay(489294139).GetEncodedId())); // 1 0 1
|
||||
|
||||
// Lithuania -> Belarus
|
||||
LOG(LINFO, (MakeOsmWay(614091318).GetEncodedId())); // 1 5 1 1 5 0
|
||||
LOG(LINFO, (MakeOsmWay(148247387).GetEncodedId()));
|
||||
|
||||
// https://www.openstreetmap.org/#map=19/55.30215/10.86668
|
||||
|
||||
// Denmark_Zealand -> Denmark_Southern Z S
|
||||
LOG(LINFO, (MakeOsmWay(2032610).GetEncodedId())); // 1 6 0 1 6 1
|
||||
|
||||
// Denmark_Southern -> Denmark_Zealand
|
||||
LOG(LINFO, (MakeOsmWay(4360600).GetEncodedId())); // 1 18 1 1 18 0
|
||||
}
|
||||
293
libs/base/base_tests/levenshtein_dfa_test.cpp
Normal file
293
libs/base/base_tests/levenshtein_dfa_test.cpp
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/dfa_helpers.hpp"
|
||||
#include "base/levenshtein_dfa.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace levenshtein_dfa_test
|
||||
{
|
||||
using namespace std;
|
||||
using namespace strings;
|
||||
|
||||
enum class Status
|
||||
{
|
||||
Accepts,
|
||||
Rejects,
|
||||
Intermediate
|
||||
};
|
||||
|
||||
struct Result
|
||||
{
|
||||
Result() = default;
|
||||
Result(Status status, size_t errorsMade = 0, size_t prefixErrorsMade = 0)
|
||||
: m_status(status)
|
||||
, m_errorsMade(errorsMade)
|
||||
, m_prefixErrorsMade(prefixErrorsMade)
|
||||
{}
|
||||
|
||||
bool operator==(Result const & rhs) const
|
||||
{
|
||||
return m_status == rhs.m_status && (m_errorsMade == rhs.m_errorsMade || m_status == Status::Rejects) &&
|
||||
(m_prefixErrorsMade == rhs.m_prefixErrorsMade || m_status == Status::Rejects);
|
||||
}
|
||||
|
||||
Status m_status = Status::Accepts;
|
||||
size_t m_errorsMade = 0;
|
||||
size_t m_prefixErrorsMade = 0;
|
||||
};
|
||||
|
||||
string DebugPrint(Status status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case Status::Accepts: return "Accepts";
|
||||
case Status::Rejects: return "Rejects";
|
||||
case Status::Intermediate: return "Intermediate";
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
string DebugPrint(Result const & result)
|
||||
{
|
||||
ostringstream os;
|
||||
os << "Result [ ";
|
||||
os << "status: " << DebugPrint(result.m_status) << ", ";
|
||||
os << "errorsMade: " << result.m_errorsMade << ", ";
|
||||
os << "prefixErrorsMade: " << result.m_prefixErrorsMade << " ]";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
Result GetResult(LevenshteinDFA const & dfa, std::string const & s)
|
||||
{
|
||||
auto it = dfa.Begin();
|
||||
DFAMove(it, s);
|
||||
if (it.Accepts())
|
||||
return Result(Status::Accepts, it.ErrorsMade(), it.PrefixErrorsMade());
|
||||
if (it.Rejects())
|
||||
return Result(Status::Rejects, it.ErrorsMade(), it.PrefixErrorsMade());
|
||||
return Result(Status::Intermediate, it.ErrorsMade(), it.PrefixErrorsMade());
|
||||
}
|
||||
|
||||
bool Accepts(LevenshteinDFA const & dfa, std::string const & s)
|
||||
{
|
||||
return GetResult(dfa, s).m_status == Status::Accepts;
|
||||
}
|
||||
|
||||
bool Rejects(LevenshteinDFA const & dfa, std::string const & s)
|
||||
{
|
||||
return GetResult(dfa, s).m_status == Status::Rejects;
|
||||
}
|
||||
|
||||
bool Intermediate(LevenshteinDFA const & dfa, std::string const & s)
|
||||
{
|
||||
return GetResult(dfa, s).m_status == Status::Intermediate;
|
||||
}
|
||||
|
||||
UNIT_TEST(LevenshteinDFA_Smoke)
|
||||
{
|
||||
{
|
||||
LevenshteinDFA dfa("", 0 /* maxErrors */);
|
||||
|
||||
auto it = dfa.Begin();
|
||||
TEST(it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
|
||||
it.Move('a');
|
||||
TEST(!it.Accepts(), ());
|
||||
TEST(it.Rejects(), ());
|
||||
|
||||
it.Move('b');
|
||||
TEST(!it.Accepts(), ());
|
||||
TEST(it.Rejects(), ());
|
||||
}
|
||||
|
||||
{
|
||||
LevenshteinDFA dfa("abc", 1 /* maxErrors */);
|
||||
|
||||
TEST(Accepts(dfa, "ab"), ());
|
||||
TEST(Accepts(dfa, "abd"), ());
|
||||
TEST(Accepts(dfa, "abcd"), ());
|
||||
TEST(Accepts(dfa, "bbc"), ());
|
||||
|
||||
TEST(Rejects(dfa, "cba"), ());
|
||||
TEST(Rejects(dfa, "abcde"), ());
|
||||
|
||||
TEST(Accepts(dfa, "ac"), ());
|
||||
TEST(Accepts(dfa, "acb"), ());
|
||||
TEST(Accepts(dfa, "acbc"), ());
|
||||
TEST(Rejects(dfa, "acbd"), ());
|
||||
|
||||
TEST(Intermediate(dfa, "a"), ());
|
||||
}
|
||||
|
||||
{
|
||||
LevenshteinDFA dfa("ленинградский", 2 /* maxErrors */);
|
||||
|
||||
TEST(Accepts(dfa, "ленинградский"), ());
|
||||
TEST(Accepts(dfa, "ленингадский"), ());
|
||||
TEST(Accepts(dfa, "ленигнрадский"), ());
|
||||
TEST(Rejects(dfa, "ленинский"), ());
|
||||
}
|
||||
|
||||
{
|
||||
LevenshteinDFA dfa("atm", 1 /* maxErrors */);
|
||||
TEST(Rejects(dfa, "san"), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(LevenshteinDFA_Prefix)
|
||||
{
|
||||
{
|
||||
LevenshteinDFA dfa("москва", 1 /* prefixSize */, 1 /* maxErrors */);
|
||||
TEST(Accepts(dfa, "москва"), ());
|
||||
TEST(Accepts(dfa, "масква"), ());
|
||||
TEST(Accepts(dfa, "моска"), ());
|
||||
TEST(Rejects(dfa, "иосква"), ());
|
||||
}
|
||||
{
|
||||
LevenshteinDFA dfa("москва", 0 /* prefixSize */, 1 /* maxErrors */);
|
||||
TEST(Accepts(dfa, "москва"), ());
|
||||
TEST(Accepts(dfa, "иосква"), ());
|
||||
TEST(Accepts(dfa, "моксва"), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(LevenshteinDFA_ErrorsMade)
|
||||
{
|
||||
{
|
||||
LevenshteinDFA dfa("москва", 1 /* prefixSize */, 2 /* maxErrors */);
|
||||
|
||||
TEST_EQUAL(GetResult(dfa, "москва"), Result(Status::Accepts, 0 /* errorsMade */, 0 /* prefixErrorsMade */), ());
|
||||
TEST_EQUAL(GetResult(dfa, "москв"), Result(Status::Accepts, 1 /* errorsMade */, 0 /* prefixErrorsMade */), ());
|
||||
TEST_EQUAL(GetResult(dfa, "моск"), Result(Status::Accepts, 2 /* errorsMade */, 0 /* prefixErrorsMade */), ());
|
||||
TEST_EQUAL(GetResult(dfa, "мос").m_status, Status::Intermediate, ());
|
||||
TEST_EQUAL(GetResult(dfa, "мос").m_prefixErrorsMade, 0, ());
|
||||
|
||||
TEST_EQUAL(GetResult(dfa, "моксав"), Result(Status::Accepts, 2 /* errorsMade */, 2 /* prefixErrorsMade */), ());
|
||||
TEST_EQUAL(GetResult(dfa, "максав").m_status, Status::Rejects, ());
|
||||
|
||||
TEST_EQUAL(GetResult(dfa, "мсовк").m_status, Status::Intermediate, ());
|
||||
TEST_EQUAL(GetResult(dfa, "мсовк").m_prefixErrorsMade, 2, ());
|
||||
TEST_EQUAL(GetResult(dfa, "мсовка"), Result(Status::Accepts, 2 /* errorsMade */, 2 /* prefixErrorsMade */), ());
|
||||
TEST_EQUAL(GetResult(dfa, "мсовкб").m_status, Status::Rejects, ());
|
||||
}
|
||||
|
||||
{
|
||||
LevenshteinDFA dfa("aa", 0 /* prefixSize */, 2 /* maxErrors */);
|
||||
TEST_EQUAL(GetResult(dfa, "abab"), Result(Status::Accepts, 2 /* errorsMade */, 2 /* prefixErrorsMade */), ());
|
||||
}
|
||||
|
||||
{
|
||||
LevenshteinDFA dfa("mississippi", 0 /* prefixSize */, 0 /* maxErrors */);
|
||||
TEST_EQUAL(GetResult(dfa, "misisipi").m_status, Status::Rejects, ());
|
||||
TEST_EQUAL(GetResult(dfa, "mississipp").m_status, Status::Intermediate, ());
|
||||
TEST_EQUAL(GetResult(dfa, "mississipp").m_prefixErrorsMade, 0, ());
|
||||
TEST_EQUAL(GetResult(dfa, "mississippi"), Result(Status::Accepts, 0 /* errorsMade */, 0 /* prefixErrorsMade */),
|
||||
());
|
||||
}
|
||||
|
||||
{
|
||||
array<UniString, 11> const allowedMisprints = {MakeUniString("yj")};
|
||||
size_t const prefixSize = 1;
|
||||
size_t const maxErrors = 1;
|
||||
string const str = "yekaterinburg";
|
||||
vector<pair<string, Result>> const queries = {
|
||||
{"yekaterinburg", Result(Status::Accepts, 0 /* errorsMade */, 0 /* prefixErrorsMade */)},
|
||||
{"ekaterinburg", Result(Status::Accepts, 1 /* errorsMade */, 1 /* prefixErrorsMade */)},
|
||||
{"jekaterinburg", Result(Status::Accepts, 1 /* errorsMade */, 1 /* prefixErrorsMade */)},
|
||||
{"iekaterinburg", Result(Status::Rejects)}};
|
||||
|
||||
for (auto const & q : queries)
|
||||
{
|
||||
LevenshteinDFA dfa(MakeUniString(q.first), prefixSize, allowedMisprints, maxErrors);
|
||||
TEST_EQUAL(GetResult(dfa, str), q.second, ("Query:", q.first, "string:", str));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
LevenshteinDFA dfa("кафе", 1 /* prefixSize */, 1 /* maxErrors */);
|
||||
TEST_EQUAL(GetResult(dfa, "кафе"), Result(Status::Accepts, 0 /* errorsMade */, 0 /* prefixErrorsMade */), ());
|
||||
TEST_EQUAL(GetResult(dfa, "кафер"), Result(Status::Accepts, 1 /* errorsMade */, 1 /* prefixErrorsMade */), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(LevenshteinDFA_PrefixDFAModifier)
|
||||
{
|
||||
{
|
||||
PrefixDFAModifier<LevenshteinDFA> dfa(LevenshteinDFA("abcde", 2 /* maxErrors */));
|
||||
|
||||
auto it = dfa.Begin();
|
||||
DFAMove(it, "ab");
|
||||
|
||||
TEST(!it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
TEST_EQUAL(it.PrefixErrorsMade(), 0, ());
|
||||
// |maxErrors| for all non-accepting states.
|
||||
TEST_EQUAL(it.ErrorsMade(), 2, ());
|
||||
|
||||
DFAMove(it, "c");
|
||||
TEST(it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
TEST_EQUAL(it.ErrorsMade(), 2, ());
|
||||
TEST_EQUAL(it.PrefixErrorsMade(), 0, ());
|
||||
|
||||
DFAMove(it, "d");
|
||||
TEST(it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
TEST_EQUAL(it.ErrorsMade(), 1, ());
|
||||
TEST_EQUAL(it.PrefixErrorsMade(), 0, ());
|
||||
|
||||
DFAMove(it, "e");
|
||||
TEST(it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
TEST_EQUAL(it.ErrorsMade(), 0, ());
|
||||
TEST_EQUAL(it.PrefixErrorsMade(), 0, ());
|
||||
|
||||
DFAMove(it, "fghijklmn");
|
||||
TEST(it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
TEST_EQUAL(it.ErrorsMade(), 0, ());
|
||||
TEST_EQUAL(it.PrefixErrorsMade(), 0, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(LevenshteinDFA_PrefixDFASmoke)
|
||||
{
|
||||
vector<char> const kAlphabet = {'a', 'b', 'c'};
|
||||
vector<string> sources;
|
||||
vector<string> queries;
|
||||
auto generate = [](vector<char> const & alphabet, size_t size, vector<string> & result)
|
||||
{
|
||||
result.clear();
|
||||
result.resize(math::PowUint(alphabet.size(), size));
|
||||
for (size_t letterNumber = 0; letterNumber < size; ++letterNumber)
|
||||
{
|
||||
for (size_t i = 0; i < result.size(); ++i)
|
||||
{
|
||||
auto const letterIndex = (i / math::PowUint(alphabet.size(), size - letterNumber - 1)) % alphabet.size();
|
||||
result[i].push_back(alphabet[letterIndex]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// @todo What do we check here?
|
||||
{
|
||||
generate(kAlphabet, 4, sources);
|
||||
generate(kAlphabet, 2, queries);
|
||||
|
||||
for (auto const & source : sources)
|
||||
{
|
||||
for (auto const & query : queries)
|
||||
{
|
||||
PrefixDFAModifier<LevenshteinDFA> dfa(LevenshteinDFA(source, 2 /* maxErrors */));
|
||||
auto it = dfa.Begin();
|
||||
for (auto const c : query)
|
||||
DFAMove(it, std::string({c}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace levenshtein_dfa_test
|
||||
52
libs/base/base_tests/linked_map_tests.cpp
Normal file
52
libs/base/base_tests/linked_map_tests.cpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/linked_map.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
UNIT_TEST(LinkedMap_Smoke)
|
||||
{
|
||||
base::LinkedMap<int, std::string, std::map> container;
|
||||
|
||||
TEST(container.IsEmpty(), ());
|
||||
|
||||
TEST(container.Emplace(1, "hello"), ());
|
||||
TEST(container.Emplace(2, "world"), ());
|
||||
TEST(container.Emplace(3, "!"), ());
|
||||
|
||||
TEST(!container.IsEmpty(), ());
|
||||
TEST_EQUAL(container.Size(), 3, ());
|
||||
|
||||
TEST(!container.Emplace(2, "again"), ());
|
||||
|
||||
TEST_EQUAL(container.Size(), 3, ());
|
||||
|
||||
TEST(container.Contains(2), ());
|
||||
auto const getResult = container.Get(2);
|
||||
TEST_EQUAL(getResult, "world", ());
|
||||
|
||||
TEST_EQUAL(container.Front(), "hello", ());
|
||||
container.PopFront();
|
||||
TEST_EQUAL(container.Front(), "world", ());
|
||||
|
||||
TEST_EQUAL(container.Size(), 2, ());
|
||||
|
||||
TEST(!container.Contains(10), ());
|
||||
TEST(!container.Erase(10), ());
|
||||
TEST_EQUAL(container.Size(), 2, ());
|
||||
|
||||
TEST(container.Contains(3), ());
|
||||
TEST(container.Erase(3), ());
|
||||
TEST_EQUAL(container.Size(), 1, ());
|
||||
TEST_EQUAL(container.Front(), "world", ());
|
||||
|
||||
decltype(container) otherContainer;
|
||||
otherContainer.Swap(container);
|
||||
|
||||
TEST(container.IsEmpty(), ());
|
||||
TEST_EQUAL(container.Size(), 0, ());
|
||||
TEST(!otherContainer.IsEmpty(), ());
|
||||
TEST_EQUAL(otherContainer.Size(), 1, ());
|
||||
TEST_EQUAL(otherContainer.Front(), "world", ());
|
||||
}
|
||||
59
libs/base/base_tests/logging_test.cpp
Normal file
59
libs/base/base_tests/logging_test.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
void TestLogMessage(base::LogLevel, base::SrcPoint const &, std::string const &) {}
|
||||
|
||||
bool g_SomeFunctionCalled;
|
||||
int SomeFunction()
|
||||
{
|
||||
g_SomeFunctionCalled = true;
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool BoolFunction(bool result, bool & called)
|
||||
{
|
||||
called = true;
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(Logging_Level)
|
||||
{
|
||||
base::LogLevel const logLevelSaved = base::g_LogLevel;
|
||||
base::g_LogLevel = LWARNING;
|
||||
|
||||
g_SomeFunctionCalled = false;
|
||||
base::LogMessageFn logMessageSaved = base::SetLogMessageFn(&TestLogMessage);
|
||||
|
||||
LOG(LINFO, ("This should not pass", SomeFunction()));
|
||||
TEST(!g_SomeFunctionCalled, ());
|
||||
|
||||
LOG(LWARNING, ("This should pass", SomeFunction()));
|
||||
TEST(g_SomeFunctionCalled, ());
|
||||
|
||||
base::SetLogMessageFn(logMessageSaved);
|
||||
base::g_LogLevel = logLevelSaved;
|
||||
}
|
||||
|
||||
UNIT_TEST(NullMessage)
|
||||
{
|
||||
char const * ptr = 0;
|
||||
LOG(LINFO, ("Null message test", ptr));
|
||||
}
|
||||
|
||||
UNIT_TEST(Logging_ConditionalLog)
|
||||
{
|
||||
bool isCalled = false;
|
||||
CLOG(LINFO, BoolFunction(true, isCalled), ("This should not be displayed"));
|
||||
TEST(isCalled, ());
|
||||
|
||||
isCalled = false;
|
||||
CLOG(LWARNING, BoolFunction(false, isCalled), ("This should be displayed"));
|
||||
TEST(isCalled, ());
|
||||
}
|
||||
174
libs/base/base_tests/lru_cache_tests.cpp
Normal file
174
libs/base/base_tests/lru_cache_tests.cpp
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/lru_cache.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
|
||||
template <typename Key, typename Value>
|
||||
class LruCacheTest
|
||||
{
|
||||
public:
|
||||
using Loader = std::function<void(Key const & key, Value & value)>;
|
||||
|
||||
LruCacheTest(size_t maxCacheSize, Loader const & loader) : m_cache(maxCacheSize), m_loader(loader) {}
|
||||
|
||||
Value const & GetValue(Key const & key)
|
||||
{
|
||||
bool found;
|
||||
auto & value = m_cache.Find(key, found);
|
||||
if (!found)
|
||||
m_loader(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool IsValid() const { return m_cache.IsValidForTesting(); }
|
||||
|
||||
private:
|
||||
LruCache<Key, Value> m_cache;
|
||||
Loader m_loader;
|
||||
};
|
||||
|
||||
template <typename Key, typename Value>
|
||||
class LruCacheKeyAgeTest
|
||||
{
|
||||
public:
|
||||
void InsertKey(Key const & key) { m_keyAge.InsertKey(key); }
|
||||
void UpdateAge(Key const & key) { m_keyAge.UpdateAge(key); }
|
||||
Key const & GetLruKey() const { return m_keyAge.GetLruKey(); }
|
||||
void RemoveLru() { m_keyAge.RemoveLru(); }
|
||||
bool IsValid() const { return m_keyAge.IsValidForTesting(); }
|
||||
|
||||
size_t GetAge() const { return m_keyAge.m_age; }
|
||||
std::map<size_t, Key> const & GetAgeToKey() const { return m_keyAge.m_ageToKey; }
|
||||
std::unordered_map<Key, size_t> const & GetKeyToAge() const { return m_keyAge.m_keyToAge; }
|
||||
|
||||
private:
|
||||
typename LruCache<Key, Value>::KeyAge m_keyAge;
|
||||
};
|
||||
|
||||
template <typename Key, typename Value>
|
||||
void TestAge(LruCacheKeyAgeTest<Key, Value> const & keyAge, size_t expectedAge,
|
||||
std::map<size_t, Key> const & expectedAgeToKey, std::unordered_map<Key, size_t> const & expectedKeyToAge)
|
||||
{
|
||||
TEST(keyAge.IsValid(), ());
|
||||
TEST_EQUAL(keyAge.GetAge(), expectedAge, ());
|
||||
TEST_EQUAL(keyAge.GetAgeToKey(), expectedAgeToKey, ());
|
||||
TEST_EQUAL(keyAge.GetKeyToAge(), expectedKeyToAge, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(LruCacheAgeTest)
|
||||
{
|
||||
using Key = int;
|
||||
using Value = double;
|
||||
LruCacheKeyAgeTest<Key, Value> age;
|
||||
|
||||
TEST_EQUAL(age.GetAge(), 0, ());
|
||||
TEST(age.GetAgeToKey().empty(), ());
|
||||
TEST(age.GetKeyToAge().empty(), ());
|
||||
|
||||
age.InsertKey(10);
|
||||
{
|
||||
std::map<size_t, Key> const expectedAgeToKey({{1 /* age */, 10 /* key */}});
|
||||
std::unordered_map<Key, size_t> const expectedKeyToAge({{10 /* key */, 1 /* age */}});
|
||||
TestAge(age, 1 /* cache age */, expectedAgeToKey, expectedKeyToAge);
|
||||
}
|
||||
|
||||
age.InsertKey(9);
|
||||
{
|
||||
std::map<size_t, Key> const expectedAgeToKey({{1, 10}, {2, 9}});
|
||||
std::unordered_map<Key, size_t> const expectedKeyToAge({{10, 1}, {9, 2}});
|
||||
TestAge(age, 2 /* cache age */, expectedAgeToKey, expectedKeyToAge);
|
||||
}
|
||||
|
||||
age.RemoveLru();
|
||||
{
|
||||
std::map<size_t, Key> const expectedAgeToKey({{2, 9}});
|
||||
std::unordered_map<Key, size_t> const expectedKeyToAge({{9, 2}});
|
||||
TestAge(age, 2 /* cache age */, expectedAgeToKey, expectedKeyToAge);
|
||||
}
|
||||
|
||||
age.InsertKey(11);
|
||||
{
|
||||
std::map<size_t, Key> const expectedAgeToKey({{2, 9}, {3, 11}});
|
||||
std::unordered_map<Key, size_t> const expectedKeyToAge({{9, 2}, {11, 3}});
|
||||
TestAge(age, 3 /* cache age */, expectedAgeToKey, expectedKeyToAge);
|
||||
}
|
||||
|
||||
age.UpdateAge(9);
|
||||
{
|
||||
std::map<size_t, Key> const expectedAgeToKey({{4, 9}, {3, 11}});
|
||||
std::unordered_map<Key, size_t> const expectedKeyToAge({{9, 4}, {11, 3}});
|
||||
TestAge(age, 4 /* cache age */, expectedAgeToKey, expectedKeyToAge);
|
||||
}
|
||||
|
||||
age.RemoveLru();
|
||||
{
|
||||
std::map<size_t, Key> const expectedAgeToKey({{4, 9}});
|
||||
std::unordered_map<Key, size_t> const expectedKeyToAge({{9, 4}});
|
||||
TestAge(age, 4 /* cache age */, expectedAgeToKey, expectedKeyToAge);
|
||||
}
|
||||
|
||||
age.InsertKey(12);
|
||||
{
|
||||
std::map<size_t, Key> const expectedAgeToKey({{4, 9}, {5, 12}});
|
||||
std::unordered_map<Key, size_t> const expectedKeyToAge({{9, 4}, {12, 5}});
|
||||
TestAge(age, 5 /* cache age */, expectedAgeToKey, expectedKeyToAge);
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(LruCacheSmokeTest)
|
||||
{
|
||||
using Key = int;
|
||||
using Value = int;
|
||||
|
||||
{
|
||||
LruCacheTest<Key, Value> cache(1 /* maxCacheSize */, [](Key k, Value & v) { v = 1; } /* loader */);
|
||||
TEST_EQUAL(cache.GetValue(1), 1, ());
|
||||
TEST_EQUAL(cache.GetValue(2), 1, ());
|
||||
TEST_EQUAL(cache.GetValue(3), 1, ());
|
||||
TEST_EQUAL(cache.GetValue(4), 1, ());
|
||||
TEST_EQUAL(cache.GetValue(1), 1, ());
|
||||
TEST(cache.IsValid(), ());
|
||||
}
|
||||
|
||||
{
|
||||
LruCacheTest<Key, Value> cache(3 /* maxCacheSize */, [](Key k, Value & v) { v = k; } /* loader */);
|
||||
TEST_EQUAL(cache.GetValue(1), 1, ());
|
||||
TEST_EQUAL(cache.GetValue(2), 2, ());
|
||||
TEST_EQUAL(cache.GetValue(2), 2, ());
|
||||
TEST_EQUAL(cache.GetValue(5), 5, ());
|
||||
TEST_EQUAL(cache.GetValue(1), 1, ());
|
||||
TEST(cache.IsValid(), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(LruCacheLoaderCallsTest)
|
||||
{
|
||||
using Key = int;
|
||||
using Value = int;
|
||||
bool shouldLoadBeCalled = true;
|
||||
auto loader = [&shouldLoadBeCalled](Key k, Value & v)
|
||||
{
|
||||
TEST(shouldLoadBeCalled, ());
|
||||
v = k;
|
||||
};
|
||||
|
||||
LruCacheTest<Key, Value> cache(3 /* maxCacheSize */, loader);
|
||||
TEST(cache.IsValid(), ());
|
||||
cache.GetValue(1);
|
||||
cache.GetValue(2);
|
||||
cache.GetValue(3);
|
||||
TEST(cache.IsValid(), ());
|
||||
shouldLoadBeCalled = false;
|
||||
cache.GetValue(3);
|
||||
cache.GetValue(2);
|
||||
cache.GetValue(1);
|
||||
TEST(cache.IsValid(), ());
|
||||
shouldLoadBeCalled = true;
|
||||
cache.GetValue(4);
|
||||
TEST(cache.IsValid(), ());
|
||||
shouldLoadBeCalled = false;
|
||||
cache.GetValue(1);
|
||||
TEST(cache.IsValid(), ());
|
||||
}
|
||||
228
libs/base/base_tests/math_test.cpp
Normal file
228
libs/base/base_tests/math_test.cpp
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/math.hpp"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <boost/math/special_functions/next.hpp>
|
||||
|
||||
namespace math_test
|
||||
{
|
||||
using namespace math;
|
||||
|
||||
namespace
|
||||
{
|
||||
// Returns the next representable floating point value without using conversion to integer.
|
||||
template <typename Float>
|
||||
Float NextFloat(Float const x, int dir = 1)
|
||||
{
|
||||
return boost::math::float_advance(x, dir);
|
||||
}
|
||||
|
||||
template <typename Float>
|
||||
void TestMaxULPs()
|
||||
{
|
||||
for (unsigned int logMaxULPs = 0; logMaxULPs <= 8; ++logMaxULPs)
|
||||
{
|
||||
unsigned int const maxULPs = (1 << logMaxULPs) - 1;
|
||||
for (int base = -1; base <= 1; ++base)
|
||||
{
|
||||
for (int dir = -1; dir <= 1; dir += 2)
|
||||
{
|
||||
Float const x = base;
|
||||
Float y = x;
|
||||
for (unsigned int i = 0; i <= maxULPs; ++i)
|
||||
{
|
||||
TEST(AlmostEqualULPs(x, y, maxULPs), (x, y, maxULPs, x - y, dir));
|
||||
Float const nextY = NextFloat(y, dir);
|
||||
TEST_NOT_EQUAL(y, nextY, (i, base, dir));
|
||||
y = nextY;
|
||||
}
|
||||
TEST(!AlmostEqualULPs(x, y, maxULPs), (x, y, maxULPs, x - y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(round_lround_smoke)
|
||||
{
|
||||
TEST_EQUAL(std::round(0.4), 0.0, ());
|
||||
TEST_EQUAL(std::round(0.6), 1.0, ());
|
||||
TEST_EQUAL(std::round(-0.4), 0.0, ());
|
||||
TEST_EQUAL(std::round(-0.6), -1.0, ());
|
||||
|
||||
TEST_EQUAL(std::lround(0.4), 0l, ());
|
||||
TEST_EQUAL(std::lround(0.6), 1l, ());
|
||||
TEST_EQUAL(std::lround(-0.4), 0l, ());
|
||||
TEST_EQUAL(std::lround(-0.6), -1l, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(PowUInt)
|
||||
{
|
||||
TEST_EQUAL(PowUint(3, 10), 59049, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(AlmostEqualULPs_double)
|
||||
{
|
||||
TEST_ALMOST_EQUAL_ULPS(3.0, 3.0, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(+0.0, -0.0, ());
|
||||
|
||||
double constexpr eps = std::numeric_limits<double>::epsilon();
|
||||
double constexpr dmax = std::numeric_limits<double>::max();
|
||||
|
||||
TEST_ALMOST_EQUAL_ULPS(1.0 + eps, 1.0, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(1.0 - eps, 1.0, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(1.0 - eps, 1.0 + eps, ());
|
||||
|
||||
TEST_ALMOST_EQUAL_ULPS(dmax, dmax, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(-dmax, -dmax, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(dmax / 2.0, dmax / 2.0, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(1.0 / dmax, 1.0 / dmax, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(-1.0 / dmax, -1.0 / dmax, ());
|
||||
|
||||
TEST(!AlmostEqualULPs(1.0, -1.0), ());
|
||||
TEST(!AlmostEqualULPs(2.0, -2.0), ());
|
||||
TEST(!AlmostEqualULPs(dmax, -dmax), ());
|
||||
|
||||
// That's why AlmostEqualULPs is a strange function, IMHO.
|
||||
TEST(!AlmostEqualULPs(0.0, eps), ());
|
||||
TEST(!AlmostEqualULPs(-eps, 0.0), ());
|
||||
TEST(!AlmostEqualULPs(eps, 2.0 * eps), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(AlmostEqualULPs_float)
|
||||
{
|
||||
TEST_ALMOST_EQUAL_ULPS(3.0f, 3.0f, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(+0.0f, -0.0f, ());
|
||||
|
||||
float const eps = std::numeric_limits<float>::epsilon();
|
||||
float const dmax = std::numeric_limits<float>::max();
|
||||
|
||||
TEST_ALMOST_EQUAL_ULPS(1.0f + eps, 1.0f, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(1.0f - eps, 1.0f, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(1.0f - eps, 1.0f + eps, ());
|
||||
|
||||
TEST_ALMOST_EQUAL_ULPS(dmax, dmax, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(-dmax, -dmax, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(dmax / 2.0f, dmax / 2.0f, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(1.0f / dmax, 1.0f / dmax, ());
|
||||
TEST_ALMOST_EQUAL_ULPS(-1.0f / dmax, -1.0f / dmax, ());
|
||||
|
||||
TEST(!AlmostEqualULPs(1.0f, -1.0f), ());
|
||||
TEST(!AlmostEqualULPs(2.0f, -2.0f), ());
|
||||
TEST(!AlmostEqualULPs(dmax, -dmax), ());
|
||||
|
||||
// That's why AlmostEqualULPs is a strange function, IMHO.
|
||||
TEST(!AlmostEqualULPs(0.0f, eps), ());
|
||||
TEST(!AlmostEqualULPs(-eps, 0.0f), ());
|
||||
TEST(!AlmostEqualULPs(eps, 2.0f * eps), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(AlmostEqual_Smoke)
|
||||
{
|
||||
double constexpr small = 1e-18;
|
||||
double constexpr eps = 1e-10;
|
||||
|
||||
TEST(AlmostEqualAbs(0.0, 0.0 + small, eps), ());
|
||||
TEST(!AlmostEqualRel(0.0, 0.0 + small, eps), ());
|
||||
TEST(!AlmostEqualULPs(0.0, 0.0 + small), ());
|
||||
|
||||
TEST(AlmostEqualAbs(1.0, 1.0 + small, eps), ());
|
||||
TEST(AlmostEqualRel(1.0, 1.0 + small, eps), ());
|
||||
TEST(AlmostEqualULPs(1.0, 1.0 + small), ());
|
||||
|
||||
TEST(AlmostEqualRel(123456789.0, 123456780.0, 1e-7), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(AlmostEqualULPs_MaxULPs_double)
|
||||
{
|
||||
TestMaxULPs<double>();
|
||||
}
|
||||
|
||||
UNIT_TEST(AlmostEqualULPs_MaxULPs_float)
|
||||
{
|
||||
TestMaxULPs<float>();
|
||||
}
|
||||
|
||||
UNIT_TEST(TEST_FLOAT_DOUBLE_EQUAL_macros)
|
||||
{
|
||||
float const fx = 3;
|
||||
float const fy = NextFloat(NextFloat(NextFloat(fx)));
|
||||
TEST_ALMOST_EQUAL_ULPS(fx, fy, ());
|
||||
TEST_NOT_ALMOST_EQUAL_ULPS(fx, 2.0f, ());
|
||||
|
||||
double const dx = 3;
|
||||
double const dy = NextFloat(NextFloat(NextFloat(dx)));
|
||||
TEST_ALMOST_EQUAL_ULPS(dx, dy, ());
|
||||
TEST_NOT_ALMOST_EQUAL_ULPS(dx, 2.0, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(GCD)
|
||||
{
|
||||
TEST_EQUAL(GCD(6, 3), 3, ());
|
||||
TEST_EQUAL(GCD(14, 7), 7, ());
|
||||
TEST_EQUAL(GCD(100, 100), 100, ());
|
||||
TEST_EQUAL(GCD(7, 3), 1, ());
|
||||
TEST_EQUAL(GCD(8, 3), 1, ());
|
||||
TEST_EQUAL(GCD(9, 3), 3, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(LCM)
|
||||
{
|
||||
TEST_EQUAL(LCM(6, 3), 6, ());
|
||||
TEST_EQUAL(LCM(14, 7), 14, ());
|
||||
TEST_EQUAL(LCM(100, 100), 100, ());
|
||||
TEST_EQUAL(LCM(7, 3), 21, ());
|
||||
TEST_EQUAL(LCM(8, 3), 24, ());
|
||||
TEST_EQUAL(LCM(9, 3), 9, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Sign)
|
||||
{
|
||||
TEST_EQUAL(1, Sign(1), ());
|
||||
TEST_EQUAL(1, Sign(10.4), ());
|
||||
|
||||
TEST_EQUAL(0, Sign(0), ());
|
||||
TEST_EQUAL(0, Sign(0.0), ());
|
||||
|
||||
TEST_EQUAL(-1, Sign(-11), ());
|
||||
TEST_EQUAL(-1, Sign(-10.4), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(is_finite)
|
||||
{
|
||||
static_assert(std::numeric_limits<double>::has_infinity);
|
||||
static_assert(std::numeric_limits<double>::has_quiet_NaN);
|
||||
|
||||
using math::is_finite, math::Nan, math::Infinity;
|
||||
|
||||
TEST(!is_finite(Nan()), ());
|
||||
TEST(!is_finite(Infinity()), ());
|
||||
TEST(!is_finite(DBL_MAX * 2.0), ());
|
||||
|
||||
TEST(is_finite(0.0), ());
|
||||
TEST(is_finite(1.0), ());
|
||||
TEST(is_finite(-2.0), ());
|
||||
TEST(is_finite(DBL_MIN), ());
|
||||
TEST(is_finite(DBL_MAX), ());
|
||||
TEST(is_finite(DBL_MIN / 2.0), ("As in cppreference example"));
|
||||
}
|
||||
|
||||
UNIT_TEST(iround)
|
||||
{
|
||||
TEST_EQUAL(iround(0.0), 0, ());
|
||||
TEST_EQUAL(iround(1.0), 1, ());
|
||||
TEST_EQUAL(iround(1.5), 2, ());
|
||||
TEST_EQUAL(iround(-1.5), -2, ());
|
||||
TEST_EQUAL(iround(2.5), 3, ());
|
||||
TEST_EQUAL(iround(-2.5), -3, ());
|
||||
|
||||
TEST_EQUAL(iround(2.5f), 3, ());
|
||||
TEST_EQUAL(iround(-2.5f), -3, ());
|
||||
|
||||
TEST_EQUAL(iround(double(std::numeric_limits<int>::max()) - 0.5), std::numeric_limits<int>::max(), ());
|
||||
TEST_EQUAL(iround(double(std::numeric_limits<int>::min()) + 0.5), std::numeric_limits<int>::min(), ());
|
||||
}
|
||||
|
||||
} // namespace math_test
|
||||
34
libs/base/base_tests/matrix_test.cpp
Normal file
34
libs/base/base_tests/matrix_test.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/matrix.hpp"
|
||||
|
||||
UNIT_TEST(Matrix_Inverse_Simple)
|
||||
{
|
||||
math::Matrix<double, 3, 3> m;
|
||||
|
||||
m = math::Identity<double, 3>();
|
||||
|
||||
m(2, 0) = 2;
|
||||
|
||||
math::Matrix<double, 3, 3> m1 = math::Inverse(m);
|
||||
|
||||
TEST_EQUAL((m1 * m).Equal(math::Identity<double, 3>()), true, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Matrix_Inverse_AllElementsNonZero)
|
||||
{
|
||||
math::Matrix<double, 3, 3> m;
|
||||
m(0, 0) = 5;
|
||||
m(0, 1) = 3;
|
||||
m(0, 2) = 6;
|
||||
m(1, 0) = 1;
|
||||
m(1, 1) = 7;
|
||||
m(1, 2) = 9;
|
||||
m(2, 0) = 2;
|
||||
m(2, 1) = 13;
|
||||
m(2, 2) = 4;
|
||||
|
||||
math::Matrix<double, 3, 3> m1 = math::Inverse(m);
|
||||
|
||||
TEST_EQUAL((m1 * m).Equal(math::Identity<double, 3>()), true, ());
|
||||
}
|
||||
190
libs/base/base_tests/mem_trie_test.cpp
Normal file
190
libs/base/base_tests/mem_trie_test.cpp
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/mem_trie.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace base;
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
using Key = string;
|
||||
using Value = int;
|
||||
using Trie = MemTrie<Key, VectorValues<Value>>;
|
||||
using Data = vector<pair<Key, Value>>;
|
||||
|
||||
Data GetTrieContents(Trie const & trie)
|
||||
{
|
||||
Data data;
|
||||
trie.ForEachInTrie([&data](string const & k, int v) { data.emplace_back(k, v); });
|
||||
sort(data.begin(), data.end());
|
||||
return data;
|
||||
}
|
||||
|
||||
class MemTrieTest
|
||||
{
|
||||
public:
|
||||
Data GetActualContents() const
|
||||
{
|
||||
Data data;
|
||||
m_trie.ForEachInTrie([&data](Key const & k, Value const & v) { data.emplace_back(k, v); });
|
||||
sort(data.begin(), data.end());
|
||||
return data;
|
||||
}
|
||||
|
||||
Data GetExpectedContents() const { return {m_data.cbegin(), m_data.cend()}; }
|
||||
|
||||
vector<Value> GetValuesByKey(Key const & key) const
|
||||
{
|
||||
vector<Value> values;
|
||||
m_trie.ForEachInNode(key, [&](Value const & value) { values.push_back(value); });
|
||||
sort(values.begin(), values.end());
|
||||
return values;
|
||||
}
|
||||
|
||||
Data GetContentsByPrefix(Key const & prefix) const
|
||||
{
|
||||
Data data;
|
||||
m_trie.ForEachInSubtree(prefix, [&data](Key const & k, Value const & v) { data.emplace_back(k, v); });
|
||||
sort(data.begin(), data.end());
|
||||
return data;
|
||||
}
|
||||
|
||||
bool HasKey(Key const & key) const { return m_trie.HasKey(key); }
|
||||
bool HasPrefix(Key const & prefix) const { return m_trie.HasPrefix(prefix); }
|
||||
|
||||
size_t GetNumNodes() const { return m_trie.GetNumNodes(); }
|
||||
|
||||
void Add(Key const & key, Value const & value)
|
||||
{
|
||||
m_trie.Add(key, value);
|
||||
m_data.insert(make_pair(key, value));
|
||||
}
|
||||
|
||||
void Erase(Key const & key, Value const & value)
|
||||
{
|
||||
m_trie.Erase(key, value);
|
||||
m_data.erase(make_pair(key, value));
|
||||
}
|
||||
|
||||
protected:
|
||||
Trie m_trie;
|
||||
multiset<pair<Key, Value>> m_data;
|
||||
};
|
||||
|
||||
UNIT_CLASS_TEST(MemTrieTest, Basic)
|
||||
{
|
||||
TEST_EQUAL(GetNumNodes(), 1, ());
|
||||
|
||||
TEST(!HasKey(""), ());
|
||||
TEST(!HasKey("a"), ());
|
||||
TEST(!HasPrefix(""), ());
|
||||
TEST(!HasPrefix("a"), ());
|
||||
|
||||
Data const data = {{"roger", 3}, {"amy", 1}, {"emma", 1}, {"ann", 1},
|
||||
{"rob", 1}, {"roger", 2}, {"", 0}, {"roger", 1}};
|
||||
for (auto const & kv : data)
|
||||
Add(kv.first, kv.second);
|
||||
|
||||
TEST_EQUAL(GetNumNodes(), 8, ());
|
||||
TEST(HasKey(""), ());
|
||||
TEST(!HasKey("a"), ());
|
||||
TEST(HasPrefix(""), ());
|
||||
TEST(HasPrefix("a"), ());
|
||||
|
||||
TEST_EQUAL(GetExpectedContents(), GetActualContents(), ());
|
||||
TEST_EQUAL(GetNumNodes(), 8, ());
|
||||
|
||||
Trie newTrie(std::move(m_trie));
|
||||
|
||||
TEST_EQUAL(m_trie.GetNumNodes(), 1, ());
|
||||
TEST(GetTrieContents(m_trie).empty(), ());
|
||||
|
||||
TEST_EQUAL(newTrie.GetNumNodes(), 8, ());
|
||||
TEST_EQUAL(GetTrieContents(newTrie), GetExpectedContents(), ());
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(MemTrieTest, KeysRemoval)
|
||||
{
|
||||
TEST_EQUAL(GetNumNodes(), 1, ());
|
||||
|
||||
TEST(!HasKey("r"), ());
|
||||
TEST(!HasPrefix("r"), ());
|
||||
TEST(!HasKey("ro"), ());
|
||||
TEST(!HasPrefix("ro"), ());
|
||||
|
||||
Data const data = {{"bobby", 1}, {"robby", 2}, {"rob", 3}, {"r", 4}, {"robert", 5}, {"bob", 6}};
|
||||
|
||||
for (auto const & kv : data)
|
||||
Add(kv.first, kv.second);
|
||||
|
||||
TEST(HasKey("r"), ());
|
||||
TEST(HasPrefix("r"), ());
|
||||
TEST(!HasKey("ro"), ());
|
||||
TEST(HasPrefix("ro"), ());
|
||||
|
||||
TEST_EQUAL(GetNumNodes(), 7, ());
|
||||
TEST_EQUAL(GetExpectedContents(), GetActualContents(), ());
|
||||
|
||||
Erase("r", 3);
|
||||
TEST_EQUAL(GetNumNodes(), 7, ());
|
||||
TEST_EQUAL(GetExpectedContents(), GetActualContents(), ());
|
||||
|
||||
Erase("r", 4);
|
||||
TEST_EQUAL(GetNumNodes(), 6, ());
|
||||
TEST_EQUAL(GetExpectedContents(), GetActualContents(), ());
|
||||
|
||||
Erase("robert", 5);
|
||||
TEST_EQUAL(GetNumNodes(), 5, ());
|
||||
TEST_EQUAL(GetExpectedContents(), GetActualContents(), ());
|
||||
|
||||
Erase("rob", 3);
|
||||
TEST_EQUAL(GetNumNodes(), 4, ());
|
||||
TEST_EQUAL(GetExpectedContents(), GetActualContents(), ());
|
||||
|
||||
Erase("robby", 2);
|
||||
TEST_EQUAL(GetNumNodes(), 3, ());
|
||||
TEST_EQUAL(GetExpectedContents(), GetActualContents(), ());
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(MemTrieTest, ForEachInNode)
|
||||
{
|
||||
Add("abracadabra", 0);
|
||||
Add("abra", 1);
|
||||
Add("abra", 2);
|
||||
Add("abrau", 3);
|
||||
|
||||
TEST_EQUAL(GetValuesByKey("a"), vector<Value>{}, ());
|
||||
TEST_EQUAL(GetValuesByKey("abrac"), vector<Value>{}, ());
|
||||
TEST_EQUAL(GetValuesByKey("abracadabr"), vector<Value>{}, ());
|
||||
TEST_EQUAL(GetValuesByKey("void"), vector<Value>{}, ());
|
||||
|
||||
TEST_EQUAL(GetValuesByKey("abra"), vector<Value>({1, 2}), ());
|
||||
TEST_EQUAL(GetValuesByKey("abracadabra"), vector<Value>({0}), ());
|
||||
TEST_EQUAL(GetValuesByKey("abrau"), vector<Value>({3}), ());
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(MemTrieTest, ForEachInSubtree)
|
||||
{
|
||||
Add("abracadabra", 0);
|
||||
Add("abra", 1);
|
||||
Add("abra", 2);
|
||||
Add("abrau", 3);
|
||||
|
||||
Data const all = {{"abra", 1}, {"abra", 2}, {"abracadabra", 0}, {"abrau", 3}};
|
||||
|
||||
TEST_EQUAL(GetContentsByPrefix(""), all, ());
|
||||
TEST_EQUAL(GetContentsByPrefix("a"), all, ());
|
||||
TEST_EQUAL(GetContentsByPrefix("abra"), all, ());
|
||||
TEST_EQUAL(GetContentsByPrefix("abracadabr"), Data({{"abracadabra", 0}}), ());
|
||||
TEST_EQUAL(GetContentsByPrefix("abracadabra"), Data({{"abracadabra", 0}}), ());
|
||||
TEST_EQUAL(GetContentsByPrefix("void"), Data{}, ());
|
||||
TEST_EQUAL(GetContentsByPrefix("abra"), all, ());
|
||||
TEST_EQUAL(GetContentsByPrefix("abrau"), Data({{"abrau", 3}}), ());
|
||||
}
|
||||
} // namespace
|
||||
20
libs/base/base_tests/message_test.cpp
Normal file
20
libs/base/base_tests/message_test.cpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
UNIT_TEST(DebugPrint_Char)
|
||||
{
|
||||
char const * s = "Тест";
|
||||
|
||||
char const arr1[] = "Тест";
|
||||
char constexpr arr2[] = "Тест";
|
||||
char arr3[] = "Тест";
|
||||
|
||||
std::string str(s);
|
||||
char * s2 = str.data();
|
||||
|
||||
TEST_EQUAL(s, DebugPrint(s), ());
|
||||
TEST_EQUAL(s, DebugPrint(arr1), ());
|
||||
TEST_EQUAL(s, DebugPrint(arr2), ());
|
||||
TEST_EQUAL(s, DebugPrint(arr3), ());
|
||||
TEST_EQUAL(s, DebugPrint(s2), ());
|
||||
TEST_EQUAL(s, DebugPrint(str), ());
|
||||
}
|
||||
115
libs/base/base_tests/newtype_test.cpp
Normal file
115
libs/base/base_tests/newtype_test.cpp
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/newtype.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace newtype_test
|
||||
{
|
||||
NEWTYPE(int, Int);
|
||||
|
||||
std::string DebugPrint(Int const & i)
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "Int(" << i.Get() << ')';
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
UNIT_TEST(NewType_TypeChecks)
|
||||
{
|
||||
TEST((std::is_constructible<Int, int>::value), ());
|
||||
TEST((std::is_constructible<Int, char>::value), ());
|
||||
TEST(!(std::is_convertible<int, Int>::value), ());
|
||||
TEST(!(std::is_convertible<Int, int>::value), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(NewType_Base)
|
||||
{
|
||||
Int a{10};
|
||||
TEST_EQUAL(a.Get(), 10, ());
|
||||
|
||||
a.Set(100);
|
||||
TEST_EQUAL(a.Get(), 100, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(NewType_Operations)
|
||||
{
|
||||
TEST(Int(10) == Int(10), ());
|
||||
TEST(Int(20) != Int(30), ());
|
||||
TEST(Int(10) < Int(20), ());
|
||||
TEST(Int(10) <= Int(20), ());
|
||||
TEST(Int(20) > Int(10), ());
|
||||
TEST(Int(20) >= Int(10), ());
|
||||
|
||||
TEST_EQUAL(Int(10) + Int(20), Int(30), ());
|
||||
TEST_EQUAL(Int(10) - Int(20), Int(-10), ());
|
||||
TEST_EQUAL(Int(10) / Int(2), Int(5), ());
|
||||
TEST_EQUAL(Int(10) * Int(2), Int(20), ());
|
||||
TEST_EQUAL(Int(10) % Int(3), Int(1), ());
|
||||
|
||||
TEST_EQUAL(Int(10) | Int(7), Int(10 | 7), ());
|
||||
TEST_EQUAL(Int(10) & Int(7), Int(10 & 7), ());
|
||||
TEST_EQUAL(Int(10) ^ Int(7), Int(10 ^ 7), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(NewTypeMember_Operations)
|
||||
{
|
||||
Int a(10);
|
||||
auto b = a--;
|
||||
TEST_EQUAL(a, Int(9), ());
|
||||
TEST_EQUAL(b, Int(10), ());
|
||||
|
||||
b = --a;
|
||||
TEST_EQUAL(a, b, ());
|
||||
TEST_EQUAL(a, Int(8), ());
|
||||
|
||||
b = ++a;
|
||||
TEST_EQUAL(a, b, ());
|
||||
TEST_EQUAL(a, Int(9), ());
|
||||
|
||||
b = a++;
|
||||
TEST_EQUAL(a, Int(10), ());
|
||||
TEST_EQUAL(b, Int(9), ());
|
||||
|
||||
a.Set(100);
|
||||
b = Int(2);
|
||||
a *= b;
|
||||
TEST_EQUAL(a, Int(200), ());
|
||||
|
||||
a /= b;
|
||||
TEST_EQUAL(a, Int(100), ());
|
||||
|
||||
b.Set(3);
|
||||
a %= b;
|
||||
TEST_EQUAL(a, Int(1), ());
|
||||
|
||||
a.Set(10);
|
||||
a |= Int(7);
|
||||
TEST_EQUAL(a, Int(10 | 7), ());
|
||||
|
||||
a.Set(10);
|
||||
a &= Int(7);
|
||||
TEST_EQUAL(a, Int(10 & 7), ());
|
||||
|
||||
a.Set(10);
|
||||
a ^= Int(7);
|
||||
TEST_EQUAL(a, Int(10 ^ 7), ());
|
||||
}
|
||||
|
||||
namespace test_output
|
||||
{
|
||||
NEWTYPE_SIMPLE_OUTPUT(Int);
|
||||
} // namespace test_output
|
||||
|
||||
UNIT_TEST(NewType_SimpleOutPut)
|
||||
{
|
||||
using namespace test_output;
|
||||
TEST_EQUAL(test_output::DebugPrint(Int(10)), "10", ());
|
||||
|
||||
std::ostringstream sstr;
|
||||
sstr << Int(20);
|
||||
TEST_EQUAL(sstr.str(), "20", ());
|
||||
}
|
||||
} // namespace newtype_test
|
||||
79
libs/base/base_tests/non_intersecting_intervals_tests.cpp
Normal file
79
libs/base/base_tests/non_intersecting_intervals_tests.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/non_intersecting_intervals.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace base;
|
||||
|
||||
UNIT_TEST(NonIntersectingIntervals_1)
|
||||
{
|
||||
NonIntersectingIntervals<int> intervals;
|
||||
|
||||
TEST(intervals.AddInterval(1, 10), ());
|
||||
TEST(intervals.AddInterval(11, 15), ());
|
||||
// Overlap with [1, 10].
|
||||
TEST(!intervals.AddInterval(1, 20), ());
|
||||
|
||||
// Overlap with [11, 15].
|
||||
TEST(!intervals.AddInterval(13, 20), ());
|
||||
|
||||
// Overlap with [1, 10] and [11, 15].
|
||||
TEST(!intervals.AddInterval(0, 100), ());
|
||||
|
||||
TEST(intervals.AddInterval(100, 150), ());
|
||||
|
||||
// Overlap with [100, 150].
|
||||
TEST(!intervals.AddInterval(90, 200), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(NonIntersectingIntervals_2)
|
||||
{
|
||||
NonIntersectingIntervals<int> intervals;
|
||||
|
||||
TEST(intervals.AddInterval(1, 10), ());
|
||||
// Overlap with [1, 10].
|
||||
TEST(!intervals.AddInterval(2, 9), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(NonIntersectingIntervals_3)
|
||||
{
|
||||
NonIntersectingIntervals<int> intervals;
|
||||
|
||||
TEST(intervals.AddInterval(1, 10), ());
|
||||
// Overlap with [1, 10].
|
||||
TEST(!intervals.AddInterval(0, 20), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(NonIntersectingIntervals_4)
|
||||
{
|
||||
NonIntersectingIntervals<int> intervals;
|
||||
|
||||
TEST(intervals.AddInterval(1, 10), ());
|
||||
// Overlap with [1, 10].
|
||||
TEST(!intervals.AddInterval(10, 20), ());
|
||||
TEST(!intervals.AddInterval(0, 1), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(NonIntersectingIntervals_5)
|
||||
{
|
||||
NonIntersectingIntervals<int> intervals;
|
||||
|
||||
TEST(intervals.AddInterval(0, 1), ());
|
||||
|
||||
// Overlap with [0, 1].
|
||||
TEST(!intervals.AddInterval(1, 2), ());
|
||||
|
||||
TEST(intervals.AddInterval(2, 3), ());
|
||||
TEST(intervals.AddInterval(4, 5), ());
|
||||
|
||||
// Overlap with [0, 1] and [2, 3].
|
||||
TEST(!intervals.AddInterval(1, 3), ());
|
||||
|
||||
// Overlap with [2, 3].
|
||||
TEST(!intervals.AddInterval(2, 2), ());
|
||||
|
||||
// Overlap with [2, 3] and [4, 5].
|
||||
TEST(!intervals.AddInterval(2, 5), ());
|
||||
}
|
||||
} // namespace
|
||||
68
libs/base/base_tests/observer_list_test.cpp
Normal file
68
libs/base/base_tests/observer_list_test.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/observer_list.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Observer
|
||||
{
|
||||
Observer() : status(0) {}
|
||||
|
||||
void OnOperationCompleted(std::string const & message, int status)
|
||||
{
|
||||
this->message = message;
|
||||
this->status = status;
|
||||
}
|
||||
|
||||
std::string message;
|
||||
int status;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(ObserverList_Basic)
|
||||
{
|
||||
Observer observer0;
|
||||
Observer observer1;
|
||||
Observer observer2;
|
||||
|
||||
base::ObserverListSafe<Observer> observers;
|
||||
|
||||
// Register all observers in a list. Also check that it's not
|
||||
// possible to add the same observer twice.
|
||||
TEST(observers.Add(observer0), ());
|
||||
TEST(!observers.Add(observer0), ());
|
||||
|
||||
TEST(observers.Add(observer1), ());
|
||||
TEST(!observers.Add(observer1), ());
|
||||
|
||||
TEST(observers.Add(observer2), ());
|
||||
TEST(!observers.Add(observer2), ());
|
||||
|
||||
TEST(!observers.Add(observer1), ());
|
||||
TEST(!observers.Add(observer2), ());
|
||||
|
||||
std::string const message = "HTTP OK";
|
||||
observers.ForEach(&Observer::OnOperationCompleted, message, 204);
|
||||
|
||||
// Check observers internal state.
|
||||
TEST_EQUAL(message, observer0.message, ());
|
||||
TEST_EQUAL(204, observer0.status, ());
|
||||
|
||||
TEST_EQUAL(message, observer1.message, ());
|
||||
TEST_EQUAL(204, observer1.status, ());
|
||||
|
||||
TEST_EQUAL(message, observer2.message, ());
|
||||
TEST_EQUAL(204, observer2.status, ());
|
||||
|
||||
// Remove all observers from a list.
|
||||
TEST(observers.Remove(observer0), ());
|
||||
TEST(!observers.Remove(observer0), ());
|
||||
|
||||
TEST(observers.Remove(observer1), ());
|
||||
TEST(!observers.Remove(observer1), ());
|
||||
|
||||
TEST(observers.Remove(observer2), ());
|
||||
TEST(!observers.Remove(observer2), ());
|
||||
}
|
||||
42
libs/base/base_tests/range_iterator_test.cpp
Normal file
42
libs/base/base_tests/range_iterator_test.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/range_iterator.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
UNIT_TEST(RangeIterator)
|
||||
{
|
||||
using namespace base;
|
||||
|
||||
{
|
||||
std::vector<int> result;
|
||||
for (auto const i : UpTo(5))
|
||||
result.push_back(i);
|
||||
TEST_EQUAL(result, (std::vector<int>{0, 1, 2, 3, 4}), ());
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> result;
|
||||
for (auto const i : UpTo(2, 5))
|
||||
result.push_back(i);
|
||||
TEST_EQUAL(result, (std::vector<int>{2, 3, 4}), ());
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> result;
|
||||
for (auto const i : DownTo(5))
|
||||
result.push_back(i);
|
||||
TEST_EQUAL(result, (std::vector<int>{4, 3, 2, 1, 0}), ());
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> result;
|
||||
for (auto const i : DownTo(2, 5))
|
||||
result.push_back(i);
|
||||
TEST_EQUAL(result, (std::vector<int>{4, 3, 2}), ());
|
||||
}
|
||||
|
||||
{
|
||||
TEST_EQUAL(std::vector<int>(MakeRangeIterator(0), MakeRangeIterator(5)), (std::vector<int>{0, 1, 2, 3, 4}), ());
|
||||
}
|
||||
}
|
||||
83
libs/base/base_tests/ref_counted_tests.cpp
Normal file
83
libs/base/base_tests/ref_counted_tests.cpp
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/ref_counted.hpp"
|
||||
|
||||
using namespace base;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Resource : public RefCounted
|
||||
{
|
||||
explicit Resource(bool & destroyed) : m_destroyed(destroyed) { m_destroyed = false; }
|
||||
|
||||
~Resource() override { m_destroyed = true; }
|
||||
|
||||
bool & m_destroyed;
|
||||
};
|
||||
|
||||
UNIT_TEST(RefCounted_Smoke)
|
||||
{
|
||||
{
|
||||
RefCountPtr<Resource> p;
|
||||
}
|
||||
|
||||
{
|
||||
bool destroyed;
|
||||
{
|
||||
RefCountPtr<Resource> p(new Resource(destroyed));
|
||||
TEST_EQUAL(1, p->NumRefs(), ());
|
||||
TEST(!destroyed, ());
|
||||
}
|
||||
TEST(destroyed, ());
|
||||
}
|
||||
|
||||
{
|
||||
bool destroyed;
|
||||
{
|
||||
RefCountPtr<Resource> a(new Resource(destroyed));
|
||||
TEST_EQUAL(1, a->NumRefs(), ());
|
||||
TEST(!destroyed, ());
|
||||
|
||||
RefCountPtr<Resource> b(a);
|
||||
TEST(a.Get() == b.Get(), ());
|
||||
TEST_EQUAL(2, a->NumRefs(), ());
|
||||
TEST(!destroyed, ());
|
||||
|
||||
{
|
||||
RefCountPtr<Resource> c;
|
||||
TEST(c.Get() == nullptr, ());
|
||||
|
||||
c = b;
|
||||
TEST(a.Get() == b.Get(), ());
|
||||
TEST(b.Get() == c.Get(), ());
|
||||
TEST_EQUAL(3, a->NumRefs(), ());
|
||||
TEST(!destroyed, ());
|
||||
}
|
||||
|
||||
TEST(a.Get() == b.Get(), ());
|
||||
TEST_EQUAL(2, a->NumRefs(), ());
|
||||
TEST(!destroyed, ());
|
||||
|
||||
RefCountPtr<Resource> d(std::move(b));
|
||||
TEST(b.Get() == nullptr, ());
|
||||
TEST(a.Get() == d.Get(), ());
|
||||
TEST_EQUAL(2, a->NumRefs(), ());
|
||||
TEST(!destroyed, ());
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wself-assign-overloaded"
|
||||
#endif // #ifdef __clang__
|
||||
a = a;
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif // #ifdef __clang__
|
||||
|
||||
TEST_EQUAL(a.Get(), d.Get(), ());
|
||||
TEST_EQUAL(2, a->NumRefs(), ());
|
||||
TEST(!destroyed, ());
|
||||
}
|
||||
TEST(destroyed, ());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
86
libs/base/base_tests/regexp_test.cpp
Normal file
86
libs/base/base_tests/regexp_test.cpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/stl_helpers.hpp"
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
namespace regexp_test
|
||||
{
|
||||
template <typename Fn>
|
||||
void ForEachMatched(std::string const & s, boost::regex const & regex, Fn && fn)
|
||||
{
|
||||
for (std::sregex_token_iterator cur(s.begin(), s.end(), regex), end; cur != end; ++cur)
|
||||
fn(*cur);
|
||||
}
|
||||
|
||||
UNIT_TEST(RegExp_Or)
|
||||
{
|
||||
boost::regex exp("\\.mwm\\.(downloading2?$|resume2?$)");
|
||||
|
||||
TEST(boost::regex_search("Aruba.mwm.downloading", exp), ());
|
||||
TEST(!regex_search("Aruba.mwm.downloading1", exp), ());
|
||||
TEST(boost::regex_search("Aruba.mwm.downloading2", exp), ());
|
||||
TEST(!regex_search("Aruba.mwm.downloading3", exp), ());
|
||||
TEST(!regex_search("Aruba.mwm.downloading.tmp", exp), ());
|
||||
|
||||
TEST(boost::regex_search("Aruba.mwm.resume", exp), ());
|
||||
TEST(!regex_search("Aruba.mwm.resume1", exp), ());
|
||||
TEST(boost::regex_search("Aruba.mwm.resume2", exp), ());
|
||||
TEST(!regex_search("Aruba.mwm.resume3", exp), ());
|
||||
TEST(!regex_search("Aruba.mwm.resume.tmp", exp), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(RegExp_ForEachMatched)
|
||||
{
|
||||
boost::regex exp("-?\\d+\\.?\\d*, *-?\\d+\\.?\\d*");
|
||||
|
||||
{
|
||||
std::string const s = "6.66, 9.99";
|
||||
std::vector<std::string> v;
|
||||
ForEachMatched(s, exp, base::MakeBackInsertFunctor(v));
|
||||
TEST_EQUAL(v.size(), 1, ());
|
||||
TEST_EQUAL(v[0], s, ());
|
||||
}
|
||||
|
||||
{
|
||||
std::string const s1 = "6.66, 9.99";
|
||||
std::string const s2 = "-5.55, -7.77";
|
||||
std::vector<std::string> v;
|
||||
ForEachMatched(s1 + " 180 , bfuewib 365@" + s2, exp, base::MakeBackInsertFunctor(v));
|
||||
TEST_EQUAL(v.size(), 2, ());
|
||||
TEST_EQUAL(v[0], s1, ());
|
||||
TEST_EQUAL(v[1], s2, ());
|
||||
}
|
||||
|
||||
{
|
||||
std::string const s = "X6.66, 9.99";
|
||||
std::vector<std::string> v;
|
||||
ForEachMatched(s, exp, base::MakeBackInsertFunctor(v));
|
||||
TEST_EQUAL(v.size(), 1, ());
|
||||
TEST_EQUAL(v[0], std::string(s.begin() + 1, s.end()), ());
|
||||
}
|
||||
|
||||
{
|
||||
std::string const s = "6.66, 9.99X";
|
||||
std::vector<std::string> v;
|
||||
ForEachMatched(s, exp, base::MakeBackInsertFunctor(v));
|
||||
TEST_EQUAL(v.size(), 1, ());
|
||||
TEST_EQUAL(v[0], std::string(s.begin(), s.end() - 1), ());
|
||||
}
|
||||
|
||||
{
|
||||
std::string const s = "6.66X, 9.99";
|
||||
std::vector<std::string> v;
|
||||
ForEachMatched(s, exp, base::MakeBackInsertFunctor(v));
|
||||
TEST_EQUAL(v.size(), 0, ());
|
||||
}
|
||||
|
||||
{
|
||||
std::string const s = "6.66, X9.99";
|
||||
std::vector<std::string> v;
|
||||
ForEachMatched(s, exp, base::MakeBackInsertFunctor(v));
|
||||
TEST_EQUAL(v.size(), 0, ());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace regexp_test
|
||||
125
libs/base/base_tests/rolling_hash_test.cpp
Normal file
125
libs/base/base_tests/rolling_hash_test.cpp
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
#include "base/rolling_hash.hpp"
|
||||
#include "testing/benchmark.hpp"
|
||||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/base.hpp"
|
||||
#include "base/logging.hpp"
|
||||
#include "base/macros.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <class RollingHasherT>
|
||||
void SmokeTest1RollingHasher()
|
||||
{
|
||||
typedef typename RollingHasherT::hash_type hash_type;
|
||||
RollingHasherT hash;
|
||||
hash_type const h0 = hash.Init("a", 1);
|
||||
TEST_EQUAL(h0, hash.Scroll('a', 'a'), (sizeof(hash_type)));
|
||||
}
|
||||
|
||||
template <class RollingHasherT>
|
||||
void SmokeTest2RollingHasher()
|
||||
{
|
||||
typedef typename RollingHasherT::hash_type hash_type;
|
||||
RollingHasherT hash;
|
||||
hash_type const hAB = hash.Init("ab", 2);
|
||||
hash_type const hBA = hash.Scroll('a', 'a');
|
||||
hash_type const hAB1 = hash.Scroll('b', 'b');
|
||||
TEST_EQUAL(hAB, hAB1, (sizeof(hash_type)));
|
||||
hash_type const hBA1 = hash.Scroll('a', 'a');
|
||||
TEST_EQUAL(hBA, hBA1, (sizeof(hash_type)));
|
||||
}
|
||||
|
||||
template <class RollingHasherT>
|
||||
void TestRollingHasher()
|
||||
{
|
||||
SmokeTest1RollingHasher<RollingHasherT>();
|
||||
SmokeTest2RollingHasher<RollingHasherT>();
|
||||
// 01234567890123
|
||||
char const s[] = "abcdefghaabcde";
|
||||
size_t const len = ARRAY_SIZE(s) - 1;
|
||||
for (uint32_t size = 1; size <= 6; ++size)
|
||||
{
|
||||
typedef typename RollingHasherT::hash_type hash_type;
|
||||
RollingHasherT hash;
|
||||
std::vector<hash_type> hashes;
|
||||
hashes.push_back(hash.Init(static_cast<char const *>(s), size));
|
||||
for (uint32_t i = size; i < len; ++i)
|
||||
hashes.push_back(hash.Scroll(s[i - size], s[i]));
|
||||
TEST_EQUAL(hashes.size(), len - size + 1, (size, len, sizeof(hash_type)));
|
||||
switch (size)
|
||||
{
|
||||
case 6:
|
||||
{
|
||||
// Test that there are no collisions.
|
||||
sort(hashes.begin(), hashes.end());
|
||||
TEST(hashes.end() == unique(hashes.begin(), hashes.end()), (size, hashes));
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
TEST_EQUAL(hashes[0], hashes[8], (size, len, sizeof(hash_type)));
|
||||
TEST_EQUAL(hashes[0], hashes[9], (size, len, sizeof(hash_type)));
|
||||
TEST_EQUAL(hashes[1], hashes[10], (size, len, sizeof(hash_type)));
|
||||
TEST_EQUAL(hashes[2], hashes[11], (size, len, sizeof(hash_type)));
|
||||
TEST_EQUAL(hashes[3], hashes[12], (size, len, sizeof(hash_type)));
|
||||
TEST_EQUAL(hashes[4], hashes[13], (size, len, sizeof(hash_type)));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
for (unsigned int i = 0; i < 6 - size; ++i)
|
||||
TEST_EQUAL(hashes[i], hashes[i + 9], (i, size, len, sizeof(hash_type)));
|
||||
sort(hashes.begin(), hashes.end());
|
||||
TEST((hashes.end() - (6 - size)) == unique(hashes.begin(), hashes.end()), (size, hashes));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(RabinKarpRollingHasher32)
|
||||
{
|
||||
TestRollingHasher<RabinKarpRollingHasher32>();
|
||||
}
|
||||
|
||||
UNIT_TEST(RabinKarpRollingHasher64)
|
||||
{
|
||||
TestRollingHasher<RabinKarpRollingHasher64>();
|
||||
}
|
||||
|
||||
UNIT_TEST(RollingHasher32)
|
||||
{
|
||||
TestRollingHasher<RollingHasher32>();
|
||||
}
|
||||
|
||||
UNIT_TEST(RollingHasher64)
|
||||
{
|
||||
TestRollingHasher<RollingHasher64>();
|
||||
}
|
||||
|
||||
#ifndef DEBUG
|
||||
BENCHMARK_TEST(RollingHasher32)
|
||||
{
|
||||
RollingHasher32 hash;
|
||||
hash.Init("abcdefghijklmnopq", 17);
|
||||
BENCHMARK_N_TIMES(IF_DEBUG_ELSE(500000, 20000000), 0.2)
|
||||
{
|
||||
FORCE_USE_VALUE(hash.Scroll(static_cast<uint32_t>('a') + benchmark.Iteration(),
|
||||
static_cast<uint32_t>('r') + benchmark.Iteration()));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_TEST(RollingHasher64)
|
||||
{
|
||||
RollingHasher64 hash;
|
||||
hash.Init("abcdefghijklmnopq", 17);
|
||||
BENCHMARK_N_TIMES(IF_DEBUG_ELSE(500000, 10000000), 0.3)
|
||||
{
|
||||
FORCE_USE_VALUE(hash.Scroll(static_cast<uint64_t>('a') + benchmark.Iteration(),
|
||||
static_cast<uint64_t>('r') + benchmark.Iteration()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
31
libs/base/base_tests/scope_guard_test.cpp
Normal file
31
libs/base/base_tests/scope_guard_test.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/scope_guard.hpp"
|
||||
|
||||
static bool b = false;
|
||||
|
||||
void SetB()
|
||||
{
|
||||
b = true;
|
||||
}
|
||||
|
||||
UNIT_TEST(ScopeGuard)
|
||||
{
|
||||
{
|
||||
b = false;
|
||||
SCOPE_GUARD(guard, &SetB);
|
||||
TEST_EQUAL(b, false, ("Start test condition"));
|
||||
}
|
||||
TEST_EQUAL(b, true, ("scope_guard works in destructor"));
|
||||
}
|
||||
|
||||
UNIT_TEST(ScopeGuardRelease)
|
||||
{
|
||||
{
|
||||
b = false;
|
||||
SCOPE_GUARD(guard, &SetB);
|
||||
TEST_EQUAL(b, false, ("Start test condition"));
|
||||
guard.release();
|
||||
}
|
||||
TEST_EQUAL(b, false, ("If relese() was called then scope_guard shouldn't work"));
|
||||
}
|
||||
269
libs/base/base_tests/small_set_test.cpp
Normal file
269
libs/base/base_tests/small_set_test.cpp
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/small_map.hpp"
|
||||
#include "base/small_set.hpp"
|
||||
#include "base/timer.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <random>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace small_set_test
|
||||
{
|
||||
using namespace base;
|
||||
|
||||
UNIT_TEST(SmallSet_Smoke)
|
||||
{
|
||||
SmallSet<300> set;
|
||||
TEST_EQUAL(set.Size(), 0, ());
|
||||
for (uint64_t i = 0; i < 300; ++i)
|
||||
TEST(!set.Contains(i), ());
|
||||
|
||||
set.Insert(0);
|
||||
TEST_EQUAL(set.Size(), 1, ());
|
||||
TEST(set.Contains(0), ());
|
||||
|
||||
set.Insert(0);
|
||||
TEST_EQUAL(set.Size(), 1, ());
|
||||
TEST(set.Contains(0), ());
|
||||
|
||||
set.Insert(5);
|
||||
TEST_EQUAL(set.Size(), 2, ());
|
||||
TEST(set.Contains(0), ());
|
||||
TEST(set.Contains(5), ());
|
||||
|
||||
set.Insert(64);
|
||||
TEST_EQUAL(set.Size(), 3, ());
|
||||
TEST(set.Contains(0), ());
|
||||
TEST(set.Contains(5), ());
|
||||
TEST(set.Contains(64), ());
|
||||
|
||||
{
|
||||
auto cur = set.begin();
|
||||
auto end = set.end();
|
||||
for (uint64_t i : {0, 5, 64})
|
||||
{
|
||||
TEST(cur != end, ());
|
||||
TEST_EQUAL(*cur, i, ());
|
||||
++cur;
|
||||
}
|
||||
TEST(cur == end, ());
|
||||
}
|
||||
|
||||
set.Remove(5);
|
||||
TEST_EQUAL(set.Size(), 2, ());
|
||||
TEST(set.Contains(0), ());
|
||||
TEST(!set.Contains(5), ());
|
||||
TEST(set.Contains(64), ());
|
||||
|
||||
set.Insert(297);
|
||||
set.Insert(298);
|
||||
set.Insert(299);
|
||||
TEST_EQUAL(set.Size(), 5, ());
|
||||
|
||||
{
|
||||
std::vector<uint64_t> const actual(set.begin(), set.end());
|
||||
std::vector<uint64_t> const expected = {0, 64, 297, 298, 299};
|
||||
TEST_EQUAL(actual, expected, ());
|
||||
}
|
||||
|
||||
TEST_EQUAL(set.Size(), std::distance(set.begin(), set.end()), ());
|
||||
}
|
||||
|
||||
bool BenchmarkTimeLessOrNear(uint64_t l, uint64_t r, double relativeTolerance)
|
||||
{
|
||||
return (l < r) || ((l - r) / static_cast<double>(l) < relativeTolerance);
|
||||
}
|
||||
|
||||
#ifndef DEBUG
|
||||
std::vector<uint32_t> GenerateIndices(uint32_t min, uint32_t max)
|
||||
{
|
||||
std::vector<uint32_t> res;
|
||||
|
||||
std::uniform_int_distribution<uint64_t> randDist(min, max);
|
||||
std::random_device randDevice;
|
||||
std::mt19937 randEngine(randDevice());
|
||||
|
||||
for (size_t i = 0; i < 10000000; ++i)
|
||||
res.push_back(randDist(randEngine));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
UNIT_TEST(SmallMap_Benchmark1)
|
||||
{
|
||||
// 1. Init maps.
|
||||
// Dataset is similar to routing::VehicleModel.
|
||||
std::unordered_map<uint32_t, bool> uMap = {
|
||||
{1, true}, {2, false}, {4, false}, {6, true}, {7, true}, {8, true}, {12, false},
|
||||
{15, false}, {26, true}, {30, false}, {36, false}, {43, false}, {54, false}, {57, true},
|
||||
{58, true}, {65, true}, {69, true}, {90, true}, {95, false}, {119, false}, {167, true},
|
||||
{176, false}, {259, true}, {272, false}, {994, true}, {1054, false}};
|
||||
|
||||
base::SmallMap<uint32_t, bool> sMap(uMap.begin(), uMap.end());
|
||||
|
||||
// 2. Generate indices.
|
||||
std::vector<uint32_t> indices = GenerateIndices(1, 1054);
|
||||
|
||||
uint64_t t1, t2;
|
||||
uint32_t sum1 = 0, sum2 = 0;
|
||||
|
||||
// 3. Run unordered_map.
|
||||
{
|
||||
base::HighResTimer timer;
|
||||
for (auto i : indices)
|
||||
sum1 += (uMap.find(i) != uMap.end() ? 1 : 0);
|
||||
t1 = timer.ElapsedMilliseconds();
|
||||
}
|
||||
|
||||
// 4. Run SmallMap.
|
||||
{
|
||||
base::HighResTimer timer;
|
||||
for (auto i : indices)
|
||||
sum2 += (sMap.Find(i) ? 1 : 0);
|
||||
t2 = timer.ElapsedMilliseconds();
|
||||
}
|
||||
|
||||
TEST_EQUAL(sum1, sum2, ());
|
||||
// At this moment, we have rare t2 > t1 on Linux CI.
|
||||
TEST(BenchmarkTimeLessOrNear(t2, t1, 0.3), (t2, t1));
|
||||
LOG(LINFO, ("unordered_map time =", t1, "SmallMap time =", t2));
|
||||
}
|
||||
|
||||
UNIT_TEST(SmallMap_Benchmark2)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
uint32_t i = 0;
|
||||
// Dataset is similar to routing::VehicleModelFactory.
|
||||
unordered_map<string, shared_ptr<int>> uMap = {
|
||||
{"", make_shared<int>(i++)},
|
||||
{"Australia", make_shared<int>(i++)},
|
||||
{"Austria", make_shared<int>(i++)},
|
||||
{"Belarus", make_shared<int>(i++)},
|
||||
{"Belgium", make_shared<int>(i++)},
|
||||
{"Brazil", make_shared<int>(i++)},
|
||||
{"Denmark", make_shared<int>(i++)},
|
||||
{"France", make_shared<int>(i++)},
|
||||
{"Finland", make_shared<int>(i++)},
|
||||
{"Germany", make_shared<int>(i++)},
|
||||
{"Hungary", make_shared<int>(i++)},
|
||||
{"Iceland", make_shared<int>(i++)},
|
||||
{"Netherlands", make_shared<int>(i++)},
|
||||
{"Norway", make_shared<int>(i++)},
|
||||
{"Oman", make_shared<int>(i++)},
|
||||
{"Poland", make_shared<int>(i++)},
|
||||
{"Romania", make_shared<int>(i++)},
|
||||
{"Russian Federation", make_shared<int>(i++)},
|
||||
{"Slovakia", make_shared<int>(i++)},
|
||||
{"Spain", make_shared<int>(i++)},
|
||||
{"Switzerland", make_shared<int>(i++)},
|
||||
{"Turkey", make_shared<int>(i++)},
|
||||
{"Ukraine", make_shared<int>(i++)},
|
||||
{"United Kingdom", make_shared<int>(i++)},
|
||||
{"United States of America", make_shared<int>(i++)},
|
||||
};
|
||||
|
||||
base::SmallMap<std::string, std::shared_ptr<int>> sMap(uMap.begin(), uMap.end());
|
||||
|
||||
// 2. Generate indices.
|
||||
std::vector<std::string> keys;
|
||||
for (auto const & e : uMap)
|
||||
{
|
||||
keys.push_back(e.first);
|
||||
keys.push_back(e.first + "_Foo");
|
||||
keys.push_back(e.first + "_Bar");
|
||||
keys.push_back(e.first + "_Bazz");
|
||||
}
|
||||
std::vector<uint32_t> indices = GenerateIndices(0, keys.size() - 1);
|
||||
|
||||
uint64_t t1, t2;
|
||||
uint32_t sum1 = 0, sum2 = 0;
|
||||
|
||||
// 3. Run unordered_map.
|
||||
{
|
||||
base::HighResTimer timer;
|
||||
for (auto i : indices)
|
||||
{
|
||||
auto const it = uMap.find(keys[i]);
|
||||
if (it != uMap.end())
|
||||
sum1 += *it->second;
|
||||
}
|
||||
t1 = timer.ElapsedMilliseconds();
|
||||
}
|
||||
|
||||
// 4. Run SmallMap.
|
||||
{
|
||||
base::HighResTimer timer;
|
||||
for (auto i : indices)
|
||||
{
|
||||
auto const * p = sMap.Find(keys[i]);
|
||||
if (p)
|
||||
sum2 += **p;
|
||||
}
|
||||
t2 = timer.ElapsedMilliseconds();
|
||||
}
|
||||
|
||||
TEST_EQUAL(sum1, sum2, ());
|
||||
// std::hash(std::string) is better than std::less(std::string)
|
||||
TEST_LESS(t1, t2, ());
|
||||
LOG(LINFO, ("unordered_map time =", t1, "SmallMap time =", t2));
|
||||
}
|
||||
|
||||
// Small 4 elements sample doesn't work for new (gcc11+, clang14+) toolchain.
|
||||
/*
|
||||
UNIT_TEST(SmallMap_Benchmark3)
|
||||
{
|
||||
// Dataset is similar to routing::VehicleModel.m_surfaceFactors.
|
||||
std::unordered_map<int, int> uMap = {
|
||||
{1, 0}, {10, 1}, {100, 2}, {1000, 3},
|
||||
};
|
||||
|
||||
base::SmallMap<int, int> sMap(uMap.begin(), uMap.end());
|
||||
base::SmallMapBase<int, int> sbMap(uMap.begin(), uMap.end());
|
||||
|
||||
std::vector<uint32_t> indices = GenerateIndices(0, 3);
|
||||
// Missing key queries are even worse for the std map.
|
||||
std::vector<int> keys;
|
||||
for (auto const & e : uMap)
|
||||
keys.push_back(e.first);
|
||||
|
||||
uint64_t t1, t2, t3;
|
||||
uint32_t sum1 = 0, sum2 = 0, sum3 = 0;
|
||||
|
||||
// 3. Run unordered_map.
|
||||
{
|
||||
base::HighResTimer timer;
|
||||
for (auto i : indices)
|
||||
sum1 += uMap.find(keys[i])->second;
|
||||
t1 = timer.ElapsedMilliseconds();
|
||||
}
|
||||
|
||||
// 4. Run SmallMap.
|
||||
{
|
||||
base::HighResTimer timer;
|
||||
for (auto i : indices)
|
||||
sum2 += *sMap.Find(keys[i]);
|
||||
t2 = timer.ElapsedMilliseconds();
|
||||
}
|
||||
|
||||
// 5. Run SmallMapBase.
|
||||
{
|
||||
base::HighResTimer timer;
|
||||
for (auto i : indices)
|
||||
sum3 += *sbMap.Find(keys[i]);
|
||||
t3 = timer.ElapsedMilliseconds();
|
||||
}
|
||||
|
||||
TEST_EQUAL(sum1, sum2, ());
|
||||
TEST_EQUAL(sum1, sum3, ());
|
||||
TEST_LESS(t2, t1, ());
|
||||
TEST(BenchmarkTimeLessOrNear(t3, t2, 0.05), (t3, t2));
|
||||
LOG(LINFO, ("unordered_map time =", t1, "SmallMap time =", t2, "SmallMapBase time =", t3));
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
} // namespace small_set_test
|
||||
364
libs/base/base_tests/stl_helpers_tests.cpp
Normal file
364
libs/base/base_tests/stl_helpers_tests.cpp
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/stl_helpers.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace stl_helpers_tests
|
||||
{
|
||||
using namespace base;
|
||||
|
||||
class Int
|
||||
{
|
||||
public:
|
||||
explicit Int(int v) : m_v(v) {}
|
||||
|
||||
inline int Get() const { return m_v; }
|
||||
|
||||
private:
|
||||
int m_v;
|
||||
};
|
||||
|
||||
template <template <typename...> class Cont>
|
||||
void TestSortUnique()
|
||||
{
|
||||
{
|
||||
Cont<int> actual = {1, 2, 1, 4, 3, 5, 2, 7, 1};
|
||||
SortUnique(actual);
|
||||
Cont<int> const expected = {1, 2, 3, 4, 5, 7};
|
||||
TEST_EQUAL(actual, expected, ());
|
||||
}
|
||||
{
|
||||
using Value = int;
|
||||
using Pair = std::pair<Value, int>;
|
||||
Cont<Pair> d = {{1, 22}, {2, 33}, {1, 23}, {4, 54}, {3, 34}, {5, 23}, {2, 23}, {7, 32}, {1, 12}};
|
||||
|
||||
SortUnique(d, LessBy(&Pair::first), EqualsBy(&Pair::first));
|
||||
|
||||
Cont<Value> const expected = {1, 2, 3, 4, 5, 7};
|
||||
TEST_EQUAL(d.size(), expected.size(), ());
|
||||
for (size_t i = 0; i < d.size(); ++i)
|
||||
TEST_EQUAL(d[i].first, expected[i], (i));
|
||||
}
|
||||
{
|
||||
using Value = double;
|
||||
using Pair = std::pair<Value, int>;
|
||||
Cont<Pair> d = {{0.5, 11}, {1000.99, 234}, {0.5, 23}, {1234.56789, 54}, {1000.99, 34}};
|
||||
|
||||
SortUnique(d, LessBy(&Pair::first), EqualsBy(&Pair::first));
|
||||
|
||||
Cont<Value> const expected = {0.5, 1000.99, 1234.56789};
|
||||
TEST_EQUAL(d.size(), expected.size(), ());
|
||||
for (size_t i = 0; i < d.size(); ++i)
|
||||
TEST_EQUAL(d[i].first, expected[i], (i));
|
||||
}
|
||||
}
|
||||
|
||||
template <template <typename...> class Cont>
|
||||
void TestEqualsBy()
|
||||
{
|
||||
{
|
||||
using Value = std::pair<int, int>;
|
||||
Cont<Value> actual = {{1, 2}, {1, 3}, {2, 100}, {3, 7}, {3, 8}, {2, 500}};
|
||||
actual.erase(std::unique(actual.begin(), actual.end(), EqualsBy(&Value::first)), actual.end());
|
||||
|
||||
Cont<int> const expected = {{1, 2, 3, 2}};
|
||||
TEST_EQUAL(expected.size(), actual.size(), ());
|
||||
for (size_t i = 0; i < actual.size(); ++i)
|
||||
TEST_EQUAL(expected[i], actual[i].first, ());
|
||||
}
|
||||
|
||||
{
|
||||
Cont<Int> actual;
|
||||
for (auto const v : {0, 0, 1, 2, 2, 0})
|
||||
actual.emplace_back(v);
|
||||
actual.erase(std::unique(actual.begin(), actual.end(), EqualsBy(&Int::Get)), actual.end());
|
||||
|
||||
Cont<int> const expected = {{0, 1, 2, 0}};
|
||||
TEST_EQUAL(expected.size(), actual.size(), ());
|
||||
for (size_t i = 0; i < actual.size(); ++i)
|
||||
TEST_EQUAL(expected[i], actual[i].Get(), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(LessBy)
|
||||
{
|
||||
{
|
||||
using Value = std::pair<int, int>;
|
||||
|
||||
std::vector<Value> v = {{2, 2}, {0, 4}, {3, 1}, {4, 0}, {1, 3}};
|
||||
std::sort(v.begin(), v.end(), LessBy(&Value::first));
|
||||
for (size_t i = 0; i < v.size(); ++i)
|
||||
TEST_EQUAL(i, static_cast<size_t>(v[i].first), ());
|
||||
|
||||
std::vector<Value const *> pv;
|
||||
for (auto const & p : v)
|
||||
pv.push_back(&p);
|
||||
|
||||
std::sort(pv.begin(), pv.end(), LessBy(&Value::second));
|
||||
for (size_t i = 0; i < pv.size(); ++i)
|
||||
TEST_EQUAL(i, static_cast<size_t>(pv[i]->second), ());
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<Int> v;
|
||||
for (int i = 9; i >= 0; --i)
|
||||
v.emplace_back(i);
|
||||
|
||||
std::sort(v.begin(), v.end(), LessBy(&Int::Get));
|
||||
for (size_t i = 0; i < v.size(); ++i)
|
||||
TEST_EQUAL(v[i].Get(), static_cast<int>(i), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(EqualsBy_VectorTest)
|
||||
{
|
||||
TestEqualsBy<std::vector>();
|
||||
TestEqualsBy<std::deque>();
|
||||
}
|
||||
|
||||
UNIT_TEST(SortUnique_VectorTest)
|
||||
{
|
||||
TestSortUnique<std::vector>();
|
||||
TestSortUnique<std::deque>();
|
||||
}
|
||||
|
||||
UNIT_TEST(IgnoreFirstArgument)
|
||||
{
|
||||
{
|
||||
int s = 0;
|
||||
auto f1 = [&](int a, int b) { s += a + b; };
|
||||
auto f2 = [&](int a, int b) { s -= a + b; };
|
||||
auto f3 = MakeIgnoreFirstArgument(f2);
|
||||
|
||||
f1(2, 3);
|
||||
TEST_EQUAL(s, 5, ());
|
||||
f3(1, 2, 3);
|
||||
TEST_EQUAL(s, 0, ());
|
||||
}
|
||||
|
||||
{
|
||||
auto f1 = [](int a, int b) -> int { return a + b; };
|
||||
auto f2 = MakeIgnoreFirstArgument(f1);
|
||||
|
||||
auto const x = f1(2, 3);
|
||||
auto const y = f2("ignored", 2, 3);
|
||||
TEST_EQUAL(x, y, ());
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct EqualZero
|
||||
{
|
||||
bool operator()(int x) { return (x == 0); }
|
||||
};
|
||||
|
||||
template <class ContT>
|
||||
void CheckNoZero(ContT & c, typename ContT::iterator i)
|
||||
{
|
||||
c.erase(i, c.end());
|
||||
TEST(find_if(c.begin(), c.end(), EqualZero()) == c.end(), ());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(RemoveIfKeepValid)
|
||||
{
|
||||
{
|
||||
std::vector<int> v;
|
||||
TEST(RemoveIfKeepValid(v.begin(), v.end(), EqualZero()) == v.end(), ());
|
||||
|
||||
v.push_back(1);
|
||||
TEST(RemoveIfKeepValid(v.begin(), v.end(), EqualZero()) == v.end(), ());
|
||||
|
||||
v.push_back(1);
|
||||
TEST(RemoveIfKeepValid(v.begin(), v.end(), EqualZero()) == v.end(), ());
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> v;
|
||||
v.push_back(0);
|
||||
TEST(RemoveIfKeepValid(v.begin(), v.end(), EqualZero()) == v.begin(), ());
|
||||
|
||||
v.push_back(0);
|
||||
TEST(RemoveIfKeepValid(v.begin(), v.end(), EqualZero()) == v.begin(), ());
|
||||
|
||||
v.push_back(1);
|
||||
CheckNoZero(v, RemoveIfKeepValid(v.begin(), v.end(), EqualZero()));
|
||||
TEST_EQUAL(v.size(), 1, ());
|
||||
|
||||
v.push_back(1);
|
||||
v.push_back(0);
|
||||
v.push_back(0);
|
||||
CheckNoZero(v, RemoveIfKeepValid(v.begin(), v.end(), EqualZero()));
|
||||
TEST_EQUAL(v.size(), 2, ());
|
||||
|
||||
v.push_back(0);
|
||||
v.push_back(0);
|
||||
v.push_back(1);
|
||||
v.push_back(1);
|
||||
CheckNoZero(v, RemoveIfKeepValid(v.begin(), v.end(), EqualZero()));
|
||||
TEST_EQUAL(v.size(), 4, ());
|
||||
}
|
||||
|
||||
{
|
||||
std::deque<int> v;
|
||||
v.push_back(1);
|
||||
v.push_back(0);
|
||||
v.push_back(1);
|
||||
v.push_back(0);
|
||||
v.push_back(1);
|
||||
v.push_back(0);
|
||||
v.push_back(1);
|
||||
CheckNoZero(v, RemoveIfKeepValid(v.begin(), v.end(), EqualZero()));
|
||||
TEST_EQUAL(v.size(), 4, ());
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template <class T, size_t N1, size_t N2, size_t N3>
|
||||
void CheckAccumulateIntervals(size_t & idTest, std::pair<T, T> (&arr1)[N1], std::pair<T, T> (&arr2)[N2],
|
||||
std::pair<T, T> (&arr3)[N3])
|
||||
{
|
||||
std::vector<std::pair<T, T>> res;
|
||||
AccumulateIntervals1With2(arr1, arr1 + N1, arr2, arr2 + N2, back_inserter(res));
|
||||
|
||||
++idTest;
|
||||
TEST_EQUAL(N3, res.size(), ("Test", idTest, res));
|
||||
TEST(equal(res.begin(), res.end(), arr3), ("Test", idTest, res));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(AccumulateIntervals)
|
||||
{
|
||||
typedef std::pair<int, int> T;
|
||||
size_t idTest = 0;
|
||||
|
||||
// bound cases
|
||||
{
|
||||
std::vector<T> res;
|
||||
T arr[] = {T(10, 20)};
|
||||
|
||||
res.clear();
|
||||
AccumulateIntervals1With2(arr, arr + 1, arr, arr, back_inserter(res));
|
||||
TEST_EQUAL(res.size(), 1, ());
|
||||
|
||||
res.clear();
|
||||
AccumulateIntervals1With2(arr, arr, arr, arr + 1, back_inserter(res));
|
||||
TEST_EQUAL(res.size(), 0, ());
|
||||
}
|
||||
|
||||
// check splice overlapped
|
||||
{
|
||||
T arr1[] = {T(10, 20), T(30, 40)};
|
||||
T arr2[] = {T(19, 31)};
|
||||
T res[] = {T(10, 40)};
|
||||
CheckAccumulateIntervals(idTest, arr1, arr2, res);
|
||||
}
|
||||
|
||||
// check skip not overlapped
|
||||
{
|
||||
T arr1[] = {T(10, 20), T(30, 40)};
|
||||
T arr2[] = {T(0, 9), T(21, 29), T(41, 50)};
|
||||
T res[2] = {T(10, 20), T(30, 40)};
|
||||
CheckAccumulateIntervals(idTest, arr1, arr2, res);
|
||||
}
|
||||
{
|
||||
T arr1[] = {T(10, 20), T(30, 40)};
|
||||
T arr2[] = {T(1, 2), T(3, 4), T(5, 6), T(21, 22), T(23, 24), T(25, 26), T(41, 42), T(43, 44), T(45, 46)};
|
||||
T res[] = {T(10, 20), T(30, 40)};
|
||||
CheckAccumulateIntervals(idTest, arr1, arr2, res);
|
||||
}
|
||||
|
||||
// check equal bounds
|
||||
{
|
||||
T arr1[] = {T(20, 30)};
|
||||
T arr2[] = {T(10, 20), T(30, 40)};
|
||||
T res[] = {T(20, 30)};
|
||||
CheckAccumulateIntervals(idTest, arr1, arr2, res);
|
||||
}
|
||||
{
|
||||
T arr1[] = {T(10, 20), T(30, 40)};
|
||||
T arr2[] = {T(20, 30)};
|
||||
T res[] = {T(10, 20), T(30, 40)};
|
||||
CheckAccumulateIntervals(idTest, arr1, arr2, res);
|
||||
}
|
||||
|
||||
// check large overlap interval
|
||||
{
|
||||
T arr1[] = {T(10, 20), T(30, 40), T(50, 60)};
|
||||
T arr2[] = {T(0, 100)};
|
||||
T res[] = {T(0, 100)};
|
||||
CheckAccumulateIntervals(idTest, arr1, arr2, res);
|
||||
}
|
||||
{
|
||||
T arr1[] = {T(0, 100)};
|
||||
T arr2[] = {T(10, 20), T(30, 40), T(50, 60)};
|
||||
T res[] = {T(0, 100)};
|
||||
CheckAccumulateIntervals(idTest, arr1, arr2, res);
|
||||
}
|
||||
|
||||
// check splice overlapped
|
||||
{
|
||||
T arr1[] = {T(10, 20), T(30, 40)};
|
||||
T arr2[] = {T(5, 15), T(35, 45)};
|
||||
T res[] = {T(5, 20), T(30, 45)};
|
||||
CheckAccumulateIntervals(idTest, arr1, arr2, res);
|
||||
}
|
||||
{
|
||||
T arr1[] = {T(10, 20), T(30, 40)};
|
||||
T arr2[] = {T(1, 2), T(3, 4), T(5, 15), T(17, 25), T(26, 27), T(28, 32), T(38, 45), T(46, 50)};
|
||||
T res[] = {T(5, 25), T(28, 45)};
|
||||
CheckAccumulateIntervals(idTest, arr1, arr2, res);
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(Map_EmplaceOrAssign)
|
||||
{
|
||||
{
|
||||
std::map<std::string, std::string, std::less<>> theMap;
|
||||
|
||||
std::string_view key = "key";
|
||||
std::string_view val1 = "value";
|
||||
TEST(EmplaceOrAssign(theMap, key, val1).second, ());
|
||||
TEST_EQUAL(theMap.find(key)->second, val1, ());
|
||||
|
||||
std::string_view val2 = "some_long_value";
|
||||
TEST(!EmplaceOrAssign(theMap, key, val2).second, ());
|
||||
TEST_EQUAL(theMap.find(key)->second, val2, ());
|
||||
|
||||
std::string_view val3 = "some_other_long_value";
|
||||
TEST(!EmplaceOrAssign(theMap, key, std::string(val3)).second, ());
|
||||
TEST_EQUAL(theMap.find(key)->second, val3, ());
|
||||
}
|
||||
|
||||
{
|
||||
class Obj
|
||||
{
|
||||
int m_v;
|
||||
|
||||
Obj(Obj const &) = delete;
|
||||
Obj & operator=(Obj const &) = delete;
|
||||
|
||||
public:
|
||||
Obj(int v) : m_v(v) {}
|
||||
Obj(Obj &&) = default;
|
||||
Obj & operator=(Obj &&) = default;
|
||||
|
||||
bool operator==(Obj const & o) const { return m_v == o.m_v; }
|
||||
bool operator<(Obj const & o) const { return m_v < o.m_v; }
|
||||
};
|
||||
|
||||
std::map<Obj, Obj> theMap;
|
||||
|
||||
TEST(EmplaceOrAssign(theMap, Obj(1), Obj(2)).second, ());
|
||||
TEST(!EmplaceOrAssign(theMap, Obj(1), Obj(3)).second, ());
|
||||
TEST(theMap.find(Obj(1))->second == Obj(3), ());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace stl_helpers_tests
|
||||
1280
libs/base/base_tests/string_utils_test.cpp
Normal file
1280
libs/base/base_tests/string_utils_test.cpp
Normal file
File diff suppressed because it is too large
Load diff
91
libs/base/base_tests/suffix_array_tests.cpp
Normal file
91
libs/base/base_tests/suffix_array_tests.cpp
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/suffix_array.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace base;
|
||||
using namespace std;
|
||||
|
||||
#define TEST_STR_EQUAL(X, Y, msg) TEST_EQUAL(string(X), string(Y), msg)
|
||||
|
||||
namespace
|
||||
{
|
||||
UNIT_TEST(Skew_Smoke)
|
||||
{
|
||||
Skew(0, nullptr /* s */, nullptr /* sa */);
|
||||
}
|
||||
|
||||
UNIT_TEST(Skew_Simple)
|
||||
{
|
||||
{
|
||||
string const s;
|
||||
vector<size_t> pos;
|
||||
Skew(s, pos);
|
||||
TEST_EQUAL(pos.size(), s.size(), ());
|
||||
}
|
||||
|
||||
{
|
||||
string const s = "a";
|
||||
vector<size_t> pos;
|
||||
Skew(s, pos);
|
||||
TEST_EQUAL(pos.size(), s.size(), ());
|
||||
TEST_EQUAL(pos[0], 0, ());
|
||||
}
|
||||
|
||||
{
|
||||
string const s = "aaaa";
|
||||
vector<size_t> pos;
|
||||
Skew(s, pos);
|
||||
TEST_EQUAL(pos.size(), s.size(), ());
|
||||
TEST_EQUAL(pos[0], 3, ());
|
||||
TEST_EQUAL(pos[1], 2, ());
|
||||
TEST_EQUAL(pos[2], 1, ());
|
||||
TEST_EQUAL(pos[3], 0, ());
|
||||
}
|
||||
|
||||
for (size_t length = 0; length < 100; ++length)
|
||||
{
|
||||
string const s(length, 'a');
|
||||
vector<size_t> pos;
|
||||
Skew(s, pos);
|
||||
TEST_EQUAL(pos.size(), s.size(), ());
|
||||
for (size_t i = 0; i < pos.size(); ++i)
|
||||
TEST_EQUAL(pos[i], pos.size() - i - 1, ());
|
||||
}
|
||||
|
||||
for (size_t length = 0; length < 100; ++length)
|
||||
{
|
||||
string const s(length, '\0');
|
||||
vector<size_t> pos;
|
||||
Skew(s, pos);
|
||||
TEST_EQUAL(pos.size(), s.size(), ());
|
||||
for (size_t i = 0; i < pos.size(); ++i)
|
||||
TEST_EQUAL(pos[i], pos.size() - i - 1, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(Skew_Classic)
|
||||
{
|
||||
char const * s = "mississippi";
|
||||
size_t const n = strlen(s);
|
||||
TEST_EQUAL(n, 11, ());
|
||||
|
||||
vector<size_t> pos(n);
|
||||
Skew(n, reinterpret_cast<uint8_t const *>(s), pos.data());
|
||||
|
||||
TEST_STR_EQUAL("i", s + pos[0], ());
|
||||
TEST_STR_EQUAL("ippi", s + pos[1], ());
|
||||
TEST_STR_EQUAL("issippi", s + pos[2], ());
|
||||
TEST_STR_EQUAL("ississippi", s + pos[3], ());
|
||||
TEST_STR_EQUAL("mississippi", s + pos[4], ());
|
||||
TEST_STR_EQUAL("pi", s + pos[5], ());
|
||||
TEST_STR_EQUAL("ppi", s + pos[6], ());
|
||||
TEST_STR_EQUAL("sippi", s + pos[7], ());
|
||||
TEST_STR_EQUAL("sissippi", s + pos[8], ());
|
||||
TEST_STR_EQUAL("ssippi", s + pos[9], ());
|
||||
TEST_STR_EQUAL("ssissippi", s + pos[10], ());
|
||||
}
|
||||
} // namespace
|
||||
488
libs/base/base_tests/sunrise_sunset_test.cpp
Normal file
488
libs/base/base_tests/sunrise_sunset_test.cpp
Normal file
|
|
@ -0,0 +1,488 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/sunrise_sunset.hpp"
|
||||
|
||||
#include "base/timegm.hpp"
|
||||
|
||||
// Test site for sunrise and sunset is
|
||||
// http://voshod-solnca.ru/
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Moscow_April)
|
||||
{
|
||||
// Moscow (utc +3), date 2015/4/12:
|
||||
// Sunrise utc time: 2015/4/12,2:34
|
||||
// Sunset utc time: 2015/4/12,16:29
|
||||
double const lat = 55.7522222;
|
||||
double const lon = 37.6155556;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 4, 12, 2, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 4, 12, 2, 45, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 4, 12, 16, 15, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 4, 12, 16, 45, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Moscow_July)
|
||||
{
|
||||
// Moscow (utc +3), date 2015/7/13:
|
||||
// Sunrise utc time: 2015/7/13,1:04
|
||||
// Sunset utc time: 2015/7/13,18:09
|
||||
double const lat = 55.7522222;
|
||||
double const lon = 37.6155556;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 7, 13, 0, 50, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 7, 13, 1, 45, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 7, 13, 18, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 7, 13, 18, 30, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Moscow_September)
|
||||
{
|
||||
// Moscow (utc +3), date 2015/9/17:
|
||||
// Sunrise utc time: 2015/9/17,3:05
|
||||
// Sunset utc time: 2015/9/17,15:46
|
||||
double const lat = 55.7522222;
|
||||
double const lon = 37.6155556;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 9, 17, 2, 55, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 9, 17, 3, 15, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 9, 17, 15, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 9, 17, 16, 0, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Moscow_December)
|
||||
{
|
||||
// Moscow (utc +3), date 2015/12/25:
|
||||
// Sunrise utc time: 2015/12/25,06:00
|
||||
// Sunset utc time: 2015/12/25,13:01
|
||||
double const lat = 55.7522222;
|
||||
double const lon = 37.6155556;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 12, 25, 5, 55, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 12, 25, 6, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 12, 25, 12, 55, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 12, 25, 13, 10, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Moscow_NewYear)
|
||||
{
|
||||
// Moscow (utc +3), date 2016/1/1:
|
||||
// Sunrise utc time: 2016/1/1,6:1
|
||||
// Sunset utc time: 2016/1/1,13:7
|
||||
double const lat = 55.7522222;
|
||||
double const lon = 37.6155556;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2016, 1, 1, 5, 55, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2016, 1, 1, 6, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2016, 1, 1, 13, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2016, 1, 1, 13, 15, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Paris_NewYear)
|
||||
{
|
||||
// Paris (utc +1)
|
||||
// Sunrise utc time: 2016/1/1,7:45
|
||||
// Sunset utc time: 2016/1/1,16:04
|
||||
double const lat = 48.875649;
|
||||
double const lon = 2.344428;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2016, 1, 1, 7, 35, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2016, 1, 1, 7, 55, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2016, 1, 1, 16, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2016, 1, 1, 16, 10, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Honolulu_February)
|
||||
{
|
||||
// Honolulu (utc -10), date 2015/2/12:
|
||||
// Sunrise utc time: 2015/2/12,17:05
|
||||
// Sunset utc time: 2015/2/13,4:29
|
||||
double const lat = 21.307431;
|
||||
double const lon = -157.848568;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 2, 12, 17, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 2, 12, 17, 15, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 2, 13, 4, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 2, 13, 4, 35, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Honolulu_July)
|
||||
{
|
||||
// Honolulu (utc -10). For date 2015/7/13:
|
||||
// Sunrise utc time: 2015/7/13,15:58
|
||||
// Sunset utc time: 2015/7/14,5:18
|
||||
double const lat = 21.307431;
|
||||
double const lon = -157.848568;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 7, 13, 15, 40, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 7, 13, 16, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 7, 14, 5, 5, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 7, 14, 5, 25, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Honolulu_June)
|
||||
{
|
||||
// Honolulu (utc -10). For date 2015/6/22:
|
||||
// Sunrise utc time: 2015/6/22,15:51
|
||||
// Sunset utc time: 2015/6/23,5:17
|
||||
double const lat = 21.307431;
|
||||
double const lon = -157.848568;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 6, 22, 15, 40, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 6, 22, 16, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 6, 23, 5, 5, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 6, 23, 5, 25, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Honolulu_December)
|
||||
{
|
||||
// Honolulu (utc -10). For date 2015/12/23:
|
||||
// Sunrise utc time: 2015/12/23,17:06
|
||||
// Sunset utc time: 2015/12/24,3:56
|
||||
double const lat = 21.307431;
|
||||
double const lon = -157.848568;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 12, 23, 16, 40, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 12, 23, 17, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 12, 23, 3, 50, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 12, 23, 4, 5, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Melbourne_Ferbuary)
|
||||
{
|
||||
// Melbourne (utc +11). For date 2015/2/12:
|
||||
// Sunrise utc time: 2015/2/11,19:46
|
||||
// Sunset utc time: 2015/2/12,9:24
|
||||
double const lat = -37.829188;
|
||||
double const lon = 144.957976;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 2, 11, 19, 30, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 2, 11, 19, 50, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 2, 12, 9, 15, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 2, 12, 9, 30, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Melbourne_NewYear)
|
||||
{
|
||||
// Melbourne (utc +11). For date 2016/1/1:
|
||||
// Sunrise utc time: 2015/12/31,19:02
|
||||
// Sunset utc time: 2016/1/1,9:46
|
||||
double const lat = -37.829188;
|
||||
double const lon = 144.957976;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 12, 31, 18, 55, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 12, 31, 19, 5, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2016, 1, 1, 9, 40, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2016, 1, 1, 9, 55, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_GetDayTime_Melbourne_August)
|
||||
{
|
||||
// Melbourne (utc +11), 2015/8/12
|
||||
// prev sunset utc 2015/8/11,7:41
|
||||
// sunrise utc 2015/8/11,21:10
|
||||
// sunset utc 2015/8/12,7:42
|
||||
// next sunrise utc 2015/8/12,21:09
|
||||
double const lat = -37.829188;
|
||||
double const lon = 144.957976;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 8, 11, 7, 30, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 8, 11, 7, 50, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 8, 11, 21, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 8, 11, 21, 20, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 8, 12, 7, 35, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 8, 12, 7, 55, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 8, 12, 21, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 8, 12, 21, 15, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Wellington_October)
|
||||
{
|
||||
// Melbourne (utc +13). For date 2015/10/20:
|
||||
// Sunrise utc time: 2015/10/19,17:26
|
||||
// Sunset utc time: 2015/10/20,6:47
|
||||
double const lat = -41.287481;
|
||||
double const lon = 174.774189;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 10, 19, 17, 15, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 10, 19, 17, 35, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 10, 20, 6, 40, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 10, 20, 6, 55, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_BuenosAires_March)
|
||||
{
|
||||
// Buenos Aires (utc -3). For date 2015/3/8:
|
||||
// Sunrise utc time: 2015/3/8,9:48
|
||||
// Sunset utc time: 2015/3/8,22:23
|
||||
double const lat = -34.607639;
|
||||
double const lon = -58.438095;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 3, 8, 9, 40, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 3, 8, 10, 5, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 3, 8, 22, 20, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 3, 8, 22, 28, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Seattle_May)
|
||||
{
|
||||
// Seattle (utc -8). For date 2015/5/9:
|
||||
// Sunrise utc time: 2015/5/9,12:41
|
||||
// Sunset utc time: 2015/5/10,3:32
|
||||
double const lat = 47.597482;
|
||||
double const lon = -122.334590;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 5, 9, 12, 35, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 5, 9, 12, 45, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 5, 10, 3, 20, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 5, 10, 3, 40, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Reykjavik_May)
|
||||
{
|
||||
// Reykjavik (utc 0). For date 2015/5/9:
|
||||
// Sunrise utc time: 2015/5/9,4:34
|
||||
// Sunset utc time: 2015/5/9,22:15
|
||||
double const lat = 64.120467;
|
||||
double const lon = -21.809448;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 5, 9, 4, 30, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 5, 9, 4, 40, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 5, 9, 22, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 5, 9, 22, 20, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Reykjavik_June)
|
||||
{
|
||||
// Reykjavik (utc 0). For date 2015/6/22:
|
||||
// Sunrise utc time: 2015/6/22,2:56
|
||||
// Sunset utc time: 2015/6/23,0:04
|
||||
double const lat = 64.120467;
|
||||
double const lon = -21.809448;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 6, 22, 2, 45, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 6, 22, 3, 5, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 6, 23, 0, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 6, 23, 0, 7, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_CapeTown_November)
|
||||
{
|
||||
// Cape Town (utc +2). For date 2015/11/11:
|
||||
// Sunrise utc time: 2015/11/11,3:38
|
||||
// Sunset utc time: 2015/11/11,17:24
|
||||
double const lat = -33.929573;
|
||||
double const lon = 18.428439;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 11, 11, 3, 30, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 11, 11, 3, 45, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 11, 11, 17, 20, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 11, 11, 17, 30, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_CapeTown_March)
|
||||
{
|
||||
// Cape Town (utc +2). For date 2015/3/1:
|
||||
// Sunrise utc time: 2015/3/1,4:34
|
||||
// Sunset utc time: 2015/3/1,17:24
|
||||
double const lat = -33.929573;
|
||||
double const lon = 18.428439;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 3, 1, 4, 30, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 3, 1, 4, 40, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 3, 1, 17, 20, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 3, 1, 17, 30, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Tiksi_March)
|
||||
{
|
||||
// Russia, Siberia, Tiksi. For date 2015/3/1:
|
||||
// Sunrise utc time: 2015/2/28,23:04
|
||||
// Sunset utc time: 2015/3/1,8:12
|
||||
double const lat = 71.635604;
|
||||
double const lon = 128.882922;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 2, 28, 23, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 2, 28, 23, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 3, 1, 8, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 3, 1, 8, 15, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Tiksi_July)
|
||||
{
|
||||
// Russia, Siberia, Tiksi. For date 2015/7/1:
|
||||
// Polar day
|
||||
double const lat = 71.635604;
|
||||
double const lon = 128.882922;
|
||||
|
||||
TEST_EQUAL(DayTimeType::PolarDay, GetDayTime(base::TimeGM(2015, 7, 1, 0, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::PolarDay, GetDayTime(base::TimeGM(2015, 7, 1, 12, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::PolarDay, GetDayTime(base::TimeGM(2015, 7, 1, 23, 0, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Tiksi_December)
|
||||
{
|
||||
// Russia, Siberia, Tiksi. For date 2015/12/1:
|
||||
// Polar night
|
||||
double const lat = 71.635604;
|
||||
double const lon = 128.882922;
|
||||
|
||||
TEST_EQUAL(DayTimeType::PolarNight, GetDayTime(base::TimeGM(2015, 12, 1, 0, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::PolarNight, GetDayTime(base::TimeGM(2015, 12, 1, 12, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::PolarNight, GetDayTime(base::TimeGM(2015, 12, 1, 23, 0, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Norilsk_NewYear)
|
||||
{
|
||||
// Norilsk. For date 2016/1/1:
|
||||
// Polar night
|
||||
double const lat = 69.350000;
|
||||
double const lon = 88.180000;
|
||||
|
||||
TEST_EQUAL(DayTimeType::PolarNight, GetDayTime(base::TimeGM(2016, 1, 1, 0, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::PolarNight, GetDayTime(base::TimeGM(2016, 1, 1, 12, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::PolarNight, GetDayTime(base::TimeGM(2016, 1, 1, 23, 0, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Norilsk_August)
|
||||
{
|
||||
// Norilsk. For date 2015/6/22:
|
||||
// Polar day
|
||||
double const lat = 69.350000;
|
||||
double const lon = 88.180000;
|
||||
|
||||
TEST_EQUAL(DayTimeType::PolarDay, GetDayTime(base::TimeGM(2015, 6, 22, 0, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::PolarDay, GetDayTime(base::TimeGM(2015, 6, 22, 12, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::PolarDay, GetDayTime(base::TimeGM(2015, 6, 22, 23, 0, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Tokio_September)
|
||||
{
|
||||
// Tokio. For date 2015/9/12:
|
||||
// Sunrise utc time: 2015/9/11,20:22
|
||||
// Sunset utc time: 2015/9/12,8:56
|
||||
double const lat = 35.715791;
|
||||
double const lon = 139.743945;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 9, 12, 20, 20, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 9, 12, 20, 25, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 9, 12, 8, 50, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 9, 12, 9, 0, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Kabul_March)
|
||||
{
|
||||
// Kabul. For date 2015/3/20:
|
||||
// Sunrise utc time: 2015/3/20,01:29
|
||||
// Sunset utc time: 2015/3/20,13:35
|
||||
double const lat = 34.552312;
|
||||
double const lon = 69.170520;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 3, 20, 1, 25, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 3, 20, 1, 35, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 3, 20, 13, 30, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 3, 20, 13, 40, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Areora_January)
|
||||
{
|
||||
// Areora. For date 2016/1/1:
|
||||
// Sunrise utc time: 2016/1/1,15:57
|
||||
// Sunset utc time: 2016/1/2,5:16
|
||||
double const lat = -20.003751;
|
||||
double const lon = -158.114640;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2016, 1, 1, 15, 50, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2016, 1, 1, 16, 5, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2016, 1, 2, 5, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2016, 1, 2, 5, 20, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Lorino_February)
|
||||
{
|
||||
// Lorino (utc +12). For date 2016/2/2:
|
||||
// Sunrise utc time: 2016/2/2,20:17
|
||||
// Sunset utc time: 2016/2/3,3:10
|
||||
double const lat = 65.499550;
|
||||
double const lon = -171.715726;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2016, 2, 2, 20, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2016, 2, 2, 20, 20, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2016, 2, 3, 3, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2016, 2, 3, 3, 20, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Anadyr_December)
|
||||
{
|
||||
// Anadyr. For date 2015/12/25:
|
||||
// Sunrise utc time: 2015/12/24,22:17
|
||||
// Sunset utc time: 2015/12/25,02:03
|
||||
double const lat = 64.722245;
|
||||
double const lon = 177.499123;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 12, 24, 22, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 12, 24, 22, 20, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 12, 25, 2, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 12, 25, 2, 5, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Nikolski_December)
|
||||
{
|
||||
// Nikolski. For date 2015/12/25:
|
||||
// Sunrise utc time: 2015/12/25,19:29
|
||||
// Sunset utc time: 2015/12/26,3:04
|
||||
double const lat = 52.933280;
|
||||
double const lon = -168.864102;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 12, 25, 19, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 12, 25, 19, 35, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 12, 26, 3, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 12, 26, 3, 10, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Kiribati_July)
|
||||
{
|
||||
// Kiribati. For date 2015/7/1:
|
||||
// Sunrise utc time: 2015/7/1,16:28
|
||||
// Sunset utc time: 2015/7/2,4:41
|
||||
double const lat = 1.928797;
|
||||
double const lon = -157.494678;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 7, 1, 16, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 7, 1, 16, 35, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 7, 2, 4, 0, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 7, 2, 4, 50, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_Kiribati_July_2)
|
||||
{
|
||||
// Kiribati. For date 2015/7/1:
|
||||
// Sunrise utc time: 2015/7/1,16:28
|
||||
// Sunset utc time: 2015/7/2,4:41
|
||||
// Next sunrise utc time: 2015/7/2,16:28
|
||||
// Next sunset utc time: 2015/7/3,4:42
|
||||
double const lat = 1.928797;
|
||||
double const lon = -157.494678;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 7, 1, 16, 20, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 7, 1, 16, 35, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 7, 2, 4, 35, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 7, 2, 4, 50, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 7, 2, 16, 20, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 7, 2, 16, 35, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 7, 3, 4, 35, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 7, 3, 4, 50, 0), lat, lon), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(SunriseSunsetAlgorithm_London_July)
|
||||
{
|
||||
// London. For date 2015/7/1:
|
||||
// Sunrise utc time: 2015/7/1,3:47
|
||||
// Sunset utc time: 2015/7/1,20:21
|
||||
double const lat = 51.500000;
|
||||
double const lon = 0.120000;
|
||||
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 7, 1, 2, 50, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 7, 1, 16, 20, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Day, GetDayTime(base::TimeGM(2015, 7, 1, 20, 10, 0), lat, lon), ());
|
||||
TEST_EQUAL(DayTimeType::Night, GetDayTime(base::TimeGM(2015, 7, 1, 21, 15, 0), lat, lon), ());
|
||||
}
|
||||
127
libs/base/base_tests/thread_pool_computational_tests.cpp
Normal file
127
libs/base/base_tests/thread_pool_computational_tests.cpp
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/thread.hpp"
|
||||
#include "base/thread_pool_computational.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
size_t const kTimes = 500;
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(ThreadPoolComputational_SomeThreads)
|
||||
{
|
||||
for (size_t t = 0; t < kTimes; ++t)
|
||||
{
|
||||
size_t const threadCount = 4;
|
||||
std::atomic<size_t> counter{0};
|
||||
{
|
||||
base::ComputationalThreadPool threadPool(threadCount);
|
||||
for (size_t i = 0; i < threadCount; ++i)
|
||||
{
|
||||
threadPool.Submit([&]()
|
||||
{
|
||||
threads::Sleep(1);
|
||||
++counter;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_EQUAL(threadCount, counter, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadPoolComputational_OneThread)
|
||||
{
|
||||
for (size_t t = 0; t < kTimes; ++t)
|
||||
{
|
||||
size_t const threadCount = 1;
|
||||
std::atomic<size_t> counter{0};
|
||||
{
|
||||
base::ComputationalThreadPool threadPool(threadCount);
|
||||
for (size_t i = 0; i < threadCount; ++i)
|
||||
{
|
||||
threadPool.Submit([&]()
|
||||
{
|
||||
threads::Sleep(1);
|
||||
++counter;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_EQUAL(threadCount, counter, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadPoolComputational_ManyThread)
|
||||
{
|
||||
for (size_t t = 0; t < kTimes; ++t)
|
||||
{
|
||||
size_t threadCount = std::thread::hardware_concurrency();
|
||||
CHECK_NOT_EQUAL(threadCount, 0, ());
|
||||
threadCount *= 2;
|
||||
std::atomic<size_t> counter{0};
|
||||
{
|
||||
base::ComputationalThreadPool threadPool(threadCount);
|
||||
for (size_t i = 0; i < threadCount; ++i)
|
||||
{
|
||||
threadPool.Submit([&]()
|
||||
{
|
||||
threads::Sleep(1);
|
||||
++counter;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_EQUAL(threadCount, counter, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadPoolComputational_ReturnValue)
|
||||
{
|
||||
for (size_t t = 0; t < kTimes; ++t)
|
||||
{
|
||||
size_t const threadCount = 4;
|
||||
base::ComputationalThreadPool threadPool(threadCount);
|
||||
std::vector<std::future<size_t>> futures;
|
||||
for (size_t i = 0; i < threadCount; ++i)
|
||||
{
|
||||
auto f = threadPool.Submit([=]()
|
||||
{
|
||||
threads::Sleep(1);
|
||||
return i;
|
||||
});
|
||||
|
||||
futures.push_back(std::move(f));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < threadCount; ++i)
|
||||
TEST_EQUAL(futures[i].get(), i, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadPoolComputational_ManyTasks)
|
||||
{
|
||||
for (size_t t = 0; t < kTimes; ++t)
|
||||
{
|
||||
size_t const taskCount = 11;
|
||||
std::atomic<size_t> counter{0};
|
||||
{
|
||||
base::ComputationalThreadPool threadPool(4);
|
||||
for (size_t i = 0; i < taskCount; ++i)
|
||||
{
|
||||
threadPool.Submit([&]()
|
||||
{
|
||||
threads::Sleep(1);
|
||||
++counter;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_EQUAL(taskCount, counter, ());
|
||||
}
|
||||
}
|
||||
249
libs/base/base_tests/thread_pool_delayed_tests.cpp
Normal file
249
libs/base/base_tests/thread_pool_delayed_tests.cpp
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/thread_pool_delayed.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
|
||||
namespace thread_pool_delayed_tests
|
||||
{
|
||||
using namespace base;
|
||||
using namespace std::chrono;
|
||||
using namespace std;
|
||||
|
||||
UNIT_TEST(ThreadPoolDelayed_Smoke)
|
||||
{
|
||||
{
|
||||
DelayedThreadPool thread;
|
||||
}
|
||||
|
||||
{
|
||||
DelayedThreadPool thread;
|
||||
TEST(thread.Shutdown(DelayedThreadPool::Exit::SkipPending), ());
|
||||
}
|
||||
|
||||
{
|
||||
DelayedThreadPool thread;
|
||||
TEST(thread.Shutdown(DelayedThreadPool::Exit::ExecPending), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadPoolDelayed_SimpleSync)
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
mutex mu;
|
||||
condition_variable cv;
|
||||
bool done = false;
|
||||
|
||||
DelayedThreadPool thread;
|
||||
auto pushResult = thread.Push([&value]() { ++value; });
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_NOT_EQUAL(pushResult.m_id, DelayedThreadPool::kNoId, ());
|
||||
|
||||
pushResult = thread.Push([&value]() { value *= 2; });
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_NOT_EQUAL(pushResult.m_id, DelayedThreadPool::kNoId, ());
|
||||
|
||||
pushResult = thread.Push([&value]() { value = value * value * value; });
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_NOT_EQUAL(pushResult.m_id, DelayedThreadPool::kNoId, ());
|
||||
|
||||
pushResult = thread.Push([&]()
|
||||
{
|
||||
lock_guard<mutex> lk(mu);
|
||||
done = true;
|
||||
cv.notify_one();
|
||||
});
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_NOT_EQUAL(pushResult.m_id, DelayedThreadPool::kNoId, ());
|
||||
|
||||
{
|
||||
unique_lock<mutex> lk(mu);
|
||||
cv.wait(lk, [&done]() { return done; });
|
||||
}
|
||||
|
||||
TEST_EQUAL(value, 8, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadPoolDelayed_SimpleFlush)
|
||||
{
|
||||
int value = 0;
|
||||
{
|
||||
DelayedThreadPool thread;
|
||||
auto pushResult = thread.Push([&value]() { ++value; });
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_NOT_EQUAL(pushResult.m_id, DelayedThreadPool::kNoId, ());
|
||||
|
||||
pushResult = thread.Push([&value]()
|
||||
{
|
||||
for (int i = 0; i < 10; ++i)
|
||||
value *= 2;
|
||||
});
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_NOT_EQUAL(pushResult.m_id, DelayedThreadPool::kNoId, ());
|
||||
|
||||
TEST(thread.Shutdown(DelayedThreadPool::Exit::ExecPending), ());
|
||||
}
|
||||
TEST_EQUAL(value, 1024, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadPoolDelayed_PushFromPendingTask)
|
||||
{
|
||||
// promise - future pair is used as a socketpair here to pass a
|
||||
// signal from the main thread to the worker thread.
|
||||
promise<void> p;
|
||||
auto f = p.get_future();
|
||||
|
||||
DelayedThreadPool thread;
|
||||
auto const pushResult = thread.Push([&f, &thread]()
|
||||
{
|
||||
f.get();
|
||||
auto const innerPushResult = thread.Push([]() { TEST(false, ("This task should not be executed")); });
|
||||
TEST(!innerPushResult.m_isSuccess, ());
|
||||
TEST_EQUAL(innerPushResult.m_id, DelayedThreadPool::kNoId, ());
|
||||
});
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_NOT_EQUAL(pushResult.m_id, DelayedThreadPool::kNoId, ());
|
||||
|
||||
thread.Shutdown(DelayedThreadPool::Exit::ExecPending);
|
||||
p.set_value();
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadPoolDelayed_DelayedAndImmediateTasks)
|
||||
{
|
||||
int const kNumTasks = 100;
|
||||
|
||||
struct DelayedTaskEntry
|
||||
{
|
||||
DelayedThreadPool::TimePoint m_start = {};
|
||||
DelayedThreadPool::Duration m_delay = {};
|
||||
DelayedThreadPool::TimePoint m_end = {};
|
||||
};
|
||||
|
||||
vector<DelayedTaskEntry> delayedEntries(kNumTasks);
|
||||
vector<DelayedThreadPool::TimePoint> immediateEntries(kNumTasks);
|
||||
|
||||
{
|
||||
DelayedThreadPool thread;
|
||||
|
||||
for (int i = kNumTasks - 1; i >= 0; --i)
|
||||
{
|
||||
auto & entry = delayedEntries[i];
|
||||
entry.m_start = thread.Now();
|
||||
entry.m_delay = milliseconds(i + 1);
|
||||
|
||||
auto const pushResult = thread.PushDelayed(entry.m_delay, [&]() { entry.m_end = thread.Now(); });
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_NOT_EQUAL(pushResult.m_id, DelayedThreadPool::kNoId, ());
|
||||
}
|
||||
|
||||
for (int i = 0; i < kNumTasks; ++i)
|
||||
{
|
||||
auto & entry = immediateEntries[i];
|
||||
auto const pushResult = thread.Push([&]() { entry = thread.Now(); });
|
||||
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_NOT_EQUAL(pushResult.m_id, DelayedThreadPool::kNoId, ());
|
||||
}
|
||||
|
||||
thread.Shutdown(DelayedThreadPool::Exit::ExecPending);
|
||||
}
|
||||
|
||||
for (int i = 0; i < kNumTasks; ++i)
|
||||
{
|
||||
auto const & entry = delayedEntries[i];
|
||||
TEST(entry.m_end >= entry.m_start + entry.m_delay, ("Failed delay for the delayed task", i));
|
||||
}
|
||||
|
||||
for (int i = 1; i < kNumTasks; ++i)
|
||||
TEST(immediateEntries[i] >= immediateEntries[i - 1], ("Failed delay for the immediate task", i));
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadPoolDelayed_CancelImmediate)
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
{
|
||||
TaskLoop::TaskId cancelTaskId;
|
||||
DelayedThreadPool thread;
|
||||
{
|
||||
auto const pushResult = thread.Push([&value]()
|
||||
{
|
||||
++value;
|
||||
testing::Wait();
|
||||
});
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_EQUAL(pushResult.m_id, DelayedThreadPool::kImmediateMinId, ());
|
||||
}
|
||||
|
||||
{
|
||||
auto const pushResult = thread.Push([&]() { value += 1023; });
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_EQUAL(pushResult.m_id, DelayedThreadPool::kImmediateMinId + 1, ());
|
||||
|
||||
cancelTaskId = pushResult.m_id;
|
||||
}
|
||||
|
||||
{
|
||||
auto const pushResult = thread.Push([&]() { ++value; });
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_EQUAL(pushResult.m_id, DelayedThreadPool::kImmediateMinId + 2, ());
|
||||
}
|
||||
|
||||
TEST(thread.Cancel(cancelTaskId), ());
|
||||
|
||||
testing::Notify();
|
||||
|
||||
thread.Shutdown(DelayedThreadPool::Exit::ExecPending);
|
||||
}
|
||||
|
||||
TEST_EQUAL(value, 2, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadPoolDelayed_CancelDelayed)
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
{
|
||||
TaskLoop::TaskId cancelTaskId;
|
||||
DelayedThreadPool thread;
|
||||
{
|
||||
auto const pushResult = thread.Push([]() { testing::Wait(); });
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_EQUAL(pushResult.m_id, DelayedThreadPool::kImmediateMinId, ());
|
||||
}
|
||||
|
||||
{
|
||||
auto const pushResult = thread.PushDelayed(milliseconds(1), [&value]() { ++value; });
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_EQUAL(pushResult.m_id, DelayedThreadPool::kDelayedMinId, ());
|
||||
}
|
||||
|
||||
{
|
||||
auto const pushResult = thread.PushDelayed(milliseconds(2), [&]() { value += 1023; });
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_EQUAL(pushResult.m_id, DelayedThreadPool::kDelayedMinId + 1, ());
|
||||
|
||||
cancelTaskId = pushResult.m_id;
|
||||
}
|
||||
|
||||
{
|
||||
auto const pushResult = thread.PushDelayed(milliseconds(3), [&value]() { ++value; });
|
||||
TEST(pushResult.m_isSuccess, ());
|
||||
TEST_EQUAL(pushResult.m_id, DelayedThreadPool::kDelayedMinId + 2, ());
|
||||
}
|
||||
|
||||
TEST(thread.Cancel(cancelTaskId), ());
|
||||
|
||||
testing::Notify();
|
||||
|
||||
thread.Shutdown(DelayedThreadPool::Exit::ExecPending);
|
||||
}
|
||||
|
||||
TEST_EQUAL(value, 2, ());
|
||||
}
|
||||
|
||||
} // namespace thread_pool_delayed_tests
|
||||
106
libs/base/base_tests/thread_pool_tests.cpp
Normal file
106
libs/base/base_tests/thread_pool_tests.cpp
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/thread.hpp"
|
||||
#include "base/thread_pool.hpp"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
|
||||
namespace
|
||||
{
|
||||
int const TASK_COUNT = 10;
|
||||
class CanceledTask : public threads::IRoutine
|
||||
{
|
||||
public:
|
||||
CanceledTask() { Cancel(); }
|
||||
|
||||
virtual void Do() { TEST_EQUAL(true, false, ()); }
|
||||
};
|
||||
struct Condition
|
||||
{
|
||||
std::mutex m;
|
||||
std::condition_variable cv;
|
||||
};
|
||||
|
||||
void JoinFinishFunction(threads::IRoutine * routine, int & finishCounter, Condition & cond)
|
||||
{
|
||||
cond.m.lock();
|
||||
finishCounter++;
|
||||
cond.m.unlock();
|
||||
|
||||
delete routine;
|
||||
cond.cv.notify_one();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(ThreadPool_CanceledTaskTest)
|
||||
{
|
||||
int finishCounter = 0;
|
||||
Condition cond;
|
||||
base::ThreadPool pool(4,
|
||||
std::bind(&JoinFinishFunction, std::placeholders::_1, std::ref(finishCounter), std::ref(cond)));
|
||||
|
||||
for (int i = 0; i < TASK_COUNT; ++i)
|
||||
pool.PushBack(new CanceledTask());
|
||||
|
||||
pool.Stop();
|
||||
|
||||
TEST_EQUAL(finishCounter, TASK_COUNT, ());
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class CancelTestTask : public threads::IRoutine
|
||||
{
|
||||
public:
|
||||
explicit CancelTestTask(bool isWaitDoCall) : m_waitDoCall(isWaitDoCall), m_doCalled(false) {}
|
||||
|
||||
~CancelTestTask() { TEST_EQUAL(m_waitDoCall, m_doCalled, ()); }
|
||||
|
||||
virtual void Do()
|
||||
{
|
||||
TEST_EQUAL(m_waitDoCall, true, ());
|
||||
m_doCalled = true;
|
||||
threads::Sleep(100);
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_waitDoCall;
|
||||
bool m_doCalled;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(ThreadPool_ExecutionTaskTest)
|
||||
{
|
||||
int finishCounter = 0;
|
||||
Condition cond;
|
||||
base::ThreadPool pool(4,
|
||||
std::bind(&JoinFinishFunction, std::placeholders::_1, std::ref(finishCounter), std::ref(cond)));
|
||||
|
||||
for (int i = 0; i < TASK_COUNT - 1; ++i)
|
||||
pool.PushBack(new CancelTestTask(true));
|
||||
|
||||
// CancelTastTask::Do method should not be called for last task
|
||||
auto * p = new CancelTestTask(false);
|
||||
pool.PushBack(p);
|
||||
p->Cancel();
|
||||
|
||||
while (true)
|
||||
{
|
||||
std::unique_lock lock(cond.m);
|
||||
if (finishCounter == TASK_COUNT)
|
||||
break;
|
||||
cond.cv.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadPool_EmptyTest)
|
||||
{
|
||||
int finishCouter = 0;
|
||||
Condition cond;
|
||||
base::ThreadPool pool(4,
|
||||
std::bind(&JoinFinishFunction, std::placeholders::_1, std::ref(finishCouter), std::ref(cond)));
|
||||
|
||||
threads::Sleep(100);
|
||||
pool.Stop();
|
||||
}
|
||||
92
libs/base/base_tests/thread_safe_queue_tests.cpp
Normal file
92
libs/base/base_tests/thread_safe_queue_tests.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/thread_pool_delayed.hpp"
|
||||
#include "base/thread_safe_queue.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
|
||||
UNIT_TEST(ThreadSafeQueue_ThreadSafeQueue)
|
||||
{
|
||||
threads::ThreadSafeQueue<size_t> queue;
|
||||
|
||||
TEST(queue.Empty(), ());
|
||||
TEST_EQUAL(queue.Size(), 0, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadSafeQueue_Push)
|
||||
{
|
||||
size_t const kSize = 100;
|
||||
threads::ThreadSafeQueue<size_t> queue;
|
||||
base::DelayedThreadPool pool(2, base::DelayedThreadPool::Exit::ExecPending);
|
||||
for (size_t i = 0; i < kSize; ++i)
|
||||
pool.Push([&, i]() { queue.Push(i); });
|
||||
|
||||
pool.ShutdownAndJoin();
|
||||
|
||||
TEST_EQUAL(queue.Size(), kSize, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadSafeQueue_WaitAndPop)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
threads::ThreadSafeQueue<size_t> queue;
|
||||
size_t const value = 101;
|
||||
size_t result;
|
||||
auto thread = std::thread([&]()
|
||||
{
|
||||
std::this_thread::sleep_for(10ms);
|
||||
queue.Push(value);
|
||||
});
|
||||
|
||||
queue.WaitAndPop(result);
|
||||
|
||||
TEST_EQUAL(result, value, ());
|
||||
|
||||
thread.join();
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadSafeQueue_TryPop)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
threads::ThreadSafeQueue<size_t> queue;
|
||||
size_t const value = 101;
|
||||
size_t result;
|
||||
auto thread = std::thread([&]()
|
||||
{
|
||||
std::this_thread::sleep_for(10ms);
|
||||
queue.Push(value);
|
||||
});
|
||||
|
||||
TEST(!queue.TryPop(result), ());
|
||||
thread.join();
|
||||
|
||||
TEST(queue.TryPop(result), ());
|
||||
TEST_EQUAL(result, value, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ThreadSafeQueue_ExampleWithDataWrapper)
|
||||
{
|
||||
size_t const kSize = 100000;
|
||||
threads::ThreadSafeQueue<std::optional<size_t>> queue;
|
||||
|
||||
auto thread = std::thread([&]()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
std::optional<size_t> dw;
|
||||
queue.WaitAndPop(dw);
|
||||
if (!dw.has_value())
|
||||
return;
|
||||
|
||||
ASSERT_LESS_OR_EQUAL(*dw, kSize, ());
|
||||
}
|
||||
});
|
||||
|
||||
base::DelayedThreadPool pool(4, base::DelayedThreadPool::Exit::ExecPending);
|
||||
for (size_t i = 0; i < kSize; ++i)
|
||||
pool.Push([&, i]() { queue.Push(i); });
|
||||
pool.Push([&]() { queue.Push({}); });
|
||||
|
||||
thread.join();
|
||||
}
|
||||
77
libs/base/base_tests/threaded_list_test.cpp
Normal file
77
libs/base/base_tests/threaded_list_test.cpp
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
#include "base/thread.hpp"
|
||||
#include "base/threaded_list.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
struct ThreadedListProcessor : public threads::IRoutine
|
||||
{
|
||||
ThreadedList<int> & m_p;
|
||||
std::mutex & m_resMutex;
|
||||
std::list<int> & m_res;
|
||||
int m_id;
|
||||
|
||||
ThreadedListProcessor(ThreadedList<int> & p, std::mutex & resMutex, std::list<int> & res, int id)
|
||||
: m_p(p)
|
||||
, m_resMutex(resMutex)
|
||||
, m_res(res)
|
||||
, m_id(id)
|
||||
{}
|
||||
|
||||
virtual void Do()
|
||||
{
|
||||
while (!m_p.IsCancelled())
|
||||
{
|
||||
int res = m_p.Front(true /* doPop */);
|
||||
{
|
||||
std::lock_guard<std::mutex> resGuard(m_resMutex);
|
||||
m_res.push_back(res);
|
||||
}
|
||||
LOG(LINFO, (m_id, " thread got ", res));
|
||||
threads::Sleep(10);
|
||||
}
|
||||
LOG(LINFO, (m_id, " thread is cancelled"));
|
||||
}
|
||||
};
|
||||
|
||||
UNIT_TEST(ThreadedList)
|
||||
{
|
||||
std::mutex resMutex;
|
||||
std::list<int> res;
|
||||
|
||||
ThreadedList<int> p;
|
||||
|
||||
threads::Thread t0;
|
||||
t0.Create(std::make_unique<ThreadedListProcessor>(p, resMutex, res, 0));
|
||||
|
||||
threads::Thread t1;
|
||||
t1.Create(std::make_unique<ThreadedListProcessor>(p, resMutex, res, 1));
|
||||
|
||||
threads::Thread t2;
|
||||
t2.Create(std::make_unique<ThreadedListProcessor>(p, resMutex, res, 2));
|
||||
|
||||
p.PushBack(0);
|
||||
threads::Sleep(200);
|
||||
|
||||
p.PushBack(1);
|
||||
threads::Sleep(200);
|
||||
|
||||
p.PushBack(2);
|
||||
threads::Sleep(200);
|
||||
|
||||
p.Cancel();
|
||||
|
||||
t0.Join();
|
||||
t1.Join();
|
||||
t2.Join();
|
||||
|
||||
TEST_EQUAL(res.front(), 0, ());
|
||||
res.pop_front();
|
||||
TEST_EQUAL(res.front(), 1, ());
|
||||
res.pop_front();
|
||||
TEST_EQUAL(res.front(), 2, ());
|
||||
res.pop_front();
|
||||
}
|
||||
116
libs/base/base_tests/threads_test.cpp
Normal file
116
libs/base/base_tests/threads_test.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/thread.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using Vector = std::vector<int>;
|
||||
|
||||
static size_t summ = 0;
|
||||
static size_t checkSumm = 0;
|
||||
static size_t const MAX_COUNT = 1000000;
|
||||
|
||||
struct GeneratorThread : public threads::IRoutine
|
||||
{
|
||||
explicit GeneratorThread(Vector & vec) : m_vec(vec) {}
|
||||
|
||||
virtual void Do()
|
||||
{
|
||||
for (size_t i = 0; i < MAX_COUNT; ++i)
|
||||
{
|
||||
m_vec.push_back(static_cast<int>(i));
|
||||
summ += i;
|
||||
}
|
||||
}
|
||||
Vector & m_vec;
|
||||
};
|
||||
|
||||
struct ReaderThread : public threads::IRoutine
|
||||
{
|
||||
explicit ReaderThread(Vector & vec) : m_vec(vec) {}
|
||||
|
||||
virtual void Do()
|
||||
{
|
||||
for (size_t i = 0; i < m_vec.size(); ++i)
|
||||
checkSumm += m_vec[i];
|
||||
}
|
||||
Vector & m_vec;
|
||||
};
|
||||
|
||||
UNIT_TEST(Simple_Threads)
|
||||
{
|
||||
Vector vec;
|
||||
|
||||
threads::Thread reader;
|
||||
bool ok = reader.Create(std::make_unique<GeneratorThread>(vec));
|
||||
TEST(ok, ("Create Generator thread"));
|
||||
|
||||
reader.Join();
|
||||
|
||||
threads::Thread writer;
|
||||
ok = writer.Create(std::make_unique<ReaderThread>(vec));
|
||||
TEST(ok, ("Create Reader thread"));
|
||||
|
||||
writer.Join();
|
||||
|
||||
TEST_EQUAL(vec.size(), MAX_COUNT, ("vector size"));
|
||||
TEST_EQUAL(summ, checkSumm, ("check summ"));
|
||||
}
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
DISALLOW_COPY(SomeClass);
|
||||
|
||||
public:
|
||||
SomeClass() {}
|
||||
void Increment(int * a, int b) { *a = *a + b; }
|
||||
};
|
||||
|
||||
static void Increment(int * a, int b)
|
||||
{
|
||||
*a = *a + b;
|
||||
}
|
||||
|
||||
UNIT_TEST(SimpleThreadTest1)
|
||||
{
|
||||
int a = 0;
|
||||
|
||||
auto fn = [&a]() { a = 1; };
|
||||
|
||||
threads::SimpleThread t(fn);
|
||||
t.join();
|
||||
|
||||
TEST_EQUAL(a, 1, ("test a"));
|
||||
}
|
||||
|
||||
UNIT_TEST(SimpleThreadTest2)
|
||||
{
|
||||
int a = 0;
|
||||
|
||||
threads::SimpleThread t([&a]() { a = 1; });
|
||||
t.join();
|
||||
|
||||
TEST_EQUAL(a, 1, ("test a"));
|
||||
}
|
||||
|
||||
UNIT_TEST(SimpleThreadTest3)
|
||||
{
|
||||
int a = 0;
|
||||
|
||||
SomeClass instance;
|
||||
threads::SimpleThread t(&SomeClass::Increment, &instance, &a, 1);
|
||||
t.join();
|
||||
|
||||
TEST_EQUAL(a, 1, ("test a"));
|
||||
}
|
||||
|
||||
UNIT_TEST(SimpleThreadTest4)
|
||||
{
|
||||
int a = 0;
|
||||
|
||||
threads::SimpleThread t(&Increment, &a, 1);
|
||||
t.join();
|
||||
|
||||
TEST_EQUAL(a, 1, ("test a"));
|
||||
}
|
||||
31
libs/base/base_tests/timegm_test.cpp
Normal file
31
libs/base/base_tests/timegm_test.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include "base/timegm.hpp"
|
||||
|
||||
UNIT_TEST(TimegmTest)
|
||||
{
|
||||
std::tm tm1{};
|
||||
std::tm tm2{};
|
||||
|
||||
TEST(strptime("2016-05-17 07:10", "%Y-%m-%d %H:%M", &tm1), ());
|
||||
TEST(strptime("2016-05-17 07:10", "%Y-%m-%d %H:%M", &tm2), ());
|
||||
TEST_EQUAL(timegm(&tm1), base::TimeGM(tm2), ());
|
||||
TEST_EQUAL(timegm(&tm1), base::TimeGM(2016, 5, 17, 7, 10, 0), ());
|
||||
|
||||
TEST(strptime("2016-03-12 11:10", "%Y-%m-%d %H:%M", &tm1), ());
|
||||
TEST(strptime("2016-03-12 11:10", "%Y-%m-%d %H:%M", &tm2), ());
|
||||
TEST_EQUAL(timegm(&tm1), base::TimeGM(tm2), ());
|
||||
TEST_EQUAL(timegm(&tm1), base::TimeGM(2016, 3, 12, 11, 10, 0), ());
|
||||
|
||||
TEST(strptime("1970-01-01 00:00", "%Y-%m-%d %H:%M", &tm1), ());
|
||||
TEST(strptime("1970-01-01 00:00", "%Y-%m-%d %H:%M", &tm2), ());
|
||||
TEST_EQUAL(timegm(&tm1), base::TimeGM(tm2), ());
|
||||
TEST_EQUAL(timegm(&tm1), base::TimeGM(1970, 1, 1, 0, 0, 0), ());
|
||||
|
||||
TEST(strptime("2012-12-02 21:08:34", "%Y-%m-%d %H:%M:%S", &tm1), ());
|
||||
TEST(strptime("2012-12-02 21:08:34", "%Y-%m-%d %H:%M:%S", &tm2), ());
|
||||
TEST_EQUAL(timegm(&tm1), base::TimeGM(tm2), ());
|
||||
TEST_EQUAL(timegm(&tm1), base::TimeGM(2012, 12, 2, 21, 8, 34), ());
|
||||
}
|
||||
75
libs/base/base_tests/timer_test.cpp
Normal file
75
libs/base/base_tests/timer_test.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
#include "base/timer.hpp"
|
||||
|
||||
UNIT_TEST(Timer_Seconds)
|
||||
{
|
||||
base::Timer timer;
|
||||
|
||||
double t1 = timer.ElapsedSeconds();
|
||||
double s = 0.0;
|
||||
for (int i = 0; i < 10000000; ++i)
|
||||
s += i * 0.01;
|
||||
double t2 = timer.ElapsedSeconds();
|
||||
|
||||
TEST_NOT_EQUAL(s, 0.0, ("Fictive, to prevent loop optimization"));
|
||||
TEST_NOT_EQUAL(t1, t2, ("Timer values should not be equal"));
|
||||
}
|
||||
|
||||
UNIT_TEST(Timer_CurrentStringTime)
|
||||
{
|
||||
LOG(LINFO, (base::FormatCurrentTime()));
|
||||
}
|
||||
|
||||
UNIT_TEST(Timer_TimestampConversion)
|
||||
{
|
||||
using namespace base;
|
||||
|
||||
TEST_EQUAL(TimestampToString(0), "1970-01-01T00:00:00Z", ());
|
||||
TEST_EQUAL(TimestampToString(1354482514), "2012-12-02T21:08:34Z", ());
|
||||
|
||||
TEST_EQUAL(StringToTimestamp("1970-01-01T00:00:00Z"), 0, ());
|
||||
TEST_EQUAL(StringToTimestamp("1970-01-01T00:00:00.1Z"), 0, ());
|
||||
TEST_EQUAL(StringToTimestamp("1970-01-01T00:00:00.12Z"), 0, ());
|
||||
TEST_EQUAL(StringToTimestamp("1970-01-01T00:00:00.123Z"), 0, ());
|
||||
TEST_EQUAL(StringToTimestamp("1970-01-01T00:00:00.000009Z"), 0, ());
|
||||
TEST_EQUAL(StringToTimestamp("2012-12-02T21:08:34"), 1354482514, ());
|
||||
TEST_EQUAL(StringToTimestamp("2012-12-02T21:08:34Z"), 1354482514, ());
|
||||
TEST_EQUAL(StringToTimestamp("2012-12-03T00:38:34+03:30"), 1354482514, ());
|
||||
TEST_EQUAL(StringToTimestamp("2012-12-02T11:08:34-10:00"), 1354482514, ());
|
||||
TEST_EQUAL(StringToTimestamp("2014-09-30T23:59:59+23:59"), 1412035259, ());
|
||||
|
||||
time_t const now = time(0);
|
||||
TEST_EQUAL(now, StringToTimestamp(TimestampToString(now)), ());
|
||||
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("asd23423adsfbhj657"), ());
|
||||
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("2012-aa-02T21:08:34Z"), ());
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("2012-12-0ZT21:08:34Z"), ());
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("2012:12:02T21-08-34Z"), ());
|
||||
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("2012-"), ());
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("2012-12-02"), ());
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("1970-01-01T"), ());
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("1970-01-01T21:"), ());
|
||||
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("2000-00-02T11:08:34-10:00"), ());
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("2000-13-02T11:08:34-10:00"), ());
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("2000-01-00T11:08:34-10:00"), ());
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("2000-01-32T11:08:34-10:00"), ());
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("2100-01--1T11:08:34-10:00"), ());
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("2100--1-02T11:08:34-10:00"), ());
|
||||
TEST_EQUAL(INVALID_TIME_STAMP, StringToTimestamp("2012-12-02T11:08:34-25:88"), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Timer_GenerateYYMMDD)
|
||||
{
|
||||
TEST_EQUAL(base::GenerateYYMMDD(116, 0, 26), 160126, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Timer_TimeTConversion)
|
||||
{
|
||||
auto const now = ::time(nullptr);
|
||||
TEST_EQUAL(base::SecondsSinceEpochToTimeT(base::TimeTToSecondsSinceEpoch(now)), now, ());
|
||||
}
|
||||
90
libs/base/base_tests/uni_string_dfa_test.cpp
Normal file
90
libs/base/base_tests/uni_string_dfa_test.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/dfa_helpers.hpp"
|
||||
#include "base/string_utils.hpp"
|
||||
#include "base/uni_string_dfa.hpp"
|
||||
|
||||
using namespace strings;
|
||||
|
||||
namespace
|
||||
{
|
||||
UNIT_TEST(UniStringDFA_Smoke)
|
||||
{
|
||||
{
|
||||
UniStringDFA dfa("");
|
||||
|
||||
auto it = dfa.Begin();
|
||||
TEST(it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
|
||||
DFAMove(it, "a");
|
||||
TEST(!it.Accepts(), ());
|
||||
TEST(it.Rejects(), ());
|
||||
}
|
||||
|
||||
{
|
||||
UniStringDFA dfa("абв");
|
||||
|
||||
auto it = dfa.Begin();
|
||||
TEST(!it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
|
||||
DFAMove(it, "а");
|
||||
TEST(!it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
|
||||
DFAMove(it, "б");
|
||||
TEST(!it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
|
||||
DFAMove(it, "в");
|
||||
TEST(it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
|
||||
DFAMove(it, "г");
|
||||
TEST(!it.Accepts(), ());
|
||||
TEST(it.Rejects(), ());
|
||||
}
|
||||
|
||||
{
|
||||
UniStringDFA dfa("абв");
|
||||
|
||||
auto it = dfa.Begin();
|
||||
TEST(!it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
|
||||
DFAMove(it, "а");
|
||||
TEST(!it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
|
||||
DFAMove(it, "г");
|
||||
TEST(!it.Accepts(), ());
|
||||
TEST(it.Rejects(), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(UniStringDFA_Prefix)
|
||||
{
|
||||
{
|
||||
PrefixDFAModifier<UniStringDFA> dfa(UniStringDFA("abc"));
|
||||
|
||||
auto it = dfa.Begin();
|
||||
DFAMove(it, "ab");
|
||||
|
||||
TEST(!it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
|
||||
DFAMove(it, "c");
|
||||
TEST(it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
|
||||
DFAMove(it, "d");
|
||||
TEST(it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
|
||||
DFAMove(it, "efghijk");
|
||||
TEST(it.Accepts(), ());
|
||||
TEST(!it.Rejects(), ());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
45
libs/base/base_tests/visitor_tests.cpp
Normal file
45
libs/base/base_tests/visitor_tests.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/visitor.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Foo
|
||||
{
|
||||
DECLARE_VISITOR()
|
||||
DECLARE_DEBUG_PRINT(Foo)
|
||||
};
|
||||
|
||||
struct Bar
|
||||
{
|
||||
Bar() = default;
|
||||
Bar(int d, string const & s) : m_d(d), m_s(s) {}
|
||||
|
||||
DECLARE_VISITOR(visitor(m_d), visitor(m_s, "string"))
|
||||
DECLARE_DEBUG_PRINT(Bar)
|
||||
|
||||
int m_d = 0;
|
||||
string m_s;
|
||||
};
|
||||
|
||||
UNIT_TEST(DebugPrintVisitor_Smoke)
|
||||
{
|
||||
{
|
||||
Foo foo;
|
||||
TEST_EQUAL(DebugPrint(foo), "Foo []", ());
|
||||
}
|
||||
|
||||
{
|
||||
Bar bar;
|
||||
TEST_EQUAL(DebugPrint(bar), "Bar [0, string: ]", ());
|
||||
|
||||
bar.m_d = 7;
|
||||
bar.m_s = "Hello, World!";
|
||||
TEST_EQUAL(DebugPrint(bar), "Bar [7, string: Hello, World!]", ());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
Loading…
Add table
Add a link
Reference in a new issue