aboutsummaryrefslogtreecommitdiff
path: root/src/vcdecoder_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/vcdecoder_test.cc')
-rw-r--r--src/vcdecoder_test.cc280
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