// 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 "headerparser.h" #include <stdlib.h> // rand, srand #include <string> #include <vector> #include "testing.h" #include "varint_bigendian.h" namespace open_vcdiff { namespace { // anonymous using std::vector; class VCDiffHeaderParserTest : public testing::Test { protected: typedef std::string string; static const int kTestSize = 1024; VCDiffHeaderParserTest() : parser(NULL) { } virtual ~VCDiffHeaderParserTest() { delete parser; } virtual void SetUp() { srand(1); // make sure each test uses the same data set } void StartParsing() { parser = new VCDiffHeaderParser( encoded_buffer_.data(), encoded_buffer_.data() + encoded_buffer_.size()); EXPECT_EQ(encoded_buffer_.data(), parser->UnparsedData()); } void VerifyByte(unsigned char expected_value) { unsigned char decoded_byte = 0; const char* prior_position = parser->UnparsedData(); EXPECT_TRUE(parser->ParseByte(&decoded_byte)); EXPECT_EQ(expected_value, decoded_byte); EXPECT_EQ(RESULT_SUCCESS, parser->GetResult()); EXPECT_EQ(prior_position + sizeof(unsigned char), parser->UnparsedData()); } void VerifyInt32(int32_t expected_value) { int32_t decoded_integer = 0; const char* prior_position = parser->UnparsedData(); EXPECT_TRUE(parser->ParseInt32("decoded int32", &decoded_integer)); EXPECT_EQ(expected_value, decoded_integer); EXPECT_EQ(RESULT_SUCCESS, parser->GetResult()); EXPECT_EQ(prior_position + VarintBE<int32_t>::Length(decoded_integer), parser->UnparsedData()); } void VerifyUInt32(uint32_t expected_value) { uint32_t decoded_integer = 0; const char* prior_position = parser->UnparsedData(); EXPECT_TRUE(parser->ParseUInt32("decoded uint32", &decoded_integer)); EXPECT_EQ(expected_value, decoded_integer); EXPECT_EQ(RESULT_SUCCESS, parser->GetResult()); EXPECT_EQ(prior_position + VarintBE<int64_t>::Length(decoded_integer), parser->UnparsedData()); } void VerifyChecksum(VCDChecksum expected_value) { VCDChecksum decoded_checksum = 0; const char* prior_position = parser->UnparsedData(); EXPECT_TRUE(parser->ParseChecksum("decoded checksum", &decoded_checksum)); EXPECT_EQ(expected_value, decoded_checksum); EXPECT_EQ(RESULT_SUCCESS, parser->GetResult()); EXPECT_EQ(prior_position + VarintBE<int64_t>::Length(decoded_checksum), parser->UnparsedData()); } string encoded_buffer_; VCDiffHeaderParser* parser; }; TEST_F(VCDiffHeaderParserTest, ParseRandomBytes) { vector<unsigned char> byte_values; for (int i = 0; i < kTestSize; ++i) { unsigned char random_byte = PortableRandomInRange<unsigned char>(0xFF); encoded_buffer_.push_back(random_byte); byte_values.push_back(random_byte); } StartParsing(); for (int position = 0; position < kTestSize; ++position) { VerifyByte(byte_values[position]); } unsigned char decoded_byte = 0; EXPECT_FALSE(parser->ParseByte(&decoded_byte)); EXPECT_EQ(RESULT_END_OF_DATA, parser->GetResult()); EXPECT_EQ(encoded_buffer_.data() + encoded_buffer_.size(), parser->UnparsedData()); } TEST_F(VCDiffHeaderParserTest, ParseRandomInt32) { vector<int32_t> integer_values; for (int i = 0; i < kTestSize; ++i) { int32_t random_integer = PortableRandomInRange<int32_t>(0x7FFFFFFF); VarintBE<int32_t>::AppendToString(random_integer, &encoded_buffer_); integer_values.push_back(random_integer); } StartParsing(); for (int i = 0; i < kTestSize; ++i) { VerifyInt32(integer_values[i]); } int32_t decoded_integer = 0; EXPECT_FALSE(parser->ParseInt32("decoded integer", &decoded_integer)); EXPECT_EQ(RESULT_END_OF_DATA, parser->GetResult()); EXPECT_EQ(encoded_buffer_.data() + encoded_buffer_.size(), parser->UnparsedData()); } TEST_F(VCDiffHeaderParserTest, ParseRandomUInt32) { vector<uint32_t> integer_values; for (int i = 0; i < kTestSize; ++i) { uint32_t random_integer = PortableRandomInRange<uint32_t>(0xFFFFFFFF); VarintBE<int64_t>::AppendToString(random_integer, &encoded_buffer_); integer_values.push_back(random_integer); } StartParsing(); uint32_t decoded_integer = 0; for (int i = 0; i < kTestSize; ++i) { VerifyUInt32(integer_values[i]); } EXPECT_FALSE(parser->ParseUInt32("decoded integer", &decoded_integer)); EXPECT_EQ(RESULT_END_OF_DATA, parser->GetResult()); EXPECT_EQ(encoded_buffer_.data() + encoded_buffer_.size(), parser->UnparsedData()); } TEST_F(VCDiffHeaderParserTest, ParseRandomChecksum) { vector<VCDChecksum> checksum_values; for (int i = 0; i < kTestSize; ++i) { VCDChecksum random_checksum = PortableRandomInRange<VCDChecksum>(0xFFFFFFFF); VarintBE<int64_t>::AppendToString(random_checksum, &encoded_buffer_); checksum_values.push_back(random_checksum); } StartParsing(); for (int i = 0; i < kTestSize; ++i) { VerifyChecksum(checksum_values[i]); } VCDChecksum decoded_checksum = 0; EXPECT_FALSE(parser->ParseChecksum("decoded checksum", &decoded_checksum)); EXPECT_EQ(RESULT_END_OF_DATA, parser->GetResult()); EXPECT_EQ(encoded_buffer_.data() + encoded_buffer_.size(), parser->UnparsedData()); } TEST_F(VCDiffHeaderParserTest, ParseMixed) { VarintBE<int64_t>::AppendToString(0xCAFECAFE, &encoded_buffer_); encoded_buffer_.push_back(0xFF); VarintBE<int32_t>::AppendToString(0x02020202, &encoded_buffer_); VarintBE<int64_t>::AppendToString(0xCAFECAFE, &encoded_buffer_); encoded_buffer_.push_back(0xFF); encoded_buffer_.push_back(0xFF); StartParsing(); VerifyUInt32(0xCAFECAFE); VerifyByte(0xFF); VerifyInt32(0x02020202); VerifyChecksum(0xCAFECAFE); int32_t incomplete_int32 = 0; EXPECT_FALSE(parser->ParseInt32("incomplete Varint", &incomplete_int32)); EXPECT_EQ(0, incomplete_int32); EXPECT_EQ(RESULT_END_OF_DATA, parser->GetResult()); EXPECT_EQ(encoded_buffer_.data() + encoded_buffer_.size() - 2, parser->UnparsedData()); } TEST_F(VCDiffHeaderParserTest, ParseInvalidVarint) { // Start with a byte that has the continuation bit plus a high-order bit set encoded_buffer_.append(1, static_cast<char>(0xC0)); // Add too many bytes with continuation bits encoded_buffer_.append(6, static_cast<char>(0x80)); StartParsing(); int32_t invalid_int32 = 0; EXPECT_FALSE(parser->ParseInt32("invalid Varint", &invalid_int32)); EXPECT_EQ(0, invalid_int32); EXPECT_EQ(RESULT_ERROR, parser->GetResult()); EXPECT_EQ(encoded_buffer_.data(), parser->UnparsedData()); // After the parse failure, any other call to Parse... should return an error, // even though there is still a byte that could be read as valid. unsigned char decoded_byte = 0; EXPECT_FALSE(parser->ParseByte(&decoded_byte)); EXPECT_EQ(0, decoded_byte); EXPECT_EQ(RESULT_ERROR, parser->GetResult()); EXPECT_EQ(encoded_buffer_.data(), parser->UnparsedData()); } } // namespace open_vcdiff } // anonymous namespace