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