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