aboutsummaryrefslogtreecommitdiff
path: root/src/addrcache_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/addrcache_test.cc')
-rw-r--r--src/addrcache_test.cc634
1 files changed, 634 insertions, 0 deletions
diff --git a/src/addrcache_test.cc b/src/addrcache_test.cc
new file mode 100644
index 0000000..64b7169
--- /dev/null
+++ b/src/addrcache_test.cc
@@ -0,0 +1,634 @@
+// Copyright 2007 Google Inc.
+// Author: Lincoln Smith
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <config.h>
+#include "addrcache.h"
+#include <limits.h> // INT_MAX, INT_MIN
+#include <stdint.h> // uint32_t
+#include <stdlib.h> // rand, srand
+#include <iostream>
+#include <string>
+#include <vector>
+#include "testing.h"
+#include "varint_bigendian.h"
+#include "vcdiff_defs.h" // RESULT_ERROR
+
+namespace open_vcdiff {
+namespace {
+
+// Provides an address_stream_ buffer and functions to manually encode
+// values into the buffer, and to manually decode and verify test results
+// from the buffer.
+//
+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());
+ }
+
+ // Benchmarks for timing encode/decode operations
+ 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() { } // to allow instantiation of this class
+
+ 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
+// This synonym is needed for the tests that use ASSERT_DEATH
+typedef VCDiffAddressCacheTest VCDiffAddressCacheDeathTest;
+#endif // GTEST_HAS_DEATH_TEST
+
+// Having either or both cache size == 0 is acceptable
+TEST_F(VCDiffAddressCacheTest, ZeroCacheSizes) {
+ VCDiffAddressCache zero_cache(0, 0);
+ EXPECT_TRUE(zero_cache.Init());
+}
+
+TEST_F(VCDiffAddressCacheTest, NegativeCacheSizes) {
+ VCDiffAddressCache negative_cache(-1, -1); // The constructor must not fail
+ EXPECT_FALSE(negative_cache.Init());
+}
+
+TEST_F(VCDiffAddressCacheTest, OnlySameCacheSizeIsNegative) {
+ VCDiffAddressCache negative_cache(0, -1); // The constructor must not fail
+ EXPECT_FALSE(negative_cache.Init());
+}
+
+TEST_F(VCDiffAddressCacheTest, ExtremePositiveCacheSizes) {
+ // The constructor must not fail
+ VCDiffAddressCache int_max_cache(INT_MAX, INT_MAX);
+ EXPECT_FALSE(int_max_cache.Init());
+}
+
+TEST_F(VCDiffAddressCacheTest, ExtremeNegativeCacheSizes) {
+ // The constructor must not fail
+ VCDiffAddressCache int_min_cache(INT_MIN, INT_MIN);
+ EXPECT_FALSE(int_min_cache.Init());
+}
+
+// VCD_MAX_MODES is the maximum number of modes, including SAME and HERE modes.
+// So neither the SAME cache nor the HERE cache can be larger than
+// (VCD_MAX_MODES - 2).
+TEST_F(VCDiffAddressCacheTest, NearCacheSizeIsTooBig) {
+ VCDiffAddressCache negative_cache(VCD_MAX_MODES - 1, 0);
+ EXPECT_FALSE(negative_cache.Init());
+}
+
+TEST_F(VCDiffAddressCacheTest, SameCacheSizeIsTooBig) {
+ VCDiffAddressCache negative_cache(0, VCD_MAX_MODES - 1);
+ EXPECT_FALSE(negative_cache.Init());
+}
+
+TEST_F(VCDiffAddressCacheTest, CombinedSizesAreTooBig) {
+ VCDiffAddressCache negative_cache((VCD_MAX_MODES / 2),
+ (VCD_MAX_MODES / 2) - 1);
+ EXPECT_FALSE(negative_cache.Init());
+}
+
+TEST_F(VCDiffAddressCacheTest, MaxLegalNearCacheSize) {
+ VCDiffAddressCache negative_cache(VCD_MAX_MODES - 2, 0);
+ EXPECT_TRUE(negative_cache.Init());
+}
+
+TEST_F(VCDiffAddressCacheTest, MaxLegalSameCacheSize) {
+ VCDiffAddressCache negative_cache(0, VCD_MAX_MODES - 2);
+ EXPECT_TRUE(negative_cache.Init());
+}
+
+TEST_F(VCDiffAddressCacheTest, MaxLegalCombinedSizes) {
+ VCDiffAddressCache negative_cache((VCD_MAX_MODES / 2) - 1,
+ (VCD_MAX_MODES / 2) - 1);
+ EXPECT_TRUE(negative_cache.Init());
+}
+
+TEST_F(VCDiffAddressCacheTest, DestroyWithoutInitialization) {
+ VCDiffAddressCache no_init_cache(4, 3);
+ // Should be destroyed without crashing
+}
+
+TEST_F(VCDiffAddressCacheTest, DestroyDefaultWithoutInitialization) {
+ VCDiffAddressCache no_init_cache;
+ // Should be destroyed without crashing
+}
+
+TEST_F(VCDiffAddressCacheTest, CacheContentsInitiallyZero) {
+ VCDAddress test_address = 0;
+ // Check that caches are initially set to zero
+ 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));
+ }
+}
+
+// Inserts values 1, 2, ... , 10 into the cache and tests its entire
+// contents for consistency.
+//
+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)); // slot 0: 1 => 5 => 9
+ EXPECT_EQ(10, cache_.NearAddress(1)); // slot 1: 2 => 6 => 10
+ EXPECT_EQ(7, cache_.NearAddress(2)); // slot 2: 3 => 7
+ EXPECT_EQ(8, cache_.NearAddress(3)); // slot 3: 4 => 8
+ 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)));
+}
+
+// Exercises all four addressing mode types by encoding five values
+// with EncodeAddress.
+// Checks to see that the proper mode was selected in each case,
+// and that the encoding is correct.
+//
+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); // SELF mode: addr 0x0000FFFF
+ ExpectEncodedVarint(0x10, 1); // HERE mode: here - 0x10 = 0x10000000
+ ExpectEncodedVarint(0x04, 1); // NEAR cache #1:
+ // last addr + 0x4 = 0x10000004
+ ExpectEncodedVarint(0x32, 1); // HERE mode: here - 0x32 = 0x0FFFFFFE
+ ExpectEncodedByte(0x04); // SAME cache #1: 0x10000004 hits
+}
+
+// Exercises all four addressing mode types by manually encoding six values
+// and calling DecodeAddress on each one.
+//
+TEST_F(VCDiffAddressCacheTest, DecodeAddressModes) {
+ ManualEncodeVarint(0xCAFE);
+ ManualEncodeVarint(0xCAFE);
+ ManualEncodeVarint(0x1000);
+ ManualEncodeByte(0xFE); // SAME mode uses a byte, not a Varint
+ 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)); // a byte, not a Varint
+ EXPECT_EQ(0xFE,
+ cache_.DecodeAddress(0x50000,
+ VCD_SELF_MODE,
+ &decode_position_,
+ decode_position_end_));
+ ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xFE));
+ // NEAR mode #0 has been overwritten by fifth computed addr (wrap around)
+ EXPECT_EQ(0x10FE,
+ cache_.DecodeAddress(0x60000,
+ cache_.FirstNearMode(),
+ &decode_position_,
+ decode_position_end_));
+ ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0x1000));
+}
+
+// Test with both cache sizes == 0. The encoder should not choose
+// a SAME or NEAR mode under these conditions.
+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); // Should not modify decode_position_
+}
+
+TEST_F(VCDiffAddressCacheDeathTest, DecodeZeroOrNegativeHereAddress) {
+ ManualEncodeVarint(0xCAFE);
+ ManualEncodeVarint(0xCAFE);
+ BeginDecode();
+ // Using a Debug build, the check will fail; using a Release build,
+ // the check will not occur, and the SELF mode does not depend on
+ // the value of here_address, so DecodeAddress() will succeed.
+ EXPECT_DEBUG_DEATH(cache_.DecodeAddress(-1,
+ VCD_SELF_MODE,
+ &decode_position_,
+ decode_position_end_),
+ "negative");
+ // A zero value for here_address should not kill the decoder,
+ // but instead should return an error value. A delta file may contain
+ // a window that has no source segment and that (erroneously)
+ // uses a COPY instruction as its first instruction. This should
+ // cause an error to be reported, not a debug check failure.
+ EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0,
+ VCD_SELF_MODE,
+ &decode_position_,
+ decode_position_end_));
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+TEST_F(VCDiffAddressCacheTest, DecodeAddressPastHereAddress) {
+ ManualEncodeVarint(0xCAFE);
+ BeginDecode();
+ EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x1000,
+ VCD_SELF_MODE,
+ &decode_position_,
+ decode_position_end_));
+ ExpectDecodedSizeInBytes(0); // Should not modify decode_position_
+}
+
+TEST_F(VCDiffAddressCacheTest, HereModeAddressTooLarge) {
+ ManualEncodeVarint(0x10001); // here_address + 1
+ BeginDecode();
+ EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x10000,
+ VCD_HERE_MODE,
+ &decode_position_,
+ decode_position_end_));
+ ExpectDecodedSizeInBytes(0); // Should not modify decode_position_
+}
+
+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));
+ // Now decode a NEAR mode address of base address 0xCAFE
+ // (the first decoded address) + offset 0x7FFFFFFF. This will cause
+ // an integer overflow and should signal an error.
+ EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x10000000,
+ cache_.FirstNearMode(),
+ &decode_position_,
+ decode_position_end_));
+ ExpectDecodedSizeInBytes(0); // Should not modify decode_position_
+}
+
+// A Varint should contain at most 9 bytes that have their continuation bit
+// (the uppermost, or 7 bit) set. A longer string of bytes that all have
+// bit 7 set is not a valid Varint. Try to parse such a string as a Varint
+// and confirm that it does not run off the end of the input buffer and
+// it returns an error value (RESULT_ERROR).
+//
+TEST_F(VCDiffAddressCacheTest, DecodeInvalidVarint) {
+ address_stream_.clear();
+ // Write 512 0xFE bytes
+ 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); // Should not modify decode_position_
+}
+
+// If only part of a Varint appears in the data to be decoded,
+// then DecodeAddress should return RESULT_END_OF_DATA,
+// which means that the Varint *may* be valid if there is more
+// data expected to be returned.
+//
+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); // Should not modify decode_position_
+ // Now add the missing last byte (supposedly read from a stream of data)
+ // and verify that the Varint is now valid.
+ ManualEncodeByte(0x01); // End the Varint with an additional byte
+ BeginDecode(); // Reset read position to start of data
+ EXPECT_EQ(0xFDFBF01,
+ cache_.DecodeAddress(0x10000000,
+ VCD_SELF_MODE,
+ &decode_position_,
+ decode_position_end_));
+ ExpectDecodedSizeInBytes(4); // ManualEncodeByte was called for 4 byte values
+}
+
+#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 // GTEST_HAS_DEATH_TEST
+
+TEST_F(VCDiffAddressCacheTest, DecodeInvalidHereAddress) {
+ ManualEncodeVarint(0x10001); // offset larger than here_address
+ 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); // offset will cause integer overflow
+ 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); // populate large_address_stream_, mode_stream_
+}
+
+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; // 20K random encode/decode operations
+ const int num_iterations = 40; // run test 40 times and take average
+ 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;
+ }
+}
+
+} // unnamed namespace
+} // namespace open_vcdiff