1// Copyright 2008 Google Inc.
2// Author: Lincoln Smith
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#include <config.h>
17#include "google/vcdecoder.h"
18#include <string>
19#include "codetable.h"
20#include "testing.h"
21#include "vcdecoder_test.h"
22
23namespace open_vcdiff {
24namespace {
25
26
27// Decode an encoding that uses a RUN instruction to allocate 64MB.
28class VCDiffLargeTargetTest : public VCDiffDecoderTest {
29 protected:
30  VCDiffLargeTargetTest();
31  virtual ~VCDiffLargeTargetTest() {}
32
33  static const char kLargeRunWindow[];
34};
35
36const char VCDiffLargeTargetTest::kLargeRunWindow[] = {
37    0x00,  // Win_Indicator: no source segment
38    0x0E,  // Length of the delta encoding
39    0xA0,  // Size of the target window (0x4000000)
40    0x80,  // Size of the target window cont'd
41    0x80,  // Size of the target window cont'd
42    0x00,  // Size of the target window cont'd
43    0x00,  // Delta_indicator (no compression)
44    0x00,  // length of data for ADDs and RUNs
45    0x06,  // length of instructions section
46    0x00,  // length of addresses for COPYs
47    // Interleaved segment
48    0x00,  // VCD_RUN size 0
49    0xA0,  // Size of RUN (0x4000000)
50    0x80,  // Size of RUN cont'd
51    0x80,  // Size of RUN cont'd
52    0x00,  // Size of RUN cont'd
53    0xBE,  // Data for RUN
54};
55
56VCDiffLargeTargetTest::VCDiffLargeTargetTest() {
57  UseInterleavedFileHeader();
58}
59
60// Ensure that, with allow_vcd_target set to false, we can decode any number of
61// 64MB windows without running out of memory.
62TEST_F(VCDiffLargeTargetTest, Decode) {
63  // 50 x 64MB = 3.2GB, which should be too large if memory usage accumulates
64  // during each iteration.
65  const int kIterations = 50;
66  decoder_.SetAllowVcdTarget(false);
67  decoder_.SetMaximumTargetFileSize(0x4000000UL * 50);
68  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
69  EXPECT_TRUE(decoder_.DecodeChunk(delta_file_header_.data(),
70                                   delta_file_header_.size(),
71                                   &output_));
72  EXPECT_EQ("", output_);
73  for (int i = 0; i < kIterations; i++) {
74    EXPECT_TRUE(decoder_.DecodeChunk(kLargeRunWindow, sizeof(kLargeRunWindow),
75                                     &output_));
76    EXPECT_EQ(0x4000000U, output_.size());
77    EXPECT_EQ(static_cast<char>(0xBE), output_[0]);
78    EXPECT_EQ(static_cast<char>(0xBE),
79              output_[output_.size() / 2]);  // middle element
80    EXPECT_EQ(static_cast<char>(0xBE),
81              output_[output_.size() - 1]);  // last element
82    output_.clear();
83  }
84  EXPECT_TRUE(decoder_.FinishDecoding());
85}
86
87// If we don't increase the maximum target file size first, the same test should
88// produce an error.
89TEST_F(VCDiffLargeTargetTest, DecodeReachesMaxFileSize) {
90  decoder_.SetAllowVcdTarget(false);
91  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
92  EXPECT_TRUE(decoder_.DecodeChunk(delta_file_header_.data(),
93                                   delta_file_header_.size(),
94                                   &output_));
95  EXPECT_EQ("", output_);
96  // The default maximum target file size is 64MB, which just matches the target
97  // data produced by a single iteration.
98  EXPECT_TRUE(decoder_.DecodeChunk(kLargeRunWindow, sizeof(kLargeRunWindow),
99                                   &output_));
100  EXPECT_EQ(0x4000000U, output_.size());
101  EXPECT_EQ(static_cast<char>(0xBE), output_[0]);
102  EXPECT_EQ(static_cast<char>(0xBE),
103            output_[output_.size() / 2]);  // middle element
104  EXPECT_EQ(static_cast<char>(0xBE),
105            output_[output_.size() - 1]);  // last element
106  output_.clear();
107  // Trying to decode a second window should exceed the target file size limit.
108  EXPECT_FALSE(decoder_.DecodeChunk(kLargeRunWindow, sizeof(kLargeRunWindow),
109                                    &output_));
110}
111
112}  // unnamed namespace
113}  // namespace open_vcdiff
114