diff options
Diffstat (limited to 'src/vcdecoder_test.cc')
-rw-r--r-- | src/vcdecoder_test.cc | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/src/vcdecoder_test.cc b/src/vcdecoder_test.cc new file mode 100644 index 0000000..e4681a9 --- /dev/null +++ b/src/vcdecoder_test.cc @@ -0,0 +1,280 @@ +// 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 "vcdecoder_test.h" +#include <string.h> // strlen +#include "checksum.h" +#include "codetable.h" +#include "testing.h" +#include "varint_bigendian.h" +#include "vcdiff_defs.h" + +namespace open_vcdiff { + +const char VCDiffDecoderTest::kStandardFileHeader[] = { + 0xD6, // 'V' | 0x80 + 0xC3, // 'C' | 0x80 + 0xC4, // 'D' | 0x80 + 0x00, // Draft standard version number + 0x00 // Hdr_Indicator: no custom code table, no compression + }; + +const char VCDiffDecoderTest::kInterleavedFileHeader[] = { + 0xD6, // 'V' | 0x80 + 0xC3, // 'C' | 0x80 + 0xC4, // 'D' | 0x80 + 'S', // SDCH version code + 0x00 // Hdr_Indicator: no custom code table, no compression + }; + +const char VCDiffDecoderTest::kDictionary[] = + "\"Just the place for a Snark!\" the Bellman cried,\n" + "As he landed his crew with care;\n" + "Supporting each man on the top of the tide\n" + "By a finger entwined in his hair.\n"; + +const char VCDiffDecoderTest::kExpectedTarget[] = + "\"Just the place for a Snark! I have said it twice:\n" + "That alone should encourage the crew.\n" + "Just the place for a Snark! I have said it thrice:\n" + "What I tell you three times is true.\"\n"; + +VCDiffDecoderTest::VCDiffDecoderTest() : fuzzer_(0), fuzzed_byte_position_(0) { + dictionary_ = kDictionary; + expected_target_ = kExpectedTarget; +} + +void VCDiffDecoderTest::SetUp() { + InitializeDeltaFile(); +} + +void VCDiffDecoderTest::UseStandardFileHeader() { + delta_file_header_.assign(kStandardFileHeader, + sizeof(kStandardFileHeader)); +} + +void VCDiffDecoderTest::UseInterleavedFileHeader() { + delta_file_header_.assign(kInterleavedFileHeader, + sizeof(kInterleavedFileHeader)); +} + +void VCDiffDecoderTest::InitializeDeltaFile() { + delta_file_ = delta_file_header_ + delta_window_header_ + delta_window_body_; +} + +char VCDiffDecoderTest::GetByteFromStringLength(const char* s, + int which_byte) { + char varint_buf[VarintBE<int32_t>::kMaxBytes]; + VarintBE<int32_t>::Encode(static_cast<int32_t>(strlen(s)), varint_buf); + return varint_buf[which_byte]; +} + +void VCDiffDecoderTest::AddChecksum(VCDChecksum checksum) { + int32_t checksum_as_int32 = static_cast<int32_t>(checksum); + delta_window_header_[0] |= VCD_CHECKSUM; + VarintBE<int32_t>::AppendToString(checksum_as_int32, &delta_window_header_); + // Adjust delta window size to include checksum. + // This method wouldn't work if adding to the length caused the VarintBE + // value to spill over into another byte. Luckily, this test data happens + // not to cause such an overflow. + delta_window_header_[4] += VarintBE<int32_t>::Length(checksum_as_int32); +} + +void VCDiffDecoderTest::ComputeAndAddChecksum() { + AddChecksum(ComputeAdler32(expected_target_.data(), + expected_target_.size())); +} + +// Write the maximum expressible positive 32-bit VarintBE +// (0x7FFFFFFF) at the given offset in the delta window. +void VCDiffDecoderTest::WriteMaxVarintAtOffset(int offset, + int bytes_to_replace) { + static const char kMaxVarint[] = { 0x87, 0xFF, 0xFF, 0xFF, 0x7F }; + delta_file_.replace(delta_file_header_.size() + offset, + bytes_to_replace, + kMaxVarint, + sizeof(kMaxVarint)); +} + +// Write a negative 32-bit VarintBE (0x80000000) at the given offset +// in the delta window. +void VCDiffDecoderTest::WriteNegativeVarintAtOffset(int offset, + int bytes_to_replace) { + static const char kNegativeVarint[] = { 0x88, 0x80, 0x80, 0x80, 0x00 }; + delta_file_.replace(delta_file_header_.size() + offset, + bytes_to_replace, + kNegativeVarint, + sizeof(kNegativeVarint)); +} + +// Write a VarintBE that has too many continuation bytes +// at the given offset in the delta window. +void VCDiffDecoderTest::WriteInvalidVarintAtOffset(int offset, + int bytes_to_replace) { + static const char kInvalidVarint[] = { 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F }; + delta_file_.replace(delta_file_header_.size() + offset, + bytes_to_replace, + kInvalidVarint, + sizeof(kInvalidVarint)); +} + +bool VCDiffDecoderTest::FuzzOneByteInDeltaFile() { + static const struct Fuzzer { + char _and; + char _or; + char _xor; + } fuzzers[] = { + { 0xff, 0x80, 0x00 }, + { 0xff, 0xff, 0x00 }, + { 0xff, 0x00, 0x80 }, + { 0xff, 0x00, 0xff }, + { 0xff, 0x01, 0x00 }, + { 0x7f, 0x00, 0x00 }, + }; + + for (; fuzzer_ < (sizeof(fuzzers) / sizeof(fuzzers[0])); ++fuzzer_) { + for (; fuzzed_byte_position_ < delta_file_.size(); + ++fuzzed_byte_position_) { + char fuzzed_byte = (((delta_file_[fuzzed_byte_position_] + & fuzzers[fuzzer_]._and) + | fuzzers[fuzzer_]._or) + ^ fuzzers[fuzzer_]._xor); + if (fuzzed_byte != delta_file_[fuzzed_byte_position_]) { + delta_file_[fuzzed_byte_position_] = fuzzed_byte; + ++fuzzed_byte_position_; + return true; + } + } + fuzzed_byte_position_ = 0; + } + return false; +} + +const char VCDiffStandardDecoderTest::kWindowHeader[] = { + VCD_SOURCE, // Win_Indicator: take source from dictionary + FirstByteOfStringLength(kDictionary), // Source segment size + SecondByteOfStringLength(kDictionary), + 0x00, // Source segment position: start of dictionary + 0x79, // Length of the delta encoding + FirstByteOfStringLength(kExpectedTarget), // Size of the target window + SecondByteOfStringLength(kExpectedTarget), + 0x00, // Delta_indicator (no compression) + 0x64, // length of data for ADDs and RUNs + 0x0C, // length of instructions section + 0x03 // length of addresses for COPYs + }; + +const char VCDiffStandardDecoderTest::kWindowBody[] = { + // Data for ADDs: 1st section (length 61) + ' ', 'I', ' ', 'h', 'a', 'v', 'e', ' ', 's', 'a', 'i', 'd', ' ', + 'i', 't', ' ', 't', 'w', 'i', 'c', 'e', ':', '\n', + 'T', 'h', 'a', 't', ' ', + 'a', 'l', 'o', 'n', 'e', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ', + 'e', 'n', 'c', 'o', 'u', 'r', 'a', 'g', 'e', ' ', + 't', 'h', 'e', ' ', 'c', 'r', 'e', 'w', '.', '\n', + // Data for ADDs: 2nd section (length 2) + 'h', 'r', + // Data for ADDs: 3rd section (length 9) + 'W', 'h', 'a', 't', ' ', + 'I', ' ', 't', 'e', + // Data for RUN: 4th section (length 1) + 'l', + // Data for ADD: 4th section (length 27) + ' ', 'y', 'o', 'u', ' ', + 't', 'h', 'r', 'e', 'e', ' ', 't', 'i', 'm', 'e', 's', ' ', 'i', 's', ' ', + 't', 'r', 'u', 'e', '.', '\"', '\n', + // Instructions and sizes (length 13) + 0x13, // VCD_COPY mode VCD_SELF, size 0 + 0x1C, // Size of COPY (28) + 0x01, // VCD_ADD size 0 + 0x3D, // Size of ADD (61) + 0x23, // VCD_COPY mode VCD_HERE, size 0 + 0x2C, // Size of COPY (44) + 0xCB, // VCD_ADD size 2 + VCD_COPY mode NEAR(1), size 5 + 0x0A, // VCD_ADD size 9 + 0x00, // VCD_RUN size 0 + 0x02, // Size of RUN (2) + 0x01, // VCD_ADD size 0 + 0x1B, // Size of ADD (27) + // Addresses for COPYs (length 3) + 0x00, // Start of dictionary + 0x58, // HERE mode address for 2nd copy (27+61 back from here_address) + 0x2D // NEAR(1) mode address for 2nd copy (45 after prior address) + }; + +VCDiffStandardDecoderTest::VCDiffStandardDecoderTest() { + UseStandardFileHeader(); + delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader)); + delta_window_body_.assign(kWindowBody, sizeof(kWindowBody)); +} + +const char VCDiffInterleavedDecoderTest::kWindowHeader[] = { + VCD_SOURCE, // Win_Indicator: take source from dictionary + FirstByteOfStringLength(kDictionary), // Source segment size + SecondByteOfStringLength(kDictionary), + 0x00, // Source segment position: start of dictionary + 0x79, // Length of the delta encoding + FirstByteOfStringLength(kExpectedTarget), // Size of the target window + SecondByteOfStringLength(kExpectedTarget), + 0x00, // Delta_indicator (no compression) + 0x00, // length of data for ADDs and RUNs (unused) + 0x73, // length of interleaved section + 0x00 // length of addresses for COPYs (unused) + }; + +const char VCDiffInterleavedDecoderTest::kWindowBody[] = { + 0x13, // VCD_COPY mode VCD_SELF, size 0 + 0x1C, // Size of COPY (28) + 0x00, // Address of COPY: Start of dictionary + 0x01, // VCD_ADD size 0 + 0x3D, // Size of ADD (61) + // Data for ADD (length 61) + ' ', 'I', ' ', 'h', 'a', 'v', 'e', ' ', 's', 'a', 'i', 'd', ' ', + 'i', 't', ' ', 't', 'w', 'i', 'c', 'e', ':', '\n', + 'T', 'h', 'a', 't', ' ', + 'a', 'l', 'o', 'n', 'e', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ', + 'e', 'n', 'c', 'o', 'u', 'r', 'a', 'g', 'e', ' ', + 't', 'h', 'e', ' ', 'c', 'r', 'e', 'w', '.', '\n', + 0x23, // VCD_COPY mode VCD_HERE, size 0 + 0x2C, // Size of COPY (44) + 0x58, // HERE mode address (27+61 back from here_address) + 0xCB, // VCD_ADD size 2 + VCD_COPY mode NEAR(1), size 5 + // Data for ADDs: 2nd section (length 2) + 'h', 'r', + 0x2D, // NEAR(1) mode address (45 after prior address) + 0x0A, // VCD_ADD size 9 + // Data for ADDs: 3rd section (length 9) + 'W', 'h', 'a', 't', ' ', + 'I', ' ', 't', 'e', + 0x00, // VCD_RUN size 0 + 0x02, // Size of RUN (2) + // Data for RUN: 4th section (length 1) + 'l', + 0x01, // VCD_ADD size 0 + 0x1B, // Size of ADD (27) + // Data for ADD: 4th section (length 27) + ' ', 'y', 'o', 'u', ' ', + 't', 'h', 'r', 'e', 'e', ' ', 't', 'i', 'm', 'e', 's', ' ', 'i', 's', ' ', + 't', 'r', 'u', 'e', '.', '\"', '\n' + }; + +VCDiffInterleavedDecoderTest::VCDiffInterleavedDecoderTest() { + UseInterleavedFileHeader(); + delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader)); + delta_window_body_.assign(kWindowBody, sizeof(kWindowBody)); +} + +} // namespace open_vcdiff |