diff options
Diffstat (limited to 'sdch/open-vcdiff/src/vcdecoder3_test.cc')
-rw-r--r-- | sdch/open-vcdiff/src/vcdecoder3_test.cc | 1238 |
1 files changed, 1238 insertions, 0 deletions
diff --git a/sdch/open-vcdiff/src/vcdecoder3_test.cc b/sdch/open-vcdiff/src/vcdecoder3_test.cc new file mode 100644 index 0000000..f3f8b5c --- /dev/null +++ b/sdch/open-vcdiff/src/vcdecoder3_test.cc @@ -0,0 +1,1238 @@ +// 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 <stdlib.h> // free, posix_memalign +#include <string.h> // memcpy +#include <string> +#include "testing.h" +#include "varint_bigendian.h" +#include "vcdecoder_test.h" +#include "vcdiff_defs.h" // VCD_SOURCE + +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif // HAVE_MALLOC_H + +#ifdef HAVE_SYS_MMAN_H +#define _XOPEN_SOURCE 600 // posix_memalign +#include <sys/mman.h> // mprotect +#endif // HAVE_SYS_MMAN_H + +#ifdef HAVE_UNISTD_H +#include <unistd.h> // getpagesize +#endif // HAVE_UNISTD_H + +namespace open_vcdiff { + +// Test headers, valid and invalid. + +TEST_F(VCDiffInterleavedDecoderTest, DecodeHeaderOnly) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_header_.data(), + delta_file_header_.size(), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, PartialHeaderNotEnough) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_header_.data(), + delta_file_header_.size() - 2, + &output_)); + EXPECT_FALSE(decoder_.FinishDecoding()); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, BadMagicNumber) { + delta_file_[1] = 'Q' | 0x80; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, BadVersionNumber) { + delta_file_[3] = 0x01; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, SecondaryCompressionNotSupported) { + delta_file_[4] = 0x01; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, 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(VCDiffInterleavedDecoderTest, 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_); +} + +TEST_F(VCDiffInterleavedDecoderTest, ChecksumDoesNotMatch) { + AddChecksum(0xBADBAD); + InitializeDeltaFile(); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, ChecksumIsInvalid64BitVarint) { + static const char kInvalidVarint[] = { 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x00 }; + delta_window_header_[0] |= VCD_CHECKSUM; + delta_window_header_.append(kInvalidVarint, sizeof(kInvalidVarint)); + // Adjust delta window size to include size of invalid Varint. + string size_of_invalid_varint; + VarintBE<int32_t>::AppendToString( + static_cast<int32_t>(delta_window_header_[4] + sizeof(kInvalidVarint)), + &size_of_invalid_varint); + delta_window_header_.replace(4, 1, size_of_invalid_varint); + InitializeDeltaFile(); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +// Remove one byte from the length of the chunk to process, and +// verify that an error is returned for FinishDecoding(). +TEST_F(VCDiffInterleavedDecoderTest, FinishAfterDecodingPartialWindow) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size() - 1, + &output_)); + EXPECT_FALSE(decoder_.FinishDecoding()); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTest, FinishAfterDecodingPartialWindowHeader) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_header_.size() + + delta_window_header_.size() - 1, + &output_)); + EXPECT_FALSE(decoder_.FinishDecoding()); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTest, TargetMatchesWindowSizeLimit) { + decoder_.SetMaximumTargetWindowSize(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(VCDiffInterleavedDecoderTest, 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(VCDiffInterleavedDecoderTest, TargetExceedsWindowSizeLimit) { + decoder_.SetMaximumTargetWindowSize(expected_target_.size() - 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, 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_); +} + +// Fuzz bits to make sure decoder does not violently crash. +// This test has no expected behavior except that no crashes should occur. +// In some cases, changing bits will still decode to the correct target; +// for example, changing unused bits within a bitfield. +TEST_F(VCDiffInterleavedDecoderTest, FuzzBits) { + while (FuzzOneByteInDeltaFile()) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + if (decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)) { + decoder_.FinishDecoding(); + } + InitializeDeltaFile(); + output_.clear(); + } +} + +// If a checksum is present, then fuzzing any of the bits may produce an error, +// but it should not result in an incorrect target being produced without +// an error. +TEST_F(VCDiffInterleavedDecoderTest, FuzzBitsWithChecksum) { + ComputeAndAddChecksum(); + InitializeDeltaFile(); + while (FuzzOneByteInDeltaFile()) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + if (decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)) { + if (decoder_.FinishDecoding()) { + // Decoding succeeded. Make sure the correct target was produced. + EXPECT_EQ(expected_target_, output_); + } + } else { + EXPECT_EQ("", output_); + } + InitializeDeltaFile(); + output_.clear(); + } +} + +TEST_F(VCDiffInterleavedDecoderTest, CopyMoreThanExpectedTarget) { + delta_file_[delta_file_header_.size() + 0x0C] = + FirstByteOfStringLength(kExpectedTarget); + delta_file_[delta_file_header_.size() + 0x0D] = + SecondByteOfStringLength(kExpectedTarget) + 1; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, CopySizeZero) { + delta_file_[delta_file_header_.size() + 0x0C] = 0; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, CopySizeTooLargeByOne) { + ++delta_file_[delta_file_header_.size() + 0x0C]; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, CopySizeTooSmallByOne) { + --delta_file_[delta_file_header_.size() + 0x0C]; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, CopySizeMaxInt) { + WriteMaxVarintAtOffset(0x0C, 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, CopySizeNegative) { + WriteNegativeVarintAtOffset(0x0C, 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, CopySizeInvalid) { + WriteInvalidVarintAtOffset(0x0C, 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, CopyAddressBeyondHereAddress) { + delta_file_[delta_file_header_.size() + 0x0D] = + FirstByteOfStringLength(kDictionary); + delta_file_[delta_file_header_.size() + 0x0E] = + SecondByteOfStringLength(kDictionary); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, CopyAddressMaxInt) { + WriteMaxVarintAtOffset(0x0D, 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, CopyAddressNegative) { + WriteNegativeVarintAtOffset(0x0D, 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, CopyAddressInvalid) { + WriteInvalidVarintAtOffset(0x0D, 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, AddMoreThanExpectedTarget) { + delta_file_[delta_file_header_.size() + 0x0F] = + FirstByteOfStringLength(kExpectedTarget); + delta_file_[delta_file_header_.size() + 0x10] = + SecondByteOfStringLength(kExpectedTarget) + 1; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, AddSizeZero) { + delta_file_[delta_file_header_.size() + 0x0F] = 0; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, AddSizeTooLargeByOne) { + ++delta_file_[delta_file_header_.size() + 0x0F]; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, AddSizeTooSmallByOne) { + --delta_file_[delta_file_header_.size() + 0x0F]; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, AddSizeMaxInt) { + WriteMaxVarintAtOffset(0x0F, 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, AddSizeNegative) { + WriteNegativeVarintAtOffset(0x0F, 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, AddSizeInvalid) { + WriteInvalidVarintAtOffset(0x0F, 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, RunMoreThanExpectedTarget) { + delta_file_[delta_file_header_.size() + 0x5F] = + FirstByteOfStringLength(kExpectedTarget); + delta_file_[delta_file_header_.size() + 0x60] = + SecondByteOfStringLength(kExpectedTarget) + 1; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, RunSizeZero) { + delta_file_[delta_file_header_.size() + 0x5F] = 0; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, RunSizeTooLargeByOne) { + ++delta_file_[delta_file_header_.size() + 0x5F]; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, RunSizeTooSmallByOne) { + --delta_file_[delta_file_header_.size() + 0x5F]; + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, RunSizeMaxInt) { + WriteMaxVarintAtOffset(0x5F, 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, RunSizeNegative) { + WriteNegativeVarintAtOffset(0x5F, 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTest, RunSizeInvalid) { + WriteInvalidVarintAtOffset(0x5F, 1); + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(), + delta_file_.size(), + &output_)); + EXPECT_EQ("", output_); +} + +#if defined(HAVE_MPROTECT) && \ + (defined(HAVE_MEMALIGN) || defined(HAVE_POSIX_MEMALIGN)) +TEST_F(VCDiffInterleavedDecoderTest, ShouldNotReadPastEndOfBuffer) { + // Allocate two memory pages. + const int page_size = getpagesize(); + void* two_pages = NULL; +#ifdef HAVE_POSIX_MEMALIGN + posix_memalign(&two_pages, page_size, 2 * page_size); +#else // !HAVE_POSIX_MEMALIGN + two_pages = memalign(page_size, 2 * page_size); +#endif // HAVE_POSIX_MEMALIGN + char* const first_page = reinterpret_cast<char*>(two_pages); + char* const second_page = first_page + page_size; + + // Place the delta string at the end of the first page. + char* delta_with_guard = second_page - delta_file_.size(); + memcpy(delta_with_guard, delta_file_.data(), delta_file_.size()); + + // Make the second page unreadable. + mprotect(second_page, page_size, PROT_NONE); + + // Now perform the decode operation, which will cause a segmentation fault + // if it reads past the end of the buffer. + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_with_guard, + delta_file_.size(), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); + + // Undo the mprotect. + mprotect(second_page, page_size, PROT_READ|PROT_WRITE); + free(two_pages); +} + +TEST_F(VCDiffInterleavedDecoderTest, ShouldNotReadPastBeginningOfBuffer) { + // Allocate two memory pages. + const int page_size = getpagesize(); + void* two_pages = NULL; +#ifdef HAVE_POSIX_MEMALIGN + posix_memalign(&two_pages, page_size, 2 * page_size); +#else // !HAVE_POSIX_MEMALIGN + two_pages = memalign(page_size, 2 * page_size); +#endif // HAVE_POSIX_MEMALIGN + char* const first_page = reinterpret_cast<char*>(two_pages); + char* const second_page = first_page + page_size; + + // Make the first page unreadable. + mprotect(first_page, page_size, PROT_NONE); + + // Place the delta string at the beginning of the second page. + char* delta_with_guard = second_page; + memcpy(delta_with_guard, delta_file_.data(), delta_file_.size()); + + // Now perform the decode operation, which will cause a segmentation fault + // if it reads past the beginning of the buffer. + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + EXPECT_TRUE(decoder_.DecodeChunk(delta_with_guard, + delta_file_.size(), + &output_)); + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ(expected_target_, output_); + + // Undo the mprotect. + mprotect(first_page, page_size, PROT_READ|PROT_WRITE); + free(two_pages); +} +#endif // HAVE_MPROTECT && (HAVE_MEMALIGN || HAVE_POSIX_MEMALIGN) + +// These are the same tests as for VCDiffInterleavedDecoderTest, with the added +// complication that instead of calling DecodeChunk() once with the entire data +// set, DecodeChunk() is called once for each byte of input. This is intended +// to shake out any bugs with rewind and resume while parsing chunked data. + +typedef VCDiffInterleavedDecoderTest VCDiffInterleavedDecoderTestByteByByte; + +// Test headers, valid and invalid. + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, DecodeHeaderOnly) { + decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); + for (size_t i = 0; i < delta_file_header_.size(); ++i) { + EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_header_[i], 1, &output_)); + } + EXPECT_TRUE(decoder_.FinishDecoding()); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, PartialHeaderNotEnough) { + delta_file_.resize(delta_file_header_.size() - 2); + 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(VCDiffInterleavedDecoderTestByteByByte, BadMagicNumber) { + delta_file_[1] = 'Q' | 0x80; + 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_)) { + // It should fail at the position that was altered + EXPECT_EQ(1U, i); + failed = true; + break; + } + } + EXPECT_TRUE(failed); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, BadVersionNumber) { + delta_file_[3] = 0x01; + 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; + // It should fail at the position that was altered + EXPECT_EQ(3U, i); + break; + } + } + EXPECT_TRUE(failed); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, + SecondaryCompressionNotSupported) { + delta_file_[4] = 0x01; + 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; + // It should fail at the position that was altered + EXPECT_EQ(4U, i); + break; + } + } + EXPECT_TRUE(failed); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, 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(VCDiffInterleavedDecoderTestByteByByte, 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_F(VCDiffInterleavedDecoderTestByteByByte, ChecksumDoesNotMatch) { + AddChecksum(0xBADBAD); + InitializeDeltaFile(); + 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; + // It should fail after decoding the entire delta file + EXPECT_EQ(delta_file_.size() - 1, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, ChecksumIsInvalid64BitVarint) { + static const char kInvalidVarint[] = { 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x00 }; + delta_window_header_[0] |= VCD_CHECKSUM; + delta_window_header_.append(kInvalidVarint, sizeof(kInvalidVarint)); + // Adjust delta window size to include size of invalid Varint. + string size_of_invalid_varint; + VarintBE<int32_t>::AppendToString( + static_cast<int32_t>(delta_window_header_[4] + sizeof(kInvalidVarint)), + &size_of_invalid_varint); + delta_window_header_.replace(4, 1, size_of_invalid_varint); + InitializeDeltaFile(); + 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; + // It should fail while trying to interpret the checksum. + EXPECT_EQ(delta_file_header_.size() + delta_window_header_.size() - 2, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, TargetMatchesWindowSizeLimit) { + decoder_.SetMaximumTargetWindowSize(expected_target_.size()); + 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(VCDiffInterleavedDecoderTestByteByByte, TargetMatchesFileSizeLimit) { + decoder_.SetMaximumTargetFileSize(expected_target_.size()); + 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(VCDiffInterleavedDecoderTestByteByByte, TargetExceedsWindowSizeLimit) { + decoder_.SetMaximumTargetWindowSize(expected_target_.size() - 1); + 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); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, TargetExceedsFileSizeLimit) { + decoder_.SetMaximumTargetFileSize(expected_target_.size() - 1); + 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); + EXPECT_EQ("", output_); +} + +// Fuzz bits to make sure decoder does not violently crash. +// This test has no expected behavior except that no crashes should occur. +// In some cases, changing bits will still decode to the correct target; +// for example, changing unused bits within a bitfield. +TEST_F(VCDiffInterleavedDecoderTestByteByByte, FuzzBits) { + while (FuzzOneByteInDeltaFile()) { + 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; + } + } + if (!failed) { + decoder_.FinishDecoding(); + } + InitializeDeltaFile(); + output_.clear(); + } +} + +// If a checksum is present, then fuzzing any of the bits may produce an error, +// but it should not result in an incorrect target being produced without +// an error. +TEST_F(VCDiffInterleavedDecoderTestByteByByte, FuzzBitsWithChecksum) { + ComputeAndAddChecksum(); + InitializeDeltaFile(); + while (FuzzOneByteInDeltaFile()) { + 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; + } + } + if (!failed) { + if (decoder_.FinishDecoding()) { + // Decoding succeeded. Make sure the correct target was produced. + EXPECT_EQ(expected_target_, output_); + } + } + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); + InitializeDeltaFile(); + output_.clear(); + } +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, + CopyInstructionsShouldFailIfNoSourceSegment) { + // Replace the Win_Indicator and the source size and source offset with a + // single 0 byte (a Win_Indicator for a window with no source segment.) + delta_window_header_.replace(0, 4, "\0", 1); + InitializeDeltaFile(); + 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; + // The first COPY instruction should fail. + EXPECT_EQ(delta_file_header_.size() + delta_window_header_.size() + 2, i); + break; + } + } + EXPECT_TRUE(failed); + EXPECT_EQ("", output_); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, CopyMoreThanExpectedTarget) { + delta_file_[delta_file_header_.size() + 0x0C] = + FirstByteOfStringLength(kExpectedTarget); + delta_file_[delta_file_header_.size() + 0x0D] = + SecondByteOfStringLength(kExpectedTarget) + 1; + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x0D, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +// A COPY instruction with an explicit size of 0 is not illegal according to the +// standard, although it is inefficient and should not be generated by any +// reasonable encoder. Changing the size of a COPY instruction to zero will +// cause a failure because the generated target window size will not match the +// expected target size. +TEST_F(VCDiffInterleavedDecoderTestByteByByte, CopySizeZero) { + delta_file_[delta_file_header_.size() + 0x0C] = 0; + 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()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, CopySizeTooLargeByOne) { + ++delta_file_[delta_file_header_.size() + 0x0C]; + 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()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, CopySizeTooSmallByOne) { + --delta_file_[delta_file_header_.size() + 0x0C]; + 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()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, CopySizeMaxInt) { + WriteMaxVarintAtOffset(0x0C, 1); + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x10, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, CopySizeNegative) { + WriteNegativeVarintAtOffset(0x0C, 1); + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x0F, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, CopySizeInvalid) { + WriteInvalidVarintAtOffset(0x0C, 1); + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x10, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, CopyAddressBeyondHereAddress) { + delta_file_[delta_file_header_.size() + 0x0D] = + FirstByteOfStringLength(kDictionary); + delta_file_[delta_file_header_.size() + 0x0E] = + SecondByteOfStringLength(kDictionary); + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x0E, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, CopyAddressMaxInt) { + WriteMaxVarintAtOffset(0x0D, 1); + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x11, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, CopyAddressNegative) { + WriteNegativeVarintAtOffset(0x0D, 1); + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x10, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, CopyAddressInvalid) { + WriteInvalidVarintAtOffset(0x0D, 1); + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x11, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, AddMoreThanExpectedTarget) { + delta_file_[delta_file_header_.size() + 0x0F] = + FirstByteOfStringLength(kExpectedTarget); + delta_file_[delta_file_header_.size() + 0x10] = + SecondByteOfStringLength(kExpectedTarget) + 1; + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x10, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +// An ADD instruction with an explicit size of 0 is not illegal according to the +// standard, although it is inefficient and should not be generated by any +// reasonable encoder. Changing the size of an ADD instruction to zero will +// cause a failure because the generated target window size will not match the +// expected target size. +TEST_F(VCDiffInterleavedDecoderTestByteByByte, AddSizeZero) { + delta_file_[delta_file_header_.size() + 0x0F] = 0; + 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()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, AddSizeTooLargeByOne) { + ++delta_file_[delta_file_header_.size() + 0x0F]; + 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()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, AddSizeTooSmallByOne) { + --delta_file_[delta_file_header_.size() + 0x0F]; + 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()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, AddSizeMaxInt) { + WriteMaxVarintAtOffset(0x0F, 1); + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x13, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, AddSizeNegative) { + WriteNegativeVarintAtOffset(0x0F, 1); + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x12, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, AddSizeInvalid) { + WriteInvalidVarintAtOffset(0x0F, 1); + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x13, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, RunMoreThanExpectedTarget) { + delta_file_[delta_file_header_.size() + 0x5F] = + FirstByteOfStringLength(kExpectedTarget); + delta_file_[delta_file_header_.size() + 0x60] = + SecondByteOfStringLength(kExpectedTarget) + 1; + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x60, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +// A RUN instruction with an explicit size of 0 is not illegal according to the +// standard, although it is inefficient and should not be generated by any +// reasonable encoder. Changing the size of a RUN instruction to zero will +// cause a failure because the generated target window size will not match the +// expected target size. +TEST_F(VCDiffInterleavedDecoderTestByteByByte, RunSizeZero) { + delta_file_[delta_file_header_.size() + 0x5F] = 0; + 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()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, RunSizeTooLargeByOne) { + ++delta_file_[delta_file_header_.size() + 0x5F]; + 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()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, RunSizeTooSmallByOne) { + --delta_file_[delta_file_header_.size() + 0x5F]; + 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()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, RunSizeMaxInt) { + WriteMaxVarintAtOffset(0x5F, 1); + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x63, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, RunSizeNegative) { + WriteNegativeVarintAtOffset(0x5F, 1); + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x62, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +TEST_F(VCDiffInterleavedDecoderTestByteByByte, RunSizeInvalid) { + WriteInvalidVarintAtOffset(0x5F, 1); + 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; + // It should fail at the position that was altered + EXPECT_EQ(delta_file_header_.size() + 0x63, i); + break; + } + } + EXPECT_TRUE(failed); + // The decoder should not create more target bytes than were expected. + EXPECT_GE(expected_target_.size(), output_.size()); +} + +} // namespace open_vcdiff |