diff options
Diffstat (limited to 'sdch/open-vcdiff/src/vcdecoder4_test.cc')
-rw-r--r-- | sdch/open-vcdiff/src/vcdecoder4_test.cc | 1063 |
1 files changed, 1063 insertions, 0 deletions
diff --git a/sdch/open-vcdiff/src/vcdecoder4_test.cc b/sdch/open-vcdiff/src/vcdecoder4_test.cc new file mode 100644 index 0000000..e1fc90f --- /dev/null +++ b/sdch/open-vcdiff/src/vcdecoder4_test.cc @@ -0,0 +1,1063 @@ +// 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 "google/vcdecoder.h" +#include <string> +#include "codetable.h" +#include "testing.h" +#include "vcdecoder_test.h" +#include "vcdiff_defs.h" // VCD_SOURCE + +namespace open_vcdiff { +namespace { + +// Use the interleaved file header with the standard encoding. Should work. +class VCDiffDecoderInterleavedAllowedButNotUsed + : public VCDiffStandardDecoderTest { + public: + VCDiffDecoderInterleavedAllowedButNotUsed() { + UseInterleavedFileHeader(); + } + virtual ~VCDiffDecoderInterleavedAllowedButNotUsed() { } +}; + +TEST_F(VCDiffDecoderInterleavedAllowedButNotUsed, Decode) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +TEST_F(VCDiffDecoderInterleavedAllowedButNotUsed, DecodeWithChecksum) { + ComputeAndAddChecksum(); + InitializeDeltaFile(); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +typedef VCDiffDecoderInterleavedAllowedButNotUsed + VCDiffDecoderInterleavedAllowedButNotUsedByteByByte; + +TEST_F(VCDiffDecoderInterleavedAllowedButNotUsedByteByByte, Decode) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_)); + } + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +TEST_F(VCDiffDecoderInterleavedAllowedButNotUsedByteByByte, + DecodeWithChecksum) { + ComputeAndAddChecksum(); + InitializeDeltaFile(); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_)); + } + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +// Use the standard file header with the interleaved encoding. Should fail. +class VCDiffDecoderInterleavedUsedButNotSupported + : public VCDiffInterleavedDecoderTest { + public: + VCDiffDecoderInterleavedUsedButNotSupported() { + UseStandardFileHeader(); + } + virtual ~VCDiffDecoderInterleavedUsedButNotSupported() { } +}; + +TEST_F(VCDiffDecoderInterleavedUsedButNotSupported, DecodeShouldFail) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffDecoderInterleavedUsedButNotSupported, + DecodeByteByByteShouldFail) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + bool failed = false; + for (size_t i = 0; i < delta_file_.size(); ++i) { + if (!decoder_.DecodeChunk(&delta_file_[i], 1, &output_)) { + failed = true; + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +// Divides up the standard encoding into eight separate delta file windows. +// Each delta instruction appears in its own window. +class VCDiffStandardWindowDecoderTest : public VCDiffDecoderTest { + protected: + static const size_t kWindow2Size = 61; + + VCDiffStandardWindowDecoderTest(); + virtual ~VCDiffStandardWindowDecoderTest() {} + + private: + static const char kWindowBody[]; +}; + +const size_t VCDiffStandardWindowDecoderTest::kWindow2Size; + +const char VCDiffStandardWindowDecoderTest::kWindowBody[] = { +// Window 1: + VCD_SOURCE, // Win_Indicator: take source from dictionary + FirstByteOfStringLength(kDictionary), // Source segment size + SecondByteOfStringLength(kDictionary), + 0x00, // Source segment position: start of dictionary + 0x08, // Length of the delta encoding + 0x1C, // Size of the target window (28) + 0x00, // Delta_indicator (no compression) + 0x00, // length of data for ADDs and RUNs + 0x02, // length of instructions section + 0x01, // length of addresses for COPYs + // No data for ADDs and RUNs + // Instructions and sizes (length 2) + 0x13, // VCD_COPY mode VCD_SELF, size 0 + 0x1C, // Size of COPY (28) + // Addresses for COPYs (length 1) + 0x00, // Start of dictionary +// Window 2: + 0x00, // Win_Indicator: No source segment (ADD only) + 0x44, // Length of the delta encoding + static_cast<char>(kWindow2Size), // Size of the target window (61) + 0x00, // Delta_indicator (no compression) + 0x3D, // length of data for ADDs and RUNs + 0x02, // length of instructions section + 0x00, // length of addresses for COPYs + // 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', + // Instructions and sizes (length 2) + 0x01, // VCD_ADD size 0 + 0x3D, // Size of ADD (61) + // No addresses for COPYs +// Window 3: + VCD_TARGET, // Win_Indicator: take source from decoded data + 0x59, // Source segment size: length of data decoded so far + 0x00, // Source segment position: start of decoded data + 0x08, // Length of the delta encoding + 0x2C, // Size of the target window + 0x00, // Delta_indicator (no compression) + 0x00, // length of data for ADDs and RUNs + 0x02, // length of instructions section + 0x01, // length of addresses for COPYs + // No data for ADDs and RUNs + // Instructions and sizes (length 2) + 0x23, // VCD_COPY mode VCD_HERE, size 0 + 0x2C, // Size of COPY (44) + // Addresses for COPYs (length 1) + 0x58, // HERE mode address (27+61 back from here_address) +// Window 4: + VCD_TARGET, // Win_Indicator: take source from decoded data + 0x05, // Source segment size: only 5 bytes needed for this COPY + 0x2E, // Source segment position: offset for COPY + 0x09, // Length of the delta encoding + 0x07, // Size of the target window + 0x00, // Delta_indicator (no compression) + 0x02, // length of data for ADDs and RUNs + 0x01, // length of instructions section + 0x01, // length of addresses for COPYs + // Data for ADD (length 2) + 'h', 'r', + // Instructions and sizes (length 1) + 0xA7, // VCD_ADD size 2 + VCD_COPY mode SELF size 5 + // Addresses for COPYs (length 1) + 0x00, // SELF mode address (start of source segment) +// Window 5: + 0x00, // Win_Indicator: No source segment (ADD only) + 0x0F, // Length of the delta encoding + 0x09, // Size of the target window + 0x00, // Delta_indicator (no compression) + 0x09, // length of data for ADDs and RUNs + 0x01, // length of instructions section + 0x00, // length of addresses for COPYs + // Data for ADD (length 9) + 'W', 'h', 'a', 't', ' ', 'I', ' ', 't', 'e', + // Instructions and sizes (length 1) + 0x0A, // VCD_ADD size 9 + // No addresses for COPYs +// Window 6: + 0x00, // Win_Indicator: No source segment (RUN only) + 0x08, // Length of the delta encoding + 0x02, // Size of the target window + 0x00, // Delta_indicator (no compression) + 0x01, // length of data for ADDs and RUNs + 0x02, // length of instructions section + 0x00, // length of addresses for COPYs + // Data for RUN (length 1) + 'l', + // Instructions and sizes (length 2) + 0x00, // VCD_RUN size 0 + 0x02, // Size of RUN (2) + // No addresses for COPYs +// Window 7: + 0x00, // Win_Indicator: No source segment (ADD only) + 0x22, // Length of the delta encoding + 0x1B, // Size of the target window + 0x00, // Delta_indicator (no compression) + 0x1B, // length of data for ADDs and RUNs + 0x02, // length of instructions section + 0x00, // length of addresses for COPYs + // 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 2) + 0x01, // VCD_ADD size 0 + 0x1B, // Size of ADD (27) + // No addresses for COPYs + }; + +VCDiffStandardWindowDecoderTest::VCDiffStandardWindowDecoderTest() { + UseStandardFileHeader(); + delta_window_body_.assign(kWindowBody, sizeof(kWindowBody)); +} + +TEST_F(VCDiffStandardWindowDecoderTest, Decode) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +// Bug 1287926: If DecodeChunk() stops in the middle of the window header, +// and the expected size of the current target window is smaller than the +// cumulative target bytes decoded so far, an underflow occurs and the decoder +// tries to allocate ~MAX_INT bytes. +TEST_F(VCDiffStandardWindowDecoderTest, DecodeBreakInFourthWindowHeader) { + // Parse file header + first two windows. + const size_t chunk_1_size = delta_file_header_.size() + 83; + // Parse third window, plus everything up to "Size of the target window" field + // of fourth window, but do not parse complete header of fourth window. + const size_t chunk_2_size = 12 + 5; + CHECK_EQ(VCD_TARGET, static_cast<unsigned char>(delta_file_[chunk_1_size])); + CHECK_EQ(0x00, static_cast<int>(delta_file_[chunk_1_size + chunk_2_size])); + string output_chunk1, output_chunk2, output_chunk3; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0], + chunk_1_size, + &output_chunk1)); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[chunk_1_size], + chunk_2_size, + &output_chunk2)); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[chunk_1_size + chunk_2_size], + delta_file_.size() + - (chunk_1_size + chunk_2_size), + &output_chunk3)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_chunk1 + output_chunk2 + output_chunk3); +} + +TEST_F(VCDiffStandardWindowDecoderTest, DecodeChunkNoVcdTargetAllowed) { + decoder_.SetAllowVcdTarget(false); + // Parse file header + first two windows. + const size_t chunk_1_size = delta_file_header_.size() + 83; + // The third window begins with Win_Indicator = VCD_TARGET which is not + // allowed. + CHECK_EQ(VCD_TARGET, static_cast<unsigned char>(delta_file_[chunk_1_size])); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0], chunk_1_size, &output_)); + // Just parsing one more byte (the VCD_TARGET) should result in an error. + EXPECT_FALSE(decoder_.DecodeChunk(&delta_file_[chunk_1_size], 1, &output_)); + // The target data for the first two windows should have been output. + EXPECT_EQ(expected_target_.substr(0, 89), output_); +} + +TEST_F(VCDiffStandardWindowDecoderTest, DecodeInTwoParts) { + const size_t delta_file_size = delta_file_.size(); + for (size_t i = 1; i < delta_file_size; i++) { + string output_chunk1, output_chunk2; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0], + i, + &output_chunk1)); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], + delta_file_size - i, + &output_chunk2)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_chunk1 + output_chunk2); + } +} + +TEST_F(VCDiffStandardWindowDecoderTest, DecodeInThreeParts) { + const size_t delta_file_size = delta_file_.size(); + for (size_t i = 1; i < delta_file_size - 1; i++) { + for (size_t j = i + 1; j < delta_file_size; j++) { + string output_chunk1, output_chunk2, output_chunk3; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0], + i, + &output_chunk1)); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], + j - i, + &output_chunk2)); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[j], + delta_file_size - j, + &output_chunk3)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, + output_chunk1 + output_chunk2 + output_chunk3); + } + } +} + +// For the window test, the maximum target window size is much smaller than the +// target file size. (The largest window is Window 2, with 61 target bytes.) +// Use the minimum values possible. +TEST_F(VCDiffStandardWindowDecoderTest, TargetMatchesWindowSizeLimit) { + decoder_.SetMaximumTargetWindowSize(kWindow2Size); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +TEST_F(VCDiffStandardWindowDecoderTest, TargetMatchesFileSizeLimit) { + decoder_.SetMaximumTargetFileSize(expected_target_.size()); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +TEST_F(VCDiffStandardWindowDecoderTest, TargetExceedsWindowSizeLimit) { + decoder_.SetMaximumTargetWindowSize(kWindow2Size - 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffStandardWindowDecoderTest, TargetExceedsFileSizeLimit) { + decoder_.SetMaximumTargetFileSize(expected_target_.size() - 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +typedef VCDiffStandardWindowDecoderTest + VCDiffStandardWindowDecoderTestByteByByte; + +TEST_F(VCDiffStandardWindowDecoderTestByteByByte, Decode) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_)); + } + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +TEST_F(VCDiffStandardWindowDecoderTestByteByByte, DecodeExplicitVcdTarget) { + decoder_.SetAllowVcdTarget(true); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_)); + } + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +// Windows 3 and 4 use the VCD_TARGET flag, so decoder should signal an error. +TEST_F(VCDiffStandardWindowDecoderTestByteByByte, DecodeNoVcdTarget) { + decoder_.SetAllowVcdTarget(false); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + size_t i = 0; + for (; i < delta_file_.size(); ++i) { + if (!decoder_.DecodeChunk(&delta_file_[i], 1, &output_)) { + break; + } + } + // The failure should occur just at the position of the first VCD_TARGET. + EXPECT_EQ(delta_file_header_.size() + 83, i); + // The target data for the first two windows should have been output. + EXPECT_EQ(expected_target_.substr(0, 89), output_); +} + +// Divides up the interleaved encoding into eight separate delta file windows. +class VCDiffInterleavedWindowDecoderTest + : public VCDiffStandardWindowDecoderTest { + protected: + VCDiffInterleavedWindowDecoderTest(); + virtual ~VCDiffInterleavedWindowDecoderTest() {} + private: + static const char kWindowBody[]; +}; + +const char VCDiffInterleavedWindowDecoderTest::kWindowBody[] = { +// Window 1: + VCD_SOURCE, // Win_Indicator: take source from dictionary + FirstByteOfStringLength(kDictionary), // Source segment size + SecondByteOfStringLength(kDictionary), + 0x00, // Source segment position: start of dictionary + 0x08, // Length of the delta encoding + 0x1C, // Size of the target window (28) + 0x00, // Delta_indicator (no compression) + 0x00, // length of data for ADDs and RUNs + 0x03, // length of instructions section + 0x00, // length of addresses for COPYs + 0x13, // VCD_COPY mode VCD_SELF, size 0 + 0x1C, // Size of COPY (28) + 0x00, // Start of dictionary +// Window 2: + 0x00, // Win_Indicator: No source segment (ADD only) + 0x44, // Length of the delta encoding + 0x3D, // Size of the target window (61) + 0x00, // Delta_indicator (no compression) + 0x00, // length of data for ADDs and RUNs + 0x3F, // length of instructions section + 0x00, // length of addresses for COPYs + 0x01, // VCD_ADD size 0 + 0x3D, // Size of ADD (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', +// Window 3: + VCD_TARGET, // Win_Indicator: take source from decoded data + 0x59, // Source segment size: length of data decoded so far + 0x00, // Source segment position: start of decoded data + 0x08, // Length of the delta encoding + 0x2C, // Size of the target window + 0x00, // Delta_indicator (no compression) + 0x00, // length of data for ADDs and RUNs + 0x03, // length of instructions section + 0x00, // length of addresses for COPYs + 0x23, // VCD_COPY mode VCD_HERE, size 0 + 0x2C, // Size of COPY (44) + 0x58, // HERE mode address (27+61 back from here_address) +// Window 4: + VCD_TARGET, // Win_Indicator: take source from decoded data + 0x05, // Source segment size: only 5 bytes needed for this COPY + 0x2E, // Source segment position: offset for COPY + 0x09, // Length of the delta encoding + 0x07, // Size of the target window + 0x00, // Delta_indicator (no compression) + 0x00, // length of data for ADDs and RUNs + 0x04, // length of instructions section + 0x00, // length of addresses for COPYs + 0xA7, // VCD_ADD size 2 + VCD_COPY mode SELF, size 5 + 'h', 'r', + 0x00, // SELF mode address (start of source segment) +// Window 5: + 0x00, // Win_Indicator: No source segment (ADD only) + 0x0F, // Length of the delta encoding + 0x09, // Size of the target window + 0x00, // Delta_indicator (no compression) + 0x00, // length of data for ADDs and RUNs + 0x0A, // length of instructions section + 0x00, // length of addresses for COPYs + 0x0A, // VCD_ADD size 9 + 'W', 'h', 'a', 't', ' ', 'I', ' ', 't', 'e', +// Window 6: + 0x00, // Win_Indicator: No source segment (RUN only) + 0x08, // Length of the delta encoding + 0x02, // Size of the target window + 0x00, // Delta_indicator (no compression) + 0x00, // length of data for ADDs and RUNs + 0x03, // length of instructions section + 0x00, // length of addresses for COPYs + 0x00, // VCD_RUN size 0 + 0x02, // Size of RUN (2) + 'l', +// Window 7: + 0x00, // Win_Indicator: No source segment (ADD only) + 0x22, // Length of the delta encoding + 0x1B, // Size of the target window + 0x00, // Delta_indicator (no compression) + 0x00, // length of data for ADDs and RUNs + 0x1D, // length of instructions section + 0x00, // length of addresses for COPYs + 0x01, // VCD_ADD size 0 + 0x1B, // Size of ADD (27) + ' ', 'y', 'o', 'u', ' ', + 't', 'h', 'r', 'e', 'e', ' ', 't', 'i', 'm', 'e', 's', ' ', 'i', 's', ' ', + 't', 'r', 'u', 'e', '.', '\"', '\n', + }; + +VCDiffInterleavedWindowDecoderTest::VCDiffInterleavedWindowDecoderTest() { + UseInterleavedFileHeader(); + // delta_window_header_ is left blank. All window headers and bodies are + // lumped together in delta_window_body_. This means that AddChecksum() + // cannot be used to test the checksum feature. + delta_window_body_.assign(kWindowBody, sizeof(kWindowBody)); +} + +TEST_F(VCDiffInterleavedWindowDecoderTest, Decode) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +TEST_F(VCDiffInterleavedWindowDecoderTest, DecodeInTwoParts) { + const size_t delta_file_size = delta_file_.size(); + for (size_t i = 1; i < delta_file_size; i++) { + string output_chunk1, output_chunk2; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0], + i, + &output_chunk1)); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], + delta_file_size - i, + &output_chunk2)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_chunk1 + output_chunk2); + } +} + +TEST_F(VCDiffInterleavedWindowDecoderTest, DecodeInThreeParts) { + const size_t delta_file_size = delta_file_.size(); + for (size_t i = 1; i < delta_file_size - 1; i++) { + for (size_t j = i + 1; j < delta_file_size; j++) { + string output_chunk1, output_chunk2, output_chunk3; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0], + i, + &output_chunk1)); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], + j - i, + &output_chunk2)); + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[j], + delta_file_size - j, + &output_chunk3)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, + output_chunk1 + output_chunk2 + output_chunk3); + } + } +} + +typedef VCDiffInterleavedWindowDecoderTest + VCDiffInterleavedWindowDecoderTestByteByByte; + +TEST_F(VCDiffInterleavedWindowDecoderTestByteByByte, Decode) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_)); + } + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +// Windows 3 and 4 use the VCD_TARGET flag, so decoder should signal an error. +TEST_F(VCDiffInterleavedWindowDecoderTestByteByByte, DecodeNoVcdTarget) { + decoder_.SetAllowVcdTarget(false); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + size_t i = 0; + for (; i < delta_file_.size(); ++i) { + if (!decoder_.DecodeChunk(&delta_file_[i], 1, &output_)) { + break; + } + } + // The failure should occur just at the position of the first VCD_TARGET. + EXPECT_EQ(delta_file_header_.size() + 83, i); + // The target data for the first two windows should have been output. + EXPECT_EQ(expected_target_.substr(0, 89), output_); +} + +// The original version of VCDiffDecoder did not allow the caller to modify the +// contents of output_string between calls to DecodeChunk(). That restriction +// has been removed. Verify that the same result is still produced if the +// output string is cleared after each call to DecodeChunk(). Use the window +// encoding because it refers back to the previously decoded target data, which +// is the feature that would fail if the restriction still applied. +// +TEST_F(VCDiffInterleavedWindowDecoderTest, OutputStringCanBeModified) { + string temp_output; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &temp_output)); + output_.append(temp_output); + temp_output.clear(); + } + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +TEST_F(VCDiffInterleavedWindowDecoderTest, OutputStringIsPreserved) { + const string previous_data("Previous data"); + output_ = previous_data; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_)); + } + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(previous_data + expected_target_, output_); +} + +// A decode job that tests the ability to COPY across the boundary between +// source data and target data. +class VCDiffStandardCrossDecoderTest : public VCDiffDecoderTest { + protected: + static const char kExpectedTarget[]; + static const char kWindowHeader[]; + static const char kWindowBody[]; + + VCDiffStandardCrossDecoderTest(); + virtual ~VCDiffStandardCrossDecoderTest() {} +}; + +const char VCDiffStandardCrossDecoderTest::kWindowHeader[] = { + VCD_SOURCE, // Win_Indicator: take source from dictionary + FirstByteOfStringLength(kDictionary), // Source segment size + SecondByteOfStringLength(kDictionary), + 0x00, // Source segment position: start of dictionary + 0x15, // Length of the delta encoding + StringLengthAsByte(kExpectedTarget), // Size of the target window + 0x00, // Delta_indicator (no compression) + 0x07, // length of data for ADDs and RUNs + 0x06, // length of instructions section + 0x03 // length of addresses for COPYs + }; + +const char VCDiffStandardCrossDecoderTest::kWindowBody[] = { + // Data for ADD (length 7) + 'S', 'p', 'i', 'd', 'e', 'r', 's', + // Instructions and sizes (length 6) + 0x01, // VCD_ADD size 0 + 0x07, // Size of ADD (7) + 0x23, // VCD_COPY mode VCD_HERE, size 0 + 0x19, // Size of COPY (25) + 0x14, // VCD_COPY mode VCD_SELF, size 4 + 0x25, // VCD_COPY mode VCD_HERE, size 5 + // Addresses for COPYs (length 3) + 0x15, // HERE mode address for 1st copy (21 back from here_address) + 0x06, // SELF mode address for 2nd copy + 0x14 // HERE mode address for 3rd copy + }; + +const char VCDiffStandardCrossDecoderTest::kExpectedTarget[] = + "Spiders in his hair.\n" + "Spiders in the air.\n"; + +VCDiffStandardCrossDecoderTest::VCDiffStandardCrossDecoderTest() { + UseStandardFileHeader(); + delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader)); + delta_window_body_.assign(kWindowBody, sizeof(kWindowBody)); + expected_target_.assign(kExpectedTarget); +} + +TEST_F(VCDiffStandardCrossDecoderTest, Decode) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +typedef VCDiffStandardCrossDecoderTest VCDiffStandardCrossDecoderTestByteByByte; + +TEST_F(VCDiffStandardCrossDecoderTestByteByByte, Decode) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_)); + } + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +// The same decode job that tests the ability to COPY across the boundary +// between source data and target data, but using the interleaved format rather +// than the standard format. +class VCDiffInterleavedCrossDecoderTest + : public VCDiffStandardCrossDecoderTest { + protected: + VCDiffInterleavedCrossDecoderTest(); + virtual ~VCDiffInterleavedCrossDecoderTest() {} + + private: + static const char kWindowHeader[]; + static const char kWindowBody[]; +}; + +const char VCDiffInterleavedCrossDecoderTest::kWindowHeader[] = { + VCD_SOURCE, // Win_Indicator: take source from dictionary + FirstByteOfStringLength(kDictionary), // Source segment size + SecondByteOfStringLength(kDictionary), + 0x00, // Source segment position: start of dictionary + 0x15, // Length of the delta encoding + StringLengthAsByte(kExpectedTarget), // Size of the target window + 0x00, // Delta_indicator (no compression) + 0x00, // length of data for ADDs and RUNs + 0x10, // length of instructions section + 0x00, // length of addresses for COPYs + }; + +const char VCDiffInterleavedCrossDecoderTest::kWindowBody[] = { + 0x01, // VCD_ADD size 0 + 0x07, // Size of ADD (7) + // Data for ADD (length 7) + 'S', 'p', 'i', 'd', 'e', 'r', 's', + 0x23, // VCD_COPY mode VCD_HERE, size 0 + 0x19, // Size of COPY (25) + 0x15, // HERE mode address for 1st copy (21 back from here_address) + 0x14, // VCD_COPY mode VCD_SELF, size 4 + 0x06, // SELF mode address for 2nd copy + 0x25, // VCD_COPY mode VCD_HERE, size 5 + 0x14 // HERE mode address for 3rd copy + }; + +VCDiffInterleavedCrossDecoderTest::VCDiffInterleavedCrossDecoderTest() { + UseInterleavedFileHeader(); + delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader)); + delta_window_body_.assign(kWindowBody, sizeof(kWindowBody)); +} + +TEST_F(VCDiffInterleavedCrossDecoderTest, Decode) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +TEST_F(VCDiffInterleavedCrossDecoderTest, DecodeWithChecksum) { + ComputeAndAddChecksum(); + InitializeDeltaFile(); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +typedef VCDiffInterleavedCrossDecoderTest + VCDiffInterleavedCrossDecoderTestByteByByte; + +TEST_F(VCDiffInterleavedCrossDecoderTestByteByByte, Decode) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_)); + } + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +TEST_F(VCDiffInterleavedCrossDecoderTestByteByByte, DecodeWithChecksum) { + ComputeAndAddChecksum(); + InitializeDeltaFile(); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_)); + } + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +// Test using a custom code table and custom cache sizes with interleaved +// format. +class VCDiffCustomCodeTableDecoderTest : public VCDiffInterleavedDecoderTest { + protected: + static const char kFileHeader[]; + static const char kWindowHeader[]; + static const char kWindowBody[]; + static const char kEncodedCustomCodeTable[]; + + VCDiffCustomCodeTableDecoderTest(); + virtual ~VCDiffCustomCodeTableDecoderTest() {} +}; + +const char VCDiffCustomCodeTableDecoderTest::kFileHeader[] = { + 0xD6, // 'V' | 0x80 + 0xC3, // 'C' | 0x80 + 0xC4, // 'D' | 0x80 + 'S', // SDCH version code + 0x02 // Hdr_Indicator: Use custom code table + }; + +// Make a custom code table that includes exactly the instructions we need +// to encode the first test's data without using any explicit length values. +// Be careful not to replace any existing opcodes that have size 0, +// to ensure that the custom code table is valid (can express all possible +// values of inst (also known as instruction type) and mode with size 0.) +// This encoding uses interleaved format, which is easier to read. +// +// Here are the changes to the standard code table: +// ADD size 2 (opcode 3) => RUN size 2 (inst1[3] = VCD_RUN) +// ADD size 16 (opcode 17) => ADD size 27 (size1[17] = 27) +// ADD size 17 (opcode 18) => ADD size 61 (size1[18] = 61) +// COPY mode 0 size 18 (opcode 34) => COPY mode 0 size 28 (size1[34] = 28) +// COPY mode 1 size 18 (opcode 50) => COPY mode 1 size 44 (size1[50] = 44) +// +const char VCDiffCustomCodeTableDecoderTest::kEncodedCustomCodeTable[] = { + 0xD6, // 'V' | 0x80 + 0xC3, // 'C' | 0x80 + 0xC4, // 'D' | 0x80 + 'S', // SDCH version code + 0x00, // Hdr_Indicator: no custom code table, no compression + VCD_SOURCE, // Win_Indicator: take source from dictionary + (sizeof(VCDiffCodeTableData) >> 7) | 0x80, // First byte of table length + sizeof(VCDiffCodeTableData) & 0x7F, // Second byte of table length + 0x00, // Source segment position: start of default code table + 0x1F, // Length of the delta encoding + (sizeof(VCDiffCodeTableData) >> 7) | 0x80, // First byte of table length + sizeof(VCDiffCodeTableData) & 0x7F, // Second byte of table length + 0x00, // Delta_indicator (no compression) + 0x00, // length of data for ADDs and RUNs (unused) + 0x19, // length of interleaved section + 0x00, // length of addresses for COPYs (unused) + 0x05, // VCD_ADD size 4 + // Data for ADD (length 4) + VCD_RUN, VCD_ADD, VCD_ADD, VCD_RUN, + 0x13, // VCD_COPY mode VCD_SELF size 0 + 0x84, // Size of copy: upper bits (512 - 4 + 17 = 525) + 0x0D, // Size of copy: lower bits + 0x04, // Address of COPY + 0x03, // VCD_ADD size 2 + // Data for ADD (length 2) + 0x1B, 0x3D, + 0x3F, // VCD_COPY mode VCD_NEAR(0) size 15 + 0x84, // Address of copy: upper bits (525 + 2 = 527) + 0x0F, // Address of copy: lower bits + 0x02, // VCD_ADD size 1 + // Data for ADD (length 1) + 0x1C, + 0x4F, // VCD_COPY mode VCD_NEAR(1) size 15 + 0x10, // Address of copy + 0x02, // VCD_ADD size 1 + // Data for ADD (length 1) + 0x2C, + 0x53, // VCD_COPY mode VCD_NEAR(2) size 0 + 0x87, // Size of copy: upper bits (256 * 4 - 51 = 973) + 0x4D, // Size of copy: lower bits + 0x10 // Address of copy + }; + +// This is similar to VCDiffInterleavedDecoderTest, but uses the custom code +// table to eliminate the need to explicitly encode instruction sizes. +// Notice that NEAR(0) mode is used here where NEAR(1) mode was used in +// VCDiffInterleavedDecoderTest. This is because the custom code table +// has the size of the NEAR cache set to 1; only the most recent +// COPY instruction is available. This will also be a test of +// custom cache sizes. +const char VCDiffCustomCodeTableDecoderTest::kWindowHeader[] = { + VCD_SOURCE, // Win_Indicator: take source from dictionary + FirstByteOfStringLength(kDictionary), // Source segment size + SecondByteOfStringLength(kDictionary), + 0x00, // Source segment position: start of dictionary + 0x74, // 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) + 0x6E, // length of interleaved section + 0x00 // length of addresses for COPYs (unused) + }; + +const char VCDiffCustomCodeTableDecoderTest::kWindowBody[] = { + 0x22, // VCD_COPY mode VCD_SELF, size 28 + 0x00, // Address of COPY: Start of dictionary + 0x12, // VCD_ADD size 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', + 0x32, // VCD_COPY mode VCD_HERE, size 44 + 0x58, // HERE mode address (27+61 back from here_address) + 0xBF, // VCD_ADD size 2 + VCD_COPY mode NEAR(0), size 5 + // Data for ADDs: 2nd section (length 2) + 'h', 'r', + 0x2D, // NEAR(0) 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', + 0x03, // VCD_RUN size 2 + // Data for RUN: 4th section (length 1) + 'l', + 0x11, // VCD_ADD size 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' + }; + +VCDiffCustomCodeTableDecoderTest::VCDiffCustomCodeTableDecoderTest() { + delta_file_header_.assign(kFileHeader, sizeof(kFileHeader)); + delta_file_header_.push_back(0x01); // NEAR cache size (custom) + delta_file_header_.push_back(0x06); // SAME cache size (custom) + delta_file_header_.append(kEncodedCustomCodeTable, + sizeof(kEncodedCustomCodeTable)); + delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader)); + delta_window_body_.assign(kWindowBody, sizeof(kWindowBody)); +} + +TEST_F(VCDiffCustomCodeTableDecoderTest, CustomCodeTableEncodingMatches) { + VCDiffCodeTableData custom_code_table( + VCDiffCodeTableData::kDefaultCodeTableData); + custom_code_table.inst1[3] = VCD_RUN; + custom_code_table.size1[17] = 27; + custom_code_table.size1[18] = 61; + custom_code_table.size1[34] = 28; + custom_code_table.size1[50] = 44; + + decoder_.StartDecoding( + reinterpret_cast<const char*>( + &VCDiffCodeTableData::kDefaultCodeTableData), + sizeof(VCDiffCodeTableData::kDefaultCodeTableData)); + EXPECT_TRUE(decoder_.DecodeChunk(kEncodedCustomCodeTable, + sizeof(kEncodedCustomCodeTable), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(sizeof(custom_code_table), output_.size()); + const VCDiffCodeTableData* decoded_table = + reinterpret_cast<const VCDiffCodeTableData*>(output_.data()); + EXPECT_EQ(VCD_RUN, decoded_table->inst1[0]); + EXPECT_EQ(VCD_RUN, decoded_table->inst1[3]); + EXPECT_EQ(27, decoded_table->size1[17]); + EXPECT_EQ(61, decoded_table->size1[18]); + EXPECT_EQ(28, decoded_table->size1[34]); + EXPECT_EQ(44, decoded_table->size1[50]); + for (int i = 0; i < VCDiffCodeTableData::kCodeTableSize; ++i) { + EXPECT_EQ(custom_code_table.inst1[i], decoded_table->inst1[i]); + EXPECT_EQ(custom_code_table.inst2[i], decoded_table->inst2[i]); + EXPECT_EQ(custom_code_table.size1[i], decoded_table->size1[i]); + EXPECT_EQ(custom_code_table.size2[i], decoded_table->size2[i]); + EXPECT_EQ(custom_code_table.mode1[i], decoded_table->mode1[i]); + EXPECT_EQ(custom_code_table.mode2[i], decoded_table->mode2[i]); + } +} + +TEST_F(VCDiffCustomCodeTableDecoderTest, DecodeUsingCustomCodeTable) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +TEST_F(VCDiffCustomCodeTableDecoderTest, IncompleteCustomCodeTable) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_header_.data(), + delta_file_header_.size() - 1, + &output_)); + EXPECT_FALSE(decoder_.FinishDecoding()); + EXPECT_EQ("", output_); +} + +typedef VCDiffCustomCodeTableDecoderTest + VCDiffCustomCodeTableDecoderTestByteByByte; + +TEST_F(VCDiffCustomCodeTableDecoderTestByteByByte, DecodeUsingCustomCodeTable) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_)); + } + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +TEST_F(VCDiffCustomCodeTableDecoderTestByteByByte, IncompleteCustomCodeTable) { + delta_file_.resize(delta_file_header_.size() - 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_)); + } + EXPECT_FALSE(decoder_.FinishDecoding()); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffCustomCodeTableDecoderTestByteByByte, CustomTableNoVcdTarget) { + decoder_.SetAllowVcdTarget(false); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_)); + } + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); +} + +#ifdef GTEST_HAS_DEATH_TEST +typedef VCDiffCustomCodeTableDecoderTest VCDiffCustomCodeTableDecoderDeathTest; + +TEST_F(VCDiffCustomCodeTableDecoderDeathTest, BadCustomCacheSizes) { + delta_file_header_.assign(kFileHeader, sizeof(kFileHeader)); + delta_file_header_.push_back(0x81); // NEAR cache size (top bit) + delta_file_header_.push_back(0x10); // NEAR cache size (custom value 0x90) + delta_file_header_.push_back(0x81); // SAME cache size (top bit) + delta_file_header_.push_back(0x10); // SAME cache size (custom value 0x90) + delta_file_header_.append(kEncodedCustomCodeTable, + sizeof(kEncodedCustomCodeTable)); + InitializeDeltaFile(); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_DEBUG_DEATH(EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)), + "cache"); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffCustomCodeTableDecoderDeathTest, BadCustomCacheSizesNoVcdTarget) { + decoder_.SetAllowVcdTarget(false); + delta_file_header_.assign(kFileHeader, sizeof(kFileHeader)); + delta_file_header_.push_back(0x81); // NEAR cache size (top bit) + delta_file_header_.push_back(0x10); // NEAR cache size (custom value 0x90) + delta_file_header_.push_back(0x81); // SAME cache size (top bit) + delta_file_header_.push_back(0x10); // SAME cache size (custom value 0x90) + delta_file_header_.append(kEncodedCustomCodeTable, + sizeof(kEncodedCustomCodeTable)); + InitializeDeltaFile(); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_DEBUG_DEATH(EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)), + "cache"); + EXPECT_EQ("", output_); +} + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace open_vcdiff +} // unnamed namespace |