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,60 @@
project(coding_tests)
set(SRC
base64_test.cpp
bit_streams_test.cpp
bwt_coder_tests.cpp
bwt_tests.cpp
compressed_bit_vector_test.cpp
csv_reader_test.cpp
dd_vector_test.cpp
diff_test.cpp
elias_coder_test.cpp
endianness_test.cpp
file_data_test.cpp
file_sort_test.cpp
files_container_tests.cpp
fixed_bits_ddvector_test.cpp
geometry_coding_test.cpp
hex_test.cpp
huffman_test.cpp
map_uint32_to_val_tests.cpp
mem_file_reader_test.cpp
mem_file_writer_test.cpp
move_to_front_tests.cpp
png_decoder_test.cpp
point_coding_tests.cpp
reader_cache_test.cpp
reader_test.cpp
reader_test.hpp
reader_writer_ops_test.cpp
serdes_json_test.cpp
simple_dense_coding_test.cpp
sha1_test.cpp
sparse_vector_tests.cpp
string_utf8_multilang_tests.cpp
succinct_ef_test.cpp
succinct_mapper_test.cpp
test_polylines.cpp
test_polylines.hpp
text_storage_tests.cpp
traffic_test.cpp
url_tests.cpp
value_opt_string_test.cpp
var_record_reader_test.cpp
var_serial_vector_test.cpp
varint_test.cpp
writer_test.cpp
xml_parser_tests.cpp
zip_creator_test.cpp
zip_reader_test.cpp
zlib_test.cpp
)
omim_add_test(${PROJECT_NAME} ${SRC})
target_link_libraries(${PROJECT_NAME}
platform_tests_support # For csv_reader_test (TODO: Move ScopedFile into a base header)
geometry # For traffic_test and serdes_json_test (TODO: Remove dependency)
coding
)

View file

@ -0,0 +1,28 @@
#include "testing/testing.hpp"
#include "coding/base64.hpp"
using namespace base64;
UNIT_TEST(Base64_Smoke)
{
char const * bytes[] = {"H", "He", "Hel", "Hell", "Hello", "Hello,", "Hello, ", "Hello, World!"};
char const * encoded[] = {
"SA==", "SGU=", "SGVs", "SGVsbA==", "SGVsbG8=", "SGVsbG8s", "SGVsbG8sIA==", "SGVsbG8sIFdvcmxkIQ=="};
TEST_EQUAL(ARRAY_SIZE(bytes), ARRAY_SIZE(encoded), ());
for (size_t i = 0; i < ARRAY_SIZE(bytes); ++i)
{
TEST_EQUAL(Encode(bytes[i]), encoded[i], ());
TEST_EQUAL(Decode(encoded[i]), bytes[i], ());
TEST_EQUAL(Decode(Encode(bytes[i])), bytes[i], ());
TEST_EQUAL(Encode(Decode(encoded[i])), encoded[i], ());
}
char const * str = "MapsWithMe is the offline maps application for any device in the world.";
char const * encStr =
"TWFwc1dpdGhNZSBpcyB0aGUgb2ZmbGluZSBtYXBzIGFwcGxpY2F0aW9uIGZvciBhbnkgZGV2aWNlIGluIHRoZSB3b3JsZC4=";
TEST_EQUAL(Encode(str), encStr, ());
TEST_EQUAL(Decode(encStr), str, ());
}

View file

@ -0,0 +1,105 @@
#include "testing/testing.hpp"
#include "coding/bit_streams.hpp"
#include "coding/reader.hpp"
#include "coding/writer.hpp"
#include "base/assert.hpp"
#include "base/bits.hpp"
#include <cstddef>
#include <cstdint>
#include <random>
#include <utility>
#include <vector>
using namespace std;
namespace
{
UNIT_TEST(BitStreams_Smoke)
{
uniform_int_distribution<uint32_t> randomBytesDistribution(0, 255);
mt19937 rng(0);
vector<pair<uint8_t, uint32_t>> nums;
for (size_t i = 0; i < 100; ++i)
{
uint32_t numBits = randomBytesDistribution(rng) % 8;
uint8_t num = static_cast<uint8_t>(randomBytesDistribution(rng) >> (CHAR_BIT - numBits));
nums.push_back(make_pair(num, numBits));
}
for (size_t i = 0; i < 100; ++i)
{
uint32_t numBits = 8;
uint8_t num = static_cast<uint8_t>(randomBytesDistribution(rng));
nums.push_back(make_pair(num, numBits));
}
vector<uint8_t> encodedBits;
{
MemWriter<vector<uint8_t>> encodedBitsWriter(encodedBits);
BitWriter<MemWriter<vector<uint8_t>>> bitSink(encodedBitsWriter);
for (size_t i = 0; i < nums.size(); ++i)
bitSink.Write(nums[i].first, nums[i].second);
}
MemReader encodedBitsReader(encodedBits.data(), encodedBits.size());
ReaderSource<MemReader> src(encodedBitsReader);
BitReader<ReaderSource<MemReader>> bitsSource(src);
for (size_t i = 0; i < nums.size(); ++i)
{
uint8_t num = bitsSource.Read(nums[i].second);
TEST_EQUAL(num, nums[i].first, (i));
}
}
UNIT_TEST(BitStreams_T1)
{
using TBuffer = vector<uint8_t>;
using TWriter = MemWriter<TBuffer>;
TBuffer buf;
{
TWriter w(buf);
BitWriter<TWriter> bits(w);
bits.Write(0, 3);
bits.Write(3, 3);
bits.Write(6, 3);
}
TEST_EQUAL(buf.size(), 2, ());
}
UNIT_TEST(BitStreams_Large)
{
using TBuffer = vector<uint8_t>;
using TWriter = MemWriter<TBuffer>;
uint64_t const kMask = 0x0123456789abcdef;
TBuffer buf;
{
TWriter w(buf);
BitWriter<TWriter> bits(w);
for (int i = 0; i <= 64; ++i)
if (i <= 32)
bits.WriteAtMost32Bits(static_cast<uint32_t>(kMask), i);
else
bits.WriteAtMost64Bits(kMask, i);
}
{
MemReader r(buf.data(), buf.size());
ReaderSource<MemReader> src(r);
BitReader<ReaderSource<MemReader>> bits(src);
for (int i = 0; i <= 64; ++i)
{
uint64_t const mask = bits::GetFullMask(i);
uint64_t const value = i <= 32 ? bits.ReadAtMost32Bits(i) : bits.ReadAtMost64Bits(i);
TEST_EQUAL(value, kMask & mask, (i));
}
}
}
} // namespace

View file

@ -0,0 +1,107 @@
#include "testing/testing.hpp"
#include "coding/bwt_coder.hpp"
#include "coding/reader.hpp"
#include "coding/writer.hpp"
#include <algorithm>
#include <iterator>
#include <random>
#include <string>
using namespace coding;
using namespace std;
namespace
{
string EncodeDecode(BWTCoder::Params const & params, string const & s)
{
vector<uint8_t> data;
{
MemWriter<decltype(data)> sink(data);
BWTCoder::EncodeAndWrite(params, sink, s.size(), reinterpret_cast<uint8_t const *>(s.data()));
}
string result;
{
MemReader reader(data.data(), data.size());
ReaderSource<MemReader> source(reader);
BWTCoder::ReadAndDecode(source, back_inserter(result));
}
return result;
}
string EncodeDecodeBlock(string const & s)
{
vector<uint8_t> data;
{
MemWriter<decltype(data)> sink(data);
BWTCoder::EncodeAndWriteBlock(sink, s.size(), reinterpret_cast<uint8_t const *>(s.data()));
}
string result;
{
MemReader reader(data.data(), data.size());
ReaderSource<MemReader> source(reader);
auto const buffer = BWTCoder::ReadAndDecodeBlock(source);
result.assign(buffer.begin(), buffer.end());
}
return result;
}
UNIT_TEST(BWTEncoder_Smoke)
{
for (size_t blockSize = 1; blockSize < 100; ++blockSize)
{
BWTCoder::Params params;
params.m_blockSize = blockSize;
string const s = "abracadabra";
TEST_EQUAL(s, EncodeDecodeBlock(s), ());
TEST_EQUAL(s, EncodeDecode(params, s), (blockSize));
}
string const strings[] = {"", "mississippi", "again and again and again"};
for (auto const & s : strings)
{
TEST_EQUAL(s, EncodeDecodeBlock(s), ());
TEST_EQUAL(s, EncodeDecode(BWTCoder::Params{}, s), ());
}
}
UNIT_TEST(BWT_Large)
{
string s;
for (size_t i = 0; i < 10000; ++i)
s += "mississippi";
TEST_EQUAL(s, EncodeDecode(BWTCoder::Params{}, s), ());
}
UNIT_TEST(BWT_AllBytes)
{
int kSeed = 42;
int kMin = 1;
int kMax = 1000;
mt19937 engine(kSeed);
uniform_int_distribution<int> uid(kMin, kMax);
string s;
for (size_t i = 0; i < 256; ++i)
{
auto const count = uid(engine);
ASSERT_GREATER_OR_EQUAL(count, kMin, ());
ASSERT_LESS_OR_EQUAL(count, kMax, ());
for (int j = 0; j < count; ++j)
s.push_back(static_cast<uint8_t>(i));
}
shuffle(s.begin(), s.end(), engine);
TEST_EQUAL(s, EncodeDecode(BWTCoder::Params{}, s), ());
}
} // namespace

View file

@ -0,0 +1,90 @@
#include "testing/testing.hpp"
#include "coding/bwt.hpp"
#include <algorithm>
#include <random>
#include <string>
using namespace coding;
using namespace std;
namespace
{
string RevRevBWT(string const & s)
{
string r;
auto const start = BWT(s, r);
string rr;
RevBWT(start, r, rr);
return rr;
}
UNIT_TEST(BWT_Smoke)
{
{
TEST_EQUAL(BWT(0 /* n */, nullptr /* s */, nullptr /* r */), 0, ());
}
{
string r;
TEST_EQUAL(BWT(string() /* s */, r /* r */), 0, ());
}
{
string const s = "aaaaaa";
string r;
TEST_EQUAL(BWT(s, r), 5, ());
TEST_EQUAL(r, s, ());
}
{
string const s = "mississippi";
string r;
TEST_EQUAL(BWT(s, r), 4, ());
TEST_EQUAL(r, "pssmipissii", ());
}
}
UNIT_TEST(RevBWT_Smoke)
{
string const strings[] = {"abaaba", "mississippi", "a b b", "Again and again and again"};
for (auto const & s : strings)
TEST_EQUAL(s, RevRevBWT(s), ());
for (size_t i = 0; i < 100; ++i)
{
string const s(i, '\0');
TEST_EQUAL(s, RevRevBWT(s), ());
}
for (size_t i = 0; i < 100; ++i)
{
string const s(i, 'a' + (i % 3));
TEST_EQUAL(s, RevRevBWT(s), ());
}
}
UNIT_TEST(RevBWT_AllBytes)
{
int kSeed = 42;
int kMin = 1;
int kMax = 10;
mt19937 engine(kSeed);
uniform_int_distribution<int> uid(kMin, kMax);
string s;
for (size_t i = 0; i < 256; ++i)
{
auto const count = uid(engine);
ASSERT_GREATER_OR_EQUAL(count, kMin, ());
ASSERT_LESS_OR_EQUAL(count, kMax, ());
for (int j = 0; j < count; ++j)
s.push_back(static_cast<uint8_t>(i));
}
shuffle(s.begin(), s.end(), engine);
TEST_EQUAL(s, RevRevBWT(s), ());
}
} // namespace

View file

@ -0,0 +1,455 @@
#include "testing/testing.hpp"
#include "coding/compressed_bit_vector.hpp"
#include "coding/writer.hpp"
#include <algorithm>
#include <cstdint>
#include <iterator>
#include <memory>
#include <set>
#include <vector>
using namespace std;
namespace
{
void Intersect(vector<uint64_t> & setBits1, vector<uint64_t> & setBits2, vector<uint64_t> & result)
{
sort(setBits1.begin(), setBits1.end());
sort(setBits2.begin(), setBits2.end());
set_intersection(setBits1.begin(), setBits1.end(), setBits2.begin(), setBits2.end(), back_inserter(result));
}
void Subtract(vector<uint64_t> & setBits1, vector<uint64_t> & setBits2, vector<uint64_t> & result)
{
sort(setBits1.begin(), setBits1.end());
sort(setBits2.begin(), setBits2.end());
set_difference(setBits1.begin(), setBits1.end(), setBits2.begin(), setBits2.end(), back_inserter(result));
}
void Union(vector<uint64_t> & setBits1, vector<uint64_t> & setBits2, vector<uint64_t> & result)
{
sort(setBits1.begin(), setBits1.end());
sort(setBits2.begin(), setBits2.end());
set_union(setBits1.begin(), setBits1.end(), setBits2.begin(), setBits2.end(), back_inserter(result));
}
template <typename TBinaryOp>
void CheckBinaryOp(TBinaryOp op, vector<uint64_t> & setBits1, vector<uint64_t> & setBits2,
coding::CompressedBitVector const & cbv)
{
vector<uint64_t> expected;
op(setBits1, setBits2, expected);
TEST_EQUAL(expected.size(), cbv.PopCount(), ());
for (size_t i = 0; i < expected.size(); ++i)
TEST(cbv.GetBit(expected[i]), ());
}
void CheckIntersection(vector<uint64_t> & setBits1, vector<uint64_t> & setBits2,
coding::CompressedBitVector const & cbv)
{
CheckBinaryOp(&Intersect, setBits1, setBits2, cbv);
}
void CheckSubtraction(vector<uint64_t> & setBits1, vector<uint64_t> & setBits2, coding::CompressedBitVector const & cbv)
{
CheckBinaryOp(&Subtract, setBits1, setBits2, cbv);
}
void CheckUnion(vector<uint64_t> & setBits1, vector<uint64_t> & setBits2, coding::CompressedBitVector const & cbv)
{
CheckBinaryOp(&Union, setBits1, setBits2, cbv);
}
void CheckUnion(vector<uint64_t> & setBits1, coding::CompressedBitVector::StorageStrategy strategy1,
vector<uint64_t> & setBits2, coding::CompressedBitVector::StorageStrategy strategy2,
coding::CompressedBitVector::StorageStrategy resultStrategy)
{
auto cbv1 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits1);
auto cbv2 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits2);
TEST(cbv1.get(), ());
TEST(cbv2.get(), ());
TEST_EQUAL(strategy1, cbv1->GetStorageStrategy(), ());
TEST_EQUAL(strategy2, cbv2->GetStorageStrategy(), ());
auto cbv3 = coding::CompressedBitVector::Union(*cbv1, *cbv2);
TEST(cbv3.get(), ());
TEST_EQUAL(resultStrategy, cbv3->GetStorageStrategy(), ());
CheckUnion(setBits1, setBits2, *cbv3);
}
} // namespace
UNIT_TEST(CompressedBitVector_Intersect1)
{
size_t const kNumBits = 100;
vector<uint64_t> setBits1;
vector<uint64_t> setBits2;
for (size_t i = 0; i < kNumBits; ++i)
{
if (i > 0)
setBits1.push_back(i);
if (i + 1 < kNumBits)
setBits2.push_back(i);
}
auto cbv1 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits1);
auto cbv2 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits2);
TEST(cbv1.get(), ());
TEST(cbv2.get(), ());
auto cbv3 = coding::CompressedBitVector::Intersect(*cbv1, *cbv2);
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Dense, cbv3->GetStorageStrategy(), ());
CheckIntersection(setBits1, setBits2, *cbv3);
}
UNIT_TEST(CompressedBitVector_Intersect2)
{
size_t const kNumBits = 100;
vector<uint64_t> setBits1;
vector<uint64_t> setBits2;
for (size_t i = 0; i < kNumBits; ++i)
{
if (i <= kNumBits / 2)
setBits1.push_back(i);
if (i >= kNumBits / 2)
setBits2.push_back(i);
}
auto cbv1 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits1);
auto cbv2 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits2);
TEST(cbv1.get(), ());
TEST(cbv2.get(), ());
auto cbv3 = coding::CompressedBitVector::Intersect(*cbv1, *cbv2);
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Sparse, cbv3->GetStorageStrategy(), ());
CheckIntersection(setBits1, setBits2, *cbv3);
}
UNIT_TEST(CompressedBitVector_Intersect3)
{
size_t const kNumBits = 100;
vector<uint64_t> setBits1;
vector<uint64_t> setBits2;
for (size_t i = 0; i < kNumBits; ++i)
{
if (i % 2 == 0)
setBits1.push_back(i);
if (i % 3 == 0)
setBits2.push_back(i);
}
auto cbv1 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits1);
auto cbv2 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits2);
TEST(cbv1.get(), ());
TEST(cbv2.get(), ());
auto cbv3 = coding::CompressedBitVector::Intersect(*cbv1, *cbv2);
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Sparse, cbv3->GetStorageStrategy(), ());
CheckIntersection(setBits1, setBits2, *cbv3);
}
UNIT_TEST(CompressedBitVector_Intersect4)
{
size_t const kNumBits = 1000;
vector<uint64_t> setBits1;
vector<uint64_t> setBits2;
for (size_t i = 0; i < kNumBits; ++i)
{
if (i % 100 == 0)
setBits1.push_back(i);
if (i % 150 == 0)
setBits2.push_back(i);
}
auto cbv1 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits1);
auto cbv2 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits2);
TEST(cbv1.get(), ());
TEST(cbv2.get(), ());
auto cbv3 = coding::CompressedBitVector::Intersect(*cbv1, *cbv2);
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Sparse, cbv3->GetStorageStrategy(), ());
CheckIntersection(setBits1, setBits2, *cbv3);
}
UNIT_TEST(CompressedBitVector_Subtract1)
{
vector<uint64_t> setBits1 = {0, 1, 2, 3, 4, 5, 6};
vector<uint64_t> setBits2 = {1, 2, 3, 4, 5, 6, 7};
auto cbv1 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits1);
auto cbv2 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits2);
TEST(cbv1.get(), ());
TEST(cbv2.get(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Dense, cbv1->GetStorageStrategy(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Dense, cbv2->GetStorageStrategy(), ());
auto cbv3 = coding::CompressedBitVector::Subtract(*cbv1, *cbv2);
TEST(cbv3.get(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Dense, cbv3->GetStorageStrategy(), ());
CheckSubtraction(setBits1, setBits2, *cbv3);
}
UNIT_TEST(CompressedBitVector_Subtract2)
{
vector<uint64_t> setBits1;
for (size_t i = 0; i < 100; ++i)
setBits1.push_back(i);
vector<uint64_t> setBits2 = {9, 14};
auto cbv1 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits1);
auto cbv2 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits2);
TEST(cbv1.get(), ());
TEST(cbv2.get(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Dense, cbv1->GetStorageStrategy(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Sparse, cbv2->GetStorageStrategy(), ());
auto cbv3 = coding::CompressedBitVector::Subtract(*cbv1, *cbv2);
TEST(cbv3.get(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Dense, cbv3->GetStorageStrategy(), ());
CheckSubtraction(setBits1, setBits2, *cbv3);
}
UNIT_TEST(CompressedBitVector_Subtract3)
{
vector<uint64_t> setBits1 = {0, 9};
vector<uint64_t> setBits2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
auto cbv1 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits1);
auto cbv2 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits2);
TEST(cbv1.get(), ());
TEST(cbv2.get(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Sparse, cbv1->GetStorageStrategy(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Dense, cbv2->GetStorageStrategy(), ());
auto cbv3 = coding::CompressedBitVector::Subtract(*cbv1, *cbv2);
TEST(cbv3.get(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Sparse, cbv3->GetStorageStrategy(), ());
CheckSubtraction(setBits1, setBits2, *cbv3);
}
UNIT_TEST(CompressedBitVector_Subtract4)
{
vector<uint64_t> setBits1 = {0, 5, 15};
vector<uint64_t> setBits2 = {0, 10};
auto cbv1 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits1);
auto cbv2 = coding::CompressedBitVectorBuilder::FromBitPositions(setBits2);
TEST(cbv1.get(), ());
TEST(cbv2.get(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Sparse, cbv1->GetStorageStrategy(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Sparse, cbv2->GetStorageStrategy(), ());
auto cbv3 = coding::CompressedBitVector::Subtract(*cbv1, *cbv2);
TEST(cbv3.get(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Sparse, cbv3->GetStorageStrategy(), ());
CheckSubtraction(setBits1, setBits2, *cbv3);
}
UNIT_TEST(CompressedBitVector_Union_Smoke)
{
vector<uint64_t> setBits1 = {};
vector<uint64_t> setBits2 = {};
CheckUnion(setBits1, coding::CompressedBitVector::StorageStrategy::Sparse /* strategy1 */, setBits2,
coding::CompressedBitVector::StorageStrategy::Sparse /* strategy2 */,
coding::CompressedBitVector::StorageStrategy::Sparse /* resultStrategy */);
}
UNIT_TEST(CompressedBitVector_Union1)
{
vector<uint64_t> setBits1 = {};
vector<uint64_t> setBits2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
CheckUnion(setBits1, coding::CompressedBitVector::StorageStrategy::Sparse /* strategy1 */, setBits2,
coding::CompressedBitVector::StorageStrategy::Dense /* strategy2 */,
coding::CompressedBitVector::StorageStrategy::Dense /* resultStrategy */);
}
UNIT_TEST(CompressedBitVector_Union2)
{
vector<uint64_t> setBits1 = {256, 1024};
vector<uint64_t> setBits2 = {0, 32, 64};
CheckUnion(setBits1, coding::CompressedBitVector::StorageStrategy::Sparse /* strategy1 */, setBits2,
coding::CompressedBitVector::StorageStrategy::Sparse /* strategy2 */,
coding::CompressedBitVector::StorageStrategy::Sparse /* resultStrategy */);
}
UNIT_TEST(CompressedBitVector_Union3)
{
vector<uint64_t> setBits1 = {0, 1, 2, 3, 4, 5, 6};
vector<uint64_t> setBits2;
for (int i = 0; i < 256; ++i)
setBits2.push_back(i);
CheckUnion(setBits1, coding::CompressedBitVector::StorageStrategy::Dense /* strategy1 */, setBits2,
coding::CompressedBitVector::StorageStrategy::Dense /* strategy2 */,
coding::CompressedBitVector::StorageStrategy::Dense /* resultStrategy */);
}
UNIT_TEST(CompressedBitVector_Union4)
{
vector<uint64_t> setBits1;
for (uint64_t i = 0; i < coding::DenseCBV::kBlockSize; ++i)
setBits1.push_back(i);
vector<uint64_t> setBits2 = {1000000000};
CheckUnion(setBits1, coding::CompressedBitVector::StorageStrategy::Dense /* strategy1 */, setBits2,
coding::CompressedBitVector::StorageStrategy::Sparse /* strategy2 */,
coding::CompressedBitVector::StorageStrategy::Sparse /* resultStrategy */);
}
UNIT_TEST(CompressedBitVector_SerializationDense)
{
int const kNumBits = 100;
vector<uint64_t> setBits;
for (size_t i = 0; i < kNumBits; ++i)
setBits.push_back(i);
vector<uint8_t> buf;
{
MemWriter<vector<uint8_t>> writer(buf);
auto cbv = coding::CompressedBitVectorBuilder::FromBitPositions(setBits);
TEST_EQUAL(setBits.size(), cbv->PopCount(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Dense, cbv->GetStorageStrategy(), ());
cbv->Serialize(writer);
}
MemReader reader(buf.data(), buf.size());
auto cbv = coding::CompressedBitVectorBuilder::DeserializeFromReader(reader);
TEST(cbv.get(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Dense, cbv->GetStorageStrategy(), ());
TEST_EQUAL(setBits.size(), cbv->PopCount(), ());
for (size_t i = 0; i < setBits.size(); ++i)
TEST(cbv->GetBit(setBits[i]), ());
}
UNIT_TEST(CompressedBitVector_SerializationSparse)
{
int const kNumBits = 100;
vector<uint64_t> setBits;
for (size_t i = 0; i < kNumBits; ++i)
if (i % 10 == 0)
setBits.push_back(i);
vector<uint8_t> buf;
{
MemWriter<vector<uint8_t>> writer(buf);
auto cbv = coding::CompressedBitVectorBuilder::FromBitPositions(setBits);
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Sparse, cbv->GetStorageStrategy(), ());
cbv->Serialize(writer);
}
MemReader reader(buf.data(), buf.size());
auto cbv = coding::CompressedBitVectorBuilder::DeserializeFromReader(reader);
TEST(cbv.get(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Sparse, cbv->GetStorageStrategy(), ());
TEST_EQUAL(setBits.size(), cbv->PopCount(), ());
for (size_t i = 0; i < setBits.size(); ++i)
TEST(cbv->GetBit(setBits[i]), ());
}
UNIT_TEST(CompressedBitVector_ForEach)
{
int const kNumBits = 150;
vector<uint64_t> denseBits;
vector<uint64_t> sparseBits;
for (size_t i = 0; i < kNumBits; ++i)
{
denseBits.push_back(i);
if (i % 15 == 0)
sparseBits.push_back(i);
}
auto denseCBV = coding::CompressedBitVectorBuilder::FromBitPositions(denseBits);
auto sparseCBV = coding::CompressedBitVectorBuilder::FromBitPositions(sparseBits);
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Dense, denseCBV->GetStorageStrategy(), ());
TEST_EQUAL(coding::CompressedBitVector::StorageStrategy::Sparse, sparseCBV->GetStorageStrategy(), ());
set<uint64_t> denseSet;
uint64_t maxPos = 0;
coding::CompressedBitVectorEnumerator::ForEach(*denseCBV, [&](uint64_t pos)
{
denseSet.insert(pos);
maxPos = max(maxPos, pos);
});
TEST_EQUAL(denseSet.size(), kNumBits, ());
TEST_EQUAL(maxPos, kNumBits - 1, ());
coding::CompressedBitVectorEnumerator::ForEach(*sparseCBV, [](uint64_t pos) { TEST_EQUAL(pos % 15, 0, ()); });
}
UNIT_TEST(CompressedBitVector_DenseOneBit)
{
vector<uint64_t> setBits = {0};
unique_ptr<coding::DenseCBV> cbv(new coding::DenseCBV(setBits));
TEST_EQUAL(cbv->PopCount(), 1, ());
coding::CompressedBitVectorEnumerator::ForEach(*cbv, [&](uint64_t pos) { TEST_EQUAL(pos, 0, ()); });
}
UNIT_TEST(CompressedBitVector_LeaveFirstNBitsSmoke)
{
auto cbv = coding::CompressedBitVectorBuilder::FromBitPositions(vector<uint64_t>{});
TEST_EQUAL(cbv->PopCount(), 0, ());
cbv = cbv->LeaveFirstSetNBits(0);
TEST_EQUAL(cbv->PopCount(), 0, ());
cbv = cbv->LeaveFirstSetNBits(200);
TEST_EQUAL(cbv->PopCount(), 0, ());
}
UNIT_TEST(CompressedBitVector_DenseLeaveFirstNBits)
{
{
vector<uint64_t> setBits;
setBits.assign(coding::DenseCBV::kBlockSize * 4, 1);
auto cbv = coding::CompressedBitVectorBuilder::FromBitPositions(setBits);
TEST_EQUAL(cbv->PopCount(), coding::DenseCBV::kBlockSize * 4, ());
TEST_EQUAL(cbv->GetStorageStrategy(), coding::CompressedBitVector::StorageStrategy::Dense, ());
cbv = cbv->LeaveFirstSetNBits(0);
TEST_EQUAL(cbv->PopCount(), 0, ());
}
{
vector<uint64_t> setBits;
for (uint64_t i = 0; i < 100; ++i)
setBits.push_back(2 * i);
auto cbv = coding::CompressedBitVectorBuilder::FromBitPositions(setBits);
TEST_EQUAL(cbv->PopCount(), 100, ());
TEST_EQUAL(cbv->GetStorageStrategy(), coding::CompressedBitVector::StorageStrategy::Dense, ());
cbv = cbv->LeaveFirstSetNBits(50);
TEST_EQUAL(cbv->PopCount(), 50, ());
TEST_EQUAL(cbv->GetStorageStrategy(), coding::CompressedBitVector::StorageStrategy::Dense, ());
for (uint64_t i = 0; i < 50; ++i)
{
TEST(cbv->GetBit(2 * i), ());
TEST(!cbv->GetBit(2 * i + 1), ());
}
}
}
UNIT_TEST(CompressedBitVector_SparseLeaveFirstNBits)
{
vector<uint64_t> setBits;
for (int p = 0; p < 10; ++p)
setBits.push_back(static_cast<uint64_t>(1) << p);
auto cbv = coding::CompressedBitVectorBuilder::FromBitPositions(setBits);
TEST_EQUAL(cbv->PopCount(), 10, ());
TEST_EQUAL(cbv->GetStorageStrategy(), coding::CompressedBitVector::StorageStrategy::Sparse, ());
cbv = cbv->LeaveFirstSetNBits(100);
TEST_EQUAL(cbv->PopCount(), 10, ());
for (uint64_t bit = 0; bit < (1 << 10); ++bit)
if (bit != 0 && (bit & (bit - 1)) == 0)
TEST(cbv->GetBit(bit), (bit));
else
TEST(!cbv->GetBit(bit), (bit));
cbv = cbv->LeaveFirstSetNBits(8);
TEST_EQUAL(cbv->PopCount(), 8, ());
for (uint64_t bit = 0; bit < (1 << 10); ++bit)
if (bit != 0 && (bit & (bit - 1)) == 0 && bit < (1 << 8))
TEST(cbv->GetBit(bit), (bit));
else
TEST(!cbv->GetBit(bit), (bit));
cbv = cbv->LeaveFirstSetNBits(0);
TEST_EQUAL(cbv->PopCount(), 0, ());
for (uint64_t bit = 0; bit < (1 << 10); ++bit)
TEST(!cbv->GetBit(bit), (bit));
}

View file

@ -0,0 +1,224 @@
#include "testing/testing.hpp"
#include "coding/csv_reader.hpp"
#include "coding/file_reader.hpp"
#include "platform/platform_tests_support/scoped_file.hpp"
#include <string>
#include <vector>
namespace csv_reader_test
{
using platform::tests_support::ScopedFile;
using Row = coding::CSVReader::Row;
using Rows = coding::CSVReader::Rows;
namespace
{
std::string const kCSV1 = "a,b,c,d\ne,f,g h";
std::string const kCSV2 = "a,b,cd a b, c";
std::string const kCSV3 = "";
std::string const kCSV4 = "1,2\n3,4\n5,6";
std::string const kCSV5 = "1,2\n3,4\n\n5,6\n";
} // namespace
UNIT_TEST(CSVReaderSmoke)
{
auto const fileName = "test.csv";
ScopedFile sf(fileName, kCSV1);
{
FileReader fileReader(sf.GetFullPath());
coding::CSVReader reader(fileReader, false /* hasHeader */);
auto const file = reader.ReadAll();
TEST_EQUAL(file.size(), 2, ());
Row const firstRow = {"a", "b", "c", "d"};
TEST_EQUAL(file[0], firstRow, ());
Row const secondRow = {"e", "f", "g h"};
TEST_EQUAL(file[1], secondRow, ());
}
{
FileReader fileReader(sf.GetFullPath());
coding::CSVReader reader(fileReader, true /* hasHeader */);
auto const file = reader.ReadAll();
TEST_EQUAL(file.size(), 1, ());
Row const headerRow = {"a", "b", "c", "d"};
TEST_EQUAL(reader.GetHeader(), headerRow, ());
}
}
UNIT_TEST(CSVReaderReadLine)
{
auto const fileName = "test.csv";
ScopedFile sf(fileName, kCSV4);
Rows const answer = {{"1", "2"}, {"3", "4"}, {"5", "6"}};
coding::CSVReader reader(sf.GetFullPath());
size_t index = 0;
while (auto const optionalRow = reader.ReadRow())
{
TEST_EQUAL(*optionalRow, answer[index], ());
++index;
}
TEST_EQUAL(index, answer.size(), ());
TEST(!reader.ReadRow(), ());
TEST(!reader.ReadRow(), ());
}
UNIT_TEST(CSVReaderCustomDelimiter)
{
auto const fileName = "test.csv";
ScopedFile sf(fileName, kCSV2);
FileReader fileReader(sf.GetFullPath());
coding::CSVReader reader(fileReader, false /* hasHeader */, ' ');
auto const file = reader.ReadAll();
TEST_EQUAL(file.size(), 1, ());
Row const firstRow = {"a,b,cd", "a", "b,", "c"};
TEST_EQUAL(file[0], firstRow, ());
}
UNIT_TEST(CSVReaderEmptyFile)
{
auto const fileName = "test.csv";
ScopedFile sf(fileName, kCSV3);
FileReader fileReader(sf.GetFullPath());
coding::CSVReader reader(fileReader);
auto const file = reader.ReadAll();
TEST_EQUAL(file.size(), 0, ());
}
UNIT_TEST(CSVReaderDifferentReaders)
{
auto const fileName = "test.csv";
ScopedFile sf(fileName, kCSV4);
Rows const answer = {{"1", "2"}, {"3", "4"}, {"5", "6"}};
{
FileReader fileReader(sf.GetFullPath());
coding::CSVReader reader(fileReader);
auto const file = reader.ReadAll();
TEST_EQUAL(file, answer, ());
}
{
coding::CSVReader reader(sf.GetFullPath());
auto const file = reader.ReadAll();
TEST_EQUAL(file, answer, ());
}
{
std::ifstream stream(sf.GetFullPath());
coding::CSVReader reader(stream);
auto const file = reader.ReadAll();
TEST_EQUAL(file, answer, ());
}
}
UNIT_TEST(CSVReaderEmptyLines)
{
auto const fileName = "test.csv";
ScopedFile sf(fileName, kCSV5);
Rows const answer = {{"1", "2"}, {"3", "4"}, {}, {"5", "6"}};
{
FileReader fileReader(sf.GetFullPath());
coding::CSVReader reader(fileReader);
auto const file = reader.ReadAll();
TEST_EQUAL(file, answer, ());
}
{
coding::CSVReader reader(sf.GetFullPath());
auto const file = reader.ReadAll();
TEST_EQUAL(file, answer, ());
}
{
std::ifstream stream(sf.GetFullPath());
coding::CSVReader reader(stream);
auto const file = reader.ReadAll();
TEST_EQUAL(file, answer, ());
}
}
UNIT_TEST(CSVReaderForEachRow)
{
auto const fileName = "test.csv";
ScopedFile sf(fileName, kCSV4);
Rows const answer = {{"1", "2"}, {"3", "4"}, {"5", "6"}};
FileReader fileReader(sf.GetFullPath());
auto reader = coding::CSVReader(fileReader);
size_t index = 0;
reader.ForEachRow([&](auto const & row)
{
TEST_EQUAL(row, answer[index], ());
++index;
});
TEST_EQUAL(answer.size(), index, ());
}
UNIT_TEST(CSVReaderIterator)
{
auto const fileName = "test.csv";
ScopedFile sf(fileName, kCSV4);
Rows const answer = {{"1", "2"}, {"3", "4"}, {"5", "6"}};
{
FileReader fileReader(sf.GetFullPath());
coding::CSVRunner runner((coding::CSVReader(fileReader)));
auto it = runner.begin();
TEST_EQUAL(*it, answer[0], ());
++it;
TEST_EQUAL(*it, answer[1], ());
auto it2 = it++;
TEST(it2 == it, ());
TEST_EQUAL(*it2, answer[1], ());
TEST_EQUAL(*it, answer[2], ());
++it;
TEST(it == runner.end(), ());
}
{
size_t index = 0;
for (auto const & row : coding::CSVRunner(coding::CSVReader(sf.GetFullPath())))
{
TEST_EQUAL(row, answer[index], ());
++index;
}
TEST_EQUAL(index, answer.size(), ());
}
}
UNIT_TEST(CSVReaderEmptyColumns)
{
auto const kContentWithEmptyColumns = ",,2,,4,\n,,,,,";
auto const fileName = "test.csv";
ScopedFile sf(fileName, kContentWithEmptyColumns);
Rows const answer = {{"", "", "2", "", "4", ""}, {"", "", "", "", "", ""}};
coding::CSVReader reader(sf.GetFullPath());
size_t index = 0;
while (auto const optionalRow = reader.ReadRow())
{
TEST_EQUAL(*optionalRow, answer[index], ());
++index;
}
TEST_EQUAL(index, answer.size(), ());
TEST(!reader.ReadRow(), ());
TEST(!reader.ReadRow(), ());
}
UNIT_TEST(CSVReaderQuotes)
{
auto const kContentWithQuotes =
R"(noquotes, "" , "with space","with, comma","""double"" quotes","""double,"", commas", """""",)";
auto const fileName = "test.csv";
ScopedFile sf(fileName, kContentWithQuotes);
Rows const answer = {
{"noquotes", "", "with space", "with, comma", "\"double\" quotes", "\"double,\", commas", "\"\"", ""}};
coding::CSVReader reader(sf.GetFullPath());
size_t index = 0;
while (auto const optionalRow = reader.ReadRow())
{
TEST_EQUAL(*optionalRow, answer[index], ());
++index;
}
TEST_EQUAL(index, answer.size(), ());
TEST(!reader.ReadRow(), ());
TEST(!reader.ReadRow(), ());
}
} // namespace csv_reader_test

View file

@ -0,0 +1,45 @@
#include "testing/testing.hpp"
#include "coding/dd_vector.hpp"
#include "coding/reader.hpp"
#include <cstdint>
#include <vector>
UNIT_TEST(DDVector_Smoke)
{
std::vector<uint16_t> data;
// Push size. Big endian is used.
data.push_back(1);
data.push_back(2);
data.push_back(3);
typedef DDVector<uint16_t, MemReader> Vector;
MemReader reader(reinterpret_cast<char const *>(&data[0]), data.size() * sizeof(data[0]));
Vector v(reader);
TEST_EQUAL(3, v.size(), ());
TEST_EQUAL(1, v[0], ());
TEST_EQUAL(2, v[1], ());
TEST_EQUAL(3, v[2], ());
Vector::const_iterator it = v.begin();
for (auto const value : v)
TEST_EQUAL(value, *it++, ());
}
UNIT_TEST(DDVector_IncorrectSize)
{
typedef DDVector<uint16_t, MemReader> Vector;
char const data[] = "ab";
MemReader reader(data, ARRAY_SIZE(data));
bool exceptionCaught = false;
try
{
Vector v(reader);
}
catch (Vector::OpenException & e)
{
exceptionCaught = true;
}
TEST(exceptionCaught, ());
}

View file

@ -0,0 +1,278 @@
#include "testing/testing.hpp"
#include "coding/byte_stream.hpp"
#include "coding/dd_vector.hpp"
#include "coding/diff.hpp"
#include "coding/reader.hpp"
#include "base/rolling_hash.hpp"
#include <cstddef>
#include <cstdint>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
UNIT_TEST(MyersSimpleDiff)
{
vector<char> tmp;
PushBackByteSink<vector<char>> sink(tmp);
TEST_EQUAL(4, diff::DiffMyersSimple(string("axxxb"), string("cxxxd"), 5, sink), ());
TEST_EQUAL(5, diff::DiffMyersSimple(string("abcabba"), string("cbabac"), 10, sink), ());
TEST_EQUAL(5, diff::DiffMyersSimple(string("abcabba"), string("cbabac"), 5, sink), ());
TEST_EQUAL(-1, diff::DiffMyersSimple(string("abcabba"), string("cbabac"), 4, sink), ());
TEST_EQUAL(-1, diff::DiffMyersSimple(string("abcabba"), string("cbabac"), 2, sink), ());
TEST_EQUAL(-1, diff::DiffMyersSimple(string("abcabba"), string("cbabac"), 1, sink), ());
}
class TestPatchWriter
{
public:
template <typename IterT>
void WriteData(IterT it, uint64_t n)
{
for (uint64_t i = 0; i < n; ++i, ++it)
m_Stream << *it;
}
void WriteOperation(uint64_t op) { m_Stream << op << "."; }
string Str() { return m_Stream.str(); }
private:
ostringstream m_Stream;
};
UNIT_TEST(PatchCoderCopyFirst)
{
TestPatchWriter patchWriter;
diff::PatchCoder<TestPatchWriter> patchCoder(patchWriter);
patchCoder.Copy(2);
patchCoder.Copy(1);
patchCoder.Insert("ab", 2);
patchCoder.Finalize();
TEST_EQUAL(patchWriter.Str(), "6.ab5.", ());
}
UNIT_TEST(PatchCoderInsertFirst)
{
TestPatchWriter patchWriter;
diff::PatchCoder<TestPatchWriter> patchCoder(patchWriter);
patchCoder.Insert("abc", 3);
patchCoder.Copy(3);
patchCoder.Insert("d", 1);
patchCoder.Insert("e", 1);
patchCoder.Delete(5);
patchCoder.Finalize();
TEST_EQUAL(patchWriter.Str(), "abc7.6.de5.11.", ());
}
UNIT_TEST(PatchCoderDeleteFirst)
{
TestPatchWriter patchWriter;
diff::PatchCoder<TestPatchWriter> patchCoder(patchWriter);
patchCoder.Delete(3);
patchCoder.Copy(2);
patchCoder.Finalize();
TEST_EQUAL(patchWriter.Str(), "6.5.", ());
}
UNIT_TEST(PatchCoderEmptyPatch)
{
TestPatchWriter patchWriter;
diff::PatchCoder<TestPatchWriter> patchCoder(patchWriter);
patchCoder.Finalize();
TEST_EQUAL(patchWriter.Str(), "", ());
}
// PatchCoder mock.
// Uses simple diff format "=x.-x.+str" where x is number, "." - operation separator, str - string.
// Ignores commands with n == 0, but doesn't merge same commands together, i.e. "=2.=2." won't be
// merged into "=4."
class TestPatchCoder
{
public:
typedef size_t size_type;
void Copy(size_t n)
{
if (n != 0)
m_Stream << "=" << n << ".";
}
void Delete(size_t n)
{
if (n != 0)
m_Stream << "-" << n << ".";
}
template <typename IterT>
void Insert(IterT it, size_t n)
{
if (n == 0)
return;
m_Stream << "+";
for (size_t i = 0; i < n; ++i, ++it)
m_Stream << *it;
m_Stream << ".";
}
void Finalize() {}
string Str() { return m_Stream.str(); }
private:
ostringstream m_Stream;
};
UNIT_TEST(DiffSimpleReplace)
{
char const src[] = "abcxxxdef";
char const dst[] = "abcyydef";
MemReader srcReader(src, ARRAY_SIZE(src) - 1);
MemReader dstReader(dst, ARRAY_SIZE(dst) - 1);
DDVector<char, MemReader> srcV(srcReader); // since sizeof(char) == 1
DDVector<char, MemReader> dstV(dstReader); // since sizeof(char) == 1
diff::SimpleReplaceDiffer differ;
TestPatchCoder testPatchCoder;
differ.Diff(srcV.begin(), srcV.end(), dstV.begin(), dstV.end(), testPatchCoder);
TEST_EQUAL(testPatchCoder.Str(), "=3.-3.+yy.=3.", ());
TestPatchWriter patchWriter;
diff::PatchCoder<TestPatchWriter> patchCoder(patchWriter);
differ.Diff(srcV.begin(), srcV.end(), dstV.begin(), dstV.end(), patchCoder);
patchCoder.Finalize();
TEST_EQUAL(patchWriter.Str(), "6.6.yy4.6.", ());
}
UNIT_TEST(DiffSimpleReplaceEmptyBegin)
{
char const src[] = "xxxdef";
char const dst[] = "yydef";
MemReader srcReader(src, ARRAY_SIZE(src) - 1);
MemReader dstReader(dst, ARRAY_SIZE(dst) - 1);
DDVector<char, MemReader> srcV(srcReader); // since sizeof(char) == 1
DDVector<char, MemReader> dstV(dstReader); // since sizeof(char) == 1
diff::SimpleReplaceDiffer differ;
TestPatchCoder testPatchCoder;
differ.Diff(srcV.begin(), srcV.end(), dstV.begin(), dstV.end(), testPatchCoder);
TEST_EQUAL(testPatchCoder.Str(), "-3.+yy.=3.", ());
TestPatchWriter patchWriter;
diff::PatchCoder<TestPatchWriter> patchCoder(patchWriter);
differ.Diff(srcV.begin(), srcV.end(), dstV.begin(), dstV.end(), patchCoder);
patchCoder.Finalize();
TEST_EQUAL(patchWriter.Str(), "6.yy4.6.", ());
}
UNIT_TEST(DiffSimpleReplaceEmptyEnd)
{
char const src[] = "abcxxx";
char const dst[] = "abcyy";
MemReader srcReader(src, ARRAY_SIZE(src) - 1);
MemReader dstReader(dst, ARRAY_SIZE(dst) - 1);
DDVector<char, MemReader> srcV(srcReader); // since sizeof(char) == 1
DDVector<char, MemReader> dstV(dstReader); // since sizeof(char) == 1
diff::SimpleReplaceDiffer differ;
TestPatchCoder testPatchCoder;
differ.Diff(srcV.begin(), srcV.end(), dstV.begin(), dstV.end(), testPatchCoder);
TEST_EQUAL(testPatchCoder.Str(), "=3.-3.+yy.", ());
TestPatchWriter patchWriter;
diff::PatchCoder<TestPatchWriter> patchCoder(patchWriter);
differ.Diff(srcV.begin(), srcV.end(), dstV.begin(), dstV.end(), patchCoder);
patchCoder.Finalize();
TEST_EQUAL(patchWriter.Str(), "6.6.yy4.", ());
}
UNIT_TEST(DiffSimpleReplaceAllEqual)
{
char const src[] = "abcdef";
char const dst[] = "abcdef";
MemReader srcReader(src, ARRAY_SIZE(src) - 1);
MemReader dstReader(dst, ARRAY_SIZE(dst) - 1);
DDVector<char, MemReader> srcV(srcReader); // since sizeof(char) == 1
DDVector<char, MemReader> dstV(dstReader); // since sizeof(char) == 1
diff::SimpleReplaceDiffer differ;
TestPatchCoder testPatchCoder;
differ.Diff(srcV.begin(), srcV.end(), dstV.begin(), dstV.end(), testPatchCoder);
TEST_EQUAL(testPatchCoder.Str(), "=6.", ());
TestPatchWriter patchWriter;
diff::PatchCoder<TestPatchWriter> patchCoder(patchWriter);
differ.Diff(srcV.begin(), srcV.end(), dstV.begin(), dstV.end(), patchCoder);
patchCoder.Finalize();
TEST_EQUAL(patchWriter.Str(), "12.", ());
}
UNIT_TEST(DiffWithRollingHashEqualStrings)
{
char const src[] = "abcdefklmno";
char const dst[] = "abcdefklmno";
MemReader srcReader(src, ARRAY_SIZE(src) - 1);
MemReader dstReader(dst, ARRAY_SIZE(dst) - 1);
DDVector<char, MemReader> srcV(srcReader); // since sizeof(char) == 1
DDVector<char, MemReader> dstV(dstReader); // since sizeof(char) == 1
diff::RollingHashDiffer<diff::SimpleReplaceDiffer, RollingHasher64> differ(3);
TestPatchCoder testPatchCoder;
differ.Diff(srcV.begin(), srcV.end(), dstV.begin(), dstV.end(), testPatchCoder);
TEST_EQUAL(testPatchCoder.Str(), "=3.=3.=3.=2.", ());
}
UNIT_TEST(DiffWithRollingHashCompletelyDifferentStrings)
{
char const src[] = "pqrstuvw";
char const dst[] = "abcdefgh";
MemReader srcReader(src, ARRAY_SIZE(src) - 1);
MemReader dstReader(dst, ARRAY_SIZE(dst) - 1);
DDVector<char, MemReader> srcV(srcReader); // since sizeof(char) == 1
DDVector<char, MemReader> dstV(dstReader); // since sizeof(char) == 1
diff::RollingHashDiffer<diff::SimpleReplaceDiffer, RollingHasher64> differ(3);
TestPatchCoder testPatchCoder;
differ.Diff(srcV.begin(), srcV.end(), dstV.begin(), dstV.end(), testPatchCoder);
TEST_EQUAL(testPatchCoder.Str(), "-8.+abcdefgh.", ());
}
UNIT_TEST(DiffWithRollingHash1)
{
char const src[] = "abcdefghijklmnop";
char const dst[] = "abcdfeghikkklmnop";
MemReader srcReader(src, ARRAY_SIZE(src) - 1);
MemReader dstReader(dst, ARRAY_SIZE(dst) - 1);
DDVector<char, MemReader> srcV(srcReader); // since sizeof(char) == 1
DDVector<char, MemReader> dstV(dstReader); // since sizeof(char) == 1
diff::RollingHashDiffer<diff::SimpleReplaceDiffer, RollingHasher64> differ(3);
TestPatchCoder testPatchCoder;
differ.Diff(srcV.begin(), srcV.end(), dstV.begin(), dstV.end(), testPatchCoder);
TEST_EQUAL(testPatchCoder.Str(), "=3.=1.-2.+fe.=3.-1.+kk.=2.=3.=1.", ());
}
UNIT_TEST(DiffWithRollingHash2)
{
char const src[] = "abcdefghijklmnop";
char const dst[] = "abxdeflmnop";
MemReader srcReader(src, ARRAY_SIZE(src) - 1);
MemReader dstReader(dst, ARRAY_SIZE(dst) - 1);
DDVector<char, MemReader> srcV(srcReader); // since sizeof(char) == 1
DDVector<char, MemReader> dstV(dstReader); // since sizeof(char) == 1
diff::RollingHashDiffer<diff::SimpleReplaceDiffer, RollingHasher64> differ(3);
TestPatchCoder testPatchCoder;
differ.Diff(srcV.begin(), srcV.end(), dstV.begin(), dstV.end(), testPatchCoder);
TEST_EQUAL(testPatchCoder.Str(), "=2.-1.+x.=3.-5.=1.=3.=1.", ());
}

View file

@ -0,0 +1,62 @@
#include "testing/testing.hpp"
#include "coding/bit_streams.hpp"
#include "coding/elias_coder.hpp"
#include "coding/reader.hpp"
#include "coding/writer.hpp"
#include "base/bits.hpp"
#include <cstdint>
#include <string>
#include <vector>
namespace
{
template <typename TCoder>
void TestCoder(std::string const & name)
{
using TBuffer = std::vector<uint8_t>;
using TWriter = MemWriter<TBuffer>;
uint64_t const kMask = 0xfedcba9876543210;
TBuffer buf;
{
TWriter w(buf);
BitWriter<TWriter> bits(w);
for (int i = 0; i <= 64; ++i)
{
uint64_t const mask = bits::GetFullMask(i);
uint64_t const value = kMask & mask;
if (value == 0)
TEST(!TCoder::Encode(bits, value), (name, i));
else
TEST(TCoder::Encode(bits, value), (name, i));
}
}
{
MemReader r(buf.data(), buf.size());
ReaderSource<MemReader> src(r);
BitReader<ReaderSource<MemReader>> bits(src);
for (int i = 0; i <= 64; ++i)
{
uint64_t const mask = bits::GetFullMask(i);
uint64_t const expected = kMask & mask;
if (expected == 0)
continue;
TEST_EQUAL(expected, TCoder::Decode(bits), (name, i));
}
}
}
UNIT_TEST(EliasCoder_Gamma)
{
TestCoder<coding::GammaCoder>("Gamma");
}
UNIT_TEST(EliasCoder_Delta)
{
TestCoder<coding::DeltaCoder>("Delta");
}
} // namespace

View file

@ -0,0 +1,40 @@
#include "testing/testing.hpp"
#include "coding/endianness.hpp"
UNIT_TEST(Endianness1Byte)
{
TEST_EQUAL(uint8_t(0), ReverseByteOrder<uint8_t>(0), ());
TEST_EQUAL(uint8_t(17), ReverseByteOrder<uint8_t>(17), ());
TEST_EQUAL(uint8_t(255), ReverseByteOrder<uint8_t>(255), ());
TEST_EQUAL(uint8_t(0), ReverseByteOrder<uint8_t>(0), ());
TEST_EQUAL(uint8_t(17), ReverseByteOrder<uint8_t>(17), ());
TEST_EQUAL(uint8_t(255), ReverseByteOrder<uint8_t>(255), ());
}
UNIT_TEST(Endianness12Bytes)
{
TEST_EQUAL(uint16_t(0), ReverseByteOrder<uint16_t>(0), ());
TEST_EQUAL(uint16_t(256), ReverseByteOrder<uint16_t>(1), ());
TEST_EQUAL(uint16_t(0xE8FD), ReverseByteOrder<uint16_t>(0xFDE8), ());
TEST_EQUAL(uint16_t(0xFFFF), ReverseByteOrder<uint16_t>(0xFFFF), ());
TEST_EQUAL(uint16_t(0), ReverseByteOrder<uint16_t>(0), ());
TEST_EQUAL(uint16_t(256), ReverseByteOrder<uint16_t>(1), ());
TEST_EQUAL(uint16_t(0xE8FD), ReverseByteOrder<uint16_t>(0xFDE8), ());
TEST_EQUAL(uint16_t(0xFFFF), ReverseByteOrder<uint16_t>(0xFFFF), ());
}
UNIT_TEST(Endianness18Bytes)
{
TEST_EQUAL(0ULL, ReverseByteOrder(0ULL), ());
TEST_EQUAL(1ULL, ReverseByteOrder(1ULL << 56), ());
TEST_EQUAL(0xE2E4D7D5B1C3B8C6ULL, ReverseByteOrder(0xC6B8C3B1D5D7E4E2ULL), ());
TEST_EQUAL(0xFFFFFFFFFFFFFFFFULL, ReverseByteOrder(0xFFFFFFFFFFFFFFFFULL), ());
TEST_EQUAL(0ULL, ReverseByteOrder(0ULL), ());
TEST_EQUAL(1ULL, ReverseByteOrder(1ULL << 56), ());
TEST_EQUAL(0xE2E4D7D5B1C3B8C6ULL, ReverseByteOrder(0xC6B8C3B1D5D7E4E2ULL), ());
TEST_EQUAL(0xFFFFFFFFFFFFFFFFULL, ReverseByteOrder(0xFFFFFFFFFFFFFFFFULL), ());
}

View file

@ -0,0 +1,278 @@
#include "testing/testing.hpp"
#include "coding/internal/file_data.hpp"
#include <cstring> // strlen
#include <fstream>
#include <string>
namespace file_data_test
{
std::string const name1 = "test1.file";
std::string const name2 = "test2.file";
void MakeFile(std::string const & name)
{
base::FileData f(name, base::FileData::Op::WRITE_TRUNCATE);
f.Write(name.c_str(), name.size());
}
void MakeFile(std::string const & name, size_t const size, char const c)
{
base::FileData f(name, base::FileData::Op::WRITE_TRUNCATE);
f.Write(std::string(size, c).c_str(), size);
}
#ifdef OMIM_OS_WINDOWS
void CheckFileOK(std::string const & name)
{
base::FileData f(name, base::FileData::Op::READ);
uint64_t const size = f.Size();
TEST_EQUAL(size, name.size(), ());
std::vector<char> buffer(size);
f.Read(0, &buffer[0], size);
TEST(equal(name.begin(), name.end(), buffer.begin()), ());
}
#endif
UNIT_TEST(FileData_ApiSmoke)
{
MakeFile(name1);
uint64_t const size = name1.size();
uint64_t sz;
TEST(base::GetFileSize(name1, sz), ());
TEST_EQUAL(sz, size, ());
TEST(base::RenameFileX(name1, name2), ());
TEST(!base::GetFileSize(name1, sz), ());
TEST(base::GetFileSize(name2, sz), ());
TEST_EQUAL(sz, size, ());
TEST(base::DeleteFileX(name2), ());
TEST(!base::GetFileSize(name2, sz), ());
}
/*
UNIT_TEST(FileData_NoDiskSpace)
{
char const * name = "/Volumes/KINDLE/file.bin";
vector<uint8_t> bytes(100000000);
try
{
base::FileData f(name, base::FileData::Op::WRITE_TRUNCATE);
for (size_t i = 0; i < 100; ++i)
f.Write(&bytes[0], bytes.size());
}
catch (Writer::Exception const & ex)
{
LOG(LINFO, ("Writer exception catched"));
}
(void)base::DeleteFileX(name);
}
*/
/*
#ifdef OMIM_OS_WINDOWS
UNIT_TEST(FileData_SharingAV_Windows)
{
{
MakeFile(name1);
// lock file, will check sharing access
base::FileData f1(name1, base::FileData::Op::READ);
// try rename or delete locked file
TEST(!base::RenameFileX(name1, name2), ());
TEST(!base::DeleteFileX(name1), ());
MakeFile(name2);
// try rename or copy to locked file
TEST(!base::RenameFileX(name2, name1), ());
TEST(!base::CopyFileX(name2, name1), ());
// files should be unchanged
CheckFileOK(name1);
CheckFileOK(name2);
//TEST(base::CopyFile(name1, name2), ());
}
// renaming to existing file is not allowed
TEST(!base::RenameFileX(name1, name2), ());
TEST(!base::RenameFileX(name2, name1), ());
TEST(base::DeleteFileX(name1), ());
TEST(base::DeleteFileX(name2), ());
}
#endif
*/
UNIT_TEST(Equal_Function_Test)
{
MakeFile(name1);
MakeFile(name2);
TEST(base::IsEqualFiles(name1, name1), ());
TEST(base::IsEqualFiles(name2, name2), ());
TEST(!base::IsEqualFiles(name1, name2), ());
TEST(base::DeleteFileX(name1), ());
TEST(base::DeleteFileX(name2), ());
}
UNIT_TEST(Equal_Function_Test_For_Big_Files)
{
{
MakeFile(name1, 1024 * 1024, 'a');
MakeFile(name2, 1024 * 1024, 'a');
TEST(base::IsEqualFiles(name1, name2), ());
TEST(base::DeleteFileX(name1), ());
TEST(base::DeleteFileX(name2), ());
}
{
MakeFile(name1, 1024 * 1024 + 512, 'a');
MakeFile(name2, 1024 * 1024 + 512, 'a');
TEST(base::IsEqualFiles(name1, name2), ());
TEST(base::DeleteFileX(name1), ());
TEST(base::DeleteFileX(name2), ());
}
{
MakeFile(name1, 1024 * 1024 + 1, 'a');
MakeFile(name2, 1024 * 1024 + 1, 'b');
TEST(base::IsEqualFiles(name1, name1), ());
TEST(base::IsEqualFiles(name2, name2), ());
TEST(!base::IsEqualFiles(name1, name2), ());
TEST(base::DeleteFileX(name1), ());
TEST(base::DeleteFileX(name2), ());
}
{
MakeFile(name1, 1024 * 1024, 'a');
MakeFile(name2, 1024 * 1024, 'b');
TEST(base::IsEqualFiles(name1, name1), ());
TEST(base::IsEqualFiles(name2, name2), ());
TEST(!base::IsEqualFiles(name1, name2), ());
TEST(base::DeleteFileX(name1), ());
TEST(base::DeleteFileX(name2), ());
}
{
MakeFile(name1, 1024 * 1024, 'a');
MakeFile(name2, 1024 * 1024 + 1, 'b');
TEST(!base::IsEqualFiles(name1, name2), ());
TEST(base::DeleteFileX(name1), ());
TEST(base::DeleteFileX(name2), ());
}
}
UNIT_TEST(EmptyFile)
{
using namespace base;
std::string const name = "test.empty";
std::string const copy = "test.empty.copy";
// Check that both files are not exist.
uint64_t sz;
TEST(!GetFileSize(name, sz), ());
TEST(!GetFileSize(copy, sz), ());
// Try to copy non existing file - failed.
TEST(!CopyFileX(name, copy), ());
// Again, both files are not exist.
TEST(!GetFileSize(name, sz), ());
TEST(!GetFileSize(copy, sz), ());
{
// Create empty file with zero size.
FileData f(name, base::FileData::Op::WRITE_TRUNCATE);
}
// Check that empty file is on disk.
TEST(GetFileSize(name, sz), ());
TEST_EQUAL(sz, 0, ());
// Do copy.
TEST(CopyFileX(name, copy), ());
// TEST(!RenameFileX(name, copy), ());
// Delete copy file and rename name -> copy.
TEST(DeleteFileX(copy), ());
TEST(RenameFileX(name, copy), ());
// Now we don't have an initial file but have a copy.
TEST(!GetFileSize(name, sz), ());
TEST(GetFileSize(copy, sz), ());
TEST_EQUAL(sz, 0, ());
// Delete copy file.
TEST(DeleteFileX(copy), ());
}
UNIT_TEST(RenameOnExistingFile)
{
using namespace base;
std::string const name = "test.empty";
std::string const copy = "test.empty.copy";
{
FileData f(name, FileData::Op::WRITE_TRUNCATE);
uint8_t const x = 1;
f.Write(&x, 1);
}
{
FileData f(copy, FileData::Op::WRITE_TRUNCATE);
uint8_t const x = 2;
f.Write(&x, 1);
}
TEST(RenameFileX(name, copy), ());
{
FileData f(copy, FileData::Op::READ);
uint8_t x;
f.Read(0, &x, 1);
TEST_EQUAL(x, 1, ());
}
TEST(DeleteFileX(copy), ());
}
// Made this 'obvious' test for getline. I had (or not?) behaviour when 'while (getline)' loop
// didn't get last string in file without trailing '\n'.
UNIT_TEST(File_StdGetLine)
{
std::string const fName = "test.txt";
for (char const * buffer : {"x\nxy\nxyz\nxyzk", "x\nxy\nxyz\nxyzk\n"})
{
{
base::FileData f(fName, base::FileData::Op::WRITE_TRUNCATE);
f.Write(buffer, std::strlen(buffer));
}
{
std::ifstream ifs(fName);
std::string line;
size_t count = 0;
while (std::getline(ifs, line))
{
++count;
TEST_EQUAL(line.size(), count, ());
}
TEST_EQUAL(count, 4, ());
}
TEST(base::DeleteFileX(fName), ());
}
}
} // namespace file_data_test

View file

@ -0,0 +1,57 @@
#include "testing/testing.hpp"
#include "coding/file_sort.hpp"
#include "coding/reader.hpp"
#include "coding/write_to_sink.hpp"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <random>
#include <vector>
using namespace std;
namespace
{
void TestFileSorter(vector<uint32_t> & data, char const * tmpFileName, size_t bufferSize)
{
vector<char> serial;
typedef MemWriter<vector<char>> MemWriterType;
MemWriterType writer(serial);
typedef WriterFunctor<MemWriterType> OutT;
OutT out(writer);
FileSorter<uint32_t, OutT> sorter(bufferSize, tmpFileName, out);
for (size_t i = 0; i < data.size(); ++i)
sorter.Add(data[i]);
sorter.SortAndFinish();
TEST_EQUAL(serial.size(), data.size() * sizeof(data[0]), ());
sort(data.begin(), data.end());
MemReader reader(&serial[0], serial.size());
TEST_EQUAL(reader.Size(), data.size() * sizeof(data[0]), ());
vector<uint32_t> result(data.size());
reader.Read(0, &result[0], reader.Size());
TEST_EQUAL(result, data, ());
}
} // namespace
UNIT_TEST(FileSorter_Smoke)
{
vector<uint32_t> data;
data.push_back(2);
data.push_back(3);
data.push_back(1);
TestFileSorter(data, "file_sorter_test_smoke.tmp", 10);
}
UNIT_TEST(FileSorter_Random)
{
mt19937 rng(0);
vector<uint32_t> data(1000);
for (size_t i = 0; i < data.size(); ++i)
data[i] = ((i + 1 % 100) ? rng() : data[i - 20]);
TestFileSorter(data, "file_sorter_test_random.tmp", data.size() / 10);
}

View file

@ -0,0 +1,421 @@
#include "testing/testing.hpp"
#include "coding/files_container.hpp"
#include "coding/varint.hpp"
#include "base/logging.hpp"
#include "base/scope_guard.hpp"
#include "base/string_utils.hpp"
#include "std/target_os.hpp"
#include <cstddef>
#include <cstdint>
#include <string>
#ifndef OMIM_OS_WINDOWS
#include <unistd.h> // _SC_PAGESIZE
#endif
using namespace std;
UNIT_TEST(FilesContainer_Smoke)
{
string const fName = "files_container.tmp";
FileWriter::DeleteFileX(fName);
size_t const count = 10;
// fill container one by one
{
FilesContainerW writer(fName);
for (size_t i = 0; i < count; ++i)
{
auto w = writer.GetWriter(strings::to_string(i));
for (uint32_t j = 0; j < i; ++j)
WriteVarUint(w, j);
}
}
// read container one by one
{
FilesContainerR reader(fName);
for (size_t i = 0; i < count; ++i)
{
FilesContainerR::TReader r = reader.GetReader(strings::to_string(i));
ReaderSource<FilesContainerR::TReader> src(r);
for (uint32_t j = 0; j < i; ++j)
{
uint32_t const test = ReadVarUint<uint32_t>(src);
TEST_EQUAL(j, test, ());
}
}
}
// append to container
uint32_t const arrAppend[] = {888, 777, 666};
for (size_t i = 0; i < ARRAY_SIZE(arrAppend); ++i)
{
{
FilesContainerW writer(fName, FileWriter::OP_WRITE_EXISTING);
auto w = writer.GetWriter(strings::to_string(arrAppend[i]));
WriteVarUint(w, arrAppend[i]);
}
// read appended
{
FilesContainerR reader(fName);
FilesContainerR::TReader r = reader.GetReader(strings::to_string(arrAppend[i]));
ReaderSource<FilesContainerR::TReader> src(r);
uint32_t const test = ReadVarUint<uint32_t>(src);
TEST_EQUAL(arrAppend[i], test, ());
}
}
FileWriter::DeleteFileX(fName);
}
namespace
{
void CheckInvariant(FilesContainerR & reader, string const & tag, int64_t test)
{
FilesContainerR::TReader r = reader.GetReader(tag);
TEST_EQUAL(test, ReadPrimitiveFromPos<int64_t>(r, 0), ());
}
} // namespace
UNIT_TEST(FilesContainer_Shared)
{
string const fName = "files_container.tmp";
FileWriter::DeleteFileX(fName);
uint32_t const count = 10;
int64_t const test64 = 908175281437210836LL;
{
// shared container fill
FilesContainerW writer(fName);
auto w1 = writer.GetWriter("5");
WriteToSink(w1, uint32_t(0));
for (uint32_t i = 0; i < count; ++i)
WriteVarUint(w1, i);
w1->Flush();
auto w2 = writer.GetWriter("2");
WriteToSink(w2, test64);
w2->Flush();
}
{
// shared container read and fill
FilesContainerR reader(fName);
FilesContainerR::TReader r1 = reader.GetReader("5");
uint64_t const offset = sizeof(uint32_t);
r1 = r1.SubReader(offset, r1.Size() - offset);
CheckInvariant(reader, "2", test64);
FilesContainerW writer(fName, FileWriter::OP_WRITE_EXISTING);
auto w = writer.GetWriter("3");
ReaderSource<FilesContainerR::TReader> src(r1);
for (uint32_t i = 0; i < count; ++i)
{
uint32_t test = ReadVarUint<uint32_t>(src);
TEST_EQUAL(test, i, ());
WriteVarUint(w, i);
}
}
{
// check invariant
FilesContainerR reader(fName);
CheckInvariant(reader, "2", test64);
}
FileWriter::DeleteFileX(fName);
}
namespace
{
void ReplaceInContainer(string const & fName, char const * key, char const * value)
{
FilesContainerW writer(fName, FileWriter::OP_WRITE_EXISTING);
auto w = writer.GetWriter(key);
w->Write(value, strlen(value));
}
void CheckContainer(string const & fName, char const * key[], char const * value[], size_t count)
{
FilesContainerR reader(fName);
LOG(LINFO, ("Size=", reader.GetFileSize()));
for (size_t i = 0; i < count; ++i)
{
FilesContainerR::TReader r = reader.GetReader(key[i]);
size_t const szBuffer = 100;
size_t const szS = strlen(value[i]);
char s[szBuffer] = {0};
ASSERT_LESS(szS, szBuffer, ());
r.Read(0, s, szS);
TEST(strcmp(value[i], s) == 0, (s));
}
}
} // namespace
UNIT_TEST(FilesContainer_RewriteExisting)
{
string const fName = "files_container.tmp";
FileWriter::DeleteFileX(fName);
char const * key[] = {"3", "2", "1"};
char const * value[] = {"prolog", "data", "epilog"};
// fill container
{
FilesContainerW writer(fName);
for (size_t i = 0; i < ARRAY_SIZE(key); ++i)
{
auto w = writer.GetWriter(key[i]);
w->Write(value[i], strlen(value[i]));
}
}
// re-write middle file in container
char const * buffer1 = "xxxxxxx";
ReplaceInContainer(fName, key[1], buffer1);
char const * value1[] = {value[0], buffer1, value[2]};
CheckContainer(fName, key, value1, 3);
// re-write end file in container
char const * buffer2 = "yyyyyyyyyyyyyy";
ReplaceInContainer(fName, key[2], buffer2);
char const * value2[] = {value[0], buffer1, buffer2};
CheckContainer(fName, key, value2, 3);
// re-write end file in container once again
char const * buffer3 = "zzz";
ReplaceInContainer(fName, key[2], buffer3);
char const * value3[] = {value[0], buffer1, buffer3};
CheckContainer(fName, key, value3, 3);
FileWriter::DeleteFileX(fName);
}
/// @todo To make this test work, need to review FilesContainerW::GetWriter logic.
/*
UNIT_TEST(FilesContainer_ConsecutiveRewriteExisting)
{
string const fName = "files_container.tmp";
FileWriter::DeleteFileX(fName);
char const * key[] = { "3", "2", "1" };
char const * value[] = { "prolog", "data", "epilog" };
// fill container
{
FilesContainerW writer(fName);
for (size_t i = 0; i < ARRAY_SIZE(key); ++i)
{
auto w = writer.GetWriter(key[i]);
w->Write(value[i], strlen(value[i]));
}
}
char const * buf0 = "xxx";
char const * buf1 = "yyy";
{
FilesContainerW writer(fName, FileWriter::OP_WRITE_EXISTING);
{
auto w = writer.GetWriter(key[0]);
w->Write(buf0, strlen(buf0));
}
{
auto w = writer.GetWriter(key[1]);
w->Write(buf1, strlen(buf1));
}
}
char const * values[] = { buf0, buf1, value[2] };
CheckContainer(fName, key, values, 3);
}
*/
UNIT_TEST(FilesMappingContainer_Handle)
{
string const fName = "files_container.tmp";
string const tag = "dummy";
{
FilesContainerW writer(fName);
auto w = writer.GetWriter(tag);
w->Write(tag.c_str(), tag.size());
}
{
FilesMappingContainer cont(fName);
FilesMappingContainer::Handle h1 = cont.Map(tag);
TEST(h1.IsValid(), ());
FilesMappingContainer::Handle h2;
TEST(!h2.IsValid(), ());
h2.Assign(std::move(h1));
TEST(!h1.IsValid(), ());
TEST(h2.IsValid(), ());
}
FileWriter::DeleteFileX(fName);
}
UNIT_TEST(FilesMappingContainer_MoveHandle)
{
static uint8_t const kNumMapTests = 200;
class HandleWrapper
{
public:
explicit HandleWrapper(FilesMappingContainer::Handle && handle) : m_handle(std::move(handle))
{
TEST(m_handle.IsValid(), ());
}
private:
FilesMappingContainer::Handle m_handle;
};
string const containerPath = "files_container.tmp";
string const tagName = "dummy";
SCOPE_GUARD(deleteContainerFileGuard, bind(&FileWriter::DeleteFileX, cref(containerPath)));
{
FilesContainerW writer(containerPath);
auto w = writer.GetWriter(tagName);
w->Write(tagName.c_str(), tagName.size());
}
{
FilesMappingContainer cont(containerPath);
FilesMappingContainer::Handle h1 = cont.Map(tagName);
TEST(h1.IsValid(), ());
FilesMappingContainer::Handle h2(std::move(h1));
TEST(h2.IsValid(), ());
TEST(!h1.IsValid(), ());
for (int i = 0; i < kNumMapTests; ++i)
{
FilesMappingContainer::Handle parent_handle = cont.Map(tagName);
HandleWrapper tmp(std::move(parent_handle));
}
}
}
UNIT_TEST(FilesMappingContainer_Smoke)
{
string const fName = "files_container.tmp";
char const * key[] = {"3", "2", "1"};
uint32_t const count = 1000000;
// fill container
{
FilesContainerW writer(fName);
for (size_t i = 0; i < ARRAY_SIZE(key); ++i)
{
auto w = writer.GetWriter(key[i]);
for (uint32_t j = 0; j < count; ++j)
{
uint32_t v = j + static_cast<uint32_t>(i);
w->Write(&v, sizeof(v));
}
}
}
{
FilesMappingContainer reader(fName);
for (size_t i = 0; i < ARRAY_SIZE(key); ++i)
{
FilesMappingContainer::Handle h = reader.Map(key[i]);
uint32_t const * data = h.GetData<uint32_t>();
for (uint32_t j = 0; j < count; ++j)
{
TEST_EQUAL(j + i, *data, ());
++data;
}
h.Unmap();
}
}
FileWriter::DeleteFileX(fName);
}
UNIT_TEST(FilesMappingContainer_PageSize)
{
string const fName = "files_container.tmp";
size_t const pageSize =
#ifndef OMIM_OS_WINDOWS
sysconf(_SC_PAGESIZE);
#else
4096;
#endif
LOG(LINFO, ("Page size:", pageSize));
char const * key[] = {"3", "2", "1"};
char const byte[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
size_t count[] = {pageSize - 1, pageSize, pageSize + 1};
size_t const sz = ARRAY_SIZE(key);
{
FilesContainerW writer(fName);
for (size_t i = 0; i < sz; ++i)
{
auto w = writer.GetWriter(key[i]);
for (size_t j = 0; j < count[i]; ++j)
w->Write(&byte[j % ARRAY_SIZE(byte)], 1);
}
}
{
FilesMappingContainer reader(fName);
FilesMappingContainer::Handle handle[sz];
for (size_t i = 0; i < sz; ++i)
{
handle[i].Assign(reader.Map(key[i]));
TEST_EQUAL(handle[i].GetSize(), count[i], ());
}
for (size_t i = 0; i < sz; ++i)
{
char const * data = handle[i].GetData<char>();
for (size_t j = 0; j < count[i]; ++j)
TEST_EQUAL(*data++, byte[j % ARRAY_SIZE(byte)], ());
}
}
FileWriter::DeleteFileX(fName);
}

View file

@ -0,0 +1,81 @@
#include "testing/testing.hpp"
#include "coding/fixed_bits_ddvector.hpp"
#include "coding/writer.hpp"
#include <cstdint>
#include <initializer_list>
#include <random>
#include <utility>
using namespace std;
namespace
{
template <size_t Bits>
void TestWithData(vector<uint32_t> const & lst)
{
using TVector = FixedBitsDDVector<Bits, MemReader>;
using TBuffer = vector<uint8_t>;
using TWriter = MemWriter<TBuffer>;
TBuffer buf;
{
TWriter writer(buf);
typename TVector::template Builder<TWriter> builder(writer);
uint32_t optCount = 0;
uint32_t const optBound = (1 << Bits) - 2;
for (uint32_t v : lst)
{
if (v < optBound)
++optCount;
builder.PushBack(v);
}
pair<uint32_t, uint32_t> expected(optCount, lst.size());
TEST_EQUAL(builder.GetCount(), expected, ());
}
MemReader reader(buf.data(), buf.size());
auto const vec = TVector::Create(reader);
uint32_t i = 0;
for (uint32_t actual : lst)
{
uint32_t expected;
TEST(vec->Get(i, expected), ());
TEST_EQUAL(expected, actual, ());
++i;
}
}
} // namespace
UNIT_TEST(FixedBitsDDVector_Smoke)
{
TestWithData<3>({0, 3, 6});
TestWithData<3>({7, 20, 50});
TestWithData<3>({1, 0, 4, 30, 5, 3, 6, 7, 2, 8, 0});
}
UNIT_TEST(FixedBitsDDVector_Rand)
{
vector<uint32_t> v;
default_random_engine gen;
uniform_int_distribution<uint32_t> distribution(0, 1000);
size_t constexpr kMaxCount = 1000;
for (size_t i = 0; i < kMaxCount; ++i)
v.push_back(distribution(gen));
TestWithData<3>(v);
TestWithData<4>(v);
TestWithData<5>(v);
TestWithData<6>(v);
TestWithData<7>(v);
TestWithData<8>(v);
TestWithData<9>(v);
}

View file

@ -0,0 +1,196 @@
#include "testing/testing.hpp"
#include "coding/byte_stream.hpp"
#include "coding/coding_tests/test_polylines.hpp"
#include "coding/geometry_coding.hpp"
#include "coding/point_coding.hpp"
#include "coding/varint.hpp"
#include "coding/writer.hpp"
#include "geometry/geometry_tests/large_polygon.hpp"
#include "geometry/mercator.hpp"
#include "geometry/parametrized_segment.hpp"
#include "geometry/simplification.hpp"
#include "base/logging.hpp"
#include <cstddef>
#include <cstdint>
#include <vector>
using namespace coding;
using namespace std;
using PU = m2::PointU;
using PD = m2::PointD;
namespace
{
m2::PointU D2U(m2::PointD const & p)
{
return PointDToPointU(p, kPointCoordBits);
}
m2::PointU GetMaxPoint()
{
return D2U(m2::PointD(mercator::Bounds::kMaxX, mercator::Bounds::kMaxY));
}
void TestPolylineEncode(string testName, vector<m2::PointU> const & points, m2::PointU const & maxPoint,
void (*fnEncode)(InPointsT const & points, m2::PointU const & basePoint,
m2::PointU const & maxPoint, OutDeltasT & deltas),
void (*fnDecode)(InDeltasT const & deltas, m2::PointU const & basePoint,
m2::PointU const & maxPoint, OutPointsT & points))
{
size_t const count = points.size();
if (count == 0)
return;
m2::PointU const basePoint = m2::PointU::Zero();
vector<uint64_t> deltas;
deltas.resize(count);
OutDeltasT deltasA(deltas);
fnEncode(make_read_adapter(points), basePoint, maxPoint, deltasA);
vector<m2::PointU> decodedPoints;
decodedPoints.resize(count);
OutPointsT decodedPointsA(decodedPoints);
fnDecode(make_read_adapter(deltas), basePoint, maxPoint, decodedPointsA);
TEST_EQUAL(points, decodedPoints, ());
if (points.size() > 10)
{
vector<char> data;
MemWriter<vector<char>> writer(data);
for (size_t i = 0; i != deltas.size(); ++i)
WriteVarUint(writer, deltas[i]);
LOG(LINFO, (testName, points.size(), data.size()));
}
}
vector<m2::PointU> SimplifyPoints(vector<m2::PointU> const & points, double eps)
{
vector<m2::PointU> simpPoints;
SimplifyDefault(points.begin(), points.end(), eps, simpPoints);
return simpPoints;
}
void TestEncodePolyline(string name, m2::PointU maxPoint, vector<m2::PointU> const & points)
{
TestPolylineEncode(name + "1", points, maxPoint, &EncodePolylinePrev1, &DecodePolylinePrev1);
TestPolylineEncode(name + "2", points, maxPoint, &EncodePolylinePrev2, &DecodePolylinePrev2);
TestPolylineEncode(name + "3", points, maxPoint, &EncodePolylinePrev3, &DecodePolylinePrev3);
}
} // namespace
UNIT_TEST(EncodePointDeltaAsUint)
{
for (int x = -100; x <= 100; ++x)
{
for (int y = -100; y <= 100; ++y)
{
PU orig = PU(100 + x, 100 + y);
PU pred = PU(100, 100);
TEST_EQUAL(orig, DecodePointDeltaFromUint(EncodePointDeltaAsUint(orig, pred), pred), ());
vector<char> data;
PushBackByteSink<vector<char>> sink(data);
WriteVarUint(sink, EncodePointDeltaAsUint(orig, pred));
size_t expectedSize = 1;
if (x >= 8 || x < -8 || y >= 4 || y < -4)
expectedSize = 2;
if (x >= 64 || x < -64 || y >= 64 || y < -64)
expectedSize = 3;
TEST_EQUAL(data.size(), expectedSize, (x, y));
}
}
}
UNIT_TEST(PredictPointsInPolyline2)
{
// Ci = Ci-1 + (Ci-1 + Ci-2) / 2
TEST_EQUAL(PU(5, 5), PredictPointInPolyline(PD(8, 7), PU(4, 4), PU(1, 2)), ());
// Clamp max
TEST_EQUAL(PU(4, 4), PredictPointInPolyline(PD(4, 4), PU(4, 4), PU(1, 2)), ());
TEST_EQUAL(PU(5, 5), PredictPointInPolyline(PD(8, 7), PU(4, 4), PU(1, 2)), ());
TEST_EQUAL(PU(5, 5), PredictPointInPolyline(PD(5, 5), PU(4, 4), PU(1, 2)), ());
// Clamp 0
TEST_EQUAL(PU(4, 0), PredictPointInPolyline(PD(5, 5), PU(4, 1), PU(4, 4)), ());
}
UNIT_TEST(PredictPointsInTriangle)
{
// Ci = Ci-1 + Ci-2 - Ci-3
TEST_EQUAL(PU(1, 1), PredictPointInTriangle(PD(100, 100), PU(1, 0), PU(0, 1), PU(0, 0)), ());
// Clamp 0
TEST_EQUAL(PU(0, 0), PredictPointInTriangle(PD(100, 100), PU(1, 0), PU(0, 1), PU(5, 5)), ());
// Clamp max
TEST_EQUAL(PU(10, 10), PredictPointInTriangle(PD(10, 10), PU(8, 7), PU(6, 5), PU(1, 1)), ());
}
/*
UNIT_TEST(PredictPointsInPolyline3_Square)
{
TEST_EQUAL(PU(5, 1), PredictPointInPolyline(PU(6, 6), PU(5, 4), PU(2, 4), PU(2, 1)), ());
TEST_EQUAL(PU(5, 3), PredictPointInPolyline(PU(6, 6), PU(4, 1), PU(2, 2), PU(3, 4)), ());
}
UNIT_TEST(PredictPointsInPolyline3_SquareClamp0)
{
TEST_EQUAL(PU(5, 1), PredictPointInPolyline(PU(6, 6), PU(5, 4), PU(2, 4), PU(2, 1)), ());
TEST_EQUAL(PU(4, 0), PredictPointInPolyline(PU(6, 6), PU(2, 0), PU(3, 2), PU(5, 1)), ());
}
UNIT_TEST(PredictPointsInPolyline3_90deg)
{
TEST_EQUAL(PU(3, 2), PredictPointInPolyline(PU(8, 8), PU(3, 6), PU(1, 6), PU(1, 5)), ());
}
*/
UNIT_TEST(EncodePolyline)
{
size_t const kSizes[] = {0, 1, 2, 3, 4, ARRAY_SIZE(LargePolygon::kLargePolygon)};
m2::PointU const maxPoint(1000000000, 1000000000);
for (size_t iSize = 0; iSize < ARRAY_SIZE(kSizes); ++iSize)
{
size_t const polygonSize = kSizes[iSize];
vector<m2::PointU> points;
points.reserve(polygonSize);
for (size_t i = 0; i < polygonSize; ++i)
points.push_back(m2::PointU(static_cast<uint32_t>(LargePolygon::kLargePolygon[i].x * 10000),
static_cast<uint32_t>((LargePolygon::kLargePolygon[i].y + 200) * 10000)));
TestEncodePolyline("Unsimp", maxPoint, points);
TestEncodePolyline("1simp", maxPoint, SimplifyPoints(points, 1));
TestEncodePolyline("2simp", maxPoint, SimplifyPoints(points, 2));
TestEncodePolyline("4simp", maxPoint, SimplifyPoints(points, 4));
TestEncodePolyline("10simp", maxPoint, SimplifyPoints(points, 10));
TestEncodePolyline("100simp", maxPoint, SimplifyPoints(points, 100));
TestEncodePolyline("500simp", maxPoint, SimplifyPoints(points, 500));
TestEncodePolyline("1000simp", maxPoint, SimplifyPoints(points, 1000));
TestEncodePolyline("2000simp", maxPoint, SimplifyPoints(points, 2000));
TestEncodePolyline("4000simp", maxPoint, SimplifyPoints(points, 4000));
}
}
// see 476c1d1d125f0c2deb8c commit for special decode test
UNIT_TEST(DecodeEncodePolyline_DataSet1)
{
size_t const count = ARRAY_SIZE(geometry_coding_tests::arr1);
vector<m2::PointU> points;
points.reserve(count);
for (size_t i = 0; i < count; ++i)
points.push_back(D2U(geometry_coding_tests::arr1[i]));
TestPolylineEncode("DataSet1", points, GetMaxPoint(), &EncodePolyline, &DecodePolyline);
}

View file

@ -0,0 +1,65 @@
#include "testing/testing.hpp"
#include "coding/byte_stream.hpp"
#include "coding/coding_tests/test_polylines.hpp"
#include "coding/geometry_coding.hpp"
#include "coding/reader.hpp"
#include "geometry/mercator.hpp"
#include "base/logging.hpp"
#include "base/math.hpp"
#include <vector>
using namespace std;
// Copy-Paste from generator/feature_builder.cpp
namespace
{
bool IsEqual(double d1, double d2)
{
return AlmostEqualAbs(d1, d2, kMwmPointAccuracy);
}
bool IsEqual(m2::PointD const & p1, m2::PointD const & p2)
{
return p1.EqualDxDy(p2, kMwmPointAccuracy);
}
bool IsEqual(m2::RectD const & r1, m2::RectD const & r2)
{
return (IsEqual(r1.minX(), r2.minX()) && IsEqual(r1.minY(), r2.minY()) && IsEqual(r1.maxX(), r2.maxX()) &&
IsEqual(r1.maxY(), r2.maxY()));
}
} // namespace
UNIT_TEST(SaveLoadPolyline_DataSet1)
{
using namespace geometry_coding_tests;
vector<m2::PointD> data1(arr1, arr1 + ARRAY_SIZE(arr1));
vector<char> buffer;
PushBackByteSink<vector<char>> w(buffer);
serial::GeometryCodingParams cp;
serial::SaveOuterPath(data1, cp, w);
vector<m2::PointD> data2;
ArrayByteSource r(&buffer[0]);
serial::LoadOuterPath(r, cp, data2);
TEST_EQUAL(data1.size(), data2.size(), ());
m2::RectD r1, r2;
for (size_t i = 0; i < data1.size(); ++i)
{
r1.Add(data1[i]);
r2.Add(data2[i]);
TEST(IsEqual(data1[i], data2[i]), (data1[i], data2[i]));
}
TEST(IsEqual(r1, r2), (r1, r2));
}

View file

@ -0,0 +1,51 @@
#include "testing/testing.hpp"
#include "coding/hex.hpp"
#include <cstddef>
#include <cstdint>
#include <random>
#include <string>
using namespace std;
UNIT_TEST(GoldenRecode)
{
string data("\x01\x23\x45\x67\x89\xAB\xCD\xEF");
string hexData("0123456789ABCDEF");
TEST_EQUAL(ToHex(data), hexData, ());
TEST_EQUAL(data, FromHex(hexData), ());
}
UNIT_TEST(RandomRecode)
{
mt19937 rng(0);
for (size_t i = 0; i < 256; ++i)
{
string data(1 + (rng() % 20), 0);
for (size_t j = 0; j < data.size(); ++j)
data[j] = static_cast<char>(rng() % 26) + 'A';
TEST_EQUAL(data, FromHex(ToHex(data)), ());
}
}
UNIT_TEST(EncodeNumber)
{
TEST_EQUAL(NumToHex(uint64_t(0x0123456789ABCDEFULL)), "0123456789ABCDEF", ());
}
UNIT_TEST(DecodeLowerCaseHex)
{
TEST_EQUAL(FromHex("fe"), "\xfe", ());
}
UNIT_TEST(EncodeEmptyString)
{
TEST_EQUAL(ToHex(string()), "", ());
}
UNIT_TEST(DecodeEmptyString)
{
TEST_EQUAL(FromHex(""), "", ());
}

View file

@ -0,0 +1,133 @@
#include "testing/testing.hpp"
#include "coding/huffman.hpp"
#include "coding/reader.hpp"
#include "coding/writer.hpp"
#include "base/string_utils.hpp"
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
using namespace std;
namespace
{
vector<strings::UniString> MakeUniStringVector(vector<string> const & v)
{
vector<strings::UniString> result(v.size());
for (size_t i = 0; i < v.size(); ++i)
result[i] = strings::MakeUniString(v[i]);
return result;
}
void TestDecode(coding::HuffmanCoder const & h, uint32_t bits, uint32_t len, uint32_t expected)
{
coding::HuffmanCoder::Code code(bits, len);
uint32_t received;
TEST(h.Decode(code, received), ("Could not decode", code.bits, "( length", code.len, ")"));
TEST_EQUAL(expected, received, ());
}
} // namespace
namespace coding
{
UNIT_TEST(Huffman_Smoke)
{
HuffmanCoder h;
h.Init(MakeUniStringVector(vector<string>{"ab", "ac"}));
TestDecode(h, 0, 1, static_cast<uint32_t>('a')); // 0
TestDecode(h, 1, 2, static_cast<uint32_t>('b')); // 10
TestDecode(h, 3, 2, static_cast<uint32_t>('c')); // 11
}
UNIT_TEST(Huffman_OneSymbol)
{
HuffmanCoder h;
h.Init(MakeUniStringVector(vector<string>{string(5, 0)}));
TestDecode(h, 0, 0, 0);
}
UNIT_TEST(Huffman_NonAscii)
{
HuffmanCoder h;
string const data = "2πΩ";
strings::UniString const uniData = strings::MakeUniString(data);
h.Init(vector<strings::UniString>{uniData});
TestDecode(h, 0, 2, static_cast<uint32_t>(uniData[0])); // 00
TestDecode(h, 1, 1, static_cast<uint32_t>(uniData[1])); // 1
TestDecode(h, 2, 2, static_cast<uint32_t>(uniData[2])); // 01
}
UNIT_TEST(Huffman_Init)
{
HuffmanCoder h;
h.Init(MakeUniStringVector(vector<string>{"ab"}));
vector<uint8_t> buf;
buf.push_back(16); // size
buf.push_back(105); // 01101001
buf.push_back(150); // 10010110
MemReader memReader(&buf[0], buf.size());
ReaderSource<MemReader> reader(memReader);
strings::UniString received = h.ReadAndDecode(reader);
strings::UniString expected = strings::MakeUniString("baababbaabbabaab");
TEST_EQUAL(expected, received, ());
}
UNIT_TEST(Huffman_Serialization_Encoding)
{
HuffmanCoder hW;
hW.Init(MakeUniStringVector(vector<string>{"aaaaaaaaaa", "bbbbbbbbbb", "ccccc", "ddddd"})); // 10, 10, 5, 5
vector<uint8_t> buf;
MemWriter<vector<uint8_t>> writer(buf);
hW.WriteEncoding(writer);
HuffmanCoder hR;
MemReader memReader(&buf[0], buf.size());
ReaderSource<MemReader> reader(memReader);
hR.ReadEncoding(reader);
TEST_EQUAL(reader.Pos(), writer.Pos(), ());
TestDecode(hW, 0, 2, static_cast<uint32_t>('a')); // 00
TestDecode(hW, 2, 2, static_cast<uint32_t>('b')); // 01
TestDecode(hW, 1, 2, static_cast<uint32_t>('c')); // 10
TestDecode(hW, 3, 2, static_cast<uint32_t>('d')); // 11
TestDecode(hR, 0, 2, static_cast<uint32_t>('a'));
TestDecode(hR, 2, 2, static_cast<uint32_t>('b'));
TestDecode(hR, 1, 2, static_cast<uint32_t>('c'));
TestDecode(hR, 3, 2, static_cast<uint32_t>('d'));
}
UNIT_TEST(Huffman_Serialization_Data)
{
HuffmanCoder hW;
hW.Init(MakeUniStringVector(vector<string>{"aaaaaaaaaa", "bbbbbbbbbb", "ccccc", "ddddd"})); // 10, 10, 5, 5
vector<uint8_t> buf;
string const data = "abacabaddddaaabbcabacabadbabd";
strings::UniString expected = strings::UniString(data.begin(), data.end());
MemWriter<vector<uint8_t>> writer(buf);
hW.WriteEncoding(writer);
hW.EncodeAndWrite(writer, expected);
HuffmanCoder hR;
MemReader memReader(&buf[0], buf.size());
ReaderSource<MemReader> reader(memReader);
hR.ReadEncoding(reader);
strings::UniString received = hR.ReadAndDecode(reader);
TEST_EQUAL(expected, received, ());
}
} // namespace coding

View file

@ -0,0 +1,108 @@
#include "testing/testing.hpp"
#include "coding/map_uint32_to_val.hpp"
#include "coding/reader.hpp"
#include "coding/varint.hpp"
#include "coding/writer.hpp"
#include <utility>
#include <vector>
namespace map_uint32_tests
{
using namespace std;
using BufferT = vector<uint8_t>;
using ValuesT = vector<uint32_t>;
using BuilderT = MapUint32ToValueBuilder<uint32_t>;
using MapT = MapUint32ToValue<uint32_t>;
UNIT_TEST(MapUint32Val_Small)
{
{
BuilderT builder;
BufferT buffer;
MemWriter writer(buffer);
builder.Freeze(writer, [](Writer &, auto, auto) {});
LOG(LINFO, ("Empty map size =", buffer.size()));
MemReader reader(buffer.data(), buffer.size());
auto map = MapT::Load(reader, [](NonOwningReaderSource &, uint32_t, ValuesT &) {});
TEST_EQUAL(map->Count(), 0, ());
uint32_t dummy;
TEST(!map->Get(1, dummy), ());
}
{
BuilderT builder;
builder.Put(1, 777);
BufferT buffer;
MemWriter writer(buffer);
builder.Freeze(writer, [](Writer & writer, auto b, auto e)
{
WriteVarUint(writer, *b++);
TEST(b == e, ());
});
MemReader reader(buffer.data(), buffer.size());
auto map = MapT::Load(reader, [](NonOwningReaderSource & source, uint32_t blockSize, ValuesT & values)
{
TEST_EQUAL(blockSize, 1, ("GetThreadsafe should pass optimal blockSize"));
while (source.Size() > 0)
values.push_back(ReadVarUint<uint32_t>(source));
TEST_EQUAL(values.size(), 1, ());
});
TEST_EQUAL(map->Count(), 1, ());
uint32_t val;
TEST(map->GetThreadsafe(1, val), ());
TEST_EQUAL(val, 777, ());
}
}
UNIT_TEST(MapUint32Val_Smoke)
{
vector<pair<uint32_t, uint32_t>> data;
size_t const dataSize = 227;
data.resize(dataSize);
for (size_t i = 0; i < data.size(); ++i)
data[i] = make_pair(static_cast<uint32_t>(i), static_cast<uint32_t>(i));
BufferT buffer;
{
BuilderT builder;
for (auto const & d : data)
builder.Put(d.first, d.second);
MemWriter writer(buffer);
builder.Freeze(writer, [](Writer & w, BuilderT::Iter begin, BuilderT::Iter end)
{
for (auto it = begin; it != end; ++it)
WriteToSink(w, *it);
});
}
{
MemReader reader(buffer.data(), buffer.size());
auto table = MapUint32ToValue<uint32_t>::Load(
reader, [](NonOwningReaderSource & source, uint32_t blockSize, ValuesT & values)
{
values.reserve(blockSize);
while (source.Size() > 0)
values.push_back(ReadPrimitiveFromSource<uint32_t>(source));
});
TEST(table.get(), ());
for (auto const & d : data)
{
uint32_t res;
TEST(table->Get(d.first, res), ());
TEST_EQUAL(res, d.second, ());
TEST(table->GetThreadsafe(d.first, res), ());
TEST_EQUAL(res, d.second, ());
}
}
}
} // namespace map_uint32_tests

View file

@ -0,0 +1,48 @@
#include "testing/testing.hpp"
#include "base/macros.hpp"
#include "coding/reader.hpp"
UNIT_TEST(MemReaderSimple)
{
char constexpr data[] = "123";
size_t constexpr n = ARRAY_SIZE(data);
MemReader const memReader(data, n);
for (size_t i = 0; i < n; ++i)
{
uint8_t c[4] = {0xff, 0xff, 0xff, 0xff};
ReadFromPos(memReader, i, c, n - i);
for (size_t j = 0; j < n; ++j)
TEST_EQUAL(c[j], i + j < n ? data[i + j] : uint8_t(0xff), (i, j, n));
}
MemReader const subReader = memReader.SubReader(1, n - 2);
for (size_t i = 1; i < n - 1; ++i)
{
uint8_t c[4] = {0xff, 0xff, 0xff, 0xff};
ReadFromPos(subReader, i, c, n - i - 2);
for (size_t j = 0; j < n; ++j)
TEST_EQUAL(c[j], i + j < n - 2 ? data[i + j + 1] : uint8_t(0xff), (i, j, n));
}
}
UNIT_TEST(MemReaderStringView)
{
std::string_view constexpr data = "1234567";
MemReader const memReader(data);
size_t constexpr n = data.size();
for (size_t i = 0; i < n; ++i)
{
uint8_t c[n] = {0};
ReadFromPos(memReader, i, c, n - i);
for (size_t j = 0; j < n; ++j)
TEST_EQUAL(c[j], i + j < n ? data[i + j] : uint8_t{0}, (i, j, n));
}
MemReader const subReader = memReader.SubReader(1, n - 2);
for (size_t i = 1; i < n - 1; ++i)
{
uint8_t c[n] = {0};
ReadFromPos(subReader, i, c, n - i - 2);
for (size_t j = 0; j < n; ++j)
TEST_EQUAL(c[j], i + j < n - 2 ? data[i + j + 1] : uint8_t{0}, (i, j, n));
}
}

View file

@ -0,0 +1,30 @@
#include "testing/testing.hpp"
#include "coding/file_writer.hpp"
#include "coding/writer.hpp"
#include "base/macros.hpp"
#include <vector>
UNIT_TEST(MemWriterEmpty)
{
std::vector<char> data;
{
MemWriter<std::vector<char>> writer(data);
}
TEST(data.empty(), (data));
}
UNIT_TEST(MemWriterSimple)
{
std::vector<char> data;
MemWriter<std::vector<char>> writer(data);
writer.Write("Hello", 5);
writer.Write(",", 1);
writer.Write("world!", 6);
char const expected[] = "Hello,world!";
TEST_EQUAL(data.size(), ARRAY_SIZE(expected) - 1, ());
TEST(equal(data.begin(), data.end(), &expected[0]), (data));
}

View file

@ -0,0 +1,32 @@
#include "testing/testing.hpp"
#include "coding/move_to_front.hpp"
#include <cstdint>
using namespace coding;
namespace
{
UNIT_TEST(MoveToFront_Smoke)
{
MoveToFront mtf;
for (size_t i = 0; i < 256; ++i)
TEST_EQUAL(mtf[i], i, ());
// Initially 3 should be on the 3rd position.
TEST_EQUAL(mtf.Transform(3), 3, ());
// After the first transform, 3 should be moved to the 0th position.
TEST_EQUAL(mtf.Transform(3), 0, ());
TEST_EQUAL(mtf.Transform(3), 0, ());
TEST_EQUAL(mtf.Transform(3), 0, ());
TEST_EQUAL(mtf[0], 3, ());
TEST_EQUAL(mtf[1], 0, ());
TEST_EQUAL(mtf[2], 1, ());
TEST_EQUAL(mtf[3], 2, ());
for (size_t i = 4; i < 256; ++i)
TEST_EQUAL(mtf[i], i, ());
}
} // namespace

View file

@ -0,0 +1,45 @@
#include "testing/testing.hpp"
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void loadFile(vector<unsigned char> & buffer,
string const & filename) // designed for loading files from hard disk in an std::vector
{
ifstream file(filename.c_str(), ios::in | ios::binary | ios::ate);
// get filesize
streamsize size = 0;
if (file.seekg(0, ios::end).good())
size = file.tellg();
if (file.seekg(0, ios::beg).good())
size -= file.tellg();
// read contents of the file into the vector
if (size > 0)
{
buffer.resize((size_t)size);
file.read((char *)(&buffer[0]), size);
}
else
buffer.clear();
}
UNIT_TEST(PngDecode)
{
// // load and decode
// vector<unsigned char> buffer, image;
// loadFile(buffer, "../../data/font_0.png");
// unsigned long w, h;
// int error = DecodePNG(image, w, h, buffer.empty() ? 0 : &buffer[0], (unsigned long)buffer.size());
//
// // if there's an error, display it
// TEST_EQUAL(error, 0, ());
// // the pixels are now in the vector "image", use it as texture, draw it, ...
// TEST_GREATER(image.size(), 4, ("Image is empty???"));
// TEST_EQUAL(w, 1024, ());
// TEST_EQUAL(h, 1024, ());
}

View file

@ -0,0 +1,200 @@
#include "testing/testing.hpp"
#include "coding/coding_tests/test_polylines.hpp"
#include "coding/point_coding.hpp"
#include "geometry/mercator.hpp"
#include "geometry/point2d.hpp"
#include "geometry/rect2d.hpp"
#include "base/logging.hpp"
#include "base/math.hpp"
#include <cmath>
#include <random>
using namespace std;
namespace
{
double const kEps = kMwmPointAccuracy;
uint8_t const kCoordBits = kPointCoordBits;
uint32_t const kBig = uint32_t{1} << 30;
void CheckEqualPoints(m2::PointD const & p1, m2::PointD const & p2)
{
TEST(p1.EqualDxDy(p2, kEps), (p1, p2));
TEST_GREATER_OR_EQUAL(p1.x, -180.0, ());
TEST_GREATER_OR_EQUAL(p1.y, -180.0, ());
TEST_LESS_OR_EQUAL(p1.x, 180.0, ());
TEST_LESS_OR_EQUAL(p1.y, 180.0, ());
TEST_GREATER_OR_EQUAL(p2.x, -180.0, ());
TEST_GREATER_OR_EQUAL(p2.y, -180.0, ());
TEST_LESS_OR_EQUAL(p2.x, 180.0, ());
TEST_LESS_OR_EQUAL(p2.y, 180.0, ());
}
} // namespace
UNIT_TEST(PointDToPointU_Epsilons)
{
m2::PointD const arrPt[] = {{-180, -180}, {-180, 180}, {180, 180}, {180, -180}};
m2::PointD const arrD[] = {{1, 1}, {1, -1}, {-1, -1}, {-1, 1}};
size_t const count = ARRAY_SIZE(arrPt);
double eps = 1.0;
while (true)
{
size_t i = 0;
for (; i < count; ++i)
{
m2::PointU p0 = PointDToPointU(arrPt[i].x, arrPt[i].y, kCoordBits);
m2::PointU p1 = PointDToPointU(arrPt[i].x + arrD[i].x * eps, arrPt[i].y + arrD[i].y * eps, kCoordBits);
if (p0 != p1)
break;
}
if (i == count)
break;
eps *= 0.1;
}
LOG(LINFO, ("Epsilon (relative error) =", eps));
for (size_t i = 0; i < count; ++i)
{
m2::PointU const p1 = PointDToPointU(arrPt[i].x, arrPt[i].y, kCoordBits);
m2::PointU const p2(p1.x + arrD[i].x, p1.y + arrD[i].y);
m2::PointD const p3 = PointUToPointD(p2, kCoordBits);
LOG(LINFO, ("Dx =", p3.x - arrPt[i].x, "Dy =", p3.y - arrPt[i].y));
}
}
UNIT_TEST(PointDToPointU_WithLimitRect)
{
mt19937 rng(0);
m2::PointD const limitRectOrigin[] = {{0.0, 0.0}, {10.0, 10.0}, {90.0, 90.0}, {160.0, 160.0}};
double const limitRectSize[] = {0.1, 1.0, 5.0, 10.0, 20.0};
size_t const pointsPerRect = 100;
for (auto const & origin : limitRectOrigin)
{
for (auto const sizeX : limitRectSize)
{
for (auto const sizeY : limitRectSize)
{
m2::RectD const limitRect(origin.x, origin.y, origin.x + sizeX, origin.y + sizeY);
auto distX = uniform_real_distribution<double>(limitRect.minX(), limitRect.maxX());
auto distY = uniform_real_distribution<double>(limitRect.minY(), limitRect.maxY());
auto const coordBits = GetCoordBits(limitRect, kEps);
TEST_NOT_EQUAL(coordBits, 0, ());
// All rects in this test are more than 2 times smaller than mercator range.
TEST_LESS(coordBits, kCoordBits, (limitRect));
for (size_t i = 0; i < pointsPerRect; ++i)
{
auto const pt = m2::PointD(distX(rng), distY(rng));
auto const pointU = PointDToPointU(pt, coordBits, limitRect);
auto const pointD = PointUToPointD(pointU, coordBits, limitRect);
TEST(AlmostEqualAbs(pt, pointD, kEps), (limitRect, pt, pointD, coordBits, kEps));
}
}
}
}
}
UNIT_TEST(PointToInt64Obsolete_Smoke)
{
m2::PointD const arr[] = {{1.25, 1.3}, {180, 90}, {-180, -90}, {0, 0}};
for (size_t i = 0; i < ARRAY_SIZE(arr); ++i)
CheckEqualPoints(arr[i], Int64ToPointObsolete(PointToInt64Obsolete(arr[i], kCoordBits), kCoordBits));
}
UNIT_TEST(PointToInt64Obsolete_Grid)
{
int const delta = 5;
for (int ix = -180; ix <= 180; ix += delta)
{
for (int iy = -180; iy <= 180; iy += delta)
{
m2::PointD const pt(ix, iy);
int64_t const id = PointToInt64Obsolete(pt, kCoordBits);
m2::PointD const pt1 = Int64ToPointObsolete(id, kCoordBits);
CheckEqualPoints(pt, pt1);
int64_t const id1 = PointToInt64Obsolete(pt1, kCoordBits);
TEST_EQUAL(id, id1, (pt, pt1));
}
}
}
UNIT_TEST(PointToInt64Obsolete_Bounds)
{
double const arrEps[] = {-1.0E-2, -1.0E-3, -1.0E-4, 0, 1.0E-4, 1.0E-3, 1.0E-2};
m2::PointD const arrPt[] = {{0, 0}, {-180, -180}, {-180, 180}, {180, 180}, {180, -180},
{-90, -90}, {-90, 90}, {90, 90}, {90, -90}};
for (size_t iP = 0; iP < ARRAY_SIZE(arrPt); ++iP)
{
for (size_t iX = 0; iX < ARRAY_SIZE(arrEps); ++iX)
{
for (size_t iY = 0; iY < ARRAY_SIZE(arrEps); ++iY)
{
m2::PointD const pt(arrPt[iP].x + arrEps[iX], arrPt[iP].y + arrEps[iY]);
m2::PointD const pt1 = Int64ToPointObsolete(PointToInt64Obsolete(pt, kCoordBits), kCoordBits);
TEST(fabs(pt.x - pt1.x) <= (fabs(arrEps[iX]) + kEps) && fabs(pt.y - pt1.y) <= (fabs(arrEps[iY]) + kEps),
(pt, pt1));
}
}
}
}
UNIT_TEST(PointUToUint64Obsolete_0)
{
TEST_EQUAL(0, PointUToUint64Obsolete(m2::PointU(0, 0)), ());
TEST_EQUAL(m2::PointU(0, 0), Uint64ToPointUObsolete(0), ());
}
UNIT_TEST(PointUToUint64Obsolete_Interlaced)
{
TEST_EQUAL(0xAAAAAAAAAAAAAAAAULL, PointUToUint64Obsolete(m2::PointU(0, 0xFFFFFFFF)), ());
TEST_EQUAL(0x5555555555555555ULL, PointUToUint64Obsolete(m2::PointU(0xFFFFFFFF, 0)), ());
TEST_EQUAL(0xAAAAAAAAAAAAAAA8ULL, PointUToUint64Obsolete(m2::PointU(0, 0xFFFFFFFE)), ());
TEST_EQUAL(0x5555555555555554ULL, PointUToUint64Obsolete(m2::PointU(0xFFFFFFFE, 0)), ());
}
UNIT_TEST(PointUToUint64Obsolete_1bit)
{
TEST_EQUAL(2, PointUToUint64Obsolete(m2::PointU(0, 1)), ());
TEST_EQUAL(m2::PointU(0, 1), Uint64ToPointUObsolete(2), ());
TEST_EQUAL(1, PointUToUint64Obsolete(m2::PointU(1, 0)), ());
TEST_EQUAL(m2::PointU(1, 0), Uint64ToPointUObsolete(1), ());
TEST_EQUAL(3ULL << 60, PointUToUint64Obsolete(m2::PointU(kBig, kBig)), ());
TEST_EQUAL((1ULL << 60) - 1, PointUToUint64Obsolete(m2::PointU(kBig - 1, kBig - 1)), ());
}
UNIT_TEST(PointToInt64Obsolete_DataSet1)
{
using namespace geometry_coding_tests;
for (size_t i = 0; i < ARRAY_SIZE(arr1); ++i)
{
m2::PointD const pt(arr1[i].x, arr1[i].y);
int64_t const id = PointToInt64Obsolete(pt, kCoordBits);
m2::PointD const pt1 = Int64ToPointObsolete(id, kCoordBits);
CheckEqualPoints(pt, pt1);
int64_t const id1 = PointToInt64Obsolete(pt1, kCoordBits);
TEST_EQUAL(id, id1, (pt, pt1));
}
}

View file

@ -0,0 +1,49 @@
#include "testing/testing.hpp"
#include "coding/reader.hpp"
#include "coding/reader_cache.hpp"
#include <algorithm>
#include <random>
#include <string>
#include <vector>
using namespace std;
namespace
{
template <class ReaderT>
class CacheReader
{
public:
CacheReader(ReaderT const & reader, uint32_t logPageSize, uint32_t logPageCount)
: m_Reader(reader)
, m_Cache(logPageSize, logPageCount)
{}
void Read(uint64_t pos, void * p, size_t size) const { m_Cache.Read(m_Reader, pos, p, size); }
private:
ReaderT m_Reader;
ReaderCache<ReaderT const> mutable m_Cache;
};
} // namespace
UNIT_TEST(CacheReaderRandomTest)
{
vector<char> data(100000);
for (size_t i = 0; i < data.size(); ++i)
data[i] = static_cast<char>(i % 253);
MemReader memReader(&data[0], data.size());
CacheReader<MemReader> cacheReader(MemReader(&data[0], data.size()), 10, 5);
mt19937 rng(0);
for (size_t i = 0; i < 100000; ++i)
{
size_t pos = rng() % data.size();
size_t len = min(static_cast<size_t>(1 + (rng() % 127)), data.size() - pos);
string readMem(len, '0'), readCache(len, '0');
memReader.Read(pos, &readMem[0], len);
cacheReader.Read(pos, &readCache[0], len);
TEST_EQUAL(readMem, readCache, (pos, len, i));
}
}

View file

@ -0,0 +1,122 @@
#include "testing/testing.hpp"
#include "coding/coding_tests/reader_test.hpp"
#include "coding/buffer_reader.hpp"
#include "coding/file_reader.hpp"
#include "coding/file_writer.hpp"
#include "coding/reader_streambuf.hpp"
#include <cstring>
#include <iostream>
#include <memory>
#include <string>
using namespace std;
namespace
{
string const kData("Quick brown fox jumps over a lazy dog...");
}
UNIT_TEST(MemReaderSmokeTest)
{
MemReader memReader(kData.c_str(), kData.size());
TestReader(memReader);
}
UNIT_TEST(FileReaderSmokeTest)
{
{
FileWriter writer("reader_test_tmp.dat");
writer.Write(&kData[0], kData.size());
}
{
FileReader fileReader("reader_test_tmp.dat");
TestReader(fileReader);
}
FileWriter::DeleteFileX("reader_test_tmp.dat");
}
UNIT_TEST(BufferReaderSmokeTest)
{
BufferReader r1(&kData[0], kData.size());
TestReader(r1);
{
string const data("BlaBla " + kData);
FileWriter writer("reader_test_tmp.dat");
writer.Write(&data[0], data.size());
}
BufferReader r2(FileReader("reader_test_tmp.dat"), 7);
TestReader(r2);
FileWriter::DeleteFileX("reader_test_tmp.dat");
}
UNIT_TEST(BufferReaderEmptyTest)
{
MemReader reader(NULL, 0);
BufferReader bufReader(reader, 0);
TEST_EQUAL(bufReader.Size(), 0, ());
}
UNIT_TEST(FileReaderNonExistentFileTest)
{
try
{
FileReader reader("skjhfaxniauiuq2bmnszmn093sklsd");
TEST(false, ("Exception should be thrown!"));
}
catch (FileReader::OpenException &)
{}
}
UNIT_TEST(FileReaderReadAsText)
{
char const fName[] = "zzzuuuuuummmba";
{
FileWriter f(fName);
f.Write(fName, ARRAY_SIZE(fName) - 1);
}
{
string text;
FileReader(fName).ReadAsString(text);
TEST_EQUAL(text, fName, ());
}
FileWriter::DeleteFileX(fName);
}
UNIT_TEST(ReaderStreamBuf)
{
string const name = "test.txt";
{
FileWriter writer(name);
WriterStreamBuf buffer(writer);
ostream s(&buffer);
s << "hey!" << '\n' << 1 << '\n' << 3.14 << '\n' << 0x0102030405060708ull << endl;
}
{
ReaderStreamBuf buffer(make_unique<FileReader>(name));
istream s(&buffer);
string str;
int i;
double d;
unsigned long long ull;
s >> str >> i >> d >> ull;
TEST_EQUAL(str, "hey!", ());
TEST_EQUAL(i, 1, ());
TEST_ALMOST_EQUAL_ULPS(d, 3.14, ());
TEST_EQUAL(ull, 0x0102030405060708ull, ());
}
FileWriter::DeleteFileX(name);
}

View file

@ -0,0 +1,51 @@
#pragma once
#include "testing/testing.hpp"
#include "coding/reader.hpp"
#include <string>
namespace
{
template <class ReaderT>
void ReadToStringFromPos(ReaderT const & reader, std::string & str, uint64_t pos, size_t size)
{
str.resize(size);
reader.Read(pos, &str[0], str.size());
}
template <class SourceT>
void ReadToStringFromSource(SourceT & source, std::string & str, size_t size)
{
str.resize(size);
source.Read(&str[0], str.size());
}
} // namespace
template <typename ReaderT>
void TestReader(ReaderT const & reader)
{
ReaderSource<ReaderT> source(reader);
std::string d1;
ReadToStringFromSource(source, d1, 6);
TEST_EQUAL(d1, "Quick ", ());
ReadToStringFromSource(source, d1, 6);
TEST_EQUAL(d1, "brown ", ());
ReaderT subReader = source.SubReader(10);
ReadToStringFromPos(subReader, d1, 1, 3);
TEST_EQUAL(d1, "ox ", ());
ReaderT subSubReader = subReader.SubReader(2, 8);
ReadToStringFromPos(subSubReader, d1, 0, 2);
TEST_EQUAL(d1, "x ", ());
ReadToStringFromSource(source, d1, 5);
TEST_EQUAL(d1, "over ", ());
ReaderSource<ReaderT> subReaderSource(subReader);
ReadToStringFromSource(subReaderSource, d1, 6);
TEST_EQUAL(d1, "fox ju", ());
}

View file

@ -0,0 +1,153 @@
#include "testing/testing.hpp"
#include "coding/byte_stream.hpp"
#include "coding/file_reader.hpp"
#include "coding/file_writer.hpp"
#include "coding/read_write_utils.hpp"
#include "coding/reader_writer_ops.hpp"
#include "base/random.hpp"
#include <algorithm>
#include <vector>
namespace rw_ops_tests
{
using namespace std;
namespace
{
void GetReverseForReaderAndTmpFile(Reader const & src, vector<char> & buffer)
{
char const * tmpFile = "reversed_file.tmp";
{
FileWriter writer(tmpFile);
rw_ops::Reverse(src, writer);
}
{
FileReader reader(tmpFile);
buffer.clear();
MemWriter<vector<char>> writer(buffer);
rw_ops::Reverse(reader, writer);
}
FileWriter::DeleteFileX(tmpFile);
}
void FillRandFile(string const & fName, size_t count)
{
FileWriter writer(fName);
base::UniformRandom<int8_t> rand;
while (count-- > 0)
{
int8_t const c = rand();
writer.Write(&c, 1);
}
}
} // namespace
UNIT_TEST(Reverse_Smoke)
{
{
char arr[] = {0xA, 0xB, 0xC, 0xD, 0xF};
size_t const sz = ARRAY_SIZE(arr);
MemReader reader(&arr[0], sz);
vector<char> buffer;
GetReverseForReaderAndTmpFile(reader, buffer);
TEST_EQUAL(buffer.size(), ARRAY_SIZE(arr), ());
TEST(equal(arr, arr + ARRAY_SIZE(arr), buffer.begin()), ());
}
{
char const * tmpFile = "random_file.tmp";
{
FillRandFile(tmpFile, 10 * 1024 + 527);
FileReader reader(tmpFile);
vector<char> buffer;
GetReverseForReaderAndTmpFile(reader, buffer);
string str;
reader.ReadAsString(str);
TEST_EQUAL(str.size(), buffer.size(), ());
TEST(equal(str.begin(), str.end(), buffer.begin()), ());
}
FileWriter::DeleteFileX(tmpFile);
}
}
namespace
{
struct ThePOD
{
uint32_t m_i;
double m_d;
};
bool operator==(ThePOD const & r1, ThePOD const & r2)
{
return (r1.m_i == r2.m_i && r1.m_d == r2.m_d);
}
} // namespace
UNIT_TEST(ReadWrite_POD)
{
base::UniformRandom<uint32_t> rand;
size_t const count = 1000;
vector<ThePOD> src(1000);
for (size_t i = 0; i < count; ++i)
{
src[i].m_i = rand();
src[i].m_d = double(rand()) / double(rand());
}
vector<char> buffer;
PushBackByteSink<vector<char>> sink(buffer);
rw::WriteVectorOfPOD(sink, src);
buffer_vector<ThePOD, 128> dest;
ArrayByteSource byteSrc(buffer.data());
rw::ReadVectorOfPOD(byteSrc, dest);
TEST(equal(src.begin(), src.end(), dest.begin()), ());
}
namespace
{
template <class T>
void TestIntegral()
{
std::vector<T> ethalon{static_cast<T>(-1), 0, 1, static_cast<T>(-2), 2, std::numeric_limits<T>::min(),
std::numeric_limits<T>::max()};
std::string buffer;
MemWriter writer(buffer);
rw::Write(writer, ethalon);
std::vector<T> expected;
MemReader reader(buffer);
ReaderSource src(reader);
rw::Read(src, expected);
TEST_EQUAL(ethalon, expected, ());
}
} // namespace
UNIT_TEST(ReadWrite_Integral)
{
TestIntegral<uint32_t>();
TestIntegral<int32_t>();
TestIntegral<uint64_t>();
TestIntegral<int64_t>();
}
} // namespace rw_ops_tests

View file

@ -0,0 +1,265 @@
#include "testing/testing.hpp"
#include "coding/serdes_json.hpp"
#include "coding/writer.hpp"
#include "base/string_utils.hpp"
#include "base/visitor.hpp"
#include <array>
#include <chrono>
#include <deque>
#include <limits>
#include <map>
#include <memory>
#include <unordered_set>
#include <vector>
using namespace std;
namespace
{
template <typename Ptr>
bool SamePtrValue(Ptr const & lhs, Ptr const & rhs)
{
return (!lhs && !rhs) || (lhs && rhs && *lhs == *rhs);
}
template <typename T>
bool TestSerDes(T const & value)
{
string jsonStr;
{
using Sink = MemWriter<string>;
Sink sink(jsonStr);
coding::SerializerJson<Sink> ser(sink);
ser(value);
}
T deserializedValue;
try
{
coding::DeserializerJson des(jsonStr);
des(deserializedValue);
}
catch (base::Json::Exception const & exception)
{
LOG(LWARNING, ("Exception while parsing json string, reason:", exception.what(), "json:", jsonStr));
return false;
}
return deserializedValue == value;
}
enum class TestEnum
{
Value0 = 0,
Value1,
Value2,
Count
};
struct ValueTypes
{
DECLARE_VISITOR(visitor(m_boolValue, "boolValue"), visitor(m_uint8Value, "uint8Value"),
visitor(m_uint32Value, "uint32Value"), visitor(m_uint64Value, "uint64Value"),
visitor(m_int8Value, "int8Value"), visitor(m_int32Value, "int32Value"),
visitor(m_int64Value, "int64Value"), visitor(m_doubleValue, "doubleValue"),
visitor(m_stringValue, "stringValue"), visitor(m_enumValue, "enumValue"),
visitor(m_timePointValue, "timePointValue"))
ValueTypes() = default;
ValueTypes(uint32_t testCounter)
: m_boolValue(static_cast<bool>(testCounter % 2))
, m_uint8Value(numeric_limits<uint8_t>::max() - static_cast<uint8_t>(testCounter))
, m_uint32Value(numeric_limits<uint32_t>::max() - testCounter)
, m_uint64Value(numeric_limits<uint64_t>::max() - testCounter)
, m_int8Value(numeric_limits<int8_t>::min() + static_cast<int8_t>(testCounter))
, m_int32Value(numeric_limits<int32_t>::min() + static_cast<int32_t>(testCounter))
, m_int64Value(numeric_limits<int64_t>::min() + static_cast<int64_t>(testCounter))
, m_doubleValue(numeric_limits<double>::max() - testCounter)
, m_stringValue(strings::to_string(testCounter))
, m_enumValue(static_cast<TestEnum>(testCounter % static_cast<uint32_t>(TestEnum::Count)))
, m_timePointValue(chrono::system_clock::now())
{}
bool operator==(ValueTypes const & rhs) const
{
return m_boolValue == rhs.m_boolValue && m_uint8Value == rhs.m_uint8Value && m_uint32Value == rhs.m_uint32Value &&
m_uint64Value == rhs.m_uint64Value && m_int8Value == rhs.m_int8Value && m_int32Value == rhs.m_int32Value &&
m_int64Value == rhs.m_int64Value && m_doubleValue == rhs.m_doubleValue &&
m_stringValue == rhs.m_stringValue && m_enumValue == rhs.m_enumValue &&
m_timePointValue == rhs.m_timePointValue;
}
bool m_boolValue;
uint8_t m_uint8Value;
uint32_t m_uint32Value;
uint64_t m_uint64Value;
int8_t m_int8Value;
int32_t m_int32Value;
int64_t m_int64Value;
double m_doubleValue;
string m_stringValue;
TestEnum m_enumValue;
chrono::system_clock::time_point m_timePointValue;
};
struct ObjectTypes
{
DECLARE_VISITOR(visitor(m_pointValue, "pointValue"), visitor(m_latLonValue, "latLonValue"),
visitor(m_pairValue, "pairValue"))
ObjectTypes() = default;
ObjectTypes(uint32_t testCounter)
: m_pointValue(testCounter, testCounter)
, m_latLonValue(testCounter, testCounter)
, m_pairValue(testCounter, strings::to_string(testCounter))
{}
bool operator==(ObjectTypes const & rhs) const
{
return m_pointValue == rhs.m_pointValue && m_latLonValue == rhs.m_latLonValue && m_pairValue == rhs.m_pairValue;
}
m2::PointD m_pointValue;
ms::LatLon m_latLonValue;
pair<uint32_t, string> m_pairValue;
};
struct PointerTypes
{
DECLARE_VISITOR(visitor(m_uniquePtrValue, "uniquePtrValue"), visitor(m_sharedPtrValue, "sharedPtrValue"))
PointerTypes() = default;
PointerTypes(uint32_t testCounter)
{
m_uniquePtrValue = make_unique<ValueTypes>(testCounter);
m_sharedPtrValue = make_shared<ValueTypes>(testCounter);
}
bool operator==(PointerTypes const & rhs) const
{
return SamePtrValue(m_uniquePtrValue, rhs.m_uniquePtrValue) && SamePtrValue(m_sharedPtrValue, rhs.m_sharedPtrValue);
}
unique_ptr<ValueTypes> m_uniquePtrValue;
shared_ptr<ValueTypes> m_sharedPtrValue;
};
struct ArrayTypes
{
DECLARE_VISITOR(visitor(m_arrayValue, "arrayValue"), visitor(m_dequeValue, "dequeValue"),
visitor(m_vectorValue, "vectorValue"), visitor(m_mapValue, "mapValue"),
visitor(m_unorderedSetValue, "unorderedSetValue"))
ArrayTypes() = default;
ArrayTypes(uint32_t testCounter)
: m_arrayValue({{testCounter, testCounter + 1, testCounter + 2}})
, m_dequeValue({testCounter + 2, testCounter + 1, testCounter})
, m_vectorValue({testCounter, testCounter + 2, testCounter + 1})
, m_mapValue({{testCounter, testCounter}, {testCounter + 1, testCounter + 1}})
, m_unorderedSetValue({testCounter + 2, testCounter, testCounter + 1})
{}
bool operator==(ArrayTypes const & rhs) const
{
return m_arrayValue == rhs.m_arrayValue && m_dequeValue == rhs.m_dequeValue && m_vectorValue == rhs.m_vectorValue &&
m_mapValue == rhs.m_mapValue && m_unorderedSetValue == rhs.m_unorderedSetValue;
}
array<uint32_t, 3> m_arrayValue;
deque<uint32_t> m_dequeValue;
vector<uint32_t> m_vectorValue;
map<uint32_t, uint32_t> m_mapValue;
unordered_set<uint32_t> m_unorderedSetValue;
};
} // namespace
UNIT_TEST(SerdesJsonTest)
{
{
ValueTypes valueTypes(0);
TEST(TestSerDes(valueTypes), ());
ObjectTypes objectTypes(0);
TEST(TestSerDes(objectTypes), ());
PointerTypes pointersTypes(0);
TEST(TestSerDes(pointersTypes), ());
ArrayTypes arrayTypes(0);
TEST(TestSerDes(arrayTypes), ());
}
{
pair<string, m2::PointD> testValue = {"test", m2::PointD(1.0, 2.0)};
TEST(TestSerDes(testValue), ());
}
{
pair<m2::PointD, m2::PointD> testValue = {m2::PointD(1.0, 2.0), m2::PointD(2.0, 3.0)};
TEST(TestSerDes(testValue), ());
}
{
pair<string, pair<string, string>> testValue = {"test", {"test1", "test2"}};
TEST(TestSerDes(testValue), ());
}
{
pair<string, ValueTypes> testValue = {"test", ValueTypes(0)};
TEST(TestSerDes(testValue), ());
}
{
array<ObjectTypes, 2> testValue = {{ObjectTypes(0), ObjectTypes(1)}};
TEST(TestSerDes(testValue), ());
}
{
struct Hasher
{
size_t operator()(pair<string, string> const & item) const { return m_hasher(item.first + item.second); }
hash<string> m_hasher;
};
unordered_set<pair<string, string>, Hasher> testValue = {{"ab", "ab"}, {"ef", "ef"}, {"cd", "cd"}};
TEST(TestSerDes(testValue), ());
}
{
vector<vector<uint32_t>> testValue;
for (uint32_t i = 0; i < 5; ++i)
testValue.push_back({i, i, i});
TEST(TestSerDes(testValue), ());
}
{
vector<ValueTypes> valuesVector;
for (uint32_t i = 0; i < 5; ++i)
valuesVector.push_back(ValueTypes(i));
TEST(TestSerDes(valuesVector), ());
}
{
map<uint32_t, ValueTypes> valuesMap;
for (uint32_t i = 0; i < 5; ++i)
valuesMap.insert(make_pair(i, ValueTypes(i)));
TEST(TestSerDes(valuesMap), ());
}
{
vector<ObjectTypes> objectsVector;
for (uint32_t i = 0; i < 5; ++i)
objectsVector.push_back(ObjectTypes(i));
TEST(TestSerDes(objectsVector), ());
}
{
map<uint32_t, ObjectTypes> objectsMap;
for (uint32_t i = 0; i < 5; ++i)
objectsMap.insert(make_pair(i, ObjectTypes(i)));
TEST(TestSerDes(objectsMap), ());
}
}

View file

@ -0,0 +1,49 @@
#include "testing/testing.hpp"
#include "coding/sha1.hpp"
namespace sha1_test
{
using namespace coding;
UNIT_TEST(SHA1_Smoke)
{
char const * bytes[] = {
"H",
"He",
"Hel",
"Hell",
"Hello",
"Hello,",
"Hello, ",
"Hello, World!",
"Organic Maps is the ultimate companion app for travellers, tourists, hikers, and cyclists!",
};
SHA1::Hash encoded[] = {
{0x7C, 0xF1, 0x84, 0xF4, 0xC6, 0x7A, 0xD5, 0x82, 0x83, 0xEC,
0xB1, 0x93, 0x49, 0x72, 0x0B, 0x0C, 0xAE, 0x75, 0x68, 0x29},
{0x53, 0xA4, 0x17, 0x79, 0x6C, 0x77, 0x78, 0x51, 0x00, 0x3B,
0x3F, 0x24, 0x31, 0xE8, 0xEE, 0xF5, 0x62, 0x5E, 0xC1, 0x5B},
{0xDB, 0xC2, 0xD1, 0xFE, 0xD0, 0xDC, 0x37, 0xA7, 0x0A, 0xEA,
0x0F, 0x37, 0x69, 0x58, 0xC8, 0x02, 0xED, 0xDC, 0x05, 0x59},
{0xED, 0x10, 0xFE, 0x11, 0x3D, 0xE1, 0xC0, 0xBD, 0xAA, 0xAA,
0xF0, 0x9B, 0x88, 0xCD, 0x34, 0x1E, 0xA0, 0xF4, 0x44, 0x28},
{0xF7, 0xFF, 0x9E, 0x8B, 0x7B, 0xB2, 0xE0, 0x9B, 0x70, 0x93,
0x5A, 0x5D, 0x78, 0x5E, 0x0C, 0xC5, 0xD9, 0xD0, 0xAB, 0xF0},
{0x65, 0x61, 0x1E, 0x95, 0x20, 0xE7, 0x68, 0x14, 0x5D, 0xAD,
0xAA, 0x1D, 0x10, 0x7F, 0xDD, 0x52, 0x07, 0xE6, 0x30, 0x57},
{0xF5, 0x2A, 0xB5, 0x7F, 0xA5, 0x1D, 0xFA, 0x71, 0x45, 0x05,
0x29, 0x44, 0x44, 0x46, 0x3A, 0xE5, 0xA0, 0x09, 0xAE, 0x34},
{0x0A, 0x0A, 0x9F, 0x2A, 0x67, 0x72, 0x94, 0x25, 0x57, 0xAB,
0x53, 0x55, 0xD7, 0x6A, 0xF4, 0x42, 0xF8, 0xF6, 0x5E, 0x01},
{0x48, 0xF5, 0x4D, 0x3D, 0x08, 0xD5, 0xC0, 0x57, 0x6B, 0x3A,
0xC5, 0x3E, 0xEF, 0x22, 0x4A, 0xB8, 0x46, 0x7B, 0xA2, 0xFC},
};
static_assert(std::size(bytes) == std::size(encoded));
for (size_t i = 0; i < std::size(bytes); ++i)
TEST_EQUAL(SHA1::CalculateForString(bytes[i]), encoded[i], ());
}
} // namespace sha1_test

View file

@ -0,0 +1,89 @@
#include "testing/testing.hpp"
#include "coding/file_writer.hpp"
#include "coding/mmap_reader.hpp"
#include "coding/simple_dense_coding.hpp"
#include "coding/succinct_mapper.hpp"
#include "base/logging.hpp"
#include "base/scope_guard.hpp"
#include <limits>
#include <random>
#include <string>
#include <vector>
namespace simple_dense_coding_test
{
using namespace coding;
using namespace std;
namespace
{
void TestSDC(vector<uint8_t> const & data, SimpleDenseCoding const & coding)
{
TEST_EQUAL(data.size(), coding.Size(), ());
for (size_t i = 0; i < data.size(); ++i)
TEST_EQUAL(data[i], coding.Get(i), ());
}
} // namespace
UNIT_TEST(SimpleDenseCoding_Smoke)
{
size_t const kSize = numeric_limits<uint8_t>::max();
vector<uint8_t> data(kSize);
for (size_t i = 0; i < data.size(); ++i)
data[i] = i;
string const kTestFile = "test.tmp";
SCOPE_GUARD(cleanup, bind(&FileWriter::DeleteFileX, kTestFile));
{
SimpleDenseCoding coding(data);
TestSDC(data, coding);
FileWriter writer(kTestFile);
Freeze(coding, writer, "SimpleDenseCoding");
}
{
MmapReader reader(kTestFile);
SimpleDenseCoding coding;
Map(coding, reader.Data(), "SimpleDenseCoding");
TestSDC(data, coding);
}
}
UNIT_TEST(SimpleDenseCoding_Ratio)
{
for (uint8_t const maxValue : {16, 32, 64})
{
size_t constexpr kSize = 1 << 20;
normal_distribution<> randDist(maxValue / 2, 2);
random_device randDevice;
mt19937 randEngine(randDevice());
vector<uint8_t> data(kSize);
for (size_t i = 0; i < kSize; ++i)
{
double d = round(randDist(randEngine));
if (d < 0)
d = 0;
else if (d > maxValue)
d = maxValue;
data[i] = static_cast<uint8_t>(d);
}
SimpleDenseCoding coding(data);
TestSDC(data, coding);
vector<uint8_t> buffer;
MemWriter writer(buffer);
Freeze(coding, writer, "");
auto const ratio = data.size() / double(buffer.size());
LOG(LINFO, (maxValue, ratio));
TEST_GREATER(ratio, 1.8, ());
}
}
} // namespace simple_dense_coding_test

View file

@ -0,0 +1,26 @@
#include "testing/testing.hpp"
#include "coding/sparse_vector.hpp"
UNIT_TEST(SparseVector_Smoke)
{
uint32_t const arr[] = {0, 0, 5, 0, 7, 1000, 0, 0, 1, 0};
uint64_t const count = std::size(arr);
coding::SparseVectorBuilder<uint32_t> builder(count);
for (uint32_t v : arr)
if (v == 0)
builder.PushEmpty();
else
builder.PushValue(v);
auto vec = builder.Build();
TEST_EQUAL(vec.GetSize(), count, ());
for (size_t i = 0; i < count; ++i)
{
TEST_EQUAL(vec.Has(i), (arr[i] != 0), ());
if (arr[i] != 0)
TEST_EQUAL(vec.Get(i), arr[i], ());
}
}

View file

@ -0,0 +1,263 @@
#include "testing/testing.hpp"
#include "coding/string_utf8_multilang.hpp"
#include "base/control_flow.hpp"
#include <utf8.h>
#include <cstddef>
#include <string>
#include <vector>
using namespace std;
namespace
{
struct lang_string
{
char const * m_lang;
char const * m_str;
};
lang_string gArr[] = {{"default", "default"},
{"en", "abcd"},
{"ru", "\xD0\xA0\xD0\xB0\xD1\x88\xD0\xBA\xD0\xB0"},
{"be", "\xE2\x82\xAC\xF0\xA4\xAD\xA2"}};
void TestMultilangString(lang_string const * arr, size_t count)
{
StringUtf8Multilang s;
for (size_t i = 0; i < count; ++i)
{
string src(arr[i].m_str);
TEST(utf8::is_valid(src.begin(), src.end()), ());
s.AddString(arr[i].m_lang, src);
string_view comp;
TEST(s.GetString(arr[i].m_lang, comp), ());
TEST_EQUAL(src, comp, ());
}
for (size_t i = 0; i < count; ++i)
{
string_view comp;
TEST(s.GetString(arr[i].m_lang, comp), ());
TEST_EQUAL(arr[i].m_str, comp, ());
}
string_view test;
TEST(!s.GetString("xxx", test), ());
}
} // namespace
UNIT_TEST(MultilangString_Smoke)
{
StringUtf8Multilang s;
TestMultilangString(gArr, ARRAY_SIZE(gArr));
}
UNIT_TEST(MultilangString_ForEach)
{
StringUtf8Multilang s;
for (size_t i = 0; i < ARRAY_SIZE(gArr); ++i)
s.AddString(gArr[i].m_lang, gArr[i].m_str);
{
size_t index = 0;
s.ForEach([&index](char lang, string_view utf8s)
{
TEST_EQUAL(lang, StringUtf8Multilang::GetLangIndex(gArr[index].m_lang), ());
TEST_EQUAL(utf8s, gArr[index].m_str, ());
++index;
});
TEST_EQUAL(index, ARRAY_SIZE(gArr), ());
}
{
size_t index = 0;
vector<string> const expected = {"default", "en", "ru"};
vector<string> actual;
s.ForEach([&index, &actual](char lang, string_view)
{
actual.push_back(gArr[index].m_lang);
++index;
if (index == 3)
return base::ControlFlow::Break;
return base::ControlFlow::Continue;
});
TEST_EQUAL(index, 3, ());
TEST_EQUAL(actual, expected, ());
}
}
UNIT_TEST(MultilangString_Unique)
{
StringUtf8Multilang s;
string_view cmp;
s.AddString(0, "xxx");
TEST(s.GetString(0, cmp), ());
TEST_EQUAL(cmp, "xxx", ());
s.AddString(1, "yyy");
TEST(s.GetString(1, cmp), ());
TEST_EQUAL(cmp, "yyy", ());
s.AddString(0, "xxxxxx");
TEST(s.GetString(0, cmp), ());
TEST_EQUAL(cmp, "xxxxxx", ());
TEST(s.GetString(1, cmp), ());
TEST_EQUAL(cmp, "yyy", ());
s.AddString(0, "x");
TEST(s.GetString(0, cmp), ());
TEST_EQUAL(cmp, "x", ());
TEST(s.GetString(1, cmp), ());
TEST_EQUAL(cmp, "yyy", ());
}
UNIT_TEST(MultilangString_LangNames)
{
// It is important to compare the contents of the strings, and not just pointers
TEST_EQUAL(string("Беларуская"), StringUtf8Multilang::GetLangNameByCode(StringUtf8Multilang::GetLangIndex("be")), ());
auto const & langs = StringUtf8Multilang::GetSupportedLanguages();
// Using size_t workaround, because our logging/testing macroses do not support passing POD types
// by value, only by reference. And our constant is a constexpr.
TEST_LESS_OR_EQUAL(langs.size(), static_cast<size_t>(StringUtf8Multilang::kMaxSupportedLanguages), ());
auto const international = StringUtf8Multilang::GetLangIndex("int_name");
TEST_EQUAL(langs[international].m_code, string("int_name"), ());
}
UNIT_TEST(MultilangString_HasString)
{
StringUtf8Multilang s;
s.AddString(0, "xxx");
s.AddString(18, "yyy");
s.AddString(63, "zzz");
TEST(s.HasString(0), ());
TEST(s.HasString(18), ());
TEST(s.HasString(63), ());
TEST(!s.HasString(1), ());
TEST(!s.HasString(32), ());
}
/*
UNIT_TEST(MultilangString_ForEachLanguage)
{
using Translations = vector<pair<string, string>>;
StringUtf8Multilang s;
Translations const scotlandTranslations = {
{"be", "Шатландыя"}, {"cs", "Skotsko"}, {"cy", "Yr Alban"}, {"da", "Skotland"},
{"de", "Schottland"}, {"eo", "Skotlando"}, {"es", "Escocia"}, {"eu", "Eskozia"},
{"fi", "Skotlanti"}, {"fr", "Écosse"}, {"ga", "Albain"}, {"gd", "Alba"},
{"hr", "Škotska"}, {"ia", "Scotia"}, {"io", "Skotia"}, {"ja", "スコットランド"},
{"ku", "Skotland"}, {"lfn", "Scotland"}, {"nl", "Schotland"}, {"pl", "Szkocja"},
{"ru", "Шотландия"}, {"sco", "Scotland"}, {"sk", "Škótsko"}, {"sr", "Шкотска"},
{"sv", "Skottland"}, {"tok", "Sukosi"}, {"tzl", "Escot"}, {"uk", "Шотландія"},
{"vo", "Skotän"}, {"zh", "苏格兰"}};
Translations const usedTranslations = {
{"be", "Шатландыя"}, {"cs", "Skotsko"}, {"eu", "Eskozia"}, {"zh", "苏格兰"}};
for (auto const & langAndTranslation : scotlandTranslations)
{
s.AddString(langAndTranslation.first, langAndTranslation.second);
}
set<string> testAccumulator;
vector<string> const preferredLanguages = {"cs", "eu", "be", "zh"};
vector<string> const preferredTranslations = {"Skotsko", "Eskozia", "Шатландыя", "苏格兰"};
auto const fn = [&testAccumulator, &usedTranslations](int8_t code, string const & name) {
testAccumulator.insert(name);
if (usedTranslations.size() > testAccumulator.size())
return base::ControlFlow::Continue;
return base::ControlFlow::Break;
};
TEST(s.ForEachLanguage(preferredLanguages, fn), ());
TEST_EQUAL(testAccumulator.size(), preferredTranslations.size(), ());
for (string const & translation : preferredTranslations)
{
TEST(testAccumulator.find(translation) != testAccumulator.end(), ());
}
testAccumulator.clear();
vector<string> const corruptedLanguages = {"Матерный", "Детский", "BirdLanguage"};
TEST(!s.ForEachLanguage(corruptedLanguages, fn), ());
TEST_EQUAL(testAccumulator.size(), 0, ());
}
*/
UNIT_TEST(MultilangString_RemoveString)
{
auto testRemove = [](vector<pair<uint8_t, string>> const & strings, set<uint8_t> const & codesToRemove)
{
StringUtf8Multilang str;
for (auto const & s : strings)
str.AddString(s.first, s.second);
string_view tmp;
for (auto const & s : strings)
{
TEST(str.HasString(s.first), ());
TEST(str.GetString(s.first, tmp), ());
TEST_EQUAL(tmp, s.second, ());
}
for (auto c : codesToRemove)
str.RemoveString(c);
for (auto const & s : strings)
{
if (codesToRemove.find(s.first) == codesToRemove.end())
{
TEST(str.HasString(s.first), ());
TEST(str.GetString(s.first, tmp), ());
TEST_EQUAL(tmp, s.second, ());
}
else
{
TEST(!str.HasString(s.first), ());
}
}
// No extra languages or other data damage.
str.ForEach([&](uint8_t lang, auto const &)
{
TEST(base::FindIf(strings, [&lang](auto const & s) { return s.first == lang; }) != strings.end(), ());
TEST(codesToRemove.find(lang) == codesToRemove.end(), ());
});
};
vector<pair<uint8_t, string>> strings = {{0, "aaa"}, {1, "bbb"}, {2, "ccc"}, {9, "ddd"},
{17, "eee"}, {27, "fff"}, {37, "ggg"}};
testRemove(strings, {0});
testRemove(strings, {1});
testRemove(strings, {9, 27});
testRemove(strings, {37});
testRemove(strings, {0, 1, 2, 9, 17, 27, 37});
testRemove(strings, {39});
}
UNIT_TEST(MultilangString_Buffers)
{
StringUtf8Multilang s;
s.AddString(StringUtf8Multilang::kInternationalCode, "blabla");
StringUtf8Multilang const ss = StringUtf8Multilang::FromBuffer(std::string(s.GetBuffer()));
std::string_view test;
TEST_EQUAL(ss.CountLangs(), 1, ());
TEST(ss.GetString(StringUtf8Multilang::kInternationalCode, test), ());
TEST_EQUAL(test, "blabla", ());
}

View file

@ -0,0 +1,90 @@
#include "testing/testing.hpp"
#include "coding/succinct_mapper.hpp"
#include "coding/writer.hpp"
#include "3party/succinct/elias_fano_compressed_list.hpp"
#include <random>
#include <vector>
namespace succinct_ef_test
{
using namespace std;
template <class T>
vector<T> GetUniformValues(size_t count)
{
// Use max - 1 because succinct makes val + 1 encoding internals.
uniform_int_distribution<T> randDist(0, numeric_limits<T>::max() - 1);
random_device randDevice;
mt19937 randEngine(randDevice());
vector<T> data(count);
for (size_t i = 0; i < count; ++i)
data[i] = randDist(randEngine);
return data;
}
template <class T>
vector<T> GetNormalValues(size_t count, T mean)
{
normal_distribution<> randDist(mean, 2);
random_device randDevice;
mt19937 randEngine(randDevice());
vector<T> data(count);
for (size_t i = 0; i < count; ++i)
{
// Use max - 1 because succinct makes val + 1 encoding internals.
T constexpr const kMax = numeric_limits<T>::max() - 1;
double d = round(randDist(randEngine));
if (d < 0)
d = 0;
else if (d > kMax)
d = kMax;
data[i] = static_cast<T>(d);
}
return data;
}
template <class T>
double GetCompressionRatio(vector<T> const & data)
{
succinct::elias_fano_compressed_list efList(data);
vector<uint8_t> buffer;
MemWriter writer(buffer);
coding::Freeze(efList, writer, "");
return data.size() * sizeof(T) / double(buffer.size());
}
UNIT_TEST(SuccinctEFList_Ratio)
{
size_t constexpr kCount = 1 << 20;
{
// No need to use EFList for generic data.
double const ratio2 = GetCompressionRatio(GetUniformValues<uint16_t>(kCount));
TEST_LESS(ratio2, 1, ());
LOG(LINFO, ("Uniform ratio 2:", ratio2));
double const ratio4 = GetCompressionRatio(GetUniformValues<uint32_t>(kCount));
TEST_LESS(ratio4, 1, ());
LOG(LINFO, ("Uniform ratio 4:", ratio4));
}
{
// EF is good for some kind of normal distribution of small values.
double const ratio2 = GetCompressionRatio(GetNormalValues(kCount, uint16_t(128)));
TEST_GREATER(ratio2, 1, ());
LOG(LINFO, ("Normal ratio 2:", ratio2));
double const ratio4 = GetCompressionRatio(GetNormalValues(kCount, uint32_t(1024)));
TEST_GREATER(ratio4, 1, ());
LOG(LINFO, ("Normal ratio 4:", ratio4));
}
}
} // namespace succinct_ef_test

View file

@ -0,0 +1,55 @@
#include "testing/testing.hpp"
#include "coding/succinct_mapper.hpp"
#include "coding/writer.hpp"
#include <cstdint>
#include <vector>
#include "3party/succinct/mapper.hpp"
using namespace coding;
UNIT_TEST(ReverseMapper_Smoke)
{
uint64_t data = 0x0123456789abcdef;
uint64_t rdata = 0x0;
TEST_EQUAL(8, ReverseMap(rdata, reinterpret_cast<uint8_t *>(&data), "uint64_t"), ());
// Test that reversed uint64_t was read.
TEST_EQUAL(0xefcdab8967452301, rdata, ());
// Test that underlying buffer was modified.
TEST_EQUAL(0xefcdab8967452301, data, ());
}
UNIT_TEST(Freeze_Smoke)
{
std::vector<uint8_t> data;
{
MemWriter<decltype(data)> writer(data);
uint64_t const data = 0x0123456789abcdef;
Freeze(data, writer, "uint64_t");
}
TEST_EQUAL(8, data.size(), ());
uint64_t value = 0x0;
TEST_EQUAL(8, Map(value, reinterpret_cast<uint8_t const *>(data.data()), "uint64_t"), ());
TEST_EQUAL(0x0123456789abcdef, value, ());
}
UNIT_TEST(ReverseFreeze_Smoke)
{
std::vector<uint8_t> data;
{
MemWriter<decltype(data)> writer(data);
uint64_t const data = 0x0123456789abcdef;
ReverseFreeze(data, writer, "uint64_t");
}
TEST_EQUAL(8, data.size(), ());
uint64_t value = 0x0;
TEST_EQUAL(8, Map(value, reinterpret_cast<uint8_t const *>(data.data()), "uint64_t"), ());
TEST_EQUAL(0xefcdab8967452301, value, ());
}

View file

@ -0,0 +1,193 @@
#include "coding/coding_tests/test_polylines.hpp"
namespace geometry_coding_tests
{
P arr1[376] = {P(25.624035299999999182, 72.26346513007850092), P(25.624273200000001083, 72.263461698303601111),
P(25.624488899999999347, 72.26341365347376211), P(25.624979400000000851, 72.263304218156179104),
P(25.626030799999998777, 72.263025101705878228), P(25.629390999999998257, 72.261676817778678128),
P(25.630162399999999678, 72.26138836631159279), P(25.631299500000000791, 72.260963603282490908),
P(25.63236829999999955, 72.26051310574631259), P(25.63325580000000059, 72.260190152533994024),
P(25.633720499999999021, 72.260019906865807116), P(25.634314799999998513, 72.259865485075735592),
P(25.634578999999998672, 72.259830215951140531), P(25.635424199999999217, 72.259772832171691448),
P(25.635776400000001018, 72.259834791404088605), P(25.638406499999998545, 72.260604806439260983),
P(25.639231599999998679, 72.260931765228107793), P(25.639867699999999928, 72.261237563690428942),
P(25.640699399999999031, 72.261850499331046649), P(25.643624299999999039, 72.264447578158552687),
P(25.644772700000000754, 72.265904403664706024), P(25.645413800000000037, 72.267106341816230497),
P(25.646751600000001758, 72.270404536824941033), P(25.64890219999999843, 72.275985791150915816),
P(25.649064599999999103, 72.276404165523842948), P(25.650549500000000336, 72.279974564589863917),
P(25.651433600000000723, 72.281545386607334081), P(25.652029899999998719, 72.282193025251160634),
P(25.652814700000000414, 72.282915237415323872), P(25.654197199999998702, 72.283799562153532747),
P(25.656540400000000801, 72.285055792411071707), P(25.658162999999998277, 72.286263412818769325),
P(25.661959599999999426, 72.289916920742129491), P(25.663380199999998865, 72.291039561736027963),
P(25.665810499999999195, 72.292780588759853799), P(25.6700361000000008, 72.29585629709197292),
P(25.670962599999999298, 72.296655718166547899), P(25.672222699999998952, 72.297961211704517837),
P(25.673103499999999855, 72.29896171301187735), P(25.674837499999998869, 72.300952077677095531),
P(25.676358000000000459, 72.302732468128681376), P(25.678018200000000348, 72.304444228347662715),
P(25.680309600000001069, 72.306619426588397914), P(25.682252600000001763, 72.308208994982337003),
P(25.685880300000000886, 72.310749482551628375), P(25.6871223999999998, 72.311619291531712861),
P(25.689502399999998516, 72.313337574126506979), P(25.689994200000001001, 72.313685586072296019),
P(25.691337099999998372, 72.314639003020189989), P(25.694014100000000411, 72.316465930359882464),
P(25.696650399999999337, 72.318133963117716689), P(25.697924300000000386, 72.31863598381848135),
P(25.699229800000001234, 72.31891418618496914), P(25.700213699999999051, 72.319045273707061483),
P(25.703616300000000194, 72.319271576784373678), P(25.707311499999999427, 72.319273484907995453),
P(25.715181600000001083, 72.318046763400587906), P(25.72608460000000008, 72.315978426880036523),
P(25.728649600000000675, 72.31539857900408208), P(25.730824299999998317, 72.315156452495600092),
P(25.732753200000001215, 72.314945427265811873), P(25.736661200000000349, 72.315042353781024076),
P(25.74480259999999987, 72.315568583243575063), P(25.747831600000001373, 72.315649864883624787),
P(25.749809599999998966, 72.315866807206518274), P(25.752535200000000515, 72.316023647210727177),
P(25.755610000000000781, 72.315910501039496694), P(25.760463999999998919, 72.315272459413776573),
P(25.762314700000001011, 72.315021747344800929), P(25.763456399999999036, 72.314812630534717641),
P(25.763716200000001066, 72.31478954377344337), P(25.771413500000001306, 72.314102668549878672),
P(25.779617200000000565, 72.313375160856324442), P(25.784148800000000534, 72.313357035273327256),
P(25.790238899999998523, 72.313577786126856495), P(25.793676300000001334, 72.313716876708198811),
P(25.796280599999999339, 72.314048100429985766), P(25.798680499999999682, 72.31463614103191162),
P(25.800190700000001698, 72.315239260045032665), P(25.803071100000000371, 72.316310615756250968),
P(25.806439499999999754, 72.316835901112042961), P(25.809219599999998707, 72.316657116642062419),
P(25.813906700000000427, 72.315918133153061831), P(25.817769800000000657, 72.31543750249576874),
P(25.819804099999998925, 72.315482531661231747), P(25.823219200000000484, 72.315995217547779816),
P(25.824360999999999677, 72.316092908788874638), P(25.825752500000000111, 72.316000750836963107),
P(25.833053499999998337, 72.315183355397863352), P(25.835087900000001326, 72.314863574077250519),
P(25.836477299999998536, 72.314986830897922232), P(25.838510800000001666, 72.315843910886087542),
P(25.84021669999999915, 72.316586137240363996), P(25.845591399999999993, 72.318366369042564656),
P(25.847287900000001315, 72.318912278071522337), P(25.852937300000000675, 72.321233538069833457),
P(25.857534099999998745, 72.324114950429262194), P(25.858493899999999144, 72.324638770105451613),
P(25.859516599999999187, 72.325101910243901671), P(25.860960299999998568, 72.325309341574609334),
P(25.864481800000000078, 72.325170990340012622), P(25.866295099999998541, 72.325066225249685203),
P(25.871619400000000155, 72.324758609934391984), P(25.873917800000000966, 72.324524655307570242),
P(25.875719000000000136, 72.324229064532204347), P(25.882352300000000866, 72.322516991669758113),
P(25.886094899999999797, 72.321551632301222412), P(25.891463999999999146, 72.320154280548763381),
P(25.892594599999998906, 72.32000410941930113), P(25.893775399999999109, 72.320041127430243932),
P(25.895055100000000436, 72.320205228136387632), P(25.901716900000000265, 72.321479884460799781),
P(25.905201399999999268, 72.322148897878847151), P(25.906758400000001075, 72.322300409542663147),
P(25.908453200000000294, 72.322276366107203671), P(25.910453700000001476, 72.322039939449879853),
P(25.912611200000000622, 72.321379323121732341), P(25.914446699999999169, 72.320507670602822259),
P(25.915890699999998503, 72.319578403757603269), P(25.916971199999998987, 72.318721085380474278),
P(25.923277999999999821, 72.312682767056259081), P(25.924315100000001166, 72.311643903530907096),
P(25.925479700000000349, 72.310661910829537646), P(25.926380200000000542, 72.31012846985993292),
P(25.927288000000000778, 72.309673827336439444), P(25.929170299999999116, 72.308742039167825055),
P(25.931695000000001272, 72.307558244187632113), P(25.935542200000000435, 72.305689970006980616),
P(25.936291600000000557, 72.305420216334297834), P(25.937011699999999337, 72.3052109385934898),
P(25.937444899999999137, 72.305171830245583919), P(25.938065999999999178, 72.305126426436075349),
P(25.939194700000001603, 72.305346959512363014), P(25.941637199999998842, 72.306187700803491225),
P(25.951531899999999098, 72.309363611414866568), P(25.958591599999998323, 72.311600021678131611),
P(25.961859900000000323, 72.312588133461261464), P(25.9623209000000017, 72.312845323461488078),
P(25.962808800000001241, 72.313126745396871797), P(25.963783500000001681, 72.313929806056449934),
P(25.964454100000001091, 72.315054565005411291), P(25.966293799999998981, 72.319575350745964215),
P(25.966609900000001687, 72.320173934482440359), P(25.966938999999999993, 72.320628647970096381),
P(25.968776200000000642, 72.322731857094510133), P(25.969766299999999859, 72.323772036806516894),
P(25.97039970000000153, 72.324406914991570261), P(25.971057800000000526, 72.324904784282267656),
P(25.972805199999999815, 72.325716763759459127), P(25.973508700000000005, 72.326106631888762877),
P(25.974174900000001287, 72.326699167072590058), P(25.974623600000001034, 72.327462886785923502),
P(25.97499170000000035, 72.32822527930542833), P(25.975826399999998984, 72.329784823533856297),
P(25.976481499999998448, 72.330935420885211329), P(25.977230399999999833, 72.332212952428704966),
P(25.978115400000000079, 72.333512265445278899), P(25.9789551000000003, 72.33474671239962106),
P(25.980276700000001, 72.336402410819303554), P(25.98169719999999927, 72.337880836033434662),
P(25.983172299999999666, 72.33911288186702393), P(25.984414600000000917, 72.340068567971513858),
P(25.985398499999998734, 72.340636603533639004), P(25.986058100000001048, 72.340908025445514795),
P(25.987230000000000274, 72.341316496490946975), P(25.988157300000001015, 72.341676869267246275),
P(25.991148400000000152, 72.342299318530393748), P(25.997876999999999015, 72.343701138883602653),
P(25.999752600000000768, 72.344154484369809666), P(26.001479700000000861, 72.344723890629211382),
P(26.003023999999999916, 72.345420432028205937), P(26.005314899999998346, 72.346859159309715892),
P(26.007066099999999409, 72.348322733682408625), P(26.008686999999998335, 72.35014618535842601),
P(26.012360000000001037, 72.354910262506038521), P(26.013286199999999582, 72.355943685106993257),
P(26.013858500000001328, 72.35652369166834319), P(26.014633599999999802, 72.357135968669368253),
P(26.015746700000001113, 72.357673410043958029), P(26.017126499999999822, 72.358212001250265644),
P(26.020520199999999988, 72.359278695677289761), P(26.021437599999998724, 72.359644892510004865),
P(26.022532699999999295, 72.360275718006846546), P(26.028545999999998628, 72.365263533617877556),
P(26.029226600000001213, 72.365797602942478761), P(26.030111600000001459, 72.366317546512846093),
P(26.032004199999999372, 72.367306080501194288), P(26.033209299999999331, 72.367834246590078351),
P(26.034265699999998844, 72.368067397148493569), P(26.035592099999998794, 72.368224167962054594),
P(26.03677019999999942, 72.368129074294643033), P(26.043432299999999202, 72.366408627750374194),
P(26.045431499999999403, 72.365842856777021552), P(26.048415399999999664, 72.36504242213915461),
P(26.052753299999999115, 72.363920454888528866), P(26.05556269999999941, 72.363008918012667436),
P(26.060303699999998628, 72.360393712052541559), P(26.065962500000001256, 72.35698705139280662),
P(26.067612400000001571, 72.356026924714299753), P(26.069255399999999412, 72.355021374242639354),
P(26.070335599999999943, 72.354163985856629893), P(26.071483900000000489, 72.353231772141796796),
P(26.073087300000000965, 72.351530224288538307), P(26.07495580000000146, 72.349052146600300262),
P(26.077375199999998756, 72.345412414793742073), P(26.079008800000000434, 72.34322240936705839),
P(26.080636800000000619, 72.341554327036718064), P(26.081818800000000635, 72.340620379333103074),
P(26.083176200000000478, 72.339615440891947173), P(26.085581000000001239, 72.338285853103528211),
P(26.092078799999999461, 72.335142167729841844), P(26.099516500000000008, 72.332061609286498083),
P(26.102282500000001164, 72.330882175026999903), P(26.105014700000001682, 72.329521843521945357),
P(26.108211900000000583, 72.327720133658942814), P(26.116759299999998234, 72.322424061632020198),
P(26.118289900000000614, 72.321345929920937579), P(26.124188000000000187, 72.316306990481081129),
P(26.126093300000000852, 72.314456217615472156), P(26.13131840000000139, 72.308768748722727082),
P(26.133807300000000851, 72.305896196846916268), P(26.135103199999999646, 72.304208818196542552),
P(26.13615610000000089, 72.3027141546473473), P(26.136958199999998698, 72.301545345164157652),
P(26.137658200000000619, 72.300474224549915903), P(26.140487000000000251, 72.29551524417688313),
P(26.146685800000000199, 72.285760107870132174), P(26.151274499999999534, 72.277504651282583836),
P(26.151979099999998368, 72.276113553331668982), P(26.152562700000000717, 72.274582520714972134),
P(26.152978600000000853, 72.272986691312326002), P(26.154697899999998612, 72.264608683472175699),
P(26.155105599999998844, 72.263003939235275652), P(26.155811400000001044, 72.261258344309723611),
P(26.156706599999999696, 72.259655777039213831), P(26.158511799999999425, 72.257073180827120495),
P(26.163497199999998344, 72.251147710512896083), P(26.164152500000000146, 72.250452144382251163),
P(26.165397099999999853, 72.249370018656591697), P(26.171159400000000517, 72.245101348184562084),
P(26.171824600000000771, 72.244502288299599968), P(26.172791700000001214, 72.243464858038208831),
P(26.173422299999998586, 72.24251111483852128), P(26.174280599999999453, 72.240982180618559028),
P(26.174924399999998315, 72.239409446329290176), P(26.175138900000000319, 72.238550480576279256),
P(26.177894599999998348, 72.222417606854094174), P(26.178249600000000896, 72.220799387733251251),
P(26.178700899999999052, 72.219414415122045625), P(26.179689899999999625, 72.217234222262234766),
P(26.182073200000001378, 72.213506738076645775), P(26.18310470000000123, 72.211533626956168064),
P(26.183614800000000855, 72.210338776927230242), P(26.18428000000000111, 72.208417574177602205),
P(26.185804499999999706, 72.203266316303412964), P(26.186153000000000901, 72.202346286216979365),
P(26.186549599999999316, 72.201465316811109574), P(26.187059699999998941, 72.200685882789031211),
P(26.187643699999998859, 72.200064170625580573), P(26.188815999999999207, 72.199110470754774838),
P(26.189986799999999789, 72.198491439723213148), P(26.190943999999998226, 72.198205925482497491),
P(26.192045499999998981, 72.198064597333782899), P(26.201502200000000187, 72.19749033573828001),
P(26.204289599999999183, 72.197194731015855496), P(26.212046699999998367, 72.196023752898682346),
P(26.217400099999998986, 72.195033541852339454), P(26.220660899999998605, 72.194099530393685882),
P(26.223864100000000121, 72.193042117073559893), P(26.227025699999998665, 72.192404096537160285),
P(26.229406099999998503, 72.192154413131575552), P(26.23379059999999896, 72.191934250652863625),
P(26.241092200000000645, 72.191652763688111349), P(26.247795599999999894, 72.191305763109099303),
P(26.259740499999999486, 72.190710990755292187), P(26.262441899999998896, 72.190662426481935654),
P(26.26396259999999927, 72.190803739092231694), P(26.265582200000000768, 72.19108065172507338),
P(26.271514700000000886, 72.192273445913514252), P(26.275603900000000124, 72.192994312937273094),
P(26.278289999999998372, 72.193506828374651718), P(26.280647800000000558, 72.193799369593079973),
P(26.284991699999999071, 72.194193426147350579), P(26.295021899999998283, 72.194996021158502231),
P(26.296629599999999272, 72.195353135208762296), P(26.298219400000000689, 72.195936520796209379),
P(26.299353599999999886, 72.196573622487093758), P(26.300700500000001369, 72.19746290844136638),
P(26.301440499999998224, 72.198127833072547332), P(26.302059899999999715, 72.198747051231549676),
P(26.302597999999999701, 72.199118470577644757), P(26.30326700000000173, 72.200164931796578571),
P(26.304018299999999186, 72.201524555689601925), P(26.305375600000001413, 72.20513574950004454),
P(26.306215500000000418, 72.206942181028665573), P(26.307179600000001329, 72.208595118825385839),
P(26.307805599999998236, 72.209443034325843769), P(26.308593200000000678, 72.210334966852684602),
P(26.309511400000001657, 72.211171854914510959), P(26.310345000000001647, 72.211829485157878139),
P(26.313103999999999161, 72.213550746524816759), P(26.313808999999999116, 72.214105903186023738),
P(26.315858999999999668, 72.21616368063173752), P(26.316473599999998356, 72.216713905276705532),
P(26.317261800000000704, 72.217105619191144683), P(26.318279199999999207, 72.217451609641841515),
P(26.31951039999999864, 72.217778930438797147), P(26.319995200000001034, 72.217883719155963718),
P(26.322028199999998321, 72.21814340535271981), P(26.323134799999998279, 72.218219615725388394),
P(26.324022500000001656, 72.218280774611798734), P(26.32581220000000144, 72.218525220186265301),
P(26.327261700000001099, 72.218861882068196678), P(26.330273800000000506, 72.219715642811124212),
P(26.337171999999998917, 72.221928497785057743), P(26.339137900000000769, 72.222394361231621929),
P(26.341438799999998821, 72.222689314479467271), P(26.343669200000000785, 72.222811640430336411),
P(26.346788899999999956, 72.222677310542948703), P(26.356923500000000615, 72.222042438730937874),
P(26.359536099999999692, 72.2221015051835451), P(26.36183730000000125, 72.222299854521224916),
P(26.366428899999998947, 72.222842507761527031), P(26.374883000000000521, 72.223912965077033732),
P(26.380090800000001394, 72.224542709845593436), P(26.39073850000000121, 72.225869670908153353),
P(26.393878699999998361, 72.226187124115313054), P(26.400813700000000495, 72.226887965488728582),
P(26.405969100000000083, 72.227408932782296347), P(26.434136200000001082, 72.23031015029567925),
P(26.437651200000001239, 72.230672215773722655), P(26.439650799999999009, 72.230860300030158783),
P(26.442400500000001529, 72.230918230849241013), P(26.444426599999999894, 72.230815518016711962),
P(26.454957100000001446, 72.229639190945519545), P(26.455386699999998257, 72.229609273288744475),
P(26.470600499999999755, 72.227804710557407475), P(26.485397899999998828, 72.226080035891357056),
P(26.487313600000000235, 72.226084418502168205), P(26.488673999999999609, 72.226209799401686951),
P(26.489974300000000085, 72.226456941463752059), P(26.493316499999998825, 72.227405883949458598),
P(26.497907399999999001, 72.228727947008763977), P(26.507186099999998419, 72.231355762593423719),
P(26.521764000000001005, 72.235531322949142918), P(26.522283200000000392, 72.235663963313356817),
P(26.52274799999999999, 72.235808991367022713), P(26.523495799999999178, 72.236006428221017472),
P(26.537509100000001183, 72.239985971537208798), P(26.540924100000001573, 72.240959309764491536),
P(26.544420699999999869, 72.241674408812258434), P(26.546888100000000321, 72.242183101965366632),
P(26.5518616999999999, 72.242874580127462991), P(26.562219100000000083, 72.244128903051048951),
P(26.564274399999998622, 72.244315309516480283), P(26.576127799999998302, 72.245028538203385438),
P(26.58263820000000166, 72.244424904560787581), P(26.591367999999999228, 72.243389190867901561),
P(26.598972199999998622, 72.242452221067154028), P(26.600826200000000199, 72.242522931717928714),
P(26.603627199999998254, 72.242683603364909573), P(26.606756300000000692, 72.243241096929352807),
P(26.612569100000001754, 72.244800578667096147), P(26.615042299999998932, 72.246052459623328446),
P(26.621848599999999863, 72.249011664844303482), P(26.627471299999999843, 72.250195383365820589),
P(26.641823800000000944, 72.252710806698729584), P(26.648778100000001245, 72.254338371527666141),
P(26.655288500000001051, 72.25700169234383452), P(26.660515000000000185, 72.259171735257126556),
P(26.662390800000000723, 72.25996099777080417), P(26.670629300000001649, 72.263625851730935779),
P(26.671595899999999801, 72.264267979553508781), P(26.676856199999999575, 72.267335711577246116),
P(26.677412499999999085, 72.267929636079472289), P(26.676856199999999575, 72.267335711577246116)};
} // namespace geometry_coding_tests

View file

@ -0,0 +1,9 @@
#pragma once
#include "geometry/point2d.hpp"
namespace geometry_coding_tests
{
using P = m2::PointD;
extern P arr1[376];
} // namespace geometry_coding_tests

View file

@ -0,0 +1,132 @@
#include "testing/testing.hpp"
#include "coding/reader.hpp"
#include "coding/text_storage.hpp"
#include "coding/writer.hpp"
#include <cstdint>
#include <random>
#include <string>
#include <vector>
using namespace coding;
using namespace std;
namespace
{
template <typename Engine>
string GenerateRandomString(Engine & engine)
{
int const kMinLength = 0;
int const kMaxLength = 400;
int const kMinByte = 0;
int const kMaxByte = 255;
uniform_int_distribution<int> length(kMinLength, kMaxLength);
uniform_int_distribution<int> byte(kMinByte, kMaxByte);
string s(length(engine), '\0');
for (auto & b : s)
b = byte(engine);
return s;
}
void DumpStrings(vector<string> const & strings, uint64_t blockSize, vector<uint8_t> & buffer)
{
MemWriter<vector<uint8_t>> writer(buffer);
BlockedTextStorageWriter<decltype(writer)> ts(writer, blockSize);
for (auto const & s : strings)
ts.Append(s);
}
UNIT_TEST(TextStorage_Smoke)
{
vector<uint8_t> buffer;
DumpStrings({} /* strings */, 10 /* blockSize */, buffer);
{
MemReader reader(buffer.data(), buffer.size());
BlockedTextStorageIndex index;
index.Read(reader);
TEST_EQUAL(index.GetNumStrings(), 0, ());
TEST_EQUAL(index.GetNumBlockInfos(), 0, ());
}
{
MemReader reader(buffer.data(), buffer.size());
BlockedTextStorage<decltype(reader)> ts(reader);
TEST_EQUAL(ts.GetNumStrings(), 0, ());
}
}
UNIT_TEST(TextStorage_Simple)
{
vector<string> const strings = {{"", "Hello", "Hello, World!", "Hola mundo", "Smoke test"}};
vector<uint8_t> buffer;
DumpStrings(strings, 10 /* blockSize */, buffer);
{
MemReader reader(buffer.data(), buffer.size());
BlockedTextStorageIndex index;
index.Read(reader);
TEST_EQUAL(index.GetNumStrings(), strings.size(), ());
TEST_EQUAL(index.GetNumBlockInfos(), 3, ());
}
{
MemReader reader(buffer.data(), buffer.size());
BlockedTextStorage<decltype(reader)> ts(reader);
TEST_EQUAL(ts.GetNumStrings(), strings.size(), ());
for (size_t i = 0; i < ts.GetNumStrings(); ++i)
TEST_EQUAL(ts.ExtractString(i), strings[i], ());
}
}
UNIT_TEST(TextStorage_Empty)
{
vector<string> strings;
for (int i = 0; i < 1000; ++i)
{
strings.emplace_back(string(1 /* size */, i % 256));
for (int j = 0; j < 1000; ++j)
strings.emplace_back();
}
vector<uint8_t> buffer;
DumpStrings(strings, 5 /* blockSize */, buffer);
{
MemReader reader(buffer.data(), buffer.size());
BlockedTextStorage<decltype(reader)> ts(reader);
TEST_EQUAL(ts.GetNumStrings(), strings.size(), ());
for (size_t i = 0; i < ts.GetNumStrings(); ++i)
TEST_EQUAL(ts.ExtractString(i), strings[i], ());
}
}
UNIT_TEST(TextStorage_Random)
{
int const kSeed = 42;
int const kNumStrings = 1000;
int const kBlockSize = 100;
mt19937 engine(kSeed);
vector<string> strings;
for (int i = 0; i < kNumStrings; ++i)
strings.push_back(GenerateRandomString(engine));
vector<uint8_t> buffer;
DumpStrings(strings, kBlockSize, buffer);
MemReader reader(buffer.data(), buffer.size());
BlockedTextStorage<decltype(reader)> ts(reader);
TEST_EQUAL(ts.GetNumStrings(), strings.size(), ());
for (size_t i = 0; i < ts.GetNumStrings(); ++i)
TEST_EQUAL(ts.ExtractString(i), strings[i], ());
for (size_t i = ts.GetNumStrings() - 1; i < ts.GetNumStrings(); --i)
TEST_EQUAL(ts.ExtractString(i), strings[i], ());
}
} // namespace

View file

@ -0,0 +1,157 @@
#include "testing/testing.hpp"
#include "coding/traffic.hpp"
#include "geometry/mercator.hpp"
#include "geometry/point2d.hpp"
#include "base/logging.hpp"
#include "base/math.hpp"
#include <cstddef>
#include <cstdint>
#include <vector>
namespace traffic_test
{
using coding::TrafficGPSEncoder;
using std::vector;
double CalculateLength(vector<TrafficGPSEncoder::DataPoint> const & path)
{
double res = 0;
for (size_t i = 1; i < path.size(); ++i)
{
auto p1 = mercator::FromLatLon(path[i - 1].m_latLon.m_lat, path[i - 1].m_latLon.m_lon);
auto p2 = mercator::FromLatLon(path[i].m_latLon.m_lat, path[i].m_latLon.m_lon);
res += mercator::DistanceOnEarth(p1, p2);
}
return res;
}
void Test(vector<TrafficGPSEncoder::DataPoint> & points)
{
double constexpr kEps = 1e-5;
for (uint32_t version = 0; version <= TrafficGPSEncoder::kLatestVersion; ++version)
{
vector<uint8_t> buf;
MemWriter<decltype(buf)> memWriter(buf);
UNUSED_VALUE(TrafficGPSEncoder::SerializeDataPoints(version, memWriter, points));
vector<TrafficGPSEncoder::DataPoint> result;
MemReader memReader(buf.data(), buf.size());
ReaderSource<MemReader> src(memReader);
TrafficGPSEncoder::DeserializeDataPoints(version, src, result);
TEST_EQUAL(points.size(), result.size(), ());
for (size_t i = 0; i < points.size(); ++i)
{
TEST_EQUAL(points[i].m_timestamp, result[i].m_timestamp, (points[i].m_timestamp, result[i].m_timestamp));
TEST(AlmostEqualAbsOrRel(points[i].m_latLon.m_lat, result[i].m_latLon.m_lat, kEps),
(points[i].m_latLon.m_lat, result[i].m_latLon.m_lat));
TEST(AlmostEqualAbsOrRel(points[i].m_latLon.m_lon, result[i].m_latLon.m_lon, kEps),
(points[i].m_latLon.m_lon, result[i].m_latLon.m_lon));
}
if (version == TrafficGPSEncoder::kLatestVersion)
{
LOG(LINFO,
("path length =", CalculateLength(points), "num points =", points.size(), "compressed size =", buf.size()));
}
}
}
UNIT_TEST(Traffic_Serialization_Smoke)
{
vector<TrafficGPSEncoder::DataPoint> data = {
{0, ms::LatLon(0.0, 1.0), 1},
{0, ms::LatLon(0.0, 2.0), 2},
};
Test(data);
}
UNIT_TEST(Traffic_Serialization_EmptyPath)
{
vector<TrafficGPSEncoder::DataPoint> data;
Test(data);
}
UNIT_TEST(Traffic_Serialization_StraightLine100m)
{
vector<TrafficGPSEncoder::DataPoint> path = {
{0, ms::LatLon(0.0, 0.0), 1},
{0, ms::LatLon(0.0, 1e-3), 2},
};
Test(path);
}
UNIT_TEST(Traffic_Serialization_StraightLine50Km)
{
vector<TrafficGPSEncoder::DataPoint> path = {
{0, ms::LatLon(0.0, 0.0), 1},
{0, ms::LatLon(0.0, 0.5), 2},
};
Test(path);
}
UNIT_TEST(Traffic_Serialization_Zigzag500m)
{
vector<TrafficGPSEncoder::DataPoint> path;
for (size_t i = 0; i < 5; ++i)
{
double const x = i * 1e-3;
double const y = i % 2 == 0 ? 0 : 1e-3;
path.emplace_back(TrafficGPSEncoder::DataPoint(0, ms::LatLon(y, x), 3));
}
Test(path);
}
UNIT_TEST(Traffic_Serialization_Zigzag10Km)
{
vector<TrafficGPSEncoder::DataPoint> path;
for (size_t i = 0; i < 10; ++i)
{
double const x = i * 1e-2;
double const y = i % 2 == 0 ? 0 : 1e-2;
path.emplace_back(TrafficGPSEncoder::DataPoint(0, ms::LatLon(y, x), 0));
}
Test(path);
}
UNIT_TEST(Traffic_Serialization_Zigzag100Km)
{
vector<TrafficGPSEncoder::DataPoint> path;
for (size_t i = 0; i < 1000; ++i)
{
double const x = i * 1e-1;
double const y = i % 2 == 0 ? 0 : 1e-1;
path.emplace_back(TrafficGPSEncoder::DataPoint(0, ms::LatLon(y, x), 0));
}
Test(path);
}
UNIT_TEST(Traffic_Serialization_Circle20KmRadius)
{
vector<TrafficGPSEncoder::DataPoint> path;
size_t const n = 100;
for (size_t i = 0; i < n; ++i)
{
double const alpha = 2 * math::pi * i / n;
double const radius = 0.25;
double const x = radius * cos(alpha);
double const y = radius * sin(alpha);
path.emplace_back(TrafficGPSEncoder::DataPoint(0, ms::LatLon(y, x), 0));
}
Test(path);
}
UNIT_TEST(Traffic_Serialization_ExtremeLatLon)
{
vector<TrafficGPSEncoder::DataPoint> path = {
{0, ms::LatLon(-90, -180), 0},
{0, ms::LatLon(90, 180), 0},
};
Test(path);
}
} // namespace traffic_test

View file

@ -0,0 +1,215 @@
#include "testing/testing.hpp"
#include "coding/url.hpp"
#include "base/math.hpp"
#include <queue>
#include <string>
#include <utility>
namespace url_tests
{
using namespace std;
using namespace url;
class TestUrl
{
public:
explicit TestUrl(string && url) : m_url(std::move(url)) {}
TestUrl & Scheme(string && scheme)
{
m_scheme = std::move(scheme);
return *this;
}
TestUrl & Host(string && host)
{
m_host = std::move(host);
return *this;
}
TestUrl & Path(string && path)
{
m_path = std::move(path);
return *this;
}
TestUrl & KV(string && key, string && value)
{
m_keyValuePairs.emplace(std::move(key), std::move(value));
return *this;
}
~TestUrl()
{
Url url(m_url);
TEST_EQUAL(url.GetScheme(), m_scheme, ());
TEST_EQUAL(url.GetHost(), m_host, ());
TEST_EQUAL(url.GetPath(), m_path, ());
TEST(!m_scheme.empty() || !url.IsValid(), ("Scheme is empty if and only if url is invalid!"));
url.ForEachParam([this](string const & name, string const & value)
{
TEST(!m_keyValuePairs.empty(), ("Failed for url = ", m_url));
TEST_EQUAL(m_keyValuePairs.front().first, name, ());
TEST_EQUAL(m_keyValuePairs.front().second, value, ());
m_keyValuePairs.pop();
});
}
private:
string m_url, m_scheme, m_host, m_path;
queue<pair<string, string>> m_keyValuePairs;
};
char const * orig1 = "http://google.com/main_index.php";
char const * enc1 = "http%3A%2F%2Fgoogle.com%2Fmain_index.php";
char const * orig2 = "Some File Name.ext";
char const * enc2 = "Some%20File%20Name.ext";
char const * orig3 = "Wow, two spaces?!";
char const * enc3 = "Wow%2C%20%20two%20spaces%3F%21";
char const * orig4 = "#$%^&@~[]{}()|*+`\"\'";
char const * enc4 = "%23%24%25%5E%26%40~%5B%5D%7B%7D%28%29%7C%2A%2B%60%22%27";
UNIT_TEST(Url_Join)
{
TEST_EQUAL("", Join("", ""), ());
TEST_EQUAL("omim/", Join("", "omim/"), ());
TEST_EQUAL("omim/", Join("omim/", ""), ());
TEST_EQUAL("omim/strings", Join("omim", "strings"), ());
TEST_EQUAL("omim/strings", Join("omim/", "strings"), ());
TEST_EQUAL("../../omim/strings", Join("..", "..", "omim", "strings"), ());
TEST_EQUAL("../../omim/strings", Join("../", "..", "omim/", "strings"), ());
TEST_EQUAL("omim/strings", Join("omim/", "/strings"), ());
TEST_EQUAL("../../omim/strings", Join("../", "/../", "/omim/", "/strings"), ());
TEST_EQUAL("../omim/strings", Join("../", "", "/omim/", "/strings"), ());
}
UNIT_TEST(Url_Encode)
{
TEST_EQUAL(UrlEncode(""), "", ());
TEST_EQUAL(UrlEncode(" "), "%20", ());
TEST_EQUAL(UrlEncode("%% "), "%25%25%20", ());
TEST_EQUAL(UrlEncode("20"), "20", ());
TEST_EQUAL(UrlEncode("Guinea-Bissau"), "Guinea-Bissau", ());
TEST_EQUAL(UrlEncode(orig1), enc1, ());
TEST_EQUAL(UrlEncode(orig2), enc2, ());
TEST_EQUAL(UrlEncode(orig3), enc3, ());
TEST_EQUAL(UrlEncode(orig4), enc4, ());
}
UNIT_TEST(Url_Decode)
{
TEST_EQUAL(UrlDecode(""), "", ());
TEST_EQUAL(UrlDecode("%20"), " ", ());
TEST_EQUAL(UrlDecode("%25%25%20"), "%% ", ());
TEST_EQUAL(UrlDecode("20"), "20", ());
TEST_EQUAL(UrlDecode("Guinea-Bissau"), "Guinea-Bissau", ());
TEST_EQUAL(UrlDecode(enc1), orig1, ());
TEST_EQUAL(UrlDecode(enc2), orig2, ());
TEST_EQUAL(UrlDecode(enc3), orig3, ());
TEST_EQUAL(UrlDecode(enc4), orig4, ());
TEST_EQUAL(UrlDecode("123+Main+St,+Seattle,+WA+98101"), "123 Main St, Seattle, WA 98101", ());
}
UNIT_TEST(Url_Invalid)
{
TEST(!Url("").IsValid(), ());
TEST(!Url(":/").IsValid(), ());
TEST(!Url("//").IsValid(), ());
}
UNIT_TEST(Url_Valid)
{
TestUrl("mapswithme://map?ll=10.3,12.3223&n=Hello%20World")
.Scheme("mapswithme")
.Host("map")
.KV("ll", "10.3,12.3223")
.KV("n", "Hello World");
TestUrl("cm:M&M//path?q=q&w=w").Scheme("cm").Host("M&M").Path("path").KV("q", "q").KV("w", "w");
TestUrl("http://www.sandwichparlour.com.au/").Scheme("http").Host("www.sandwichparlour.com.au").Path("");
TestUrl("cm:/&test").Scheme("cm").Host("&test").Path("");
}
UNIT_TEST(Url_Fragment)
{
TestUrl("https://www.openstreetmap.org/way/179409926#map=19/46.34998/48.03213&layers=N")
.Scheme("https")
.Host("www.openstreetmap.org")
.Path("way/179409926")
.KV("map", "19/46.34998/48.03213")
.KV("layers", "N");
TestUrl("https://www.openstreetmap.org/search?query=Falafel%20Sahyoun#map=16/33.89041/35.50664")
.Scheme("https")
.Host("www.openstreetmap.org")
.Path("search")
.KV("query", "Falafel Sahyoun")
.KV("map", "16/33.89041/35.50664");
}
UNIT_TEST(UrlScheme_Comprehensive)
{
TestUrl("");
TestUrl("scheme:").Scheme("scheme").Host("").Path("");
TestUrl("scheme:/").Scheme("scheme").Host("").Path("");
TestUrl("scheme://").Scheme("scheme").Host("").Path("");
TestUrl("sometext");
TestUrl(":noscheme");
TestUrl("://noscheme?");
TestUrl("mwm://?").Scheme("mwm").Host("").Path("");
TestUrl("http://host/path/to/something").Scheme("http").Host("host").Path("path/to/something");
TestUrl("http://host?").Scheme("http").Host("host").Path("");
TestUrl("maps://host?&&key=&").Scheme("maps").Host("host").KV("key", "");
TestUrl("mapswithme://map?ll=1.2,3.4&z=15")
.Scheme("mapswithme")
.Host("map")
.Path("")
.KV("ll", "1.2,3.4")
.KV("z", "15");
TestUrl("nopathnovalues://?key1&key2=val2")
.Scheme("nopathnovalues")
.Host("")
.Path("")
.KV("key1", "")
.KV("key2", "val2");
TestUrl("s://?key1&key2").Scheme("s").Host("").Path("").KV("key1", "").KV("key2", "");
TestUrl("g://h/p?key1=val1&key2=").Scheme("g").Host("h").Path("p").KV("key1", "val1").KV("key2", "");
TestUrl("g://h?=val1&key2=").Scheme("g").Host("h").Path("").KV("", "val1").KV("key2", "");
TestUrl("g://?k&key2").Scheme("g").Host("").Path("").KV("k", "").KV("key2", "");
TestUrl("m:?%26Amp%26%3D%26Amp%26&name=%31%20%30")
.Scheme("m")
.Host("")
.Path("")
.KV("&Amp&=&Amp&", "")
.KV("name", "1 0");
TestUrl("s://?key1=value1&key1=value2&key1=value3&key2&key2&key3=value1&key3&key3=value2")
.Scheme("s")
.Host("")
.Path("")
.KV("key1", "value1")
.KV("key1", "value2")
.KV("key1", "value3")
.KV("key2", "")
.KV("key2", "")
.KV("key3", "value1")
.KV("key3", "")
.KV("key3", "value2");
}
UNIT_TEST(UrlApi_Smoke)
{
url::Url url("https://2gis.ru/moscow/firm/4504127908589159?m=37.618632%2C55.760069%2F15.232");
TEST_EQUAL(url.GetScheme(), "https", ());
TEST_EQUAL(url.GetHost(), "2gis.ru", ());
TEST_EQUAL(url.GetPath(), "moscow/firm/4504127908589159", ());
TEST_EQUAL(url.GetHostAndPath(), "2gis.ru/moscow/firm/4504127908589159", ());
TEST(url.GetLastParam(), ());
TEST(url.GetParamValue("m"), ());
}
} // namespace url_tests

View file

@ -0,0 +1,76 @@
#include "testing/testing.hpp"
#include "coding/reader.hpp"
#include "coding/value_opt_string.hpp"
#include "coding/writer.hpp"
#include <algorithm>
#include <string>
#include <vector>
namespace
{
template <class T>
void TestStringCodingT(T const * arr, size_t count, size_t maxSize)
{
for (size_t i = 0; i < count; ++i)
{
auto const ethalon = strings::to_string(arr[i]);
StringNumericOptimal s;
s.Set(ethalon);
std::vector<char> buffer;
MemWriter<std::vector<char>> w(buffer);
s.Write(w);
size_t const sz = buffer.size();
TEST_GREATER(sz, 0, ());
TEST_LESS_OR_EQUAL(sz, maxSize, ());
MemReader r(&buffer[0], sz);
ReaderSource<MemReader> src(r);
s.Read(src);
TEST_EQUAL(ethalon, s.Get(), ());
}
}
} // namespace
UNIT_TEST(StringNumericOptimal_Zero)
{
int t1 = 0;
TestStringCodingT(&t1, 1, 1); // should be coded as VarUint
std::string t2 = "01";
TestStringCodingT(&t2, 1, 3); // should be coded as String
}
UNIT_TEST(StringNumericOptimal_IntCoding1)
{
int arr[] = {0, 1, 2, 666, 0x0FFFFFFF, 0x7FFFFFFF - 1, 0x7FFFFFFF};
TestStringCodingT(arr, ARRAY_SIZE(arr), 5); // should be coded as VarUint
}
UNIT_TEST(StringNumericOptimal_IntCoding2)
{
int arr[] = {-1, -2, -666666, static_cast<int>(0xFFFFFFFE), static_cast<int>(0xFFFFFFFF)};
TestStringCodingT(arr, ARRAY_SIZE(arr), 12); // should be coded as String
}
UNIT_TEST(StringNumericOptimal_StringCoding)
{
char const * arr[] = {"xxx", "yyy", "a", "0xFFFFFF", "123456UL"};
TestStringCodingT(arr, ARRAY_SIZE(arr), 12); // should be coded as String
}
UNIT_TEST(StringNumericOptimal_LargeStringCoding)
{
std::string s;
fill_n(back_inserter(s), 10000, 'x');
TestStringCodingT(&s, 1, 10006);
}

View file

@ -0,0 +1,69 @@
#include "testing/testing.hpp"
#include "coding/reader.hpp"
#include "coding/var_record_reader.hpp"
#include "coding/varint.hpp"
#include "coding/writer.hpp"
#include "base/macros.hpp"
#include <cstddef>
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
using namespace std;
namespace
{
struct SaveForEachParams
{
explicit SaveForEachParams(vector<pair<uint64_t, string>> & data) : m_data(data) {}
void operator()(uint64_t pos, vector<uint8_t> && data) const
{
m_data.emplace_back(pos, string(data.begin(), data.end()));
}
vector<pair<uint64_t, string>> & m_data;
};
} // namespace
UNIT_TEST(VarRecordReader_Simple)
{
vector<uint8_t> data;
char const longString[] =
"0123456789012345678901234567890123456789012345678901234567890123456789"
"012345678901234567890123456789012345678901234567890123456789012345";
size_t const longStringSize = sizeof(longString) - 1;
TEST_GREATER(longStringSize, 128, ());
{
MemWriter<vector<uint8_t>> writer(data);
WriteVarUint(writer, 3U); // 0
writer.Write("abc", 3); // 1
WriteVarUint(writer, longStringSize); // 4
writer.Write(longString, longStringSize); // 6
WriteVarUint(writer, 4U); // 6 + longStringSize
writer.Write("defg", 4); // 7 + longStringSize
// 11 + longStringSize
}
MemReader reader(&data[0], data.size());
VarRecordReader<MemReader> recordReader(reader);
auto r = recordReader.ReadRecord(0);
TEST_EQUAL(string(r.begin(), r.end()), "abc", ());
r = recordReader.ReadRecord(6 + longStringSize);
TEST_EQUAL(string(r.begin(), r.end()), "defg", ());
r = recordReader.ReadRecord(4);
TEST_EQUAL(string(r.begin(), r.end()), longString, ());
vector<pair<uint64_t, string>> forEachCalls;
recordReader.ForEachRecord(SaveForEachParams(forEachCalls));
vector<pair<uint64_t, string>> expectedForEachCalls = {{0, "abc"}, {4, longString}, {6 + longStringSize, "defg"}};
TEST_EQUAL(forEachCalls, expectedForEachCalls, ());
}

View file

@ -0,0 +1,118 @@
#include "testing/testing.hpp"
#include "coding/byte_stream.hpp"
#include "coding/hex.hpp"
#include "coding/reader.hpp"
#include "coding/var_serial_vector.hpp"
#include "coding/writer.hpp"
#include "base/macros.hpp"
#include <cstddef>
#include <cstdint>
#include <random>
#include <string>
#include <vector>
using namespace std;
char const kHexSerial[] =
"03000000"
"01000000"
"04000000"
"06000000"
"616263646566";
namespace
{
template <typename ItT, typename TDstStream>
void WriteVarSerialVector(ItT begin, ItT end, TDstStream & dst)
{
vector<uint32_t> offsets;
uint32_t offset = 0;
for (ItT it = begin; it != end; ++it)
{
offset += it->size() * sizeof((*it)[0]);
offsets.push_back(offset);
}
WriteToSink(dst, static_cast<uint32_t>(end - begin));
for (size_t i = 0; i < offsets.size(); ++i)
WriteToSink(dst, offsets[i]);
for (ItT it = begin; it != end; ++it)
{
typename ItT::value_type const & v = *it;
if (!v.empty())
dst.Write(&v[0], v.size() * sizeof(v[0]));
}
}
} // namespace
UNIT_TEST(WriteSerial)
{
vector<string> elements;
elements.push_back("a");
elements.push_back("bcd");
elements.push_back("ef");
string output;
PushBackByteSink<string> sink(output);
WriteVarSerialVector(elements.begin(), elements.end(), sink);
TEST_EQUAL(ToHex(output), kHexSerial, ());
}
UNIT_TEST(WriteSerialWithWriter)
{
string output;
MemWriter<string> writer(output);
VarSerialVectorWriter<MemWriter<string>> recordWriter(writer, 3);
writer.Write("a", 1);
recordWriter.FinishRecord();
writer.Write("bcd", 3);
recordWriter.FinishRecord();
writer.Write("ef", 2);
recordWriter.FinishRecord();
TEST_EQUAL(ToHex(output), kHexSerial, ());
}
UNIT_TEST(ReadSerial)
{
string serial(FromHex(string(kHexSerial)));
MemReader memReader(&serial[0], serial.size());
ReaderSource<MemReader> memSource(memReader);
VarSerialVectorReader<MemReader> reader(memSource);
TEST_EQUAL(reader.Read(0), "a", ());
TEST_EQUAL(reader.Read(1), "bcd", ());
TEST_EQUAL(reader.Read(2), "ef", ());
}
UNIT_TEST(EncodeDecode)
{
mt19937 rng(0);
vector<string> elements;
for (size_t i = 0; i < 1024; ++i)
{
string s(1 + (rng() % 20), 0);
for (size_t j = 0; j < s.size(); ++j)
s[j] = static_cast<char>(rng() % 26) + 'a';
elements.push_back(s);
}
string serial;
PushBackByteSink<string> sink(serial);
WriteVarSerialVector(elements.begin(), elements.end(), sink);
MemReader memReader(serial.c_str(), serial.size());
ReaderSource<MemReader> memSource(memReader);
VarSerialVectorReader<MemReader> reader(memSource);
for (size_t i = 0; i < elements.size(); ++i)
TEST_EQUAL(reader.Read(static_cast<uint32_t>(i)), elements[i], ());
}

View file

@ -0,0 +1,214 @@
#include "testing/testing.hpp"
#include "coding/byte_stream.hpp"
#include "coding/reader.hpp"
#include "coding/varint.hpp"
#include "base/macros.hpp"
#include "base/stl_helpers.hpp"
#include <vector>
using namespace std;
namespace
{
template <typename T>
void TestVarUint(T const x)
{
vector<unsigned char> data;
PushBackByteSink<vector<uint8_t>> dst(data);
WriteVarUint(dst, x);
ArrayByteSource src(&data[0]);
TEST_EQUAL(ReadVarUint<T>(src), x, ());
size_t const bytesRead = src.PtrUint8() - data.data();
TEST_EQUAL(bytesRead, data.size(), (x));
}
template <typename T>
void TestVarInt(T const x)
{
vector<uint8_t> data;
PushBackByteSink<vector<uint8_t>> dst(data);
WriteVarInt(dst, x);
ArrayByteSource src(&data[0]);
TEST_EQUAL(ReadVarInt<T>(src), x, ());
size_t const bytesRead = src.PtrUint8() - data.data();
TEST_EQUAL(bytesRead, data.size(), (x));
}
} // namespace
UNIT_TEST(VarUint0)
{
// TestVarUint(static_cast<uint8_t>(0));
// TestVarUint(static_cast<uint16_t>(0));
TestVarUint(static_cast<uint32_t>(0));
TestVarUint(static_cast<uint64_t>(0));
}
UNIT_TEST(VarUintMinus1)
{
// TestVarUint(static_cast<uint8_t>(-1));
// TestVarUint(static_cast<uint16_t>(-1));
TestVarUint(static_cast<uint32_t>(-1));
TestVarUint(static_cast<uint64_t>(-1));
}
UNIT_TEST(VarUint32)
{
for (int b = 0; b <= 32; ++b)
for (uint64_t i = (1ULL << b) - 3; i <= uint32_t(-1) && i <= (1ULL << b) + 147; ++i)
TestVarUint(static_cast<uint32_t>(i));
}
UNIT_TEST(VarInt32)
{
for (int b = 0; b <= 32; ++b)
{
for (uint64_t i = (1ULL << b) - 3; i <= uint32_t(-1) && i <= (1ULL << b) + 147; ++i)
{
TestVarInt(static_cast<int32_t>(i));
TestVarInt(static_cast<int32_t>(-i));
}
}
int const bound = 10000;
for (int i = -bound; i <= bound; ++i)
TestVarInt(static_cast<int32_t>(i));
for (int i = 0; i <= bound; ++i)
TestVarUint(static_cast<uint32_t>(i));
}
UNIT_TEST(VarIntSize)
{
vector<unsigned char> data;
PushBackByteSink<vector<unsigned char>> dst(data);
WriteVarInt(dst, 60);
TEST_EQUAL(data.size(), 1, ());
data.clear();
WriteVarInt(dst, -60);
TEST_EQUAL(data.size(), 1, ());
data.clear();
WriteVarInt(dst, 120);
TEST_EQUAL(data.size(), 2, ());
data.clear();
WriteVarInt(dst, -120);
TEST_EQUAL(data.size(), 2, ());
}
UNIT_TEST(VarIntMax)
{
TestVarUint(uint32_t(-1));
TestVarUint(uint64_t(-1));
TestVarInt(int32_t(2147483647));
TestVarInt(int32_t(-2147483648LL));
TestVarInt(int64_t(9223372036854775807LL));
// TestVarInt(int64_t(-9223372036854775808LL));
}
UNIT_TEST(ReadVarInt64Array_EmptyArray)
{
vector<int64_t> result;
void const * pEnd = ReadVarInt64Array(NULL, (void *)0, base::MakeBackInsertFunctor(result));
TEST_EQUAL(result, vector<int64_t>(), ("UntilBufferEnd"));
TEST_EQUAL(reinterpret_cast<uintptr_t>(pEnd), 0, ("UntilBufferEnd"));
pEnd = ReadVarInt64Array(NULL, (size_t)0, base::MakeBackInsertFunctor(result));
TEST_EQUAL(result, vector<int64_t>(), ("GivenSize"));
TEST_EQUAL(reinterpret_cast<uintptr_t>(pEnd), 0, ("GivenSize"));
}
UNIT_TEST(ReadVarInt64Array)
{
vector<int64_t> values;
// Fill in values.
{
int64_t const baseValues[] = {0,
127,
128,
(2 << 28) - 1,
(2 << 28),
(2LL << 31),
(2LL << 31) - 1,
0xFFFFFFFF - 1,
0xFFFFFFFF,
0xFFFFFFFFFFULL};
for (size_t i = 0; i < ARRAY_SIZE(baseValues); ++i)
{
values.push_back(baseValues[i]);
values.push_back(-baseValues[i]);
}
sort(values.begin(), values.end());
values.erase(unique(values.begin(), values.end()), values.end());
}
// Test all subsets.
for (size_t i = 1; i < 1U << values.size(); ++i)
{
vector<int64_t> testValues;
for (size_t j = 0; j < values.size(); ++j)
if (i & (1 << j))
testValues.push_back(values[j]);
vector<unsigned char> data;
{
PushBackByteSink<vector<unsigned char>> dst(data);
for (size_t j = 0; j < testValues.size(); ++j)
WriteVarInt(dst, testValues[j]);
}
ASSERT_GREATER(data.size(), 0, ());
{
// Factor out variables here to show the obvious compiler error.
// clang 3.5, loop optimization.
/// @todo Need to check with the new XCode (and clang) update.
void const * pDataStart = &data[0];
void const * pDataEnd = &data[0] + data.size();
vector<int64_t> result;
void const * pEnd = ReadVarInt64Array(pDataStart, pDataEnd, base::MakeBackInsertFunctor(result));
TEST_EQUAL(pEnd, pDataEnd, ("UntilBufferEnd", data.size()));
TEST_EQUAL(result, testValues, ("UntilBufferEnd", data.size()));
}
{
vector<int64_t> result;
void const * pEnd = ReadVarInt64Array(&data[0], testValues.size(), base::MakeBackInsertFunctor(result));
TEST_EQUAL(pEnd, &data[0] + data.size(), ("GivenSize", data.size()));
TEST_EQUAL(result, testValues, ("GivenSize", data.size()));
}
}
}
UNIT_TEST(VarInt_ShortSortedArray)
{
uint32_t constexpr maxVal = (uint32_t(1) << 30) - 1;
std::vector<uint32_t> samples[] = {
{0},
{10, 10000},
{maxVal - 2, maxVal - 1, maxVal},
};
for (auto const & s : samples)
{
std::vector<uint8_t> buffer;
PushBackByteSink sink(buffer);
WriteVarUInt32SortedShortArray(s, sink);
MemReader reader(buffer.data(), buffer.size());
ReaderSource src(reader);
std::vector<uint32_t> actual;
ReadVarUInt32SortedShortArray(src, actual);
TEST_EQUAL(s, actual, ());
}
}

View file

@ -0,0 +1,259 @@
#include "testing/testing.hpp"
#include "coding/buffered_file_writer.hpp"
#include "coding/file_reader.hpp"
#include "coding/file_writer.hpp"
#include "coding/internal/file_data.hpp"
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
using namespace std;
namespace
{
static char const kTestWriteStr[] = "01234567";
template <class WriterT>
void TestWrite(WriterT & writer)
{
writer.Write("01", 2); // "01"
TEST_EQUAL(writer.Pos(), 2, ());
writer.Write("x", 1); // "01x"
TEST_EQUAL(writer.Pos(), 3, ());
writer.Write("3", 1); // "01x3"
TEST_EQUAL(writer.Pos(), 4, ());
writer.Seek(2);
TEST_EQUAL(writer.Pos(), 2, ());
writer.Write("2", 1); // "0123"
TEST_EQUAL(writer.Pos(), 3, ());
writer.Seek(7);
TEST_EQUAL(writer.Pos(), 7, ());
writer.Write("7", 1); // "0123???7"
TEST_EQUAL(writer.Pos(), 8, ());
writer.Seek(4);
TEST_EQUAL(writer.Pos(), 4, ());
writer.Write("45", 2); // "012345?7"
writer.Write("6", 1); // "01234567"
}
} // namespace
UNIT_TEST(MemWriter_Smoke)
{
vector<char> s;
MemWriter<vector<char>> writer(s);
TestWrite(writer);
TEST_EQUAL(string(s.begin(), s.end()), kTestWriteStr, ());
}
UNIT_TEST(FileWriter_Smoke)
{
char const fileName[] = "file_writer_smoke_test.tmp";
{
FileWriter writer(fileName);
TestWrite(writer);
}
vector<char> s;
{
FileReader reader(fileName);
s.resize(reader.Size());
reader.Read(0, &s[0], reader.Size());
}
TEST_EQUAL(string(s.begin(), s.end()), kTestWriteStr, ());
FileWriter::DeleteFileX(fileName);
}
UNIT_TEST(SubWriter_MemWriter_Smoke)
{
vector<char> s;
MemWriter<vector<char>> writer(s);
writer.Write("aa", 2);
{
SubWriter<MemWriter<vector<char>>> subWriter(writer);
TestWrite(subWriter);
}
writer.Write("bb", 2);
TEST_EQUAL(string(s.begin(), s.end()), "aa" + string(kTestWriteStr) + "bb", ());
}
UNIT_TEST(SubWriter_FileWriter_Smoke)
{
char const fileName[] = "sub_file_writer_smoke_test.tmp";
{
FileWriter writer(fileName);
writer.Write("aa", 2);
{
SubWriter<FileWriter> subWriter(writer);
TestWrite(subWriter);
}
writer.Write("bb", 2);
}
vector<char> s;
{
FileReader reader(fileName);
s.resize(reader.Size());
reader.Read(0, &s[0], reader.Size());
}
TEST_EQUAL(string(s.begin(), s.end()), "aa" + string(kTestWriteStr) + "bb", ());
FileWriter::DeleteFileX(fileName);
}
UNIT_TEST(FileWriter_DeleteFile)
{
char const fileName[] = "delete_file_test";
{
FileWriter writer(fileName);
writer.Write("123", 3);
}
{
FileReader reader(fileName);
TEST_EQUAL(reader.Size(), 3, ());
}
FileWriter::DeleteFileX(fileName);
try
{
FileReader reader(fileName);
TEST(false, ("Exception should be thrown!"));
}
catch (FileReader::OpenException &)
{}
}
UNIT_TEST(FileWriter_AppendAndOpenExisting)
{
char const fileName[] = "append_openexisting_file_test";
{
FileWriter writer(fileName);
}
{
FileWriter writer(fileName, FileWriter::OP_WRITE_EXISTING);
TEST_EQUAL(writer.Size(), 0, ());
writer.Write("abcd", 4);
}
{
FileReader reader(fileName);
TEST_EQUAL(reader.Size(), 4, ());
string s(static_cast<uint32_t>(reader.Size()), 0);
reader.Read(0, &s[0], s.size());
TEST_EQUAL(s, "abcd", ());
}
{
FileWriter writer(fileName);
writer.Write("123", 3);
}
{
FileReader reader(fileName);
TEST_EQUAL(reader.Size(), 3, ());
}
{
FileWriter writer(fileName, FileWriter::OP_APPEND);
writer.Write("4", 1);
}
{
FileReader reader(fileName);
TEST_EQUAL(reader.Size(), 4, ());
string s(static_cast<uint32_t>(reader.Size()), 0);
reader.Read(0, &s[0], s.size());
TEST_EQUAL(s, "1234", ());
}
{
FileWriter writer(fileName, FileWriter::OP_WRITE_EXISTING);
TEST_EQUAL(writer.Size(), 4, ());
writer.Write("56", 2);
}
{
FileReader reader(fileName);
TEST_EQUAL(reader.Size(), 4, ());
string s(static_cast<uint32_t>(reader.Size()), 0);
reader.Read(0, &s[0], 4);
TEST_EQUAL(s, "5634", ());
}
FileWriter::DeleteFileX(fileName);
}
size_t const CHUNK_SIZE = 1024;
size_t const CHUNKS_COUNT = 21;
string const TEST_STRING = "Some Test String";
void WriteTestData1(Writer & w)
{
w.Seek(CHUNKS_COUNT * CHUNK_SIZE);
w.Write(TEST_STRING.data(), TEST_STRING.size());
}
void WriteTestData2(Writer & w)
{
char c[CHUNK_SIZE];
for (size_t i = 1; i < CHUNKS_COUNT; i += 2)
{
for (size_t j = 0; j < ARRAY_SIZE(c); ++j)
c[j] = i;
w.Seek(i * CHUNK_SIZE);
w.Write(&c[0], ARRAY_SIZE(c));
}
for (size_t i = 0; i < CHUNKS_COUNT; i += 2)
{
for (size_t j = 0; j < ARRAY_SIZE(c); ++j)
c[j] = i;
w.Seek(i * CHUNK_SIZE);
w.Write(&c[0], ARRAY_SIZE(c));
}
}
void ReadTestData(Reader & r)
{
string s;
r.ReadAsString(s);
for (size_t i = 0; i < CHUNKS_COUNT; ++i)
for (size_t j = 0; j < CHUNK_SIZE; ++j)
TEST_EQUAL(s[i * CHUNK_SIZE + j], static_cast<char>(i), (i, j));
string const sub = s.substr(CHUNKS_COUNT * CHUNK_SIZE);
TEST_EQUAL(sub, TEST_STRING, (sub, TEST_STRING));
}
template <typename WriterType>
void WriteToFileAndTest()
{
string const TEST_FILE = "FileWriter_Chunks.test";
{
WriterType fileWriter(TEST_FILE, FileWriter::OP_WRITE_TRUNCATE);
WriteTestData1(fileWriter);
}
{
WriterType fileWriter(TEST_FILE, FileWriter::OP_WRITE_EXISTING);
WriteTestData2(fileWriter);
}
{
FileReader r(TEST_FILE);
ReadTestData(r);
}
FileWriter::DeleteFileX(TEST_FILE);
}
UNIT_TEST(FileWriter_Chunks)
{
WriteToFileAndTest<FileWriter>();
}
UNIT_TEST(BufferedFileWriter_Smoke)
{
WriteToFileAndTest<BufferedFileWriter>();
}
UNIT_TEST(MemWriter_Chunks)
{
string buffer;
{
MemWriter<string> memWriter(buffer);
WriteTestData1(memWriter);
}
{
MemWriter<string> memWriter(buffer);
WriteTestData2(memWriter);
}
{
MemReader r(buffer.data(), buffer.size());
ReadTestData(r);
}
}

View file

@ -0,0 +1,119 @@
#include "testing/testing.hpp"
#include "coding/parse_xml.hpp"
#include "coding/reader.hpp"
#include <string>
#include <vector>
namespace
{
std::string const smokeXml = R"(
<root>
</root>
)";
std::string const longXml = R"(
<root>
<ruler>
<portrait>
<anchor vertical="bottom" horizontal="left"/>
<offset x="10"/>
</portrait>
</ruler>
<compass>
<portrait>
<anchor vertical="center"/>
<relative vertical="top"/>
</portrait>
<landscape>
<relative vertical="top"/>
<offset x="34" y="48"/>
</landscape>
</compass>
</root>
)";
class SmokeDispatcher
{
public:
void CharData(std::string const &) {}
void AddAttr(char const *, char const *) {}
bool Push(std::string_view push)
{
TEST_EQUAL(push, "root", ());
return true;
}
void Pop(std::string_view pop) { TEST_EQUAL(pop, "root", ()); }
};
class Dispatcher
{
public:
using PairsOfStrings = std::vector<std::pair<std::string, std::string>>;
using Strings = std::vector<std::string>;
void CharData(std::string const & ch) {}
void AddAttr(std::string key, std::string value) { m_addAttrs.emplace_back(std::move(key), std::move(value)); }
bool Push(std::string push)
{
m_pushes.emplace_back(std::move(push));
return true;
}
void Pop(std::string pop) { m_pops.emplace_back(std::move(pop)); }
void TestAddAttrs(PairsOfStrings const & addAttrs) { TestEquality(m_addAttrs, addAttrs); }
void TestPushes(Strings const & pushes) { TestEquality(m_pushes, pushes); }
void TestPops(Strings const & pops) { TestEquality(m_pops, pops); }
private:
template <typename F>
void TestEquality(F const & f1, F const & f2)
{
TEST_EQUAL(f1.size(), f2.size(), ());
for (size_t i = 0; i < f1.size(); ++i)
TEST_EQUAL(f1[i], f2[i], (i));
}
PairsOfStrings m_addAttrs;
Strings m_pushes;
Strings m_pops;
};
template <typename D>
void TestXML(std::string const & xmlStr, D & dispatcher)
{
std::vector<uint8_t> xml(xmlStr.cbegin(), xmlStr.cend());
MemReader reader(xml.data(), xml.size());
ReaderSource<MemReader> source(reader);
ParseXML(source, dispatcher);
}
UNIT_TEST(XmlParser_SmokeTest)
{
Dispatcher d;
TestXML(smokeXml, d);
d.TestAddAttrs({});
d.TestPushes({"root"});
d.TestPops({"root"});
}
UNIT_TEST(XmlParser_LongTest)
{
Dispatcher d;
TestXML(longXml, d);
d.TestAddAttrs({std::make_pair("vertical", "bottom"), std::make_pair("horizontal", "left"), std::make_pair("x", "10"),
std::make_pair("vertical", "center"), std::make_pair("vertical", "top"),
std::make_pair("vertical", "top"), std::make_pair("x", "34"), std::make_pair("y", "48")});
d.TestPushes({"root", "ruler", "portrait", "anchor", "offset", "compass", "portrait", "anchor", "relative",
"landscape", "relative", "offset"});
d.TestPops({"anchor", "offset", "portrait", "ruler", "anchor", "relative", "portrait", "relative", "offset",
"landscape", "compass", "root"});
}
} // namespace

View file

@ -0,0 +1,154 @@
#include "testing/testing.hpp"
#include "coding/constants.hpp"
#include "coding/file_writer.hpp"
#include "coding/internal/file_data.hpp"
#include "coding/zip_creator.hpp"
#include "coding/zip_reader.hpp"
#include "base/scope_guard.hpp"
#include <string>
#include <vector>
namespace
{
void CreateAndTestZip(std::string const & filePath, std::string const & zipPath)
{
TEST(CreateZipFromFiles({filePath}, zipPath, CompressionLevel::DefaultCompression), ());
ZipFileReader::FileList files;
ZipFileReader::FilesList(zipPath, files);
TEST_EQUAL(files[0].second, FileReader(filePath).Size(), ());
std::string const unzippedFile = "unzipped.tmp";
ZipFileReader::UnzipFile(zipPath, files[0].first, unzippedFile);
TEST(base::IsEqualFiles(filePath, unzippedFile), ());
TEST(base::DeleteFileX(filePath), ());
TEST(base::DeleteFileX(zipPath), ());
TEST(base::DeleteFileX(unzippedFile), ());
}
void CreateAndTestZip(std::vector<std::string> const & files, std::string const & zipPath, CompressionLevel compression)
{
TEST(CreateZipFromFiles(files, zipPath, compression), ());
ZipFileReader::FileList fileList;
ZipFileReader::FilesList(zipPath, fileList);
std::string const unzippedFile = "unzipped.tmp";
for (size_t i = 0; i < files.size(); ++i)
{
TEST_EQUAL(fileList[i].second, FileReader(files[i]).Size(), ());
ZipFileReader::UnzipFile(zipPath, fileList[i].first, unzippedFile);
TEST(base::IsEqualFiles(files[i], unzippedFile), ());
TEST(base::DeleteFileX(unzippedFile), ());
}
TEST(base::DeleteFileX(zipPath), ());
}
void CreateAndTestZipWithFolder(std::vector<std::string> const & files, std::vector<std::string> const & filesInArchive,
std::string const & zipPath, CompressionLevel compression)
{
TEST(CreateZipFromFiles(files, filesInArchive, zipPath, compression), ());
ZipFileReader::FileList fileList;
ZipFileReader::FilesList(zipPath, fileList);
std::string const unzippedFile = "unzipped.tmp";
for (size_t i = 0; i < files.size(); ++i)
{
TEST_EQUAL(fileList[i].second, FileReader(files[i]).Size(), ());
ZipFileReader::UnzipFile(zipPath, fileList[i].first, unzippedFile);
TEST(base::IsEqualFiles(files[i], unzippedFile), ());
TEST(base::DeleteFileX(unzippedFile), ());
}
TEST(base::DeleteFileX(zipPath), ());
}
std::vector<CompressionLevel> GetCompressionLevels()
{
return {CompressionLevel::DefaultCompression, CompressionLevel::BestCompression, CompressionLevel::BestSpeed,
CompressionLevel::NoCompression};
}
} // namespace
UNIT_TEST(CreateZip_BigFile)
{
std::string const name = "testfileforzip.txt";
{
FileWriter f(name);
std::string s(READ_FILE_BUFFER_SIZE + 1, '1');
f.Write(s.c_str(), s.size());
}
CreateAndTestZip(name, "testzip.zip");
}
UNIT_TEST(CreateZip_Smoke)
{
std::string const name = "testfileforzip.txt";
{
FileWriter f(name);
f.Write(name.c_str(), name.size());
}
CreateAndTestZip(name, "testzip.zip");
}
UNIT_TEST(CreateZip_MultipleFiles)
{
std::vector<std::string> const fileData{"testf1", "testfile2", "testfile3_longname.txt.xml.csv"};
SCOPE_GUARD(deleteFileGuard, [&fileData]()
{
for (auto const & file : fileData)
TEST(base::DeleteFileX(file), ());
});
for (auto const & name : fileData)
{
FileWriter f(name);
f.Write(name.c_str(), name.size());
}
for (auto compression : GetCompressionLevels())
CreateAndTestZip(fileData, "testzip.zip", compression);
}
UNIT_TEST(CreateZip_MultipleFilesWithFolders)
{
std::vector<std::string> const fileData{"testf1", "testfile2", "testfile3_longname.txt.xml.csv"};
std::vector<std::string> const fileInArchiveData{"testf1", "f2/testfile2", "f3/testfile3_longname.txt.xml.csv"};
SCOPE_GUARD(deleteFileGuard, [&fileData]()
{
for (auto const & file : fileData)
TEST(base::DeleteFileX(file), ());
});
for (auto const & name : fileData)
{
FileWriter f(name);
f.Write(name.c_str(), name.size());
}
for (auto compression : GetCompressionLevels())
CreateAndTestZipWithFolder(fileData, fileInArchiveData, "testzip.zip", compression);
}
UNIT_TEST(CreateZip_MultipleFilesSingleEmpty)
{
std::vector<std::string> const fileData{"singleEmptyfile.txt"};
SCOPE_GUARD(deleteFileGuard, [&fileData]() { TEST(base::DeleteFileX(fileData[0]), ()); });
{
FileWriter f(fileData[0]);
}
for (auto compression : GetCompressionLevels())
CreateAndTestZip(fileData, "testzip.zip", compression);
}

View file

@ -0,0 +1,224 @@
#include "testing/testing.hpp"
#include "coding/file_writer.hpp"
#include "coding/zip_reader.hpp"
#include "base/logging.hpp"
#include "base/macros.hpp"
#include <exception>
#include <string>
using namespace std;
static char const zipBytes[] =
"PK\003\004\n\0\0\0\0\0\222\226\342>\302\032"
"x\372\005\0\0\0\005\0\0\0\b\0\034\0te"
"st.txtUT\t\0\003\303>\017N\017"
"?\017Nux\v\0\001\004\365\001\0\0\004P\0"
"\0\0Test\nPK\001\002\036\003\n\0\0"
"\0\0\0\222\226\342>\302\032x\372\005\0\0\0\005"
"\0\0\0\b\0\030\0\0\0\0\0\0\0\0\0\244"
"\201\0\0\0\0test.txtUT\005"
"\0\003\303>\017Nux\v\0\001\004\365\001\0\0"
"\004P\0\0\0PK\005\006\0\0\0\0\001\0\001"
"\0N\0\0\0G\0\0\0\0\0";
UNIT_TEST(ZipReaderSmoke)
{
string const ZIPFILE = "smoke_test.zip";
{
FileWriter f(ZIPFILE);
f.Write(zipBytes, ARRAY_SIZE(zipBytes) - 1);
}
bool noException = true;
try
{
ZipFileReader r(ZIPFILE, "test.txt");
string s;
r.ReadAsString(s);
TEST_EQUAL(s, "Test\n", ("Invalid zip file contents"));
}
catch (exception const & e)
{
noException = false;
LOG(LERROR, (e.what()));
}
TEST(noException, ("Unhandled exception"));
// invalid zip
noException = true;
try
{
ZipFileReader r("some_nonexisting_filename", "test.txt");
}
catch (exception const &)
{
noException = false;
}
TEST(!noException, ());
// invalid file inside zip
noException = true;
try
{
ZipFileReader r(ZIPFILE, "test");
}
catch (exception const &)
{
noException = false;
}
TEST(!noException, ());
FileWriter::DeleteFileX(ZIPFILE);
}
/// zip file with 3 files inside: 1.txt, 2.txt, 3.ttt
static char const zipBytes2[] =
"\x50\x4b\x3\x4\xa\x0\x0\x0\x0\x0\x92\x6b\xf6\x3e\x53\xfc\x51\x67\x2\x0\x0"
"\x0\x2\x0\x0\x0\x5\x0\x1c\x0\x31\x2e\x74\x78\x74\x55\x54\x9\x0\x3\xd3\x50\x29\x4e\xd4\x50\x29\x4e\x75\x78"
"\xb\x0\x1\x4\xf5\x1\x0\x0\x4\x14\x0\x0\x0\x31\xa\x50\x4b\x3\x4\xa\x0\x0\x0\x0\x0\x95\x6b\xf6\x3e\x90\xaf"
"\x7c\x4c\x2\x0\x0\x0\x2\x0\x0\x0\x5\x0\x1c\x0\x32\x2e\x74\x78\x74\x55\x54\x9\x0\x3\xd9\x50\x29\x4e\xd9\x50"
"\x29\x4e\x75\x78\xb\x0\x1\x4\xf5\x1\x0\x0\x4\x14\x0\x0\x0\x32\xa\x50\x4b\x3\x4\xa\x0\x0\x0\x0\x0\x9c\x6b"
"\xf6\x3e\xd1\x9e\x67\x55\x2\x0\x0\x0\x2\x0\x0\x0\x5\x0\x1c\x0\x33\x2e\x74\x74\x74\x55\x54\x9\x0\x3\xe8\x50"
"\x29\x4e\xe9\x50\x29\x4e\x75\x78\xb\x0\x1\x4\xf5\x1\x0\x0\x4\x14\x0\x0\x0\x33\xa\x50\x4b\x1\x2\x1e\x3\xa"
"\x0\x0\x0\x0\x0\x92\x6b\xf6\x3e\x53\xfc\x51\x67\x2\x0\x0\x0\x2\x0\x0\x0\x5\x0\x18\x0\x0\x0\x0\x0\x1\x0\x0"
"\x0\xa4\x81\x0\x0\x0\x0\x31\x2e\x74\x78\x74\x55\x54\x5\x0\x3\xd3\x50\x29\x4e\x75\x78\xb\x0\x1\x4\xf5\x1\x0"
"\x0\x4\x14\x0\x0\x0\x50\x4b\x1\x2\x1e\x3\xa\x0\x0\x0\x0\x0\x95\x6b\xf6\x3e\x90\xaf\x7c\x4c\x2\x0\x0\x0\x2"
"\x0\x0\x0\x5\x0\x18\x0\x0\x0\x0\x0\x1\x0\x0\x0\xa4\x81\x41\x0\x0\x0\x32\x2e\x74\x78\x74\x55\x54\x5\x0\x3"
"\xd9\x50\x29\x4e\x75\x78\xb\x0\x1\x4\xf5\x1\x0\x0\x4\x14\x0\x0\x0\x50\x4b\x1\x2\x1e\x3\xa\x0\x0\x0\x0\x0"
"\x9c\x6b\xf6\x3e\xd1\x9e\x67\x55\x2\x0\x0\x0\x2\x0\x0\x0\x5\x0\x18\x0\x0\x0\x0\x0\x1\x0\x0\x0\xa4\x81\x82"
"\x0\x0\x0\x33\x2e\x74\x74\x74\x55\x54\x5\x0\x3\xe8\x50\x29\x4e\x75\x78\xb\x0\x1\x4\xf5\x1\x0\x0\x4\x14\x0"
"\x0\x0\x50\x4b\x5\x6\x0\x0\x0\x0\x3\x0\x3\x0\xe1\x0\x0\x0\xc3\x0\x0\x0\x0\x0";
static char const invalidZip[] = "1234567890asdqwetwezxvcbdhg322353tgfsd";
UNIT_TEST(ZipFilesList)
{
string const ZIPFILE = "list_test.zip";
{
FileWriter f(ZIPFILE);
f.Write(zipBytes2, ARRAY_SIZE(zipBytes2) - 1);
}
TEST(ZipFileReader::IsZip(ZIPFILE), ());
string const ZIPFILE_INVALID = "invalid_test.zip";
{
FileWriter f(ZIPFILE_INVALID);
f.Write(invalidZip, ARRAY_SIZE(invalidZip) - 1);
}
TEST(!ZipFileReader::IsZip(ZIPFILE_INVALID), ());
try
{
ZipFileReader::FileList files;
ZipFileReader::FilesList(ZIPFILE, files);
TEST_EQUAL(files.size(), 3, ());
TEST_EQUAL(files[0].first, "1.txt", ());
TEST_EQUAL(files[0].second, 2, ());
TEST_EQUAL(files[1].first, "2.txt", ());
TEST_EQUAL(files[1].second, 2, ());
TEST_EQUAL(files[2].first, "3.ttt", ());
TEST_EQUAL(files[2].second, 2, ());
}
catch (exception const & e)
{
TEST(false, ("Can't get list of files inside zip", e.what()));
}
try
{
ZipFileReader::FileList files;
ZipFileReader::FilesList(ZIPFILE_INVALID, files);
TEST(false, ("This test shouldn't be reached - exception should be thrown"));
}
catch (exception const &)
{}
FileWriter::DeleteFileX(ZIPFILE_INVALID);
FileWriter::DeleteFileX(ZIPFILE);
}
/// Compressed zip file with 2 files in assets folder:
/// assets/aaaaaaaaaa.txt (contains text "aaaaaaaaaa\x0A")
/// assets/holalala.txt (contains text "Holalala\x0A")
static char const zipBytes3[] =
"\x50\x4B\x03\x04\x14\x00\x02\x00\x08\x00\xAF\x96\x56\x40\x42\xE5\x26\x8F\x06\x00"
"\x00\x00\x0B\x00\x00\x00\x15\x00\x1C\x00\x61\x73\x73\x65\x74\x73\x2F\x61\x61\x61"
"\x61\x61\x61\x61\x61\x61\x61\x2E\x74\x78\x74\x55\x54\x09\x00\x03\x7A\x0F\x45\x4F"
"\xD8\x0F\x45\x4F\x75\x78\x0B\x00\x01\x04\xF5\x01\x00\x00\x04\x14\x00\x00\x00\x4B"
"\x4C\x84\x01\x2E\x00\x50\x4B\x03\x04\x14\x00\x02\x00\x08\x00\xE6\x96\x56\x40\x5E"
"\x76\x90\x07\x08\x00\x00\x00\x09\x00\x00\x00\x13\x00\x1C\x00\x61\x73\x73\x65\x74"
"\x73\x2F\x68\x6F\x6C\x61\x6C\x61\x6C\x61\x2E\x74\x78\x74\x55\x54\x09\x00\x03\xDF"
"\x0F\x45\x4F\xDC\x0F\x45\x4F\x75\x78\x0B\x00\x01\x04\xF5\x01\x00\x00\x04\x14\x00"
"\x00\x00\xF3\xC8\xCF\x49\x04\x41\x2E\x00\x50\x4B\x01\x02\x1E\x03\x14\x00\x02\x00"
"\x08\x00\xAF\x96\x56\x40\x42\xE5\x26\x8F\x06\x00\x00\x00\x0B\x00\x00\x00\x15\x00"
"\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xA4\x81\x00\x00\x00\x00\x61\x73\x73\x65"
"\x74\x73\x2F\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x2E\x74\x78\x74\x55\x54\x05"
"\x00\x03\x7A\x0F\x45\x4F\x75\x78\x0B\x00\x01\x04\xF5\x01\x00\x00\x04\x14\x00\x00"
"\x00\x50\x4B\x01\x02\x1E\x03\x14\x00\x02\x00\x08\x00\xE6\x96\x56\x40\x5E\x76\x90"
"\x07\x08\x00\x00\x00\x09\x00\x00\x00\x13\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00"
"\x00\xA4\x81\x55\x00\x00\x00\x61\x73\x73\x65\x74\x73\x2F\x68\x6F\x6C\x61\x6C\x61"
"\x6C\x61\x2E\x74\x78\x74\x55\x54\x05\x00\x03\xDF\x0F\x45\x4F\x75\x78\x0B\x00\x01"
"\x04\xF5\x01\x00\x00\x04\x14\x00\x00\x00\x50\x4B\x05\x06\x00\x00\x00\x00\x02\x00"
"\x02\x00\xB4\x00\x00\x00\xAA\x00\x00\x00\x00\x00";
UNIT_TEST(ZipExtract)
{
string const ZIPFILE = "test.zip";
{
FileWriter f(ZIPFILE);
f.Write(zipBytes3, ARRAY_SIZE(zipBytes3));
}
TEST(ZipFileReader::IsZip(ZIPFILE), ("Not a zip file"));
ZipFileReader::FileList files;
ZipFileReader::FilesList(ZIPFILE, files);
TEST_EQUAL(files.size(), 2, ());
string const OUTFILE = "out.tmp";
string s;
ZipFileReader::UnzipFile(ZIPFILE, files[0].first, OUTFILE);
{
FileReader(OUTFILE).ReadAsString(s);
}
TEST_EQUAL(s, "aaaaaaaaaa\x0A", ());
// OUTFILE should be rewritten correctly in the next lines
ZipFileReader::UnzipFile(ZIPFILE, files[1].first, OUTFILE);
{
FileReader(OUTFILE).ReadAsString(s);
}
TEST_EQUAL(s, "Holalala\x0A", ());
FileWriter::DeleteFileX(OUTFILE);
FileWriter::DeleteFileX(ZIPFILE);
}
UNIT_TEST(ZipFileSizes)
{
string const ZIPFILE = "test.zip";
{
FileWriter f(ZIPFILE);
f.Write(zipBytes3, ARRAY_SIZE(zipBytes3));
}
TEST(ZipFileReader::IsZip(ZIPFILE), ("Not a zip file"));
ZipFileReader::FileList files;
ZipFileReader::FilesList(ZIPFILE, files);
TEST_EQUAL(files.size(), 2, ());
{
ZipFileReader file(ZIPFILE, files[0].first);
TEST_EQUAL(file.Size(), 6, ());
TEST_EQUAL(file.UncompressedSize(), 11, ());
}
{
ZipFileReader file(ZIPFILE, files[1].first);
TEST_EQUAL(file.Size(), 8, ());
TEST_EQUAL(file.UncompressedSize(), 9, ());
}
FileWriter::DeleteFileX(ZIPFILE);
}

View file

@ -0,0 +1,103 @@
#include "testing/testing.hpp"
#include "coding/zlib.hpp"
#include "base/macros.hpp"
#include "base/string_utils.hpp"
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
using namespace coding;
using namespace std;
using Deflate = ZLib::Deflate;
using Inflate = ZLib::Inflate;
pair<Deflate::Format, Inflate::Format> const g_combinations[] = {{Deflate::Format::ZLib, Inflate::Format::ZLib},
{Deflate::Format::ZLib, Inflate::Format::Both},
{Deflate::Format::GZip, Inflate::Format::GZip},
{Deflate::Format::GZip, Inflate::Format::Both}};
namespace
{
void TestDeflateInflate(string const & original)
{
for (auto const & p : g_combinations)
{
Deflate const deflate(p.first /* format */, Deflate::Level::BestCompression);
Inflate const inflate(p.second /* format */);
string compressed;
TEST(deflate(original, back_inserter(compressed)), ());
string decompressed;
TEST(inflate(compressed, back_inserter(decompressed)), ());
TEST_EQUAL(original, decompressed, ());
}
}
UNIT_TEST(ZLib_Smoke)
{
Deflate const deflate(Deflate::Format::ZLib, Deflate::Level::BestCompression);
Inflate const inflate(Inflate::Format::ZLib);
{
string s;
TEST(!deflate(nullptr /* data */, 0 /* size */, back_inserter(s) /* out */), ());
TEST(!deflate(nullptr /* data */, 4 /* size */, back_inserter(s) /* out */), ());
TEST(!inflate(nullptr /* data */, 0 /* size */, back_inserter(s) /* out */), ());
TEST(!inflate(nullptr /* data */, 4 /* size */, back_inserter(s) /* out */), ());
}
TestDeflateInflate("");
TestDeflateInflate("Hello, World!");
}
UNIT_TEST(ZLib_Large)
{
string original;
for (size_t i = 0; i < 1000; ++i)
original += strings::to_string(i);
TestDeflateInflate(original);
}
UNIT_TEST(GZip_ForeignData)
{
// To get this array of bytes, type following:
//
// echo -n 'Hello World!' | gzip -c | od -t x1
uint8_t const data[] = {0x1f, 0x8b, 0x08, 0x08, 0x6d, 0x55, 0x08, 0x59, 0x00, 0x03, 0x73, 0x61, 0x6d, 0x70, 0x6c,
0x65, 0x2e, 0x74, 0x78, 0x74, 0x00, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51, 0x08, 0xcf,
0x2f, 0xca, 0x49, 0x51, 0x04, 0x00, 0xd0, 0xc3, 0x4a, 0xec, 0x0d, 0x00, 0x00, 0x00};
string s;
Inflate const inflate(Inflate::Format::GZip);
TEST(inflate(data, ARRAY_SIZE(data), back_inserter(s)), ());
TEST_EQUAL(s, "Hello, World!", ());
}
UNIT_TEST(GZip_ExtraDataInBuffer)
{
// Data from GZip_ForeignData + extra \n at the end of the buffer.
uint8_t const data[] = {0x1f, 0x8b, 0x08, 0x08, 0x6d, 0x55, 0x08, 0x59, 0x00, 0x03, 0x73, 0x61, 0x6d, 0x70, 0x6c,
0x65, 0x2e, 0x74, 0x78, 0x74, 0x00, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51, 0x08, 0xcf,
0x2f, 0xca, 0x49, 0x51, 0x04, 0x00, 0xd0, 0xc3, 0x4a, 0xec, 0x0d, 0x00, 0x00, 0x00, 0x0a};
string s;
Inflate const inflate(Inflate::Format::GZip);
// inflate should fail becase there is unconsumed data at the end of buffer.
TEST(!inflate(data, ARRAY_SIZE(data), back_inserter(s)), ());
// inflate should decompress everything but the last byte.
TEST_EQUAL(s, "Hello, World!", ());
}
} // namespace