// 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" namespace open_vcdiff { namespace { // Decode an encoding that uses a RUN instruction to allocate 64MB. class VCDiffLargeTargetTest : public VCDiffDecoderTest { protected: VCDiffLargeTargetTest(); virtual ~VCDiffLargeTargetTest() {} static const char kLargeRunWindow[]; }; const char VCDiffLargeTargetTest::kLargeRunWindow[] = { 0x00, // Win_Indicator: no source segment 0x0E, // Length of the delta encoding 0xA0, // Size of the target window (0x4000000) 0x80, // Size of the target window cont'd 0x80, // Size of the target window cont'd 0x00, // Size of the target window cont'd 0x00, // Delta_indicator (no compression) 0x00, // length of data for ADDs and RUNs 0x06, // length of instructions section 0x00, // length of addresses for COPYs // Interleaved segment 0x00, // VCD_RUN size 0 0xA0, // Size of RUN (0x4000000) 0x80, // Size of RUN cont'd 0x80, // Size of RUN cont'd 0x00, // Size of RUN cont'd 0xBE, // Data for RUN }; VCDiffLargeTargetTest::VCDiffLargeTargetTest() { UseInterleavedFileHeader(); } // Ensure that, with allow_vcd_target set to false, we can decode any number of // 64MB windows without running out of memory. TEST_F(VCDiffLargeTargetTest, Decode) { // 50 x 64MB = 3.2GB, which should be too large if memory usage accumulates // during each iteration. const int kIterations = 50; decoder_.SetAllowVcdTarget(false); decoder_.SetMaximumTargetFileSize(0x4000000UL * 50); decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); EXPECT_TRUE(decoder_.DecodeChunk(delta_file_header_.data(), delta_file_header_.size(), &output_)); EXPECT_EQ("", output_); for (int i = 0; i < kIterations; i++) { EXPECT_TRUE(decoder_.DecodeChunk(kLargeRunWindow, sizeof(kLargeRunWindow), &output_)); EXPECT_EQ(0x4000000U, output_.size()); EXPECT_EQ(static_cast<char>(0xBE), output_[0]); EXPECT_EQ(static_cast<char>(0xBE), output_[output_.size() / 2]); // middle element EXPECT_EQ(static_cast<char>(0xBE), output_[output_.size() - 1]); // last element output_.clear(); } EXPECT_TRUE(decoder_.FinishDecoding()); } // If we don't increase the maximum target file size first, the same test should // produce an error. TEST_F(VCDiffLargeTargetTest, DecodeReachesMaxFileSize) { decoder_.SetAllowVcdTarget(false); decoder_.StartDecoding(dictionary_.data(), dictionary_.size()); EXPECT_TRUE(decoder_.DecodeChunk(delta_file_header_.data(), delta_file_header_.size(), &output_)); EXPECT_EQ("", output_); // The default maximum target file size is 64MB, which just matches the target // data produced by a single iteration. EXPECT_TRUE(decoder_.DecodeChunk(kLargeRunWindow, sizeof(kLargeRunWindow), &output_)); EXPECT_EQ(0x4000000U, output_.size()); EXPECT_EQ(static_cast<char>(0xBE), output_[0]); EXPECT_EQ(static_cast<char>(0xBE), output_[output_.size() / 2]); // middle element EXPECT_EQ(static_cast<char>(0xBE), output_[output_.size() - 1]); // last element output_.clear(); // Trying to decode a second window should exceed the target file size limit. EXPECT_FALSE(decoder_.DecodeChunk(kLargeRunWindow, sizeof(kLargeRunWindow), &output_)); } } // unnamed namespace } // namespace open_vcdiff