| // 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 |