openvcdiff | 311c714 | 2008-08-26 19:29:25 +0000 | [diff] [blame] | 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 "vcdecoder_test.h" |
openvcdiff | 28db807 | 2008-10-10 23:29:11 +0000 | [diff] [blame] | 18 | #include <string.h> // strlen |
openvcdiff | 311c714 | 2008-08-26 19:29:25 +0000 | [diff] [blame] | 19 | #include "checksum.h" |
| 20 | #include "codetable.h" |
| 21 | #include "testing.h" |
| 22 | #include "varint_bigendian.h" |
| 23 | #include "vcdiff_defs.h" |
| 24 | |
| 25 | namespace open_vcdiff { |
| 26 | |
openvcdiff | 311c714 | 2008-08-26 19:29:25 +0000 | [diff] [blame] | 27 | const char VCDiffDecoderTest::kStandardFileHeader[] = { |
| 28 | 0xD6, // 'V' | 0x80 |
| 29 | 0xC3, // 'C' | 0x80 |
| 30 | 0xC4, // 'D' | 0x80 |
| 31 | 0x00, // Draft standard version number |
| 32 | 0x00 // Hdr_Indicator: no custom code table, no compression |
| 33 | }; |
| 34 | |
| 35 | const char VCDiffDecoderTest::kInterleavedFileHeader[] = { |
| 36 | 0xD6, // 'V' | 0x80 |
| 37 | 0xC3, // 'C' | 0x80 |
| 38 | 0xC4, // 'D' | 0x80 |
| 39 | 'S', // SDCH version code |
| 40 | 0x00 // Hdr_Indicator: no custom code table, no compression |
| 41 | }; |
| 42 | |
| 43 | const char VCDiffDecoderTest::kDictionary[] = |
| 44 | "\"Just the place for a Snark!\" the Bellman cried,\n" |
| 45 | "As he landed his crew with care;\n" |
| 46 | "Supporting each man on the top of the tide\n" |
| 47 | "By a finger entwined in his hair.\n"; |
| 48 | |
| 49 | const char VCDiffDecoderTest::kExpectedTarget[] = |
| 50 | "\"Just the place for a Snark! I have said it twice:\n" |
| 51 | "That alone should encourage the crew.\n" |
| 52 | "Just the place for a Snark! I have said it thrice:\n" |
| 53 | "What I tell you three times is true.\"\n"; |
| 54 | |
openvcdiff | 311c714 | 2008-08-26 19:29:25 +0000 | [diff] [blame] | 55 | VCDiffDecoderTest::VCDiffDecoderTest() : fuzzer_(0), fuzzed_byte_position_(0) { |
| 56 | dictionary_ = kDictionary; |
| 57 | expected_target_ = kExpectedTarget; |
openvcdiff | 311c714 | 2008-08-26 19:29:25 +0000 | [diff] [blame] | 58 | } |
| 59 | |
| 60 | void VCDiffDecoderTest::SetUp() { |
| 61 | InitializeDeltaFile(); |
| 62 | } |
| 63 | |
| 64 | void VCDiffDecoderTest::UseStandardFileHeader() { |
| 65 | delta_file_header_.assign(kStandardFileHeader, |
| 66 | sizeof(kStandardFileHeader)); |
| 67 | } |
| 68 | |
| 69 | void VCDiffDecoderTest::UseInterleavedFileHeader() { |
| 70 | delta_file_header_.assign(kInterleavedFileHeader, |
| 71 | sizeof(kInterleavedFileHeader)); |
| 72 | } |
| 73 | |
| 74 | void VCDiffDecoderTest::InitializeDeltaFile() { |
| 75 | delta_file_ = delta_file_header_ + delta_window_header_ + delta_window_body_; |
| 76 | } |
| 77 | |
| 78 | char VCDiffDecoderTest::GetByteFromStringLength(const char* s, |
| 79 | int which_byte) { |
| 80 | char varint_buf[VarintBE<int32_t>::kMaxBytes]; |
| 81 | VarintBE<int32_t>::Encode(static_cast<int32_t>(strlen(s)), varint_buf); |
| 82 | return varint_buf[which_byte]; |
| 83 | } |
| 84 | |
| 85 | void VCDiffDecoderTest::AddChecksum(VCDChecksum checksum) { |
| 86 | int32_t checksum_as_int32 = static_cast<int32_t>(checksum); |
| 87 | delta_window_header_[0] |= VCD_CHECKSUM; |
| 88 | VarintBE<int32_t>::AppendToString(checksum_as_int32, &delta_window_header_); |
| 89 | // Adjust delta window size to include checksum. |
| 90 | // This method wouldn't work if adding to the length caused the VarintBE |
| 91 | // value to spill over into another byte. Luckily, this test data happens |
| 92 | // not to cause such an overflow. |
| 93 | delta_window_header_[4] += VarintBE<int32_t>::Length(checksum_as_int32); |
| 94 | } |
| 95 | |
| 96 | void VCDiffDecoderTest::ComputeAndAddChecksum() { |
| 97 | AddChecksum(ComputeAdler32(expected_target_.data(), |
| 98 | expected_target_.size())); |
| 99 | } |
| 100 | |
| 101 | // Write the maximum expressible positive 32-bit VarintBE |
| 102 | // (0x7FFFFFFF) at the given offset in the delta window. |
| 103 | void VCDiffDecoderTest::WriteMaxVarintAtOffset(int offset, |
| 104 | int bytes_to_replace) { |
| 105 | static const char kMaxVarint[] = { 0x87, 0xFF, 0xFF, 0xFF, 0x7F }; |
| 106 | delta_file_.replace(delta_file_header_.size() + offset, |
| 107 | bytes_to_replace, |
| 108 | kMaxVarint, |
| 109 | sizeof(kMaxVarint)); |
| 110 | } |
| 111 | |
| 112 | // Write a negative 32-bit VarintBE (0x80000000) at the given offset |
| 113 | // in the delta window. |
| 114 | void VCDiffDecoderTest::WriteNegativeVarintAtOffset(int offset, |
| 115 | int bytes_to_replace) { |
| 116 | static const char kNegativeVarint[] = { 0x88, 0x80, 0x80, 0x80, 0x00 }; |
| 117 | delta_file_.replace(delta_file_header_.size() + offset, |
| 118 | bytes_to_replace, |
| 119 | kNegativeVarint, |
| 120 | sizeof(kNegativeVarint)); |
| 121 | } |
| 122 | |
| 123 | // Write a VarintBE that has too many continuation bytes |
| 124 | // at the given offset in the delta window. |
| 125 | void VCDiffDecoderTest::WriteInvalidVarintAtOffset(int offset, |
| 126 | int bytes_to_replace) { |
| 127 | static const char kInvalidVarint[] = { 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F }; |
| 128 | delta_file_.replace(delta_file_header_.size() + offset, |
| 129 | bytes_to_replace, |
| 130 | kInvalidVarint, |
| 131 | sizeof(kInvalidVarint)); |
| 132 | } |
| 133 | |
| 134 | bool VCDiffDecoderTest::FuzzOneByteInDeltaFile() { |
| 135 | static const struct Fuzzer { |
| 136 | char _and; |
| 137 | char _or; |
| 138 | char _xor; |
| 139 | } fuzzers[] = { |
| 140 | { 0xff, 0x80, 0x00 }, |
| 141 | { 0xff, 0xff, 0x00 }, |
| 142 | { 0xff, 0x00, 0x80 }, |
| 143 | { 0xff, 0x00, 0xff }, |
| 144 | { 0xff, 0x01, 0x00 }, |
| 145 | { 0x7f, 0x00, 0x00 }, |
| 146 | }; |
| 147 | |
| 148 | for (; fuzzer_ < (sizeof(fuzzers) / sizeof(fuzzers[0])); ++fuzzer_) { |
| 149 | for (; fuzzed_byte_position_ < delta_file_.size(); |
| 150 | ++fuzzed_byte_position_) { |
| 151 | char fuzzed_byte = (((delta_file_[fuzzed_byte_position_] |
| 152 | & fuzzers[fuzzer_]._and) |
| 153 | | fuzzers[fuzzer_]._or) |
| 154 | ^ fuzzers[fuzzer_]._xor); |
| 155 | if (fuzzed_byte != delta_file_[fuzzed_byte_position_]) { |
| 156 | delta_file_[fuzzed_byte_position_] = fuzzed_byte; |
| 157 | ++fuzzed_byte_position_; |
| 158 | return true; |
| 159 | } |
| 160 | } |
| 161 | fuzzed_byte_position_ = 0; |
| 162 | } |
| 163 | return false; |
| 164 | } |
| 165 | |
| 166 | const char VCDiffStandardDecoderTest::kWindowHeader[] = { |
| 167 | VCD_SOURCE, // Win_Indicator: take source from dictionary |
| 168 | FirstByteOfStringLength(kDictionary), // Source segment size |
| 169 | SecondByteOfStringLength(kDictionary), |
| 170 | 0x00, // Source segment position: start of dictionary |
| 171 | 0x79, // Length of the delta encoding |
| 172 | FirstByteOfStringLength(kExpectedTarget), // Size of the target window |
| 173 | SecondByteOfStringLength(kExpectedTarget), |
| 174 | 0x00, // Delta_indicator (no compression) |
| 175 | 0x64, // length of data for ADDs and RUNs |
| 176 | 0x0C, // length of instructions section |
| 177 | 0x03 // length of addresses for COPYs |
| 178 | }; |
| 179 | |
| 180 | const char VCDiffStandardDecoderTest::kWindowBody[] = { |
| 181 | // Data for ADDs: 1st section (length 61) |
| 182 | ' ', 'I', ' ', 'h', 'a', 'v', 'e', ' ', 's', 'a', 'i', 'd', ' ', |
| 183 | 'i', 't', ' ', 't', 'w', 'i', 'c', 'e', ':', '\n', |
| 184 | 'T', 'h', 'a', 't', ' ', |
| 185 | 'a', 'l', 'o', 'n', 'e', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ', |
| 186 | 'e', 'n', 'c', 'o', 'u', 'r', 'a', 'g', 'e', ' ', |
| 187 | 't', 'h', 'e', ' ', 'c', 'r', 'e', 'w', '.', '\n', |
| 188 | // Data for ADDs: 2nd section (length 2) |
| 189 | 'h', 'r', |
| 190 | // Data for ADDs: 3rd section (length 9) |
| 191 | 'W', 'h', 'a', 't', ' ', |
| 192 | 'I', ' ', 't', 'e', |
| 193 | // Data for RUN: 4th section (length 1) |
| 194 | 'l', |
| 195 | // Data for ADD: 4th section (length 27) |
| 196 | ' ', 'y', 'o', 'u', ' ', |
| 197 | 't', 'h', 'r', 'e', 'e', ' ', 't', 'i', 'm', 'e', 's', ' ', 'i', 's', ' ', |
| 198 | 't', 'r', 'u', 'e', '.', '\"', '\n', |
| 199 | // Instructions and sizes (length 13) |
| 200 | 0x13, // VCD_COPY mode VCD_SELF, size 0 |
| 201 | 0x1C, // Size of COPY (28) |
| 202 | 0x01, // VCD_ADD size 0 |
| 203 | 0x3D, // Size of ADD (61) |
| 204 | 0x23, // VCD_COPY mode VCD_HERE, size 0 |
| 205 | 0x2C, // Size of COPY (44) |
| 206 | 0xCB, // VCD_ADD size 2 + VCD_COPY mode NEAR(1), size 5 |
| 207 | 0x0A, // VCD_ADD size 9 |
| 208 | 0x00, // VCD_RUN size 0 |
| 209 | 0x02, // Size of RUN (2) |
| 210 | 0x01, // VCD_ADD size 0 |
| 211 | 0x1B, // Size of ADD (27) |
| 212 | // Addresses for COPYs (length 3) |
| 213 | 0x00, // Start of dictionary |
| 214 | 0x58, // HERE mode address for 2nd copy (27+61 back from here_address) |
| 215 | 0x2D // NEAR(1) mode address for 2nd copy (45 after prior address) |
| 216 | }; |
| 217 | |
| 218 | VCDiffStandardDecoderTest::VCDiffStandardDecoderTest() { |
| 219 | UseStandardFileHeader(); |
| 220 | delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader)); |
| 221 | delta_window_body_.assign(kWindowBody, sizeof(kWindowBody)); |
| 222 | } |
| 223 | |
| 224 | const char VCDiffInterleavedDecoderTest::kWindowHeader[] = { |
| 225 | VCD_SOURCE, // Win_Indicator: take source from dictionary |
| 226 | FirstByteOfStringLength(kDictionary), // Source segment size |
| 227 | SecondByteOfStringLength(kDictionary), |
| 228 | 0x00, // Source segment position: start of dictionary |
| 229 | 0x79, // Length of the delta encoding |
| 230 | FirstByteOfStringLength(kExpectedTarget), // Size of the target window |
| 231 | SecondByteOfStringLength(kExpectedTarget), |
| 232 | 0x00, // Delta_indicator (no compression) |
| 233 | 0x00, // length of data for ADDs and RUNs (unused) |
| 234 | 0x73, // length of interleaved section |
| 235 | 0x00 // length of addresses for COPYs (unused) |
| 236 | }; |
| 237 | |
| 238 | const char VCDiffInterleavedDecoderTest::kWindowBody[] = { |
| 239 | 0x13, // VCD_COPY mode VCD_SELF, size 0 |
| 240 | 0x1C, // Size of COPY (28) |
| 241 | 0x00, // Address of COPY: Start of dictionary |
| 242 | 0x01, // VCD_ADD size 0 |
| 243 | 0x3D, // Size of ADD (61) |
| 244 | // Data for ADD (length 61) |
| 245 | ' ', 'I', ' ', 'h', 'a', 'v', 'e', ' ', 's', 'a', 'i', 'd', ' ', |
| 246 | 'i', 't', ' ', 't', 'w', 'i', 'c', 'e', ':', '\n', |
| 247 | 'T', 'h', 'a', 't', ' ', |
| 248 | 'a', 'l', 'o', 'n', 'e', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ', |
| 249 | 'e', 'n', 'c', 'o', 'u', 'r', 'a', 'g', 'e', ' ', |
| 250 | 't', 'h', 'e', ' ', 'c', 'r', 'e', 'w', '.', '\n', |
| 251 | 0x23, // VCD_COPY mode VCD_HERE, size 0 |
| 252 | 0x2C, // Size of COPY (44) |
| 253 | 0x58, // HERE mode address (27+61 back from here_address) |
| 254 | 0xCB, // VCD_ADD size 2 + VCD_COPY mode NEAR(1), size 5 |
| 255 | // Data for ADDs: 2nd section (length 2) |
| 256 | 'h', 'r', |
| 257 | 0x2D, // NEAR(1) mode address (45 after prior address) |
| 258 | 0x0A, // VCD_ADD size 9 |
| 259 | // Data for ADDs: 3rd section (length 9) |
| 260 | 'W', 'h', 'a', 't', ' ', |
| 261 | 'I', ' ', 't', 'e', |
| 262 | 0x00, // VCD_RUN size 0 |
| 263 | 0x02, // Size of RUN (2) |
| 264 | // Data for RUN: 4th section (length 1) |
| 265 | 'l', |
| 266 | 0x01, // VCD_ADD size 0 |
| 267 | 0x1B, // Size of ADD (27) |
| 268 | // Data for ADD: 4th section (length 27) |
| 269 | ' ', 'y', 'o', 'u', ' ', |
| 270 | 't', 'h', 'r', 'e', 'e', ' ', 't', 'i', 'm', 'e', 's', ' ', 'i', 's', ' ', |
| 271 | 't', 'r', 'u', 'e', '.', '\"', '\n' |
| 272 | }; |
| 273 | |
| 274 | VCDiffInterleavedDecoderTest::VCDiffInterleavedDecoderTest() { |
| 275 | UseInterleavedFileHeader(); |
| 276 | delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader)); |
| 277 | delta_window_body_.assign(kWindowBody, sizeof(kWindowBody)); |
| 278 | } |
| 279 | |
| 280 | } // namespace open_vcdiff |