// Copyright 2008 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 "varint_bigendian.h" #include <stdlib.h> // rand, srand #include <string.h> // strlen #include <string> #include <vector> #include "testing.h" namespace open_vcdiff { namespace { class VarintBETestCommon : public testing::Test { protected: typedef std::string string; VarintBETestCommon() : varint_buf_(VarintBE<int64_t>::kMaxBytes), verify_encoded_byte_index_(0), verify_expected_length_(0), parse_data_ptr_(parse_data_all_FFs) { } virtual ~VarintBETestCommon() { } void ExpectEncodedByte(char expected_byte) { EXPECT_EQ(expected_byte, varint_buf_[verify_encoded_byte_index_]); EXPECT_EQ(expected_byte, s_[verify_encoded_byte_index_]); ++verify_encoded_byte_index_; } static const char parse_data_all_FFs[]; static const char parse_data_CADA1[]; std::vector<char> varint_buf_; string s_; int verify_encoded_byte_index_; int verify_expected_length_; const char* parse_data_ptr_; }; template <typename SignedIntegerType> class VarintBETestTemplate : public VarintBETestCommon { protected: VarintBETestTemplate() { } virtual ~VarintBETestTemplate() { } typedef SignedIntegerType SignedIntType; typedef VarintBE<SignedIntegerType> VarintType; void StartEncodingTest(SignedIntegerType v, int expected_length) { verify_expected_length_ = expected_length; EXPECT_EQ(expected_length, VarintType::Length(v)); EXPECT_EQ(expected_length, VarintType::Encode(v, &varint_buf_[0])); VarintType::AppendToString(v, &s_); EXPECT_EQ(static_cast<size_t>(expected_length), s_.length()); } void TestEncodeInvalid(SignedIntegerType v) { EXPECT_DEATH(VarintType::Length(v), "v >= 0"); EXPECT_DEATH(VarintType::Encode(v, &varint_buf_[0]), "v >= 0"); EXPECT_DEATH(VarintType::AppendToString(v, &s_), ">= 0"); } // Need one function for each test type that will be applied to // multiple classes void TemplateTestDISABLED_EncodeNegative(); void TemplateTestEncodeZero(); void TemplateTestEncodeEightBits(); void TemplateTestEncodeCADAD1A(); void TemplateTestEncode32BitMaxInt(); void TemplateTestEncodeDoesNotOverwriteExistingString(); void TemplateTestParseNullPointer(); void TemplateTestEndPointerPrecedesBeginning(); void TemplateTestParseVarintTooLong(); void TemplateTestParseZero(); void TemplateTestParseCADA1(); void TemplateTestParseEmpty(); void TemplateTestParse123456789(); void TemplateTestDecode31Bits(); void TemplateTestEncodeDecodeRandom(); void TemplateTestContinuationBytesPastEndOfInput(); }; typedef VarintBETestTemplate<int32_t> VarintBEInt32Test; typedef VarintBETestTemplate<int64_t> VarintBEInt64Test; #ifdef GTEST_HAS_DEATH_TEST // These synonyms are needed for the tests that use ASSERT_DEATH typedef VarintBEInt32Test VarintBEInt32DeathTest; typedef VarintBEInt64Test VarintBEInt64DeathTest; #endif // GTEST_HAS_DEATH_TEST const char VarintBETestCommon::parse_data_all_FFs[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; const char VarintBETestCommon::parse_data_CADA1[] = { 0xCA, 0xDA, 0x01 }; // A macro to allow defining tests once and having them run against // both VarintBE<int32_t> and VarintBE<int64_t>. // #define TEMPLATE_TEST_F(TEST_TYPE, TEST_NAME) \ TEST_F(VarintBEInt32##TEST_TYPE, TEST_NAME) { \ TemplateTest##TEST_NAME(); \ } \ TEST_F(VarintBEInt64##TEST_TYPE, TEST_NAME) { \ TemplateTest##TEST_NAME(); \ } \ template <class CacheType> \ void VarintBETestTemplate<CacheType>::TemplateTest##TEST_NAME() // Encoding tests: Length(), Encode(), AppendToString(), AppendToBuffer() #ifdef GTEST_HAS_DEATH_TEST // This test hangs for non-debug build (DeathTest threading problem) TEMPLATE_TEST_F(DeathTest, DISABLED_EncodeNegative) { TestEncodeInvalid(-1); } #endif // GTEST_HAS_DEATH_TEST TEMPLATE_TEST_F(Test, EncodeZero) { StartEncodingTest(/* value */ 0x00, /* expected length */ 1); ExpectEncodedByte(0x00); EXPECT_EQ(verify_expected_length_, verify_encoded_byte_index_); } TEMPLATE_TEST_F(Test, EncodeEightBits) { StartEncodingTest(/* value */ 0xFF, /* expected length */ 2); ExpectEncodedByte(0x81); ExpectEncodedByte(0x7F); EXPECT_EQ(verify_expected_length_, verify_encoded_byte_index_); } TEMPLATE_TEST_F(Test, EncodeCADAD1A) { StartEncodingTest(/* value */ 0x0CADAD1A, /* expected length */ 4); ExpectEncodedByte(0xE5); ExpectEncodedByte(0xB6); ExpectEncodedByte(0xDA); ExpectEncodedByte(0x1A); EXPECT_EQ(verify_expected_length_, verify_encoded_byte_index_); } TEMPLATE_TEST_F(Test, Encode32BitMaxInt) { StartEncodingTest(/* value */ 0x7FFFFFFF, /* expected length */ 5); ExpectEncodedByte(0x87); ExpectEncodedByte(0xFF); ExpectEncodedByte(0xFF); ExpectEncodedByte(0xFF); ExpectEncodedByte(0x7F); EXPECT_EQ(verify_expected_length_, verify_encoded_byte_index_); } #ifdef GTEST_HAS_DEATH_TEST // This test hangs for non-debug build (DeathTest threading problem) TEST_F(VarintBEInt32DeathTest, DISABLED_Encode32BitsTooBig) { TestEncodeInvalid(0x80000000); } #endif // GTEST_HAS_DEATH_TEST TEST_F(VarintBEInt64Test, Encode32Bits) { StartEncodingTest(/* value */ 0x80000000, /* expected length */ 5); ExpectEncodedByte(0x88); ExpectEncodedByte(0x80); ExpectEncodedByte(0x80); ExpectEncodedByte(0x80); ExpectEncodedByte(0x00); EXPECT_EQ(verify_expected_length_, verify_encoded_byte_index_); } TEST_F(VarintBEInt64Test, Encode63Bits) { StartEncodingTest(/* value */ 0x7FFFFFFFFFFFFFFFULL, /* expected length */ 9); ExpectEncodedByte(0xFF); ExpectEncodedByte(0xFF); ExpectEncodedByte(0xFF); ExpectEncodedByte(0xFF); ExpectEncodedByte(0xFF); ExpectEncodedByte(0xFF); ExpectEncodedByte(0xFF); ExpectEncodedByte(0xFF); ExpectEncodedByte(0x7F); EXPECT_EQ(verify_expected_length_, verify_encoded_byte_index_); } #ifdef GTEST_HAS_DEATH_TEST // This test hangs for non-debug build (DeathTest threading problem) TEST_F(VarintBEInt64DeathTest, DISABLED_Encode64BitsTooBig) { TestEncodeInvalid(0x8000000000000000ULL); } #endif // GTEST_HAS_DEATH_TEST TEMPLATE_TEST_F(Test, EncodeDoesNotOverwriteExistingString) { s_.append("Test"); VarintType::AppendToString('1', &s_); EXPECT_EQ(strlen("Test1"), s_.length()); EXPECT_EQ("Test1", s_); } // Decoding tests: Parse(), ParseFromBuffer() TEMPLATE_TEST_F(Test, ParseVarintTooLong) { EXPECT_EQ(RESULT_ERROR, VarintType::Parse(parse_data_ptr_ + VarintType::kMaxBytes, &parse_data_ptr_)); } TEST_F(VarintBEInt32Test, ParseFourFFs) { // For a 31-bit non-negative VarintBE, the sequence FF FF FF FF is invalid. // Even though the largest allowable 31-bit value occupies 5 bytes as a // Varint, it shouldn't have the highest bits set and so can't begin with FF. EXPECT_EQ(RESULT_ERROR, VarintType::Parse(parse_data_ptr_ + 4, &parse_data_ptr_)); } TEST_F(VarintBEInt32Test, ParseThreeFFs) { EXPECT_EQ(RESULT_END_OF_DATA, VarintType::Parse(parse_data_ptr_ + 3, &parse_data_ptr_)); } TEST_F(VarintBEInt64Test, ParseEightFFs) { // For a 63-bit non-negative VarintBE, a series of eight FFs is valid, because // the largest allowable 63-bit value is expressed as eight FF bytes followed // by a 7F byte. This is in contrast to the 32-bit case (see ParseFourFFs, // above.) EXPECT_EQ(RESULT_END_OF_DATA, VarintType::Parse(parse_data_ptr_ + 8, &parse_data_ptr_)); } TEMPLATE_TEST_F(Test, ParseZero) { const char zero_data[] = { 0x00 }; parse_data_ptr_ = zero_data; EXPECT_EQ(0x00, VarintType::Parse(parse_data_ptr_ + 1, &parse_data_ptr_)); EXPECT_EQ(zero_data + 1, parse_data_ptr_); } TEMPLATE_TEST_F(Test, ParseCADA1) { parse_data_ptr_ = parse_data_CADA1; EXPECT_EQ(0x12AD01, VarintType::Parse(parse_data_CADA1 + sizeof(parse_data_CADA1), &parse_data_ptr_)); EXPECT_EQ(parse_data_CADA1 + 3, parse_data_ptr_); } TEMPLATE_TEST_F(Test, ParseNullPointer) { parse_data_ptr_ = parse_data_CADA1; EXPECT_EQ(RESULT_ERROR, VarintType::Parse((const char*) NULL, &parse_data_ptr_)); } TEMPLATE_TEST_F(Test, EndPointerPrecedesBeginning) { // This is not an error. parse_data_ptr_ = parse_data_CADA1; EXPECT_EQ(RESULT_END_OF_DATA, VarintType::Parse(parse_data_ptr_ - 1, &parse_data_ptr_)); } TEMPLATE_TEST_F(Test, ParseEmpty) { EXPECT_EQ(RESULT_END_OF_DATA, VarintType::Parse(parse_data_ptr_, &parse_data_ptr_)); } // This example is taken from the Varint description in RFC 3284, section 2. TEMPLATE_TEST_F(Test, Parse123456789) { const char parse_data_123456789[] = { 0x80 + 58, 0x80 + 111, 0x80 + 26, 21 }; parse_data_ptr_ = parse_data_123456789; EXPECT_EQ(123456789, VarintType::Parse(parse_data_123456789 + sizeof(parse_data_123456789), &parse_data_ptr_)); } TEMPLATE_TEST_F(Test, Decode31Bits) { const char parse_data_31_bits[] = { 0x87, 0xFF, 0xFF, 0xFF, 0x7F }; parse_data_ptr_ = parse_data_31_bits; EXPECT_EQ(0x7FFFFFFF, VarintType::Parse(parse_data_31_bits + sizeof(parse_data_31_bits), &parse_data_ptr_)); } TEST_F(VarintBEInt32Test, Decode32Bits) { const char parse_data_32_bits[] = { 0x88, 0x80, 0x80, 0x80, 0x00 }; parse_data_ptr_ = parse_data_32_bits; EXPECT_EQ(RESULT_ERROR, VarintType::Parse(parse_data_32_bits + sizeof(parse_data_32_bits), &parse_data_ptr_)); } TEST_F(VarintBEInt64Test, Decode32Bits) { const char parse_data_32_bits[] = { 0x88, 0x80, 0x80, 0x80, 0x00 }; parse_data_ptr_ = parse_data_32_bits; EXPECT_EQ(0x80000000, VarintType::Parse(parse_data_32_bits + sizeof(parse_data_32_bits), &parse_data_ptr_)); } TEMPLATE_TEST_F(Test, EncodeDecodeRandom) { const int test_size = 1024; // 1K random encode/decode operations char encode_buffer[VarintType::kMaxBytes]; srand(1); for (int i = 0; i < test_size; ++i) { SignedIntType value = PortableRandomInRange(VarintType::kMaxVal); int length = VarintType::Encode(value, encode_buffer); EXPECT_EQ(length, VarintType::Length(value)); const char* parse_pointer = encode_buffer; EXPECT_EQ(value, VarintType::Parse(encode_buffer + sizeof(encode_buffer), &parse_pointer)); EXPECT_EQ(encode_buffer + length, parse_pointer); } for (int i = 0; i < test_size; ++i) { s_.clear(); SignedIntType value = PortableRandomInRange(VarintType::kMaxVal); VarintType::AppendToString(value, &s_); const int varint_length = static_cast<int>(s_.length()); EXPECT_EQ(VarintType::Length(value), varint_length); const char* parse_pointer = s_.c_str(); const char* const buffer_end_pointer = s_.c_str() + s_.length(); EXPECT_EQ(value, VarintType::Parse(buffer_end_pointer, &parse_pointer)); EXPECT_EQ(buffer_end_pointer, parse_pointer); } } // If only 10 bytes of data are available, but there are 20 continuation // bytes, Parse() should not read to the end of the continuation bytes. It is // legal (according to the RFC3284 spec) to use any number of continuation // bytes, but they should not cause us to read past the end of available input. TEMPLATE_TEST_F(Test, ContinuationBytesPastEndOfInput) { const char parse_data_20_continuations[] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00 }; parse_data_ptr_ = parse_data_20_continuations; EXPECT_EQ(RESULT_END_OF_DATA, VarintType::Parse(parse_data_20_continuations + 10, &parse_data_ptr_)); } } // anonymous namespace } // namespace open_vcdiff