• 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_.c_str(), 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_.c_str(), 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_.c_str(), 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_.c_str(), 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_.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.
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_.c_str(),
283             output_chunk1 + output_chunk2 + output_chunk3);
284 }
285 
TEST_F(VCDiffStandardWindowDecoderTest,DecodeChunkNoVcdTargetAllowed)286 TEST_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 
TEST_F(VCDiffStandardWindowDecoderTest,DecodeInTwoParts)301 TEST_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 
TEST_F(VCDiffStandardWindowDecoderTest,DecodeInThreeParts)317 TEST_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.
TEST_F(VCDiffStandardWindowDecoderTest,TargetMatchesWindowSizeLimit)342 TEST_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 
TEST_F(VCDiffStandardWindowDecoderTest,TargetMatchesFileSizeLimit)352 TEST_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 
TEST_F(VCDiffStandardWindowDecoderTest,TargetExceedsWindowSizeLimit)362 TEST_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 
TEST_F(VCDiffStandardWindowDecoderTest,TargetExceedsFileSizeLimit)371 TEST_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 
380 typedef VCDiffStandardWindowDecoderTest
381     VCDiffStandardWindowDecoderTestByteByByte;
382 
TEST_F(VCDiffStandardWindowDecoderTestByteByByte,Decode)383 TEST_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 
TEST_F(VCDiffStandardWindowDecoderTestByteByByte,DecodeExplicitVcdTarget)392 TEST_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.
TEST_F(VCDiffStandardWindowDecoderTestByteByByte,DecodeNoVcdTarget)403 TEST_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.
419 class VCDiffInterleavedWindowDecoderTest
420     : public VCDiffStandardWindowDecoderTest {
421  protected:
422   VCDiffInterleavedWindowDecoderTest();
~VCDiffInterleavedWindowDecoderTest()423   virtual ~VCDiffInterleavedWindowDecoderTest() {}
424  private:
425   static const char kWindowBody[];
426 };
427 
428 const 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 
VCDiffInterleavedWindowDecoderTest()521 VCDiffInterleavedWindowDecoderTest::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 
TEST_F(VCDiffInterleavedWindowDecoderTest,Decode)529 TEST_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 
TEST_F(VCDiffInterleavedWindowDecoderTest,DecodeInTwoParts)538 TEST_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 
TEST_F(VCDiffInterleavedWindowDecoderTest,DecodeInThreeParts)554 TEST_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 
576 typedef VCDiffInterleavedWindowDecoderTest
577     VCDiffInterleavedWindowDecoderTestByteByByte;
578 
TEST_F(VCDiffInterleavedWindowDecoderTestByteByByte,Decode)579 TEST_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.
TEST_F(VCDiffInterleavedWindowDecoderTestByteByByte,DecodeNoVcdTarget)589 TEST_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 //
TEST_F(VCDiffInterleavedWindowDecoderTest,OutputStringCanBeModified)611 TEST_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 
TEST_F(VCDiffInterleavedWindowDecoderTest,OutputStringIsPreserved)623 TEST_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.
636 class VCDiffStandardCrossDecoderTest : public VCDiffDecoderTest {
637  protected:
638   static const char kExpectedTarget[];
639   static const char kWindowHeader[];
640   static const char kWindowBody[];
641 
642   VCDiffStandardCrossDecoderTest();
~VCDiffStandardCrossDecoderTest()643   virtual ~VCDiffStandardCrossDecoderTest() {}
644 };
645 
646 const 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 
659 const 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 
675 const char VCDiffStandardCrossDecoderTest::kExpectedTarget[] =
676     "Spiders in his hair.\n"
677     "Spiders in the air.\n";
678 
VCDiffStandardCrossDecoderTest()679 VCDiffStandardCrossDecoderTest::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 
TEST_F(VCDiffStandardCrossDecoderTest,Decode)686 TEST_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 
695 typedef VCDiffStandardCrossDecoderTest VCDiffStandardCrossDecoderTestByteByByte;
696 
TEST_F(VCDiffStandardCrossDecoderTestByteByByte,Decode)697 TEST_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.
709 class VCDiffInterleavedCrossDecoderTest
710     : public VCDiffStandardCrossDecoderTest {
711  protected:
712   VCDiffInterleavedCrossDecoderTest();
~VCDiffInterleavedCrossDecoderTest()713   virtual ~VCDiffInterleavedCrossDecoderTest() {}
714 
715  private:
716   static const char kWindowHeader[];
717   static const char kWindowBody[];
718 };
719 
720 const 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 
733 const 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 
VCDiffInterleavedCrossDecoderTest()747 VCDiffInterleavedCrossDecoderTest::VCDiffInterleavedCrossDecoderTest() {
748   UseInterleavedFileHeader();
749   delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader));
750   delta_window_body_.assign(kWindowBody, sizeof(kWindowBody));
751 }
752 
TEST_F(VCDiffInterleavedCrossDecoderTest,Decode)753 TEST_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 
TEST_F(VCDiffInterleavedCrossDecoderTest,DecodeWithChecksum)762 TEST_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 
773 typedef VCDiffInterleavedCrossDecoderTest
774     VCDiffInterleavedCrossDecoderTestByteByByte;
775 
TEST_F(VCDiffInterleavedCrossDecoderTestByteByByte,Decode)776 TEST_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 
TEST_F(VCDiffInterleavedCrossDecoderTestByteByByte,DecodeWithChecksum)785 TEST_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.
798 class 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();
~VCDiffCustomCodeTableDecoderTest()806   virtual ~VCDiffCustomCodeTableDecoderTest() {}
807 };
808 
809 const 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 //
831 const 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.
882 const 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 
896 const 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 
VCDiffCustomCodeTableDecoderTest()927 VCDiffCustomCodeTableDecoderTest::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 
TEST_F(VCDiffCustomCodeTableDecoderTest,CustomCodeTableEncodingMatches)937 TEST_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 
TEST_F(VCDiffCustomCodeTableDecoderTest,DecodeUsingCustomCodeTable)973 TEST_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 
TEST_F(VCDiffCustomCodeTableDecoderTest,IncompleteCustomCodeTable)982 TEST_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 
991 typedef VCDiffCustomCodeTableDecoderTest
992     VCDiffCustomCodeTableDecoderTestByteByByte;
993 
TEST_F(VCDiffCustomCodeTableDecoderTestByteByByte,DecodeUsingCustomCodeTable)994 TEST_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 
TEST_F(VCDiffCustomCodeTableDecoderTestByteByByte,IncompleteCustomCodeTable)1003 TEST_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 
TEST_F(VCDiffCustomCodeTableDecoderTestByteByByte,CustomTableNoVcdTarget)1013 TEST_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
1024 typedef VCDiffCustomCodeTableDecoderTest VCDiffCustomCodeTableDecoderDeathTest;
1025 
TEST_F(VCDiffCustomCodeTableDecoderDeathTest,BadCustomCacheSizes)1026 TEST_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 
TEST_F(VCDiffCustomCodeTableDecoderDeathTest,BadCustomCacheSizesNoVcdTarget)1043 TEST_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