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#include "vcdiff_defs.h"  // VCD_SOURCE
23
24namespace open_vcdiff {
25namespace {
26
27// Use the interleaved file header with the standard encoding.  Should work.
28class VCDiffDecoderInterleavedAllowedButNotUsed
29    : public VCDiffStandardDecoderTest {
30 public:
31  VCDiffDecoderInterleavedAllowedButNotUsed() {
32    UseInterleavedFileHeader();
33  }
34  virtual ~VCDiffDecoderInterleavedAllowedButNotUsed() { }
35};
36
37TEST_F(VCDiffDecoderInterleavedAllowedButNotUsed, Decode) {
38  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
39  EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
40                                   delta_file_.size(),
41                                   &output_));
42  EXPECT_TRUE(decoder_.FinishDecoding());
43  EXPECT_EQ(expected_target_.c_str(), output_);
44}
45
46TEST_F(VCDiffDecoderInterleavedAllowedButNotUsed, DecodeWithChecksum) {
47  ComputeAndAddChecksum();
48  InitializeDeltaFile();
49  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
50  EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
51                                   delta_file_.size(),
52                                   &output_));
53  EXPECT_TRUE(decoder_.FinishDecoding());
54  EXPECT_EQ(expected_target_.c_str(), output_);
55}
56
57typedef VCDiffDecoderInterleavedAllowedButNotUsed
58    VCDiffDecoderInterleavedAllowedButNotUsedByteByByte;
59
60TEST_F(VCDiffDecoderInterleavedAllowedButNotUsedByteByByte, Decode) {
61  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
62  for (size_t i = 0; i < delta_file_.size(); ++i) {
63    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
64  }
65  EXPECT_TRUE(decoder_.FinishDecoding());
66  EXPECT_EQ(expected_target_.c_str(), output_);
67}
68
69TEST_F(VCDiffDecoderInterleavedAllowedButNotUsedByteByByte,
70       DecodeWithChecksum) {
71  ComputeAndAddChecksum();
72  InitializeDeltaFile();
73  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
74  for (size_t i = 0; i < delta_file_.size(); ++i) {
75    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
76  }
77  EXPECT_TRUE(decoder_.FinishDecoding());
78  EXPECT_EQ(expected_target_.c_str(), output_);
79}
80
81// Use the standard file header with the interleaved encoding.  Should fail.
82class VCDiffDecoderInterleavedUsedButNotSupported
83    : public VCDiffInterleavedDecoderTest {
84 public:
85  VCDiffDecoderInterleavedUsedButNotSupported() {
86    UseStandardFileHeader();
87  }
88  virtual ~VCDiffDecoderInterleavedUsedButNotSupported() { }
89};
90
91TEST_F(VCDiffDecoderInterleavedUsedButNotSupported, DecodeShouldFail) {
92  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
93  EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(),
94                                    delta_file_.size(),
95                                    &output_));
96  EXPECT_EQ("", output_);
97}
98
99TEST_F(VCDiffDecoderInterleavedUsedButNotSupported,
100       DecodeByteByByteShouldFail) {
101  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
102  bool failed = false;
103  for (size_t i = 0; i < delta_file_.size(); ++i) {
104    if (!decoder_.DecodeChunk(&delta_file_[i], 1, &output_)) {
105      failed = true;
106      break;
107    }
108  }
109  EXPECT_TRUE(failed);
110  // The decoder should not create more target bytes than were expected.
111  EXPECT_GE(expected_target_.size(), output_.size());
112}
113
114// Divides up the standard encoding into eight separate delta file windows.
115// Each delta instruction appears in its own window.
116class VCDiffStandardWindowDecoderTest : public VCDiffDecoderTest {
117 protected:
118  static const size_t kWindow2Size = 61;
119
120  VCDiffStandardWindowDecoderTest();
121  virtual ~VCDiffStandardWindowDecoderTest() {}
122
123 private:
124  static const char kWindowBody[];
125};
126
127const size_t VCDiffStandardWindowDecoderTest::kWindow2Size;
128
129const char VCDiffStandardWindowDecoderTest::kWindowBody[] = {
130// Window 1:
131    VCD_SOURCE,  // Win_Indicator: take source from dictionary
132    FirstByteOfStringLength(kDictionary),  // Source segment size
133    SecondByteOfStringLength(kDictionary),
134    0x00,  // Source segment position: start of dictionary
135    0x08,  // Length of the delta encoding
136    0x1C,  // Size of the target window (28)
137    0x00,  // Delta_indicator (no compression)
138    0x00,  // length of data for ADDs and RUNs
139    0x02,  // length of instructions section
140    0x01,  // length of addresses for COPYs
141    // No data for ADDs and RUNs
142    // Instructions and sizes (length 2)
143    0x13,  // VCD_COPY mode VCD_SELF, size 0
144    0x1C,  // Size of COPY (28)
145    // Addresses for COPYs (length 1)
146    0x00,  // Start of dictionary
147// Window 2:
148    0x00,  // Win_Indicator: No source segment (ADD only)
149    0x44,  // Length of the delta encoding
150    static_cast<char>(kWindow2Size),  // Size of the target window (61)
151    0x00,  // Delta_indicator (no compression)
152    0x3D,  // length of data for ADDs and RUNs
153    0x02,  // length of instructions section
154    0x00,  // length of addresses for COPYs
155    // Data for ADD (length 61)
156    ' ', 'I', ' ', 'h', 'a', 'v', 'e', ' ', 's', 'a', 'i', 'd', ' ',
157    'i', 't', ' ', 't', 'w', 'i', 'c', 'e', ':', '\n',
158    'T', 'h', 'a', 't', ' ',
159    'a', 'l', 'o', 'n', 'e', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ',
160    'e', 'n', 'c', 'o', 'u', 'r', 'a', 'g', 'e', ' ',
161    't', 'h', 'e', ' ', 'c', 'r', 'e', 'w', '.', '\n',
162    // Instructions and sizes (length 2)
163    0x01,  // VCD_ADD size 0
164    0x3D,  // Size of ADD (61)
165    // No addresses for COPYs
166// Window 3:
167    VCD_TARGET,  // Win_Indicator: take source from decoded data
168    0x59,  // Source segment size: length of data decoded so far
169    0x00,  // Source segment position: start of decoded data
170    0x08,  // Length of the delta encoding
171    0x2C,  // Size of the target window
172    0x00,  // Delta_indicator (no compression)
173    0x00,  // length of data for ADDs and RUNs
174    0x02,  // length of instructions section
175    0x01,  // length of addresses for COPYs
176    // No data for ADDs and RUNs
177    // Instructions and sizes (length 2)
178    0x23,  // VCD_COPY mode VCD_HERE, size 0
179    0x2C,  // Size of COPY (44)
180    // Addresses for COPYs (length 1)
181    0x58,  // HERE mode address (27+61 back from here_address)
182// Window 4:
183    VCD_TARGET,  // Win_Indicator: take source from decoded data
184    0x05,  // Source segment size: only 5 bytes needed for this COPY
185    0x2E,  // Source segment position: offset for COPY
186    0x09,  // Length of the delta encoding
187    0x07,  // Size of the target window
188    0x00,  // Delta_indicator (no compression)
189    0x02,  // length of data for ADDs and RUNs
190    0x01,  // length of instructions section
191    0x01,  // length of addresses for COPYs
192    // Data for ADD (length 2)
193    'h', 'r',
194    // Instructions and sizes (length 1)
195    0xA7,  // VCD_ADD size 2 + VCD_COPY mode SELF size 5
196    // Addresses for COPYs (length 1)
197    0x00,  // SELF mode address (start of source segment)
198// Window 5:
199    0x00,  // Win_Indicator: No source segment (ADD only)
200    0x0F,  // Length of the delta encoding
201    0x09,  // Size of the target window
202    0x00,  // Delta_indicator (no compression)
203    0x09,  // length of data for ADDs and RUNs
204    0x01,  // length of instructions section
205    0x00,  // length of addresses for COPYs
206    // Data for ADD (length 9)
207    'W', 'h', 'a', 't', ' ', 'I', ' ', 't', 'e',
208    // Instructions and sizes (length 1)
209    0x0A,       // VCD_ADD size 9
210    // No addresses for COPYs
211// Window 6:
212    0x00,  // Win_Indicator: No source segment (RUN only)
213    0x08,  // Length of the delta encoding
214    0x02,  // Size of the target window
215    0x00,  // Delta_indicator (no compression)
216    0x01,  // length of data for ADDs and RUNs
217    0x02,  // length of instructions section
218    0x00,  // length of addresses for COPYs
219    // Data for RUN (length 1)
220    'l',
221    // Instructions and sizes (length 2)
222    0x00,  // VCD_RUN size 0
223    0x02,  // Size of RUN (2)
224    // No addresses for COPYs
225// Window 7:
226    0x00,  // Win_Indicator: No source segment (ADD only)
227    0x22,  // Length of the delta encoding
228    0x1B,  // Size of the target window
229    0x00,  // Delta_indicator (no compression)
230    0x1B,  // length of data for ADDs and RUNs
231    0x02,  // length of instructions section
232    0x00,  // length of addresses for COPYs
233    // Data for ADD: 4th section (length 27)
234    ' ', 'y', 'o', 'u', ' ',
235    't', 'h', 'r', 'e', 'e', ' ', 't', 'i', 'm', 'e', 's', ' ', 'i', 's', ' ',
236    't', 'r', 'u', 'e', '.', '\"', '\n',
237    // Instructions and sizes (length 2)
238    0x01,  // VCD_ADD size 0
239    0x1B,  // Size of ADD (27)
240    // No addresses for COPYs
241  };
242
243VCDiffStandardWindowDecoderTest::VCDiffStandardWindowDecoderTest() {
244  UseStandardFileHeader();
245  delta_window_body_.assign(kWindowBody, sizeof(kWindowBody));
246}
247
248TEST_F(VCDiffStandardWindowDecoderTest, Decode) {
249  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
250  EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
251                                   delta_file_.size(),
252                                   &output_));
253  EXPECT_TRUE(decoder_.FinishDecoding());
254  EXPECT_EQ(expected_target_.c_str(), output_);
255}
256
257// Bug 1287926: If DecodeChunk() stops in the middle of the window header,
258// and the expected size of the current target window is smaller than the
259// cumulative target bytes decoded so far, an underflow occurs and the decoder
260// tries to allocate ~MAX_INT bytes.
261TEST_F(VCDiffStandardWindowDecoderTest, DecodeBreakInFourthWindowHeader) {
262  // Parse file header + first two windows.
263  const size_t chunk_1_size = delta_file_header_.size() + 83;
264  // Parse third window, plus everything up to "Size of the target window" field
265  // of fourth window, but do not parse complete header of fourth window.
266  const size_t chunk_2_size = 12 + 5;
267  CHECK_EQ(VCD_TARGET, static_cast<unsigned char>(delta_file_[chunk_1_size]));
268  CHECK_EQ(0x00, static_cast<int>(delta_file_[chunk_1_size + chunk_2_size]));
269  string output_chunk1, output_chunk2, output_chunk3;
270  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
271  EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0],
272                                   chunk_1_size,
273                                   &output_chunk1));
274  EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[chunk_1_size],
275                                   chunk_2_size,
276                                   &output_chunk2));
277  EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[chunk_1_size + chunk_2_size],
278                                   delta_file_.size()
279                                       - (chunk_1_size + chunk_2_size),
280                                   &output_chunk3));
281  EXPECT_TRUE(decoder_.FinishDecoding());
282  EXPECT_EQ(expected_target_.c_str(),
283            output_chunk1 + output_chunk2 + output_chunk3);
284}
285
286TEST_F(VCDiffStandardWindowDecoderTest, DecodeChunkNoVcdTargetAllowed) {
287  decoder_.SetAllowVcdTarget(false);
288  // Parse file header + first two windows.
289  const size_t chunk_1_size = delta_file_header_.size() + 83;
290  // The third window begins with Win_Indicator = VCD_TARGET which is not
291  // allowed.
292  CHECK_EQ(VCD_TARGET, static_cast<unsigned char>(delta_file_[chunk_1_size]));
293  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
294  EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0], chunk_1_size, &output_));
295  // Just parsing one more byte (the VCD_TARGET) should result in an error.
296  EXPECT_FALSE(decoder_.DecodeChunk(&delta_file_[chunk_1_size], 1, &output_));
297  // The target data for the first two windows should have been output.
298  EXPECT_EQ(expected_target_.substr(0, 89).c_str(), output_);
299}
300
301TEST_F(VCDiffStandardWindowDecoderTest, DecodeInTwoParts) {
302  const size_t delta_file_size = delta_file_.size();
303  for (size_t i = 1; i < delta_file_size; i++) {
304    string output_chunk1, output_chunk2;
305    decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
306    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0],
307                                     i,
308                                     &output_chunk1));
309    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i],
310                                     delta_file_size - i,
311                                     &output_chunk2));
312    EXPECT_TRUE(decoder_.FinishDecoding());
313    EXPECT_EQ(expected_target_.c_str(), output_chunk1 + output_chunk2);
314  }
315}
316
317TEST_F(VCDiffStandardWindowDecoderTest, DecodeInThreeParts) {
318  const size_t delta_file_size = delta_file_.size();
319  for (size_t i = 1; i < delta_file_size - 1; i++) {
320    for (size_t j = i + 1; j < delta_file_size; j++) {
321      string output_chunk1, output_chunk2, output_chunk3;
322      decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
323      EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0],
324                                       i,
325                                       &output_chunk1));
326      EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i],
327                                       j - i,
328                                       &output_chunk2));
329      EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[j],
330                                       delta_file_size - j,
331                                       &output_chunk3));
332      EXPECT_TRUE(decoder_.FinishDecoding());
333      EXPECT_EQ(expected_target_.c_str(),
334                output_chunk1 + output_chunk2 + output_chunk3);
335    }
336  }
337}
338
339// For the window test, the maximum target window size is much smaller than the
340// target file size.  (The largest window is Window 2, with 61 target bytes.)
341// Use the minimum values possible.
342TEST_F(VCDiffStandardWindowDecoderTest, TargetMatchesWindowSizeLimit) {
343  decoder_.SetMaximumTargetWindowSize(kWindow2Size);
344  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
345  EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
346                                   delta_file_.size(),
347                                   &output_));
348  EXPECT_TRUE(decoder_.FinishDecoding());
349  EXPECT_EQ(expected_target_.c_str(), output_);
350}
351
352TEST_F(VCDiffStandardWindowDecoderTest, TargetMatchesFileSizeLimit) {
353  decoder_.SetMaximumTargetFileSize(expected_target_.size());
354  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
355  EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
356                                   delta_file_.size(),
357                                   &output_));
358  EXPECT_TRUE(decoder_.FinishDecoding());
359  EXPECT_EQ(expected_target_.c_str(), output_);
360}
361
362TEST_F(VCDiffStandardWindowDecoderTest, TargetExceedsWindowSizeLimit) {
363  decoder_.SetMaximumTargetWindowSize(kWindow2Size - 1);
364  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
365  EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(),
366                                    delta_file_.size(),
367                                    &output_));
368  EXPECT_EQ("", output_);
369}
370
371TEST_F(VCDiffStandardWindowDecoderTest, TargetExceedsFileSizeLimit) {
372  decoder_.SetMaximumTargetFileSize(expected_target_.size() - 1);
373  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
374  EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(),
375                                    delta_file_.size(),
376                                    &output_));
377  EXPECT_EQ("", output_);
378}
379
380typedef VCDiffStandardWindowDecoderTest
381    VCDiffStandardWindowDecoderTestByteByByte;
382
383TEST_F(VCDiffStandardWindowDecoderTestByteByByte, Decode) {
384  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
385  for (size_t i = 0; i < delta_file_.size(); ++i) {
386    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
387  }
388  EXPECT_TRUE(decoder_.FinishDecoding());
389  EXPECT_EQ(expected_target_.c_str(), output_);
390}
391
392TEST_F(VCDiffStandardWindowDecoderTestByteByByte, DecodeExplicitVcdTarget) {
393  decoder_.SetAllowVcdTarget(true);
394  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
395  for (size_t i = 0; i < delta_file_.size(); ++i) {
396    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
397  }
398  EXPECT_TRUE(decoder_.FinishDecoding());
399  EXPECT_EQ(expected_target_.c_str(), output_);
400}
401
402// Windows 3 and 4 use the VCD_TARGET flag, so decoder should signal an error.
403TEST_F(VCDiffStandardWindowDecoderTestByteByByte, DecodeNoVcdTarget) {
404  decoder_.SetAllowVcdTarget(false);
405  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
406  size_t i = 0;
407  for (; i < delta_file_.size(); ++i) {
408    if (!decoder_.DecodeChunk(&delta_file_[i], 1, &output_)) {
409      break;
410    }
411  }
412  // The failure should occur just at the position of the first VCD_TARGET.
413  EXPECT_EQ(delta_file_header_.size() + 83, i);
414  // The target data for the first two windows should have been output.
415  EXPECT_EQ(expected_target_.substr(0, 89).c_str(), output_);
416}
417
418// Divides up the interleaved encoding into eight separate delta file windows.
419class VCDiffInterleavedWindowDecoderTest
420    : public VCDiffStandardWindowDecoderTest {
421 protected:
422  VCDiffInterleavedWindowDecoderTest();
423  virtual ~VCDiffInterleavedWindowDecoderTest() {}
424 private:
425  static const char kWindowBody[];
426};
427
428const char VCDiffInterleavedWindowDecoderTest::kWindowBody[] = {
429// Window 1:
430    VCD_SOURCE,  // Win_Indicator: take source from dictionary
431    FirstByteOfStringLength(kDictionary),  // Source segment size
432    SecondByteOfStringLength(kDictionary),
433    0x00,  // Source segment position: start of dictionary
434    0x08,  // Length of the delta encoding
435    0x1C,  // Size of the target window (28)
436    0x00,  // Delta_indicator (no compression)
437    0x00,  // length of data for ADDs and RUNs
438    0x03,  // length of instructions section
439    0x00,  // length of addresses for COPYs
440    0x13,  // VCD_COPY mode VCD_SELF, size 0
441    0x1C,  // Size of COPY (28)
442    0x00,  // Start of dictionary
443// Window 2:
444    0x00,  // Win_Indicator: No source segment (ADD only)
445    0x44,  // Length of the delta encoding
446    0x3D,  // Size of the target window (61)
447    0x00,  // Delta_indicator (no compression)
448    0x00,  // length of data for ADDs and RUNs
449    0x3F,  // length of instructions section
450    0x00,  // length of addresses for COPYs
451    0x01,  // VCD_ADD size 0
452    0x3D,  // Size of ADD (61)
453    ' ', 'I', ' ', 'h', 'a', 'v', 'e', ' ', 's', 'a', 'i', 'd', ' ',
454    'i', 't', ' ', 't', 'w', 'i', 'c', 'e', ':', '\n',
455    'T', 'h', 'a', 't', ' ',
456    'a', 'l', 'o', 'n', 'e', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ',
457    'e', 'n', 'c', 'o', 'u', 'r', 'a', 'g', 'e', ' ',
458    't', 'h', 'e', ' ', 'c', 'r', 'e', 'w', '.', '\n',
459// Window 3:
460    VCD_TARGET,  // Win_Indicator: take source from decoded data
461    0x59,  // Source segment size: length of data decoded so far
462    0x00,  // Source segment position: start of decoded data
463    0x08,  // Length of the delta encoding
464    0x2C,  // Size of the target window
465    0x00,  // Delta_indicator (no compression)
466    0x00,  // length of data for ADDs and RUNs
467    0x03,  // length of instructions section
468    0x00,  // length of addresses for COPYs
469    0x23,  // VCD_COPY mode VCD_HERE, size 0
470    0x2C,  // Size of COPY (44)
471    0x58,  // HERE mode address (27+61 back from here_address)
472// Window 4:
473    VCD_TARGET,  // Win_Indicator: take source from decoded data
474    0x05,  // Source segment size: only 5 bytes needed for this COPY
475    0x2E,  // Source segment position: offset for COPY
476    0x09,  // Length of the delta encoding
477    0x07,  // Size of the target window
478    0x00,  // Delta_indicator (no compression)
479    0x00,  // length of data for ADDs and RUNs
480    0x04,  // length of instructions section
481    0x00,  // length of addresses for COPYs
482    0xA7,  // VCD_ADD size 2 + VCD_COPY mode SELF, size 5
483    'h', 'r',
484    0x00,  // SELF mode address (start of source segment)
485// Window 5:
486    0x00,  // Win_Indicator: No source segment (ADD only)
487    0x0F,  // Length of the delta encoding
488    0x09,  // Size of the target window
489    0x00,  // Delta_indicator (no compression)
490    0x00,  // length of data for ADDs and RUNs
491    0x0A,  // length of instructions section
492    0x00,  // length of addresses for COPYs
493    0x0A,       // VCD_ADD size 9
494    'W', 'h', 'a', 't', ' ', 'I', ' ', 't', 'e',
495// Window 6:
496    0x00,  // Win_Indicator: No source segment (RUN only)
497    0x08,  // Length of the delta encoding
498    0x02,  // Size of the target window
499    0x00,  // Delta_indicator (no compression)
500    0x00,  // length of data for ADDs and RUNs
501    0x03,  // length of instructions section
502    0x00,  // length of addresses for COPYs
503    0x00,  // VCD_RUN size 0
504    0x02,  // Size of RUN (2)
505    'l',
506// Window 7:
507    0x00,  // Win_Indicator: No source segment (ADD only)
508    0x22,  // Length of the delta encoding
509    0x1B,  // Size of the target window
510    0x00,  // Delta_indicator (no compression)
511    0x00,  // length of data for ADDs and RUNs
512    0x1D,  // length of instructions section
513    0x00,  // length of addresses for COPYs
514    0x01,  // VCD_ADD size 0
515    0x1B,  // Size of ADD (27)
516    ' ', 'y', 'o', 'u', ' ',
517    't', 'h', 'r', 'e', 'e', ' ', 't', 'i', 'm', 'e', 's', ' ', 'i', 's', ' ',
518    't', 'r', 'u', 'e', '.', '\"', '\n',
519  };
520
521VCDiffInterleavedWindowDecoderTest::VCDiffInterleavedWindowDecoderTest() {
522  UseInterleavedFileHeader();
523  // delta_window_header_ is left blank.  All window headers and bodies are
524  // lumped together in delta_window_body_.  This means that AddChecksum()
525  // cannot be used to test the checksum feature.
526  delta_window_body_.assign(kWindowBody, sizeof(kWindowBody));
527}
528
529TEST_F(VCDiffInterleavedWindowDecoderTest, Decode) {
530  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
531  EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
532                                   delta_file_.size(),
533                                   &output_));
534  EXPECT_TRUE(decoder_.FinishDecoding());
535  EXPECT_EQ(expected_target_.c_str(), output_);
536}
537
538TEST_F(VCDiffInterleavedWindowDecoderTest, DecodeInTwoParts) {
539  const size_t delta_file_size = delta_file_.size();
540  for (size_t i = 1; i < delta_file_size; i++) {
541    string output_chunk1, output_chunk2;
542    decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
543    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0],
544                                     i,
545                                     &output_chunk1));
546    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i],
547                                     delta_file_size - i,
548                                     &output_chunk2));
549    EXPECT_TRUE(decoder_.FinishDecoding());
550    EXPECT_EQ(expected_target_.c_str(), output_chunk1 + output_chunk2);
551  }
552}
553
554TEST_F(VCDiffInterleavedWindowDecoderTest, DecodeInThreeParts) {
555  const size_t delta_file_size = delta_file_.size();
556  for (size_t i = 1; i < delta_file_size - 1; i++) {
557    for (size_t j = i + 1; j < delta_file_size; j++) {
558      string output_chunk1, output_chunk2, output_chunk3;
559      decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
560      EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0],
561                                       i,
562                                       &output_chunk1));
563      EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i],
564                                       j - i,
565                                       &output_chunk2));
566      EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[j],
567                                       delta_file_size - j,
568                                       &output_chunk3));
569      EXPECT_TRUE(decoder_.FinishDecoding());
570      EXPECT_EQ(expected_target_.c_str(),
571                output_chunk1 + output_chunk2 + output_chunk3);
572    }
573  }
574}
575
576typedef VCDiffInterleavedWindowDecoderTest
577    VCDiffInterleavedWindowDecoderTestByteByByte;
578
579TEST_F(VCDiffInterleavedWindowDecoderTestByteByByte, Decode) {
580  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
581  for (size_t i = 0; i < delta_file_.size(); ++i) {
582    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
583  }
584  EXPECT_TRUE(decoder_.FinishDecoding());
585  EXPECT_EQ(expected_target_.c_str(), output_);
586}
587
588// Windows 3 and 4 use the VCD_TARGET flag, so decoder should signal an error.
589TEST_F(VCDiffInterleavedWindowDecoderTestByteByByte, DecodeNoVcdTarget) {
590  decoder_.SetAllowVcdTarget(false);
591  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
592  size_t i = 0;
593  for (; i < delta_file_.size(); ++i) {
594    if (!decoder_.DecodeChunk(&delta_file_[i], 1, &output_)) {
595      break;
596    }
597  }
598  // The failure should occur just at the position of the first VCD_TARGET.
599  EXPECT_EQ(delta_file_header_.size() + 83, i);
600  // The target data for the first two windows should have been output.
601  EXPECT_EQ(expected_target_.substr(0, 89).c_str(), output_);
602}
603
604// The original version of VCDiffDecoder did not allow the caller to modify the
605// contents of output_string between calls to DecodeChunk().  That restriction
606// has been removed.  Verify that the same result is still produced if the
607// output string is cleared after each call to DecodeChunk().  Use the window
608// encoding because it refers back to the previously decoded target data, which
609// is the feature that would fail if the restriction still applied.
610//
611TEST_F(VCDiffInterleavedWindowDecoderTest, OutputStringCanBeModified) {
612  string temp_output;
613  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
614  for (size_t i = 0; i < delta_file_.size(); ++i) {
615    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &temp_output));
616    output_.append(temp_output);
617    temp_output.clear();
618  }
619  EXPECT_TRUE(decoder_.FinishDecoding());
620  EXPECT_EQ(expected_target_.c_str(), output_);
621}
622
623TEST_F(VCDiffInterleavedWindowDecoderTest, OutputStringIsPreserved) {
624  const string previous_data("Previous data");
625  output_ = previous_data;
626  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
627  for (size_t i = 0; i < delta_file_.size(); ++i) {
628    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
629  }
630  EXPECT_TRUE(decoder_.FinishDecoding());
631  EXPECT_EQ((previous_data + expected_target_).c_str(), output_);
632}
633
634// A decode job that tests the ability to COPY across the boundary between
635// source data and target data.
636class VCDiffStandardCrossDecoderTest : public VCDiffDecoderTest {
637 protected:
638  static const char kExpectedTarget[];
639  static const char kWindowHeader[];
640  static const char kWindowBody[];
641
642  VCDiffStandardCrossDecoderTest();
643  virtual ~VCDiffStandardCrossDecoderTest() {}
644};
645
646const char VCDiffStandardCrossDecoderTest::kWindowHeader[] = {
647    VCD_SOURCE,  // Win_Indicator: take source from dictionary
648    FirstByteOfStringLength(kDictionary),  // Source segment size
649    SecondByteOfStringLength(kDictionary),
650    0x00,  // Source segment position: start of dictionary
651    0x15,  // Length of the delta encoding
652    StringLengthAsByte(kExpectedTarget),  // Size of the target window
653    0x00,  // Delta_indicator (no compression)
654    0x07,  // length of data for ADDs and RUNs
655    0x06,  // length of instructions section
656    0x03   // length of addresses for COPYs
657  };
658
659const char VCDiffStandardCrossDecoderTest::kWindowBody[] = {
660    // Data for ADD (length 7)
661    'S', 'p', 'i', 'd', 'e', 'r', 's',
662    // Instructions and sizes (length 6)
663    0x01,  // VCD_ADD size 0
664    0x07,  // Size of ADD (7)
665    0x23,  // VCD_COPY mode VCD_HERE, size 0
666    0x19,  // Size of COPY (25)
667    0x14,  // VCD_COPY mode VCD_SELF, size 4
668    0x25,  // VCD_COPY mode VCD_HERE, size 5
669    // Addresses for COPYs (length 3)
670    0x15,  // HERE mode address for 1st copy (21 back from here_address)
671    0x06,  // SELF mode address for 2nd copy
672    0x14   // HERE mode address for 3rd copy
673  };
674
675const char VCDiffStandardCrossDecoderTest::kExpectedTarget[] =
676    "Spiders in his hair.\n"
677    "Spiders in the air.\n";
678
679VCDiffStandardCrossDecoderTest::VCDiffStandardCrossDecoderTest() {
680  UseStandardFileHeader();
681  delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader));
682  delta_window_body_.assign(kWindowBody, sizeof(kWindowBody));
683  expected_target_.assign(kExpectedTarget);
684}
685
686TEST_F(VCDiffStandardCrossDecoderTest, Decode) {
687  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
688  EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
689                                   delta_file_.size(),
690                                   &output_));
691  EXPECT_TRUE(decoder_.FinishDecoding());
692  EXPECT_EQ(expected_target_.c_str(), output_);
693}
694
695typedef VCDiffStandardCrossDecoderTest VCDiffStandardCrossDecoderTestByteByByte;
696
697TEST_F(VCDiffStandardCrossDecoderTestByteByByte, Decode) {
698  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
699  for (size_t i = 0; i < delta_file_.size(); ++i) {
700    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
701  }
702  EXPECT_TRUE(decoder_.FinishDecoding());
703  EXPECT_EQ(expected_target_.c_str(), output_);
704}
705
706// The same decode job that tests the ability to COPY across the boundary
707// between source data and target data, but using the interleaved format rather
708// than the standard format.
709class VCDiffInterleavedCrossDecoderTest
710    : public VCDiffStandardCrossDecoderTest {
711 protected:
712  VCDiffInterleavedCrossDecoderTest();
713  virtual ~VCDiffInterleavedCrossDecoderTest() {}
714
715 private:
716  static const char kWindowHeader[];
717  static const char kWindowBody[];
718};
719
720const char VCDiffInterleavedCrossDecoderTest::kWindowHeader[] = {
721    VCD_SOURCE,  // Win_Indicator: take source from dictionary
722    FirstByteOfStringLength(kDictionary),  // Source segment size
723    SecondByteOfStringLength(kDictionary),
724    0x00,  // Source segment position: start of dictionary
725    0x15,  // Length of the delta encoding
726    StringLengthAsByte(kExpectedTarget),  // Size of the target window
727    0x00,  // Delta_indicator (no compression)
728    0x00,  // length of data for ADDs and RUNs
729    0x10,  // length of instructions section
730    0x00,  // length of addresses for COPYs
731  };
732
733const char VCDiffInterleavedCrossDecoderTest::kWindowBody[] = {
734    0x01,  // VCD_ADD size 0
735    0x07,  // Size of ADD (7)
736    // Data for ADD (length 7)
737    'S', 'p', 'i', 'd', 'e', 'r', 's',
738    0x23,  // VCD_COPY mode VCD_HERE, size 0
739    0x19,  // Size of COPY (25)
740    0x15,  // HERE mode address for 1st copy (21 back from here_address)
741    0x14,  // VCD_COPY mode VCD_SELF, size 4
742    0x06,  // SELF mode address for 2nd copy
743    0x25,  // VCD_COPY mode VCD_HERE, size 5
744    0x14   // HERE mode address for 3rd copy
745  };
746
747VCDiffInterleavedCrossDecoderTest::VCDiffInterleavedCrossDecoderTest() {
748  UseInterleavedFileHeader();
749  delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader));
750  delta_window_body_.assign(kWindowBody, sizeof(kWindowBody));
751}
752
753TEST_F(VCDiffInterleavedCrossDecoderTest, Decode) {
754  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
755  EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
756                                   delta_file_.size(),
757                                   &output_));
758  EXPECT_TRUE(decoder_.FinishDecoding());
759  EXPECT_EQ(expected_target_.c_str(), output_);
760}
761
762TEST_F(VCDiffInterleavedCrossDecoderTest, DecodeWithChecksum) {
763  ComputeAndAddChecksum();
764  InitializeDeltaFile();
765  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
766  EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
767                                   delta_file_.size(),
768                                   &output_));
769  EXPECT_TRUE(decoder_.FinishDecoding());
770  EXPECT_EQ(expected_target_.c_str(), output_);
771}
772
773typedef VCDiffInterleavedCrossDecoderTest
774    VCDiffInterleavedCrossDecoderTestByteByByte;
775
776TEST_F(VCDiffInterleavedCrossDecoderTestByteByByte, Decode) {
777  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
778  for (size_t i = 0; i < delta_file_.size(); ++i) {
779    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
780  }
781  EXPECT_TRUE(decoder_.FinishDecoding());
782  EXPECT_EQ(expected_target_.c_str(), output_);
783}
784
785TEST_F(VCDiffInterleavedCrossDecoderTestByteByByte, DecodeWithChecksum) {
786  ComputeAndAddChecksum();
787  InitializeDeltaFile();
788  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
789  for (size_t i = 0; i < delta_file_.size(); ++i) {
790    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
791  }
792  EXPECT_TRUE(decoder_.FinishDecoding());
793  EXPECT_EQ(expected_target_.c_str(), output_);
794}
795
796// Test using a custom code table and custom cache sizes with interleaved
797// format.
798class VCDiffCustomCodeTableDecoderTest : public VCDiffInterleavedDecoderTest {
799 protected:
800  static const char kFileHeader[];
801  static const char kWindowHeader[];
802  static const char kWindowBody[];
803  static const char kEncodedCustomCodeTable[];
804
805  VCDiffCustomCodeTableDecoderTest();
806  virtual ~VCDiffCustomCodeTableDecoderTest() {}
807};
808
809const char VCDiffCustomCodeTableDecoderTest::kFileHeader[] = {
810    0xD6,  // 'V' | 0x80
811    0xC3,  // 'C' | 0x80
812    0xC4,  // 'D' | 0x80
813    'S',   // SDCH version code
814    0x02   // Hdr_Indicator: Use custom code table
815  };
816
817// Make a custom code table that includes exactly the instructions we need
818// to encode the first test's data without using any explicit length values.
819// Be careful not to replace any existing opcodes that have size 0,
820// to ensure that the custom code table is valid (can express all possible
821// values of inst (also known as instruction type) and mode with size 0.)
822// This encoding uses interleaved format, which is easier to read.
823//
824// Here are the changes to the standard code table:
825// ADD size 2 (opcode 3) => RUN size 2 (inst1[3] = VCD_RUN)
826// ADD size 16 (opcode 17) => ADD size 27 (size1[17] = 27)
827// ADD size 17 (opcode 18) => ADD size 61 (size1[18] = 61)
828// COPY mode 0 size 18 (opcode 34) => COPY mode 0 size 28 (size1[34] = 28)
829// COPY mode 1 size 18 (opcode 50) => COPY mode 1 size 44 (size1[50] = 44)
830//
831const char VCDiffCustomCodeTableDecoderTest::kEncodedCustomCodeTable[] = {
832    0xD6,  // 'V' | 0x80
833    0xC3,  // 'C' | 0x80
834    0xC4,  // 'D' | 0x80
835    'S',   // SDCH version code
836    0x00,  // Hdr_Indicator: no custom code table, no compression
837    VCD_SOURCE,  // Win_Indicator: take source from dictionary
838    (sizeof(VCDiffCodeTableData) >> 7) | 0x80,  // First byte of table length
839    sizeof(VCDiffCodeTableData) & 0x7F,  // Second byte of table length
840    0x00,  // Source segment position: start of default code table
841    0x1F,  // Length of the delta encoding
842    (sizeof(VCDiffCodeTableData) >> 7) | 0x80,  // First byte of table length
843    sizeof(VCDiffCodeTableData) & 0x7F,  // Second byte of table length
844    0x00,  // Delta_indicator (no compression)
845    0x00,  // length of data for ADDs and RUNs (unused)
846    0x19,  // length of interleaved section
847    0x00,  // length of addresses for COPYs (unused)
848    0x05,  // VCD_ADD size 4
849    // Data for ADD (length 4)
850    VCD_RUN, VCD_ADD, VCD_ADD, VCD_RUN,
851    0x13,  // VCD_COPY mode VCD_SELF size 0
852    0x84,  // Size of copy: upper bits (512 - 4 + 17 = 525)
853    0x0D,  // Size of copy: lower bits
854    0x04,  // Address of COPY
855    0x03,  // VCD_ADD size 2
856    // Data for ADD (length 2)
857    0x1B, 0x3D,
858    0x3F,  // VCD_COPY mode VCD_NEAR(0) size 15
859    0x84,  // Address of copy: upper bits (525 + 2 = 527)
860    0x0F,  // Address of copy: lower bits
861    0x02,  // VCD_ADD size 1
862    // Data for ADD (length 1)
863    0x1C,
864    0x4F,  // VCD_COPY mode VCD_NEAR(1) size 15
865    0x10,  // Address of copy
866    0x02,  // VCD_ADD size 1
867    // Data for ADD (length 1)
868    0x2C,
869    0x53,  // VCD_COPY mode VCD_NEAR(2) size 0
870    0x87,  // Size of copy: upper bits (256 * 4 - 51 = 973)
871    0x4D,  // Size of copy: lower bits
872    0x10   // Address of copy
873  };
874
875// This is similar to VCDiffInterleavedDecoderTest, but uses the custom code
876// table to eliminate the need to explicitly encode instruction sizes.
877// Notice that NEAR(0) mode is used here where NEAR(1) mode was used in
878// VCDiffInterleavedDecoderTest.  This is because the custom code table
879// has the size of the NEAR cache set to 1; only the most recent
880// COPY instruction is available.  This will also be a test of
881// custom cache sizes.
882const char VCDiffCustomCodeTableDecoderTest::kWindowHeader[] = {
883    VCD_SOURCE,  // Win_Indicator: take source from dictionary
884    FirstByteOfStringLength(kDictionary),  // Source segment size
885    SecondByteOfStringLength(kDictionary),
886    0x00,  // Source segment position: start of dictionary
887    0x74,  // Length of the delta encoding
888    FirstByteOfStringLength(kExpectedTarget),  // Size of the target window
889    SecondByteOfStringLength(kExpectedTarget),
890    0x00,  // Delta_indicator (no compression)
891    0x00,  // length of data for ADDs and RUNs (unused)
892    0x6E,  // length of interleaved section
893    0x00   // length of addresses for COPYs (unused)
894  };
895
896const char VCDiffCustomCodeTableDecoderTest::kWindowBody[] = {
897    0x22,  // VCD_COPY mode VCD_SELF, size 28
898    0x00,  // Address of COPY: Start of dictionary
899    0x12,  // VCD_ADD size 61
900    // Data for ADD (length 61)
901    ' ', 'I', ' ', 'h', 'a', 'v', 'e', ' ', 's', 'a', 'i', 'd', ' ',
902    'i', 't', ' ', 't', 'w', 'i', 'c', 'e', ':', '\n',
903    'T', 'h', 'a', 't', ' ',
904    'a', 'l', 'o', 'n', 'e', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ',
905    'e', 'n', 'c', 'o', 'u', 'r', 'a', 'g', 'e', ' ',
906    't', 'h', 'e', ' ', 'c', 'r', 'e', 'w', '.', '\n',
907    0x32,  // VCD_COPY mode VCD_HERE, size 44
908    0x58,  // HERE mode address (27+61 back from here_address)
909    0xBF,  // VCD_ADD size 2 + VCD_COPY mode NEAR(0), size 5
910    // Data for ADDs: 2nd section (length 2)
911    'h', 'r',
912    0x2D,  // NEAR(0) mode address (45 after prior address)
913    0x0A,  // VCD_ADD size 9
914    // Data for ADDs: 3rd section (length 9)
915    'W', 'h', 'a', 't', ' ',
916    'I', ' ', 't', 'e',
917    0x03,  // VCD_RUN size 2
918    // Data for RUN: 4th section (length 1)
919    'l',
920    0x11,  // VCD_ADD size 27
921    // Data for ADD: 4th section (length 27)
922    ' ', 'y', 'o', 'u', ' ',
923    't', 'h', 'r', 'e', 'e', ' ', 't', 'i', 'm', 'e', 's', ' ', 'i', 's', ' ',
924    't', 'r', 'u', 'e', '.', '\"', '\n'
925  };
926
927VCDiffCustomCodeTableDecoderTest::VCDiffCustomCodeTableDecoderTest() {
928  delta_file_header_.assign(kFileHeader, sizeof(kFileHeader));
929  delta_file_header_.push_back(0x01);  // NEAR cache size (custom)
930  delta_file_header_.push_back(0x06);  // SAME cache size (custom)
931  delta_file_header_.append(kEncodedCustomCodeTable,
932                            sizeof(kEncodedCustomCodeTable));
933  delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader));
934  delta_window_body_.assign(kWindowBody, sizeof(kWindowBody));
935}
936
937TEST_F(VCDiffCustomCodeTableDecoderTest, CustomCodeTableEncodingMatches) {
938  VCDiffCodeTableData custom_code_table(
939    VCDiffCodeTableData::kDefaultCodeTableData);
940  custom_code_table.inst1[3] = VCD_RUN;
941  custom_code_table.size1[17] = 27;
942  custom_code_table.size1[18] = 61;
943  custom_code_table.size1[34] = 28;
944  custom_code_table.size1[50] = 44;
945
946  decoder_.StartDecoding(
947      reinterpret_cast<const char*>(
948          &VCDiffCodeTableData::kDefaultCodeTableData),
949      sizeof(VCDiffCodeTableData::kDefaultCodeTableData));
950  EXPECT_TRUE(decoder_.DecodeChunk(kEncodedCustomCodeTable,
951                                   sizeof(kEncodedCustomCodeTable),
952                                   &output_));
953  EXPECT_TRUE(decoder_.FinishDecoding());
954  EXPECT_EQ(sizeof(custom_code_table), output_.size());
955  const VCDiffCodeTableData* decoded_table =
956      reinterpret_cast<const VCDiffCodeTableData*>(output_.data());
957  EXPECT_EQ(VCD_RUN, decoded_table->inst1[0]);
958  EXPECT_EQ(VCD_RUN, decoded_table->inst1[3]);
959  EXPECT_EQ(27, decoded_table->size1[17]);
960  EXPECT_EQ(61, decoded_table->size1[18]);
961  EXPECT_EQ(28, decoded_table->size1[34]);
962  EXPECT_EQ(44, decoded_table->size1[50]);
963  for (int i = 0; i < VCDiffCodeTableData::kCodeTableSize; ++i) {
964    EXPECT_EQ(custom_code_table.inst1[i], decoded_table->inst1[i]);
965    EXPECT_EQ(custom_code_table.inst2[i], decoded_table->inst2[i]);
966    EXPECT_EQ(custom_code_table.size1[i], decoded_table->size1[i]);
967    EXPECT_EQ(custom_code_table.size2[i], decoded_table->size2[i]);
968    EXPECT_EQ(custom_code_table.mode1[i], decoded_table->mode1[i]);
969    EXPECT_EQ(custom_code_table.mode2[i], decoded_table->mode2[i]);
970  }
971}
972
973TEST_F(VCDiffCustomCodeTableDecoderTest, DecodeUsingCustomCodeTable) {
974  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
975  EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
976                                   delta_file_.size(),
977                                   &output_));
978  EXPECT_TRUE(decoder_.FinishDecoding());
979  EXPECT_EQ(expected_target_.c_str(), output_);
980}
981
982TEST_F(VCDiffCustomCodeTableDecoderTest, IncompleteCustomCodeTable) {
983  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
984  EXPECT_TRUE(decoder_.DecodeChunk(delta_file_header_.data(),
985                                   delta_file_header_.size() - 1,
986                                   &output_));
987  EXPECT_FALSE(decoder_.FinishDecoding());
988  EXPECT_EQ("", output_);
989}
990
991typedef VCDiffCustomCodeTableDecoderTest
992    VCDiffCustomCodeTableDecoderTestByteByByte;
993
994TEST_F(VCDiffCustomCodeTableDecoderTestByteByByte, DecodeUsingCustomCodeTable) {
995  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
996  for (size_t i = 0; i < delta_file_.size(); ++i) {
997    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
998  }
999  EXPECT_TRUE(decoder_.FinishDecoding());
1000  EXPECT_EQ(expected_target_.c_str(), output_);
1001}
1002
1003TEST_F(VCDiffCustomCodeTableDecoderTestByteByByte, IncompleteCustomCodeTable) {
1004  delta_file_.resize(delta_file_header_.size() - 1);
1005  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
1006  for (size_t i = 0; i < delta_file_.size(); ++i) {
1007    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
1008  }
1009  EXPECT_FALSE(decoder_.FinishDecoding());
1010  EXPECT_EQ("", output_);
1011}
1012
1013TEST_F(VCDiffCustomCodeTableDecoderTestByteByByte, CustomTableNoVcdTarget) {
1014  decoder_.SetAllowVcdTarget(false);
1015  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
1016  for (size_t i = 0; i < delta_file_.size(); ++i) {
1017    EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
1018  }
1019  EXPECT_TRUE(decoder_.FinishDecoding());
1020  EXPECT_EQ(expected_target_.c_str(), output_);
1021}
1022
1023#ifdef GTEST_HAS_DEATH_TEST
1024typedef VCDiffCustomCodeTableDecoderTest VCDiffCustomCodeTableDecoderDeathTest;
1025
1026TEST_F(VCDiffCustomCodeTableDecoderDeathTest, BadCustomCacheSizes) {
1027  delta_file_header_.assign(kFileHeader, sizeof(kFileHeader));
1028  delta_file_header_.push_back(0x81);  // NEAR cache size (top bit)
1029  delta_file_header_.push_back(0x10);  // NEAR cache size (custom value 0x90)
1030  delta_file_header_.push_back(0x81);  // SAME cache size (top bit)
1031  delta_file_header_.push_back(0x10);  // SAME cache size (custom value 0x90)
1032  delta_file_header_.append(kEncodedCustomCodeTable,
1033                            sizeof(kEncodedCustomCodeTable));
1034  InitializeDeltaFile();
1035  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
1036  EXPECT_DEBUG_DEATH(EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(),
1037                                                       delta_file_.size(),
1038                                                       &output_)),
1039                     "cache");
1040  EXPECT_EQ("", output_);
1041}
1042
1043TEST_F(VCDiffCustomCodeTableDecoderDeathTest, BadCustomCacheSizesNoVcdTarget) {
1044  decoder_.SetAllowVcdTarget(false);
1045  delta_file_header_.assign(kFileHeader, sizeof(kFileHeader));
1046  delta_file_header_.push_back(0x81);  // NEAR cache size (top bit)
1047  delta_file_header_.push_back(0x10);  // NEAR cache size (custom value 0x90)
1048  delta_file_header_.push_back(0x81);  // SAME cache size (top bit)
1049  delta_file_header_.push_back(0x10);  // SAME cache size (custom value 0x90)
1050  delta_file_header_.append(kEncodedCustomCodeTable,
1051                            sizeof(kEncodedCustomCodeTable));
1052  InitializeDeltaFile();
1053  decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
1054  EXPECT_DEBUG_DEATH(EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(),
1055                                                       delta_file_.size(),
1056                                                       &output_)),
1057                     "cache");
1058  EXPECT_EQ("", output_);
1059}
1060
1061#endif  // GTEST_HAS_DEATH_TEST
1062
1063}  // namespace open_vcdiff
1064}  // unnamed namespace
1065