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