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