#include <config.h>
#include "addrcache.h"
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <vector>
#include "testing.h"
#include "varint_bigendian.h"
#include "vcdiff_defs.h"
namespace open_vcdiff {
namespace {
class VCDiffAddressCacheTest : public testing::Test {
public:
typedef std::string string;
VCDiffAddressCacheTest() : decode_position_(NULL),
decode_position_end_(NULL),
verify_encode_position_(NULL),
last_encode_size_(0),
last_decode_position_(NULL) { }
virtual ~VCDiffAddressCacheTest() { }
virtual void SetUp() {
EXPECT_TRUE(cache_.Init());
}
void BM_Setup(int test_size);
void BM_CacheEncode(int iterations, int test_size);
void BM_CacheDecode(int iterations, int test_size);
protected:
virtual void TestBody() { }
void BeginDecode() {
decode_position_ = address_stream_.data();
EXPECT_TRUE(decode_position_ != NULL);
last_decode_position_ = decode_position_;
decode_position_end_ = decode_position_ + address_stream_.size();
}
void ExpectEncodedSizeInBytes(int n) {
EXPECT_EQ(last_encode_size_ + n, address_stream_.size());
last_encode_size_ = address_stream_.size();
}
void ExpectDecodedSizeInBytes(int n) {
EXPECT_EQ(last_decode_position_ + n, decode_position_);
last_decode_position_ = decode_position_;
}
void ManualEncodeVarint(VCDAddress value) {
VarintBE<VCDAddress>::AppendToString(value, &address_stream_);
}
void ManualEncodeByte(unsigned char byte) {
address_stream_.push_back(byte);
}
void ExpectEncodedVarint(VCDAddress expected_value, int expected_size) {
if (!verify_encode_position_) {
verify_encode_position_ = address_stream_.data();
}
EXPECT_EQ(expected_size, VarintBE<VCDAddress>::Length(expected_value));
VCDAddress output_val = VarintBE<VCDAddress>::Parse(
address_stream_.data() + address_stream_.size(),
&verify_encode_position_);
EXPECT_EQ(expected_value, output_val);
}
void ExpectEncodedByte(unsigned char expected_value) {
if (!verify_encode_position_) {
verify_encode_position_ = address_stream_.data();
}
EXPECT_EQ(expected_value, *verify_encode_position_);
++verify_encode_position_;
}
void TestEncode(VCDAddress address,
VCDAddress here_address,
unsigned char mode,
int size) {
VCDAddress encoded_addr = 0;
EXPECT_EQ(mode, cache_.EncodeAddress(address, here_address, &encoded_addr));
if (cache_.WriteAddressAsVarintForMode(mode)) {
ManualEncodeVarint(encoded_addr);
} else {
EXPECT_GT(256, encoded_addr);
ManualEncodeByte(static_cast<unsigned char>(encoded_addr));
}
ExpectEncodedSizeInBytes(size);
}
VCDiffAddressCache cache_;
string address_stream_;
const char* decode_position_;
const char* decode_position_end_;
string large_address_stream_;
std::vector<unsigned char> mode_stream_;
std::vector<VCDAddress> verify_stream_;
private:
const char* verify_encode_position_;
string::size_type last_encode_size_;
const char* last_decode_position_;
};
#ifdef GTEST_HAS_DEATH_TEST
typedef VCDiffAddressCacheTest VCDiffAddressCacheDeathTest;
#endif
TEST_F(VCDiffAddressCacheTest, ZeroCacheSizes) {
VCDiffAddressCache zero_cache(0, 0);
EXPECT_TRUE(zero_cache.Init());
}
TEST_F(VCDiffAddressCacheTest, NearCacheSizeIsTooBig) {
VCDiffAddressCache cache(VCD_MAX_MODES - 1, 0);
EXPECT_FALSE(cache.Init());
}
TEST_F(VCDiffAddressCacheTest, SameCacheSizeIsTooBig) {
VCDiffAddressCache cache(0, VCD_MAX_MODES - 1);
EXPECT_FALSE(cache.Init());
}
TEST_F(VCDiffAddressCacheTest, CombinedSizesAreTooBig) {
VCDiffAddressCache cache1((VCD_MAX_MODES / 2), (VCD_MAX_MODES / 2) - 1);
EXPECT_FALSE(cache1.Init());
VCDiffAddressCache cache2(VCD_MAX_MODES - 1, VCD_MAX_MODES- 1);
EXPECT_FALSE(cache2.Init());
}
TEST_F(VCDiffAddressCacheTest, MaxLegalNearCacheSize) {
VCDiffAddressCache cache(VCD_MAX_MODES - 2, 0);
EXPECT_TRUE(cache.Init());
}
TEST_F(VCDiffAddressCacheTest, MaxLegalSameCacheSize) {
VCDiffAddressCache cache(0, VCD_MAX_MODES - 2);
EXPECT_TRUE(cache.Init());
}
TEST_F(VCDiffAddressCacheTest, MaxLegalCombinedSizes) {
VCDiffAddressCache cache((VCD_MAX_MODES / 2) - 1, (VCD_MAX_MODES / 2) - 1);
EXPECT_TRUE(cache.Init());
}
TEST_F(VCDiffAddressCacheTest, DestroyWithoutInitialization) {
VCDiffAddressCache no_init_cache(4, 3);
}
TEST_F(VCDiffAddressCacheTest, DestroyDefaultWithoutInitialization) {
VCDiffAddressCache no_init_cache;
}
TEST_F(VCDiffAddressCacheTest, CacheContentsInitiallyZero) {
VCDAddress test_address = 0;
for (test_address = 0; test_address < 4; ++test_address) {
EXPECT_EQ(0, cache_.NearAddress(test_address));
}
for (test_address = 0; test_address < 256 * 3; ++test_address) {
EXPECT_EQ(0, cache_.SameAddress(test_address));
}
}
TEST_F(VCDiffAddressCacheTest, InsertFirstTen) {
VCDAddress test_address = 0;
for (test_address = 1; test_address <= 10; ++test_address) {
cache_.UpdateCache(test_address);
}
EXPECT_EQ(9, cache_.NearAddress(0)); EXPECT_EQ(10, cache_.NearAddress(1)); EXPECT_EQ(7, cache_.NearAddress(2)); EXPECT_EQ(8, cache_.NearAddress(3)); EXPECT_EQ(0, cache_.SameAddress(0));
for (test_address = 1; test_address <= 10; ++test_address) {
EXPECT_EQ(test_address, cache_.SameAddress(test_address));
}
for (test_address = 11; test_address < 256 * 3; ++test_address) {
EXPECT_EQ(0, cache_.SameAddress(test_address));
}
}
TEST_F(VCDiffAddressCacheTest, InsertIntMax) {
cache_.UpdateCache(INT_MAX);
EXPECT_EQ(INT_MAX, cache_.NearAddress(0));
EXPECT_EQ(INT_MAX, cache_.SameAddress(INT_MAX % (256 * 3)));
EXPECT_EQ(0, cache_.SameAddress((INT_MAX - 256) % (256 * 3)));
EXPECT_EQ(0, cache_.SameAddress((INT_MAX - 512) % (256 * 3)));
}
TEST_F(VCDiffAddressCacheTest, EncodeAddressModes) {
TestEncode(0x0000FFFF, 0x10000000, VCD_SELF_MODE, 3);
TestEncode(0x10000000, 0x10000010, VCD_HERE_MODE, 1);
TestEncode(0x10000004, 0x10000020, cache_.FirstNearMode() + 0x01, 1);
TestEncode(0x0FFFFFFE, 0x10000030, VCD_HERE_MODE, 1);
TestEncode(0x10000004, 0x10000040, cache_.FirstSameMode() + 0x01, 1);
ExpectEncodedVarint(0xFFFF, 3); ExpectEncodedVarint(0x10, 1); ExpectEncodedVarint(0x04, 1); ExpectEncodedVarint(0x32, 1); ExpectEncodedByte(0x04); }
TEST_F(VCDiffAddressCacheTest, DecodeAddressModes) {
ManualEncodeVarint(0xCAFE);
ManualEncodeVarint(0xCAFE);
ManualEncodeVarint(0x1000);
ManualEncodeByte(0xFE); ManualEncodeVarint(0xFE);
ManualEncodeVarint(0x1000);
BeginDecode();
EXPECT_EQ(0xCAFE,
cache_.DecodeAddress(0x10000,
VCD_SELF_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xCAFE));
EXPECT_EQ(0x20000 - 0xCAFE,
cache_.DecodeAddress(0x20000,
VCD_HERE_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xCAFE));
EXPECT_EQ(0xDAFE,
cache_.DecodeAddress(0x30000,
cache_.FirstNearMode(),
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0x1000));
EXPECT_EQ(0xCAFE,
cache_.DecodeAddress(0x40000,
cache_.FirstSameMode() + (0xCA % 3),
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(sizeof(unsigned char)); EXPECT_EQ(0xFE,
cache_.DecodeAddress(0x50000,
VCD_SELF_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xFE));
EXPECT_EQ(0x10FE,
cache_.DecodeAddress(0x60000,
cache_.FirstNearMode(),
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0x1000));
}
TEST_F(VCDiffAddressCacheTest, EncodeAddressZeroCacheSizes) {
VCDAddress encoded_addr = 0;
VCDiffAddressCache zero_cache(0, 0);
EXPECT_TRUE(zero_cache.Init());
EXPECT_EQ(VCD_SELF_MODE,
zero_cache.EncodeAddress(0x0000FFFF, 0x10000000, &encoded_addr));
EXPECT_EQ(0xFFFF, encoded_addr);
EXPECT_EQ(VCD_HERE_MODE,
zero_cache.EncodeAddress(0x10000000, 0x10000010, &encoded_addr));
EXPECT_EQ(0x10, encoded_addr);
EXPECT_EQ(VCD_HERE_MODE,
zero_cache.EncodeAddress(0x10000004, 0x10000020, &encoded_addr));
EXPECT_EQ(0x1C, encoded_addr);
EXPECT_EQ(VCD_HERE_MODE,
zero_cache.EncodeAddress(0x0FFFFFFE, 0x10000030, &encoded_addr));
EXPECT_EQ(0x32, encoded_addr);
EXPECT_EQ(VCD_HERE_MODE,
zero_cache.EncodeAddress(0x10000004, 0x10000040, &encoded_addr));
EXPECT_EQ(0x3C, encoded_addr);
}
TEST_F(VCDiffAddressCacheTest, DecodeAddressZeroCacheSizes) {
VCDiffAddressCache zero_cache(0, 0);
EXPECT_TRUE(zero_cache.Init());
ManualEncodeVarint(0xCAFE);
ManualEncodeVarint(0xCAFE);
ManualEncodeVarint(0xDAFE);
BeginDecode();
EXPECT_EQ(0xCAFE, zero_cache.DecodeAddress(0x10000,
VCD_SELF_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xCAFE));
EXPECT_EQ(0x20000 - 0xCAFE, zero_cache.DecodeAddress(0x20000,
VCD_HERE_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xCAFE));
EXPECT_EQ(0xDAFE, zero_cache.DecodeAddress(0x30000,
VCD_SELF_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xDAFE));
}
#ifdef GTEST_HAS_DEATH_TEST
TEST_F(VCDiffAddressCacheDeathTest, EncodeNegativeAddress) {
VCDAddress dummy_encoded_address = 0;
EXPECT_DEBUG_DEATH(cache_.EncodeAddress(-1, -1, &dummy_encoded_address),
"negative");
}
TEST_F(VCDiffAddressCacheDeathTest, EncodeAddressPastHereAddress) {
VCDAddress dummy_encoded_address = 0;
EXPECT_DEBUG_DEATH(cache_.EncodeAddress(0x100, 0x100, &dummy_encoded_address),
"address.*<.*here_address");
EXPECT_DEBUG_DEATH(cache_.EncodeAddress(0x200, 0x100, &dummy_encoded_address),
"address.*<.*here_address");
}
TEST_F(VCDiffAddressCacheDeathTest, DecodeInvalidMode) {
ManualEncodeVarint(0xCAFE);
BeginDecode();
EXPECT_DEBUG_DEATH(EXPECT_EQ(RESULT_ERROR,
cache_.DecodeAddress(0x10000000,
cache_.LastMode() + 1,
&decode_position_,
decode_position_end_)),
"mode");
EXPECT_DEBUG_DEATH(EXPECT_EQ(RESULT_ERROR,
cache_.DecodeAddress(0x10000000,
0xFF,
&decode_position_,
decode_position_end_)),
"mode");
ExpectDecodedSizeInBytes(0); }
TEST_F(VCDiffAddressCacheDeathTest, DecodeZeroOrNegativeHereAddress) {
ManualEncodeVarint(0xCAFE);
ManualEncodeVarint(0xCAFE);
BeginDecode();
EXPECT_DEBUG_DEATH(cache_.DecodeAddress(-1,
VCD_SELF_MODE,
&decode_position_,
decode_position_end_),
"negative");
EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0,
VCD_SELF_MODE,
&decode_position_,
decode_position_end_));
}
#endif
TEST_F(VCDiffAddressCacheTest, DecodeAddressPastHereAddress) {
ManualEncodeVarint(0xCAFE);
BeginDecode();
EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x1000,
VCD_SELF_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(0); }
TEST_F(VCDiffAddressCacheTest, HereModeAddressTooLarge) {
ManualEncodeVarint(0x10001); BeginDecode();
EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x10000,
VCD_HERE_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(0); }
TEST_F(VCDiffAddressCacheTest, NearModeAddressOverflow) {
ManualEncodeVarint(0xCAFE);
ManualEncodeVarint(0x7FFFFFFF);
BeginDecode();
EXPECT_EQ(0xCAFE, cache_.DecodeAddress(0x10000,
VCD_SELF_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xCAFE));
EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x10000000,
cache_.FirstNearMode(),
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(0); }
TEST_F(VCDiffAddressCacheTest, DecodeInvalidVarint) {
address_stream_.clear();
address_stream_.append(512, static_cast<char>(0xFE));
BeginDecode();
EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x10000000,
VCD_SELF_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(0); }
TEST_F(VCDiffAddressCacheTest, DecodePartialVarint) {
address_stream_.clear();
ManualEncodeByte(0xFE);
ManualEncodeByte(0xFE);
ManualEncodeByte(0xFE);
BeginDecode();
EXPECT_EQ(RESULT_END_OF_DATA,
cache_.DecodeAddress(0x10000000,
VCD_SELF_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(0); ManualEncodeByte(0x01); BeginDecode(); EXPECT_EQ(0xFDFBF01,
cache_.DecodeAddress(0x10000000,
VCD_SELF_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(4); }
#ifdef GTEST_HAS_DEATH_TEST
TEST_F(VCDiffAddressCacheDeathTest, DecodeBadMode) {
ManualEncodeVarint(0xCAFE);
BeginDecode();
EXPECT_DEBUG_DEATH(EXPECT_EQ(RESULT_ERROR,
cache_.DecodeAddress(0x10000,
cache_.LastMode() + 1,
&decode_position_,
decode_position_end_)),
"maximum");
ExpectDecodedSizeInBytes(0);
}
#endif
TEST_F(VCDiffAddressCacheTest, DecodeInvalidHereAddress) {
ManualEncodeVarint(0x10001); BeginDecode();
EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x10000,
VCD_HERE_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(0);
}
TEST_F(VCDiffAddressCacheTest, DecodeInvalidNearAddress) {
ManualEncodeVarint(0xCAFE);
ManualEncodeVarint(INT_MAX); BeginDecode();
EXPECT_EQ(0xCAFE,
cache_.DecodeAddress(0x10000,
VCD_SELF_MODE,
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xCAFE));
EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x10000,
cache_.FirstNearMode(),
&decode_position_,
decode_position_end_));
ExpectDecodedSizeInBytes(0);
}
void VCDiffAddressCacheTest::BM_Setup(int test_size) {
mode_stream_.resize(test_size);
verify_stream_.resize(test_size);
VCDAddress here_address = 1;
srand(1);
for (int i = 0; i < test_size; ++i) {
verify_stream_[i] = PortableRandomInRange(here_address - 1);
here_address += 4;
}
BM_CacheEncode(1, test_size); }
void VCDiffAddressCacheTest::BM_CacheEncode(int iterations, int test_size) {
VCDAddress here_address = 1;
VCDAddress encoded_addr = 0;
for (int test_iteration = 0; test_iteration < iterations; ++test_iteration) {
cache_.Init();
large_address_stream_.clear();
here_address = 1;
for (int i = 0; i < test_size; ++i) {
const unsigned char mode = cache_.EncodeAddress(verify_stream_[i],
here_address,
&encoded_addr);
if (cache_.WriteAddressAsVarintForMode(mode)) {
VarintBE<VCDAddress>::AppendToString(encoded_addr,
&large_address_stream_);
} else {
EXPECT_GT(256, encoded_addr);
large_address_stream_.push_back(
static_cast<unsigned char>(encoded_addr));
}
mode_stream_[i] = mode;
here_address += 4;
}
}
}
void VCDiffAddressCacheTest::BM_CacheDecode(int iterations, int test_size) {
VCDAddress here_address = 1;
for (int test_iteration = 0; test_iteration < iterations; ++test_iteration) {
cache_.Init();
const char* large_decode_pointer = large_address_stream_.data();
const char* const end_of_encoded_data =
large_decode_pointer + large_address_stream_.size();
here_address = 1;
for (int i = 0; i < test_size; ++i) {
EXPECT_EQ(verify_stream_[i],
cache_.DecodeAddress(here_address,
mode_stream_[i],
&large_decode_pointer,
end_of_encoded_data));
here_address += 4;
}
EXPECT_EQ(end_of_encoded_data, large_decode_pointer);
}
}
TEST_F(VCDiffAddressCacheTest, PerformanceTest) {
const int test_size = 20 * 1024; const int num_iterations = 40; BM_Setup(test_size);
{
CycleTimer encode_timer;
encode_timer.Start();
BM_CacheEncode(num_iterations, test_size);
encode_timer.Stop();
double encode_time_in_ms =
static_cast<double>(encode_timer.GetInUsec()) / 1000;
std::cout << "Time to encode: "
<< (encode_time_in_ms / num_iterations) << " ms" << std::endl;
}
{
CycleTimer decode_timer;
decode_timer.Start();
BM_CacheDecode(num_iterations, test_size);
decode_timer.Stop();
double decode_time_in_ms =
static_cast<double>(decode_timer.GetInUsec()) / 1000;
std::cout << "Time to decode: "
<< (decode_time_in_ms / num_iterations) << " ms" << std::endl;
}
}
} }