Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:58:55 +01:00
parent 4af19165ec
commit 68073add76
12458 changed files with 12350765 additions and 2 deletions

View 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)

View 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()));
}
}

View 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

View 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(), ());
}
}

View 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), ());
}

View 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

View 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, ());
}

View 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

View 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__

View 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

View 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}), ());
}

View 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(), ());
}

View 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, ());
}
}

View 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

View 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(), ());
}

View 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

View 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
}

View 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

View 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", ());
}

View 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, ());
}

View 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(), ());
}

View 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

View 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, ());
}

View 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

View 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), ());
}

View 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

View 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

View 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), ());
}

View 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}), ());
}
}

View 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

View 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

View 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

View 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"));
}

View 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

View 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

File diff suppressed because it is too large Load diff

View 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

View 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), ());
}

View 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, ());
}
}

View 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

View 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();
}

View 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();
}

View 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();
}

View 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"));
}

View 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), ());
}

View 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, ());
}

View 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

View 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