blob: 55c0c61ca2ec21ca41f7669e066040fd391649e8 [file] [log] [blame]
openvcdiff311c7142008-08-26 19:29:25 +00001// Copyright 2008 Google Inc.
2// Author: Lincoln Smith
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#include <config.h>
17#include "google/vcdecoder.h"
18#include <string>
19#include "codetable.h"
20#include "testing.h"
21#include "vcdecoder_test.h"
22#include "vcdiff_defs.h" // VCD_SOURCE
23
24namespace open_vcdiff {
25namespace {
26
openvcdiff311c7142008-08-26 19:29:25 +000027// Use the interleaved file header with the standard encoding. Should work.
28class VCDiffDecoderInterleavedAllowedButNotUsed
29 : public VCDiffStandardDecoderTest {
30 public:
31 VCDiffDecoderInterleavedAllowedButNotUsed() {
32 UseInterleavedFileHeader();
33 }
34 virtual ~VCDiffDecoderInterleavedAllowedButNotUsed() { }
35};
36
37TEST_F(VCDiffDecoderInterleavedAllowedButNotUsed, Decode) {
38 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
39 EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
40 delta_file_.size(),
41 &output_));
42 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +000043 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +000044}
45
46TEST_F(VCDiffDecoderInterleavedAllowedButNotUsed, DecodeWithChecksum) {
47 ComputeAndAddChecksum();
48 InitializeDeltaFile();
49 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
50 EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
51 delta_file_.size(),
52 &output_));
53 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +000054 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +000055}
56
57typedef VCDiffDecoderInterleavedAllowedButNotUsed
58 VCDiffDecoderInterleavedAllowedButNotUsedByteByByte;
59
60TEST_F(VCDiffDecoderInterleavedAllowedButNotUsedByteByByte, Decode) {
61 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
62 for (size_t i = 0; i < delta_file_.size(); ++i) {
63 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
64 }
65 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +000066 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +000067}
68
69TEST_F(VCDiffDecoderInterleavedAllowedButNotUsedByteByByte,
70 DecodeWithChecksum) {
71 ComputeAndAddChecksum();
72 InitializeDeltaFile();
73 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
74 for (size_t i = 0; i < delta_file_.size(); ++i) {
75 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
76 }
77 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +000078 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +000079}
80
81// Use the standard file header with the interleaved encoding. Should fail.
82class VCDiffDecoderInterleavedUsedButNotSupported
83 : public VCDiffInterleavedDecoderTest {
84 public:
85 VCDiffDecoderInterleavedUsedButNotSupported() {
86 UseStandardFileHeader();
87 }
88 virtual ~VCDiffDecoderInterleavedUsedButNotSupported() { }
89};
90
91TEST_F(VCDiffDecoderInterleavedUsedButNotSupported, DecodeShouldFail) {
92 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
93 EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(),
94 delta_file_.size(),
95 &output_));
96 EXPECT_EQ("", output_);
97}
98
99TEST_F(VCDiffDecoderInterleavedUsedButNotSupported,
100 DecodeByteByByteShouldFail) {
101 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
102 bool failed = false;
103 for (size_t i = 0; i < delta_file_.size(); ++i) {
104 if (!decoder_.DecodeChunk(&delta_file_[i], 1, &output_)) {
105 failed = true;
106 break;
107 }
108 }
109 EXPECT_TRUE(failed);
110 // The decoder should not create more target bytes than were expected.
111 EXPECT_GE(expected_target_.size(), output_.size());
112}
113
114// Divides up the standard encoding into eight separate delta file windows.
115// Each delta instruction appears in its own window.
116class VCDiffStandardWindowDecoderTest : public VCDiffDecoderTest {
117 protected:
openvcdiff28db8072008-10-10 23:29:11 +0000118 static const size_t kWindow2Size = 61;
119
openvcdiff311c7142008-08-26 19:29:25 +0000120 VCDiffStandardWindowDecoderTest();
121 virtual ~VCDiffStandardWindowDecoderTest() {}
122
123 private:
openvcdiff311c7142008-08-26 19:29:25 +0000124 static const char kWindowBody[];
125};
126
openvcdiff28db8072008-10-10 23:29:11 +0000127const size_t VCDiffStandardWindowDecoderTest::kWindow2Size;
128
openvcdiff311c7142008-08-26 19:29:25 +0000129const 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
openvcdiff28db8072008-10-10 23:29:11 +0000150 static_cast<char>(kWindow2Size), // Size of the target window (61)
openvcdiff311c7142008-08-26 19:29:25 +0000151 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
openvcdiff311c7142008-08-26 19:29:25 +0000243VCDiffStandardWindowDecoderTest::VCDiffStandardWindowDecoderTest() {
244 UseStandardFileHeader();
openvcdiff311c7142008-08-26 19:29:25 +0000245 delta_window_body_.assign(kWindowBody, sizeof(kWindowBody));
246}
247
248TEST_F(VCDiffStandardWindowDecoderTest, Decode) {
249 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
250 EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
251 delta_file_.size(),
252 &output_));
253 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000254 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +0000255}
256
257// Bug 1287926: If DecodeChunk() stops in the middle of the window header,
258// and the expected size of the current target window is smaller than the
259// cumulative target bytes decoded so far, an underflow occurs and the decoder
260// tries to allocate ~MAX_INT bytes.
261TEST_F(VCDiffStandardWindowDecoderTest, DecodeBreakInFourthWindowHeader) {
262 // Parse file header + first two windows.
openvcdiff83bbde02008-10-23 23:43:46 +0000263 const size_t chunk_1_size = delta_file_header_.size() + 83;
openvcdiff311c7142008-08-26 19:29:25 +0000264 // 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.
openvcdiff83bbde02008-10-23 23:43:46 +0000266 const size_t chunk_2_size = 12 + 5;
openvcdiff311c7142008-08-26 19:29:25 +0000267 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());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000282 EXPECT_EQ(expected_target_.c_str(),
283 output_chunk1 + output_chunk2 + output_chunk3);
openvcdiff311c7142008-08-26 19:29:25 +0000284}
285
openvcdiffbaf44ea2009-04-09 19:20:49 +0000286TEST_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.
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000298 EXPECT_EQ(expected_target_.substr(0, 89).c_str(), output_);
openvcdiffbaf44ea2009-04-09 19:20:49 +0000299}
300
openvcdiff311c7142008-08-26 19:29:25 +0000301TEST_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());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000313 EXPECT_EQ(expected_target_.c_str(), output_chunk1 + output_chunk2);
openvcdiff311c7142008-08-26 19:29:25 +0000314 }
315}
316
317TEST_F(VCDiffStandardWindowDecoderTest, DecodeInThreeParts) {
318 const size_t delta_file_size = delta_file_.size();
319 for (size_t i = 1; i < delta_file_size - 1; i++) {
320 for (size_t j = i + 1; j < delta_file_size; j++) {
321 string output_chunk1, output_chunk2, output_chunk3;
322 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
323 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0],
324 i,
325 &output_chunk1));
326 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i],
327 j - i,
328 &output_chunk2));
329 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[j],
330 delta_file_size - j,
331 &output_chunk3));
332 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000333 EXPECT_EQ(expected_target_.c_str(),
openvcdiff311c7142008-08-26 19:29:25 +0000334 output_chunk1 + output_chunk2 + output_chunk3);
335 }
336 }
337}
338
openvcdiff28db8072008-10-10 23:29:11 +0000339// For the window test, the maximum target window size is much smaller than the
340// target file size. (The largest window is Window 2, with 61 target bytes.)
341// Use the minimum values possible.
342TEST_F(VCDiffStandardWindowDecoderTest, TargetMatchesWindowSizeLimit) {
343 decoder_.SetMaximumTargetWindowSize(kWindow2Size);
344 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
345 EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
346 delta_file_.size(),
347 &output_));
348 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000349 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff28db8072008-10-10 23:29:11 +0000350}
351
352TEST_F(VCDiffStandardWindowDecoderTest, TargetMatchesFileSizeLimit) {
353 decoder_.SetMaximumTargetFileSize(expected_target_.size());
354 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
355 EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
356 delta_file_.size(),
357 &output_));
358 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000359 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff28db8072008-10-10 23:29:11 +0000360}
361
362TEST_F(VCDiffStandardWindowDecoderTest, TargetExceedsWindowSizeLimit) {
363 decoder_.SetMaximumTargetWindowSize(kWindow2Size - 1);
364 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
365 EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(),
366 delta_file_.size(),
367 &output_));
368 EXPECT_EQ("", output_);
369}
370
371TEST_F(VCDiffStandardWindowDecoderTest, TargetExceedsFileSizeLimit) {
372 decoder_.SetMaximumTargetFileSize(expected_target_.size() - 1);
373 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
374 EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(),
375 delta_file_.size(),
376 &output_));
377 EXPECT_EQ("", output_);
378}
379
openvcdiff311c7142008-08-26 19:29:25 +0000380typedef VCDiffStandardWindowDecoderTest
381 VCDiffStandardWindowDecoderTestByteByByte;
openvcdiffbaf44ea2009-04-09 19:20:49 +0000382
openvcdiff311c7142008-08-26 19:29:25 +0000383TEST_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());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000389 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +0000390}
391
openvcdiffbaf44ea2009-04-09 19:20:49 +0000392TEST_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());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000399 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiffbaf44ea2009-04-09 19:20:49 +0000400}
401
402// Windows 3 and 4 use the VCD_TARGET flag, so decoder should signal an error.
403TEST_F(VCDiffStandardWindowDecoderTestByteByByte, DecodeNoVcdTarget) {
404 decoder_.SetAllowVcdTarget(false);
405 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
406 size_t i = 0;
407 for (; i < delta_file_.size(); ++i) {
408 if (!decoder_.DecodeChunk(&delta_file_[i], 1, &output_)) {
409 break;
410 }
411 }
412 // The failure should occur just at the position of the first VCD_TARGET.
413 EXPECT_EQ(delta_file_header_.size() + 83, i);
414 // The target data for the first two windows should have been output.
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000415 EXPECT_EQ(expected_target_.substr(0, 89).c_str(), output_);
openvcdiffbaf44ea2009-04-09 19:20:49 +0000416}
417
openvcdiff311c7142008-08-26 19:29:25 +0000418// Divides up the interleaved encoding into eight separate delta file windows.
419class VCDiffInterleavedWindowDecoderTest
420 : public VCDiffStandardWindowDecoderTest {
421 protected:
422 VCDiffInterleavedWindowDecoderTest();
423 virtual ~VCDiffInterleavedWindowDecoderTest() {}
424 private:
425 static const char kWindowBody[];
426};
427
428const char VCDiffInterleavedWindowDecoderTest::kWindowBody[] = {
429// Window 1:
430 VCD_SOURCE, // Win_Indicator: take source from dictionary
431 FirstByteOfStringLength(kDictionary), // Source segment size
432 SecondByteOfStringLength(kDictionary),
433 0x00, // Source segment position: start of dictionary
434 0x08, // Length of the delta encoding
435 0x1C, // Size of the target window (28)
436 0x00, // Delta_indicator (no compression)
437 0x00, // length of data for ADDs and RUNs
438 0x03, // length of instructions section
439 0x00, // length of addresses for COPYs
440 0x13, // VCD_COPY mode VCD_SELF, size 0
441 0x1C, // Size of COPY (28)
442 0x00, // Start of dictionary
443// Window 2:
444 0x00, // Win_Indicator: No source segment (ADD only)
445 0x44, // Length of the delta encoding
446 0x3D, // Size of the target window (61)
447 0x00, // Delta_indicator (no compression)
448 0x00, // length of data for ADDs and RUNs
449 0x3F, // length of instructions section
450 0x00, // length of addresses for COPYs
451 0x01, // VCD_ADD size 0
452 0x3D, // Size of ADD (61)
453 ' ', 'I', ' ', 'h', 'a', 'v', 'e', ' ', 's', 'a', 'i', 'd', ' ',
454 'i', 't', ' ', 't', 'w', 'i', 'c', 'e', ':', '\n',
455 'T', 'h', 'a', 't', ' ',
456 'a', 'l', 'o', 'n', 'e', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ',
457 'e', 'n', 'c', 'o', 'u', 'r', 'a', 'g', 'e', ' ',
458 't', 'h', 'e', ' ', 'c', 'r', 'e', 'w', '.', '\n',
459// Window 3:
460 VCD_TARGET, // Win_Indicator: take source from decoded data
461 0x59, // Source segment size: length of data decoded so far
462 0x00, // Source segment position: start of decoded data
463 0x08, // Length of the delta encoding
464 0x2C, // Size of the target window
465 0x00, // Delta_indicator (no compression)
466 0x00, // length of data for ADDs and RUNs
467 0x03, // length of instructions section
468 0x00, // length of addresses for COPYs
469 0x23, // VCD_COPY mode VCD_HERE, size 0
470 0x2C, // Size of COPY (44)
471 0x58, // HERE mode address (27+61 back from here_address)
472// Window 4:
473 VCD_TARGET, // Win_Indicator: take source from decoded data
474 0x05, // Source segment size: only 5 bytes needed for this COPY
475 0x2E, // Source segment position: offset for COPY
476 0x09, // Length of the delta encoding
477 0x07, // Size of the target window
478 0x00, // Delta_indicator (no compression)
479 0x00, // length of data for ADDs and RUNs
480 0x04, // length of instructions section
481 0x00, // length of addresses for COPYs
482 0xA7, // VCD_ADD size 2 + VCD_COPY mode SELF, size 5
483 'h', 'r',
484 0x00, // SELF mode address (start of source segment)
485// Window 5:
486 0x00, // Win_Indicator: No source segment (ADD only)
487 0x0F, // Length of the delta encoding
488 0x09, // Size of the target window
489 0x00, // Delta_indicator (no compression)
490 0x00, // length of data for ADDs and RUNs
491 0x0A, // length of instructions section
492 0x00, // length of addresses for COPYs
493 0x0A, // VCD_ADD size 9
494 'W', 'h', 'a', 't', ' ', 'I', ' ', 't', 'e',
495// Window 6:
496 0x00, // Win_Indicator: No source segment (RUN only)
497 0x08, // Length of the delta encoding
498 0x02, // Size of the target window
499 0x00, // Delta_indicator (no compression)
500 0x00, // length of data for ADDs and RUNs
501 0x03, // length of instructions section
502 0x00, // length of addresses for COPYs
503 0x00, // VCD_RUN size 0
504 0x02, // Size of RUN (2)
505 'l',
506// Window 7:
507 0x00, // Win_Indicator: No source segment (ADD only)
508 0x22, // Length of the delta encoding
509 0x1B, // Size of the target window
510 0x00, // Delta_indicator (no compression)
511 0x00, // length of data for ADDs and RUNs
512 0x1D, // length of instructions section
513 0x00, // length of addresses for COPYs
514 0x01, // VCD_ADD size 0
515 0x1B, // Size of ADD (27)
516 ' ', 'y', 'o', 'u', ' ',
517 't', 'h', 'r', 'e', 'e', ' ', 't', 'i', 'm', 'e', 's', ' ', 'i', 's', ' ',
518 't', 'r', 'u', 'e', '.', '\"', '\n',
519 };
520
521VCDiffInterleavedWindowDecoderTest::VCDiffInterleavedWindowDecoderTest() {
522 UseInterleavedFileHeader();
523 // delta_window_header_ is left blank. All window headers and bodies are
524 // lumped together in delta_window_body_. This means that AddChecksum()
525 // cannot be used to test the checksum feature.
526 delta_window_body_.assign(kWindowBody, sizeof(kWindowBody));
527}
528
529TEST_F(VCDiffInterleavedWindowDecoderTest, Decode) {
530 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
531 EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
532 delta_file_.size(),
533 &output_));
534 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000535 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +0000536}
537
538TEST_F(VCDiffInterleavedWindowDecoderTest, DecodeInTwoParts) {
539 const size_t delta_file_size = delta_file_.size();
540 for (size_t i = 1; i < delta_file_size; i++) {
541 string output_chunk1, output_chunk2;
542 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
543 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0],
544 i,
545 &output_chunk1));
546 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i],
547 delta_file_size - i,
548 &output_chunk2));
549 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000550 EXPECT_EQ(expected_target_.c_str(), output_chunk1 + output_chunk2);
openvcdiff311c7142008-08-26 19:29:25 +0000551 }
552}
553
554TEST_F(VCDiffInterleavedWindowDecoderTest, DecodeInThreeParts) {
555 const size_t delta_file_size = delta_file_.size();
556 for (size_t i = 1; i < delta_file_size - 1; i++) {
557 for (size_t j = i + 1; j < delta_file_size; j++) {
558 string output_chunk1, output_chunk2, output_chunk3;
559 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
560 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[0],
561 i,
562 &output_chunk1));
563 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i],
564 j - i,
565 &output_chunk2));
566 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[j],
567 delta_file_size - j,
568 &output_chunk3));
569 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000570 EXPECT_EQ(expected_target_.c_str(),
openvcdiff311c7142008-08-26 19:29:25 +0000571 output_chunk1 + output_chunk2 + output_chunk3);
572 }
573 }
574}
575
576typedef VCDiffInterleavedWindowDecoderTest
577 VCDiffInterleavedWindowDecoderTestByteByByte;
578
579TEST_F(VCDiffInterleavedWindowDecoderTestByteByByte, Decode) {
580 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
581 for (size_t i = 0; i < delta_file_.size(); ++i) {
582 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
583 }
584 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000585 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +0000586}
587
openvcdiffbaf44ea2009-04-09 19:20:49 +0000588// Windows 3 and 4 use the VCD_TARGET flag, so decoder should signal an error.
589TEST_F(VCDiffInterleavedWindowDecoderTestByteByByte, DecodeNoVcdTarget) {
590 decoder_.SetAllowVcdTarget(false);
591 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
592 size_t i = 0;
593 for (; i < delta_file_.size(); ++i) {
594 if (!decoder_.DecodeChunk(&delta_file_[i], 1, &output_)) {
595 break;
596 }
597 }
598 // The failure should occur just at the position of the first VCD_TARGET.
599 EXPECT_EQ(delta_file_header_.size() + 83, i);
600 // The target data for the first two windows should have been output.
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000601 EXPECT_EQ(expected_target_.substr(0, 89).c_str(), output_);
openvcdiffbaf44ea2009-04-09 19:20:49 +0000602}
603
openvcdiff311c7142008-08-26 19:29:25 +0000604// The original version of VCDiffDecoder did not allow the caller to modify the
605// contents of output_string between calls to DecodeChunk(). That restriction
606// has been removed. Verify that the same result is still produced if the
607// output string is cleared after each call to DecodeChunk(). Use the window
608// encoding because it refers back to the previously decoded target data, which
609// is the feature that would fail if the restriction still applied.
610//
611TEST_F(VCDiffInterleavedWindowDecoderTest, OutputStringCanBeModified) {
612 string temp_output;
613 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
614 for (size_t i = 0; i < delta_file_.size(); ++i) {
615 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &temp_output));
616 output_.append(temp_output);
617 temp_output.clear();
618 }
619 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000620 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +0000621}
622
623TEST_F(VCDiffInterleavedWindowDecoderTest, OutputStringIsPreserved) {
624 const string previous_data("Previous data");
625 output_ = previous_data;
626 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
627 for (size_t i = 0; i < delta_file_.size(); ++i) {
628 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
629 }
630 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000631 EXPECT_EQ((previous_data + expected_target_).c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +0000632}
633
634// A decode job that tests the ability to COPY across the boundary between
635// source data and target data.
636class VCDiffStandardCrossDecoderTest : public VCDiffDecoderTest {
637 protected:
638 static const char kExpectedTarget[];
openvcdiff311c7142008-08-26 19:29:25 +0000639 static const char kWindowHeader[];
640 static const char kWindowBody[];
641
642 VCDiffStandardCrossDecoderTest();
643 virtual ~VCDiffStandardCrossDecoderTest() {}
644};
645
646const char VCDiffStandardCrossDecoderTest::kWindowHeader[] = {
647 VCD_SOURCE, // Win_Indicator: take source from dictionary
648 FirstByteOfStringLength(kDictionary), // Source segment size
649 SecondByteOfStringLength(kDictionary),
650 0x00, // Source segment position: start of dictionary
651 0x15, // Length of the delta encoding
652 StringLengthAsByte(kExpectedTarget), // Size of the target window
653 0x00, // Delta_indicator (no compression)
654 0x07, // length of data for ADDs and RUNs
655 0x06, // length of instructions section
656 0x03 // length of addresses for COPYs
657 };
658
659const char VCDiffStandardCrossDecoderTest::kWindowBody[] = {
660 // Data for ADD (length 7)
661 'S', 'p', 'i', 'd', 'e', 'r', 's',
662 // Instructions and sizes (length 6)
663 0x01, // VCD_ADD size 0
664 0x07, // Size of ADD (7)
665 0x23, // VCD_COPY mode VCD_HERE, size 0
666 0x19, // Size of COPY (25)
667 0x14, // VCD_COPY mode VCD_SELF, size 4
668 0x25, // VCD_COPY mode VCD_HERE, size 5
669 // Addresses for COPYs (length 3)
670 0x15, // HERE mode address for 1st copy (21 back from here_address)
671 0x06, // SELF mode address for 2nd copy
672 0x14 // HERE mode address for 3rd copy
673 };
674
675const char VCDiffStandardCrossDecoderTest::kExpectedTarget[] =
676 "Spiders in his hair.\n"
677 "Spiders in the air.\n";
678
openvcdiff311c7142008-08-26 19:29:25 +0000679VCDiffStandardCrossDecoderTest::VCDiffStandardCrossDecoderTest() {
680 UseStandardFileHeader();
681 delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader));
682 delta_window_body_.assign(kWindowBody, sizeof(kWindowBody));
683 expected_target_.assign(kExpectedTarget);
openvcdiff311c7142008-08-26 19:29:25 +0000684}
685
686TEST_F(VCDiffStandardCrossDecoderTest, Decode) {
687 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
688 EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
689 delta_file_.size(),
690 &output_));
691 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000692 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +0000693}
694
695typedef VCDiffStandardCrossDecoderTest VCDiffStandardCrossDecoderTestByteByByte;
696
697TEST_F(VCDiffStandardCrossDecoderTestByteByByte, Decode) {
698 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
699 for (size_t i = 0; i < delta_file_.size(); ++i) {
700 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
701 }
702 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000703 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +0000704}
705
706// The same decode job that tests the ability to COPY across the boundary
707// between source data and target data, but using the interleaved format rather
708// than the standard format.
709class VCDiffInterleavedCrossDecoderTest
710 : public VCDiffStandardCrossDecoderTest {
711 protected:
712 VCDiffInterleavedCrossDecoderTest();
713 virtual ~VCDiffInterleavedCrossDecoderTest() {}
714
715 private:
716 static const char kWindowHeader[];
717 static const char kWindowBody[];
718};
719
720const char VCDiffInterleavedCrossDecoderTest::kWindowHeader[] = {
721 VCD_SOURCE, // Win_Indicator: take source from dictionary
722 FirstByteOfStringLength(kDictionary), // Source segment size
723 SecondByteOfStringLength(kDictionary),
724 0x00, // Source segment position: start of dictionary
725 0x15, // Length of the delta encoding
726 StringLengthAsByte(kExpectedTarget), // Size of the target window
727 0x00, // Delta_indicator (no compression)
728 0x00, // length of data for ADDs and RUNs
729 0x10, // length of instructions section
730 0x00, // length of addresses for COPYs
731 };
732
733const char VCDiffInterleavedCrossDecoderTest::kWindowBody[] = {
734 0x01, // VCD_ADD size 0
735 0x07, // Size of ADD (7)
736 // Data for ADD (length 7)
737 'S', 'p', 'i', 'd', 'e', 'r', 's',
738 0x23, // VCD_COPY mode VCD_HERE, size 0
739 0x19, // Size of COPY (25)
740 0x15, // HERE mode address for 1st copy (21 back from here_address)
741 0x14, // VCD_COPY mode VCD_SELF, size 4
742 0x06, // SELF mode address for 2nd copy
743 0x25, // VCD_COPY mode VCD_HERE, size 5
744 0x14 // HERE mode address for 3rd copy
745 };
746
747VCDiffInterleavedCrossDecoderTest::VCDiffInterleavedCrossDecoderTest() {
748 UseInterleavedFileHeader();
749 delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader));
750 delta_window_body_.assign(kWindowBody, sizeof(kWindowBody));
751}
752
753TEST_F(VCDiffInterleavedCrossDecoderTest, Decode) {
754 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
755 EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
756 delta_file_.size(),
757 &output_));
758 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000759 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +0000760}
761
762TEST_F(VCDiffInterleavedCrossDecoderTest, DecodeWithChecksum) {
763 ComputeAndAddChecksum();
764 InitializeDeltaFile();
765 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
766 EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
767 delta_file_.size(),
768 &output_));
769 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000770 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +0000771}
772
773typedef VCDiffInterleavedCrossDecoderTest
774 VCDiffInterleavedCrossDecoderTestByteByByte;
775
776TEST_F(VCDiffInterleavedCrossDecoderTestByteByByte, Decode) {
777 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
778 for (size_t i = 0; i < delta_file_.size(); ++i) {
779 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
780 }
781 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000782 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +0000783}
784
785TEST_F(VCDiffInterleavedCrossDecoderTestByteByByte, DecodeWithChecksum) {
786 ComputeAndAddChecksum();
787 InitializeDeltaFile();
788 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
789 for (size_t i = 0; i < delta_file_.size(); ++i) {
790 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
791 }
792 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000793 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +0000794}
795
796// Test using a custom code table and custom cache sizes with interleaved
797// format.
798class VCDiffCustomCodeTableDecoderTest : public VCDiffInterleavedDecoderTest {
799 protected:
800 static const char kFileHeader[];
801 static const char kWindowHeader[];
802 static const char kWindowBody[];
803 static const char kEncodedCustomCodeTable[];
804
805 VCDiffCustomCodeTableDecoderTest();
806 virtual ~VCDiffCustomCodeTableDecoderTest() {}
807};
808
809const char VCDiffCustomCodeTableDecoderTest::kFileHeader[] = {
810 0xD6, // 'V' | 0x80
811 0xC3, // 'C' | 0x80
812 0xC4, // 'D' | 0x80
813 'S', // SDCH version code
814 0x02 // Hdr_Indicator: Use custom code table
815 };
816
817// Make a custom code table that includes exactly the instructions we need
818// to encode the first test's data without using any explicit length values.
819// Be careful not to replace any existing opcodes that have size 0,
820// to ensure that the custom code table is valid (can express all possible
821// values of inst (also known as instruction type) and mode with size 0.)
822// This encoding uses interleaved format, which is easier to read.
823//
824// Here are the changes to the standard code table:
825// ADD size 2 (opcode 3) => RUN size 2 (inst1[3] = VCD_RUN)
826// ADD size 16 (opcode 17) => ADD size 27 (size1[17] = 27)
827// ADD size 17 (opcode 18) => ADD size 61 (size1[18] = 61)
828// COPY mode 0 size 18 (opcode 34) => COPY mode 0 size 28 (size1[34] = 28)
829// COPY mode 1 size 18 (opcode 50) => COPY mode 1 size 44 (size1[50] = 44)
830//
831const char VCDiffCustomCodeTableDecoderTest::kEncodedCustomCodeTable[] = {
832 0xD6, // 'V' | 0x80
833 0xC3, // 'C' | 0x80
834 0xC4, // 'D' | 0x80
835 'S', // SDCH version code
836 0x00, // Hdr_Indicator: no custom code table, no compression
837 VCD_SOURCE, // Win_Indicator: take source from dictionary
838 (sizeof(VCDiffCodeTableData) >> 7) | 0x80, // First byte of table length
839 sizeof(VCDiffCodeTableData) & 0x7F, // Second byte of table length
840 0x00, // Source segment position: start of default code table
841 0x1F, // Length of the delta encoding
842 (sizeof(VCDiffCodeTableData) >> 7) | 0x80, // First byte of table length
843 sizeof(VCDiffCodeTableData) & 0x7F, // Second byte of table length
844 0x00, // Delta_indicator (no compression)
845 0x00, // length of data for ADDs and RUNs (unused)
846 0x19, // length of interleaved section
847 0x00, // length of addresses for COPYs (unused)
848 0x05, // VCD_ADD size 4
849 // Data for ADD (length 4)
850 VCD_RUN, VCD_ADD, VCD_ADD, VCD_RUN,
851 0x13, // VCD_COPY mode VCD_SELF size 0
852 0x84, // Size of copy: upper bits (512 - 4 + 17 = 525)
853 0x0D, // Size of copy: lower bits
854 0x04, // Address of COPY
855 0x03, // VCD_ADD size 2
856 // Data for ADD (length 2)
857 0x1B, 0x3D,
858 0x3F, // VCD_COPY mode VCD_NEAR(0) size 15
859 0x84, // Address of copy: upper bits (525 + 2 = 527)
860 0x0F, // Address of copy: lower bits
861 0x02, // VCD_ADD size 1
862 // Data for ADD (length 1)
863 0x1C,
864 0x4F, // VCD_COPY mode VCD_NEAR(1) size 15
865 0x10, // Address of copy
866 0x02, // VCD_ADD size 1
867 // Data for ADD (length 1)
868 0x2C,
869 0x53, // VCD_COPY mode VCD_NEAR(2) size 0
870 0x87, // Size of copy: upper bits (256 * 4 - 51 = 973)
871 0x4D, // Size of copy: lower bits
872 0x10 // Address of copy
873 };
874
875// This is similar to VCDiffInterleavedDecoderTest, but uses the custom code
876// table to eliminate the need to explicitly encode instruction sizes.
877// Notice that NEAR(0) mode is used here where NEAR(1) mode was used in
878// VCDiffInterleavedDecoderTest. This is because the custom code table
879// has the size of the NEAR cache set to 1; only the most recent
880// COPY instruction is available. This will also be a test of
881// custom cache sizes.
882const char VCDiffCustomCodeTableDecoderTest::kWindowHeader[] = {
883 VCD_SOURCE, // Win_Indicator: take source from dictionary
884 FirstByteOfStringLength(kDictionary), // Source segment size
885 SecondByteOfStringLength(kDictionary),
886 0x00, // Source segment position: start of dictionary
887 0x74, // Length of the delta encoding
888 FirstByteOfStringLength(kExpectedTarget), // Size of the target window
889 SecondByteOfStringLength(kExpectedTarget),
890 0x00, // Delta_indicator (no compression)
891 0x00, // length of data for ADDs and RUNs (unused)
892 0x6E, // length of interleaved section
893 0x00 // length of addresses for COPYs (unused)
894 };
895
896const char VCDiffCustomCodeTableDecoderTest::kWindowBody[] = {
897 0x22, // VCD_COPY mode VCD_SELF, size 28
898 0x00, // Address of COPY: Start of dictionary
899 0x12, // VCD_ADD size 61
900 // Data for ADD (length 61)
901 ' ', 'I', ' ', 'h', 'a', 'v', 'e', ' ', 's', 'a', 'i', 'd', ' ',
902 'i', 't', ' ', 't', 'w', 'i', 'c', 'e', ':', '\n',
903 'T', 'h', 'a', 't', ' ',
904 'a', 'l', 'o', 'n', 'e', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ',
905 'e', 'n', 'c', 'o', 'u', 'r', 'a', 'g', 'e', ' ',
906 't', 'h', 'e', ' ', 'c', 'r', 'e', 'w', '.', '\n',
907 0x32, // VCD_COPY mode VCD_HERE, size 44
908 0x58, // HERE mode address (27+61 back from here_address)
909 0xBF, // VCD_ADD size 2 + VCD_COPY mode NEAR(0), size 5
910 // Data for ADDs: 2nd section (length 2)
911 'h', 'r',
912 0x2D, // NEAR(0) mode address (45 after prior address)
913 0x0A, // VCD_ADD size 9
914 // Data for ADDs: 3rd section (length 9)
915 'W', 'h', 'a', 't', ' ',
916 'I', ' ', 't', 'e',
917 0x03, // VCD_RUN size 2
918 // Data for RUN: 4th section (length 1)
919 'l',
920 0x11, // VCD_ADD size 27
921 // Data for ADD: 4th section (length 27)
922 ' ', 'y', 'o', 'u', ' ',
923 't', 'h', 'r', 'e', 'e', ' ', 't', 'i', 'm', 'e', 's', ' ', 'i', 's', ' ',
924 't', 'r', 'u', 'e', '.', '\"', '\n'
925 };
926
927VCDiffCustomCodeTableDecoderTest::VCDiffCustomCodeTableDecoderTest() {
928 delta_file_header_.assign(kFileHeader, sizeof(kFileHeader));
929 delta_file_header_.push_back(0x01); // NEAR cache size (custom)
930 delta_file_header_.push_back(0x06); // SAME cache size (custom)
931 delta_file_header_.append(kEncodedCustomCodeTable,
932 sizeof(kEncodedCustomCodeTable));
933 delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader));
934 delta_window_body_.assign(kWindowBody, sizeof(kWindowBody));
935}
936
937TEST_F(VCDiffCustomCodeTableDecoderTest, CustomCodeTableEncodingMatches) {
938 VCDiffCodeTableData custom_code_table(
939 VCDiffCodeTableData::kDefaultCodeTableData);
940 custom_code_table.inst1[3] = VCD_RUN;
941 custom_code_table.size1[17] = 27;
942 custom_code_table.size1[18] = 61;
943 custom_code_table.size1[34] = 28;
944 custom_code_table.size1[50] = 44;
945
946 decoder_.StartDecoding(
947 reinterpret_cast<const char*>(
948 &VCDiffCodeTableData::kDefaultCodeTableData),
949 sizeof(VCDiffCodeTableData::kDefaultCodeTableData));
950 EXPECT_TRUE(decoder_.DecodeChunk(kEncodedCustomCodeTable,
951 sizeof(kEncodedCustomCodeTable),
952 &output_));
953 EXPECT_TRUE(decoder_.FinishDecoding());
954 EXPECT_EQ(sizeof(custom_code_table), output_.size());
955 const VCDiffCodeTableData* decoded_table =
956 reinterpret_cast<const VCDiffCodeTableData*>(output_.data());
957 EXPECT_EQ(VCD_RUN, decoded_table->inst1[0]);
958 EXPECT_EQ(VCD_RUN, decoded_table->inst1[3]);
959 EXPECT_EQ(27, decoded_table->size1[17]);
960 EXPECT_EQ(61, decoded_table->size1[18]);
961 EXPECT_EQ(28, decoded_table->size1[34]);
962 EXPECT_EQ(44, decoded_table->size1[50]);
963 for (int i = 0; i < VCDiffCodeTableData::kCodeTableSize; ++i) {
964 EXPECT_EQ(custom_code_table.inst1[i], decoded_table->inst1[i]);
965 EXPECT_EQ(custom_code_table.inst2[i], decoded_table->inst2[i]);
966 EXPECT_EQ(custom_code_table.size1[i], decoded_table->size1[i]);
967 EXPECT_EQ(custom_code_table.size2[i], decoded_table->size2[i]);
968 EXPECT_EQ(custom_code_table.mode1[i], decoded_table->mode1[i]);
969 EXPECT_EQ(custom_code_table.mode2[i], decoded_table->mode2[i]);
970 }
971}
972
973TEST_F(VCDiffCustomCodeTableDecoderTest, DecodeUsingCustomCodeTable) {
974 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
975 EXPECT_TRUE(decoder_.DecodeChunk(delta_file_.data(),
976 delta_file_.size(),
977 &output_));
978 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +0000979 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +0000980}
981
982TEST_F(VCDiffCustomCodeTableDecoderTest, IncompleteCustomCodeTable) {
983 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
984 EXPECT_TRUE(decoder_.DecodeChunk(delta_file_header_.data(),
985 delta_file_header_.size() - 1,
986 &output_));
987 EXPECT_FALSE(decoder_.FinishDecoding());
988 EXPECT_EQ("", output_);
989}
990
991typedef VCDiffCustomCodeTableDecoderTest
992 VCDiffCustomCodeTableDecoderTestByteByByte;
993
994TEST_F(VCDiffCustomCodeTableDecoderTestByteByByte, DecodeUsingCustomCodeTable) {
995 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
996 for (size_t i = 0; i < delta_file_.size(); ++i) {
997 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
998 }
999 EXPECT_TRUE(decoder_.FinishDecoding());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +00001000 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiff311c7142008-08-26 19:29:25 +00001001}
1002
1003TEST_F(VCDiffCustomCodeTableDecoderTestByteByByte, IncompleteCustomCodeTable) {
1004 delta_file_.resize(delta_file_header_.size() - 1);
1005 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
1006 for (size_t i = 0; i < delta_file_.size(); ++i) {
1007 EXPECT_TRUE(decoder_.DecodeChunk(&delta_file_[i], 1, &output_));
1008 }
1009 EXPECT_FALSE(decoder_.FinishDecoding());
1010 EXPECT_EQ("", output_);
1011}
1012
openvcdiffbaf44ea2009-04-09 19:20:49 +00001013TEST_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());
openvcdiff@gmail.com732fff22010-08-04 18:00:00 +00001020 EXPECT_EQ(expected_target_.c_str(), output_);
openvcdiffbaf44ea2009-04-09 19:20:49 +00001021}
1022
openvcdiff311c7142008-08-26 19:29:25 +00001023#ifdef GTEST_HAS_DEATH_TEST
1024typedef VCDiffCustomCodeTableDecoderTest VCDiffCustomCodeTableDecoderDeathTest;
1025
1026TEST_F(VCDiffCustomCodeTableDecoderDeathTest, BadCustomCacheSizes) {
1027 delta_file_header_.assign(kFileHeader, sizeof(kFileHeader));
1028 delta_file_header_.push_back(0x81); // NEAR cache size (top bit)
1029 delta_file_header_.push_back(0x10); // NEAR cache size (custom value 0x90)
1030 delta_file_header_.push_back(0x81); // SAME cache size (top bit)
1031 delta_file_header_.push_back(0x10); // SAME cache size (custom value 0x90)
1032 delta_file_header_.append(kEncodedCustomCodeTable,
1033 sizeof(kEncodedCustomCodeTable));
1034 InitializeDeltaFile();
1035 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
1036 EXPECT_DEBUG_DEATH(EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(),
1037 delta_file_.size(),
1038 &output_)),
1039 "cache");
1040 EXPECT_EQ("", output_);
1041}
openvcdiffbaf44ea2009-04-09 19:20:49 +00001042
1043TEST_F(VCDiffCustomCodeTableDecoderDeathTest, BadCustomCacheSizesNoVcdTarget) {
1044 decoder_.SetAllowVcdTarget(false);
1045 delta_file_header_.assign(kFileHeader, sizeof(kFileHeader));
1046 delta_file_header_.push_back(0x81); // NEAR cache size (top bit)
1047 delta_file_header_.push_back(0x10); // NEAR cache size (custom value 0x90)
1048 delta_file_header_.push_back(0x81); // SAME cache size (top bit)
1049 delta_file_header_.push_back(0x10); // SAME cache size (custom value 0x90)
1050 delta_file_header_.append(kEncodedCustomCodeTable,
1051 sizeof(kEncodedCustomCodeTable));
1052 InitializeDeltaFile();
1053 decoder_.StartDecoding(dictionary_.data(), dictionary_.size());
1054 EXPECT_DEBUG_DEATH(EXPECT_FALSE(decoder_.DecodeChunk(delta_file_.data(),
1055 delta_file_.size(),
1056 &output_)),
1057 "cache");
1058 EXPECT_EQ("", output_);
1059}
1060
openvcdiff311c7142008-08-26 19:29:25 +00001061#endif // GTEST_HAS_DEATH_TEST
1062
1063} // namespace open_vcdiff
1064} // unnamed namespace