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: 31 VCDiffDecoderInterleavedAllowedButNotUsed() { 32 UseInterleavedFileHeader(); 33 } 34 virtual ~VCDiffDecoderInterleavedAllowedButNotUsed() { } 35 }; 36 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 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 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 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: 85 VCDiffDecoderInterleavedUsedButNotSupported() { 86 UseStandardFileHeader(); 87 } 88 virtual ~VCDiffDecoderInterleavedUsedButNotSupported() { } 89 }; 90 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 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(); 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 243 VCDiffStandardWindowDecoderTest::VCDiffStandardWindowDecoderTest() { 244 UseStandardFileHeader(); 245 delta_window_body_.assign(kWindowBody, sizeof(kWindowBody)); 246 } 247 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. 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 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 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 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. 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 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 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 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 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 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. 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(); 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 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 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 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 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 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. 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 // 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 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(); 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 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 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 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(); 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 746 VCDiffInterleavedCrossDecoderTest::VCDiffInterleavedCrossDecoderTest() { 747 UseInterleavedFileHeader(); 748 delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader)); 749 delta_window_body_.assign(kWindowBody, sizeof(kWindowBody)); 750 } 751 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 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 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 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(); 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 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 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 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 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 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 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 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 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 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