1// Copyright 2015, Joe Tsai. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE.md file. 4 5package meta 6 7import ( 8 "bytes" 9 "io" 10 "io/ioutil" 11 "math/rand" 12 "strings" 13 "testing" 14 15 "github.com/dsnet/compress/internal/errors" 16 "github.com/dsnet/compress/internal/testutil" 17) 18 19// TestReader tests that the reader is able to properly decode a set of valid 20// input strings or properly detect corruption in a set of invalid input 21// strings. A third-party decoder should verify that it has the same behavior 22// when processing these input vectors. 23func TestReader(t *testing.T) { 24 db := testutil.MustDecodeBitGen 25 dh := testutil.MustDecodeHex 26 27 errFuncs := map[string]func(error) bool{ 28 "IsEOF": func(err error) bool { return err == io.EOF }, 29 "IsUnexpectedEOF": func(err error) bool { return err == io.ErrUnexpectedEOF }, 30 "IsCorrupted": errors.IsCorrupted, 31 } 32 vectors := []struct { 33 desc string // Description of the test 34 input []byte // Test input string 35 output []byte // Expected output string 36 final FinalMode // Expected FinalMode value 37 errf string // Name of error checking callback 38 }{{ 39 desc: "empty string", 40 input: dh(""), 41 output: dh(""), 42 errf: "IsEOF", 43 }, { 44 desc: "bad empty meta block (FinalNil, first symbol not symZero)", 45 input: db(`<<< 46 < (0 10) (00100 00000 1010) (011 000 011 001 000 (000 000)*4 010) 47 > (111 <D7:127) (111 <D7:100) 10 (110 <D2:3) 10 48 < 0*4 0 1*3 49 `), 50 output: dh(""), 51 errf: "IsCorrupted", 52 }, { 53 desc: "empty meta block (FinalNil)", 54 input: db(`<<< 55 < (0 10) (00011 00000 1010) (011 000 011 001 000 (000 000)*4 010) 0 56 > (111 <D7:127) (111 <D7:99) 10 (110 <D2:3) 10 57 < 0*3 0 1*3 58 `), 59 output: dh(""), 60 final: FinalNil, 61 }, { 62 desc: "empty meta block (FinalMeta)", 63 input: db(`<<< 64 < (0 10) (00011 00000 1010) (011 000 011 001 000 (000 000)*4 010) 0 65 > 10 (111 <D7:127) (111 <D7:99) 10 (110 <D2:3) 66 < 0*3 0 1*3 67 `), 68 output: dh(""), 69 final: FinalMeta, 70 }, { 71 desc: "bad empty meta block, contains the magic value mid way", 72 input: db(`<<< 73 < (1 10) (00000 00000 1100) (011 000 011 001 000 (000 000)*5 010) 0 74 > 10 0*14 10 0*13 (110 <D2:0) 0 (110 <D2:1) 0*4 (111 <D7:127) 75 (111 <D7:59) 0*5 10*2 76 < 0*0 0 1*2 77 `), 78 output: dh(""), 79 errf: "IsCorrupted", 80 }, { 81 desc: "meta block containing the string 'a'", 82 input: db(`<<< 83 < (0 10) (00010 00000 1000) (011 000 011 001 000 (000 000)*3 010) 0 84 > 10 0 10 0*4 10 0*4 10*2 (111 <D7:127) (111 <D7:82) 10 (110 <D2:3) 85 (110 <D2:1) 86 < 0*2 0 1*4 87 `), 88 output: []byte("a"), 89 final: FinalMeta, 90 }, { 91 desc: "meta block containing the string 'ab'", 92 input: db(`<<< 93 < (0 10) (00010 00000 1000) (011 000 011 001 000 (000 000)*3 010) 0 94 > 10 0*2 10 0*3 10 0*4 10*2 0*2 10 0*3 10*2 (111 <D7:127) 95 (111 <D7:77) 10 (110 <D2:3) 10 96 < 0*2 0 1*4 97 `), 98 output: []byte("ab"), 99 final: FinalMeta, 100 }, { 101 desc: "meta block containing the string 'abc'", 102 input: db(`<<< 103 < (0 10) (00010 00000 0110) (011 000 011 001 000 (000 000)*2 010) 0 104 > 10 0 10*2 0*3 10 0*4 10*2 0*2 10 0*3 10*2 0 10*2 0*3 10*2 105 (111 <D7:127) (111 <D7:58) 10 (110 <D2:3) (110 <D2:3) (110 <D2:3) 106 < 0*2 0 1*5 107 `), 108 output: []byte("abc"), 109 final: FinalMeta, 110 }, { 111 desc: "meta block containing the string 'Hello, world!'", 112 input: db(`<<< 113 < (0 10) (00010 00000 0100) (011 000 011 001 000 (000 000)*1 010) 0 114 > 10 0 10 0 10*2 0*4 10 0*2 10 0 10 0 10 0*2 10*2 0*3 10*2 0 10*2 115 0*3 10*2 0 10*2 0 10 (110 <D2:0) 0 10*2 0*3 10*2 0 10 0 116 (110 <D2:3) 10 0*2 10*3 0 10*3 0 10 (110 <D2:0) 0 10*2 0*2 10 0*2 117 10*3 0*3 10*2 0 10*2 0*3 10 0*2 10*2 0 10 0*4 10 (111 <D7:125) 118 10 (110 <D2:3) (110 <D2:1) 119 < 0*2 0 1*6 120 `), 121 output: []byte("Hello, world!"), 122 final: FinalMeta, 123 }, { 124 desc: "meta block containing the hex-string '00'*4", 125 input: db(`<<< 126 < (0 10) (00110 00000 1010) (011 000 011 001 000 (000 000)*4 010) 0 127 > 10 0*3 10 (111 <D7:127) (111 <D7:96) 10 (110 <D2:2) 128 < 0*6 0 1*3 129 `), 130 output: dh("00000000"), 131 final: FinalMeta, 132 }, { 133 desc: "meta block containing the hex-string '00'*8", 134 input: db(`<<< 135 < (0 10) (00101 00000 1010) (011 000 011 001 000 (000 000)*4 010) 0 136 > 10 0*4 10 (111 <D7:127) (111 <D7:95) 10 (110 <D2:2) 137 < 0*5 0 1*3 138 `), 139 output: dh("0000000000000000"), 140 final: FinalMeta, 141 }, { 142 desc: "meta block containing the hex-string '00'*16", 143 input: db(`<<< 144 < (0 10) (00100 00000 1010) (011 000 011 001 000 (000 000)*4 010) 0 145 > 10 0*5 10 (111 <D7:127) (111 <D7:94) 10 (110 <D2:2) 146 < 0*4 0 1*3 147 `), 148 output: dh("00000000000000000000000000000000"), 149 final: FinalMeta, 150 }, { 151 desc: "meta block containing the hex-string 'ff'*4", 152 input: db(`<<< 153 < (0 10) (00101 00000 1010) (011 000 011 001 000 (000 000)*4 010) 0 154 > 10*2 0*2 10 (111 <D7:127) (111 <D7:97) 10 (110 <D2:1) 155 < 0*5 0 1*3 156 `), 157 output: dh("ffffffff"), 158 final: FinalMeta, 159 }, { 160 desc: "meta block containing the hex-string 'ff'*8", 161 input: db(`<<< 162 < (0 10) (00100 00000 1010) (011 000 011 001 000 (000 000)*4 010) 0 163 > 10*2 0*3 10 (111 <D7:127) (111 <D7:96) 10 (110 <D2:1) 164 < 0*4 0 1*3 165 `), 166 output: dh("ffffffffffffffff"), 167 final: FinalMeta, 168 }, { 169 desc: "meta block containing the hex-string 'ff'*16", 170 input: db(`<<< 171 < (0 10) (00011 00000 1010) (011 000 011 001 000 (000 000)*4 010) 0 172 > 10*2 0*4 10 (111 <D7:127) (111 <D7:95) 10 (110 <D2:1) 173 < 0*3 0 1*3 174 `), 175 output: dh("ffffffffffffffffffffffffffffffff"), 176 final: FinalMeta, 177 }, { 178 desc: "meta block containing the random hex-string '911fe47084a4668b'", 179 input: db(`<<< 180 < (0 10) (00011 00000 0100) (011 000 011 001 000 (000 000) 010) 0 181 > 10 0*4 10 0 10 0*3 10 0*2 10 (110 <D2:2) 0*5 10 0*2 10*3 0*4 10*3 182 0*3 10 0*4 10 0*2 10 0*2 10 0 10 0 10*2 0*2 10*2 0 10*2 0 10 0*3 183 10 (111 <D7:127) (111 <D7:2) 10 (110 <D2:3)*5 (110 <D2:0) 184 < 0*3 0 1*6 185 `), 186 output: dh("911fe47084a4668b"), 187 final: FinalMeta, 188 }, { 189 desc: "meta block containing the random hex-string 'de9fa94cb16f40fc'", 190 input: db(`<<< 191 < (0 10) (00100 00000 0100) (011 000 011 001 000 (000 000) 010) 0 192 > 10*2 0*3 10 0 10 0*4 10 0 (110 <D2:3) 10*2 0*2 10*2 0 10 0 10 0 193 10*2 0*2 10*2 0 10 0 10*2 10 0*2 10 0*5 10 0*2 10 (110 <D2:3) 0 194 10*3 (111 <D7:127) (111 <D7:9) 10 (110 <D2:3)*5 10*2 195 < 0*4 0 1*6 196 `), 197 output: dh("de9fa94cb16f40fc"), 198 final: FinalMeta, 199 }, { 200 desc: "empty meta block with a huffLen of 1", 201 input: db(`<<< 202 < (0 10) (00110 00000 1110) (011 000 011 001 000 (000 000)*6 010) 0 203 > 10 (111 <D7:127) (111 <D7:105) 10 204 < 0*6 0 1*1 205 `), 206 output: dh(""), 207 final: FinalMeta, 208 }, { 209 desc: "empty meta block with a huffLen of 2", 210 input: db(`<<< 211 < (0 10) (00111 00000 1100) (011 000 011 001 000 (000 000)*5 010) 0 212 > 10 (111 <D7:127) 10*2 (111 <D7:103) 10 213 < 0*7 0 1*2 214 `), 215 output: dh(""), 216 final: FinalMeta, 217 }, { 218 desc: "empty meta block with a huffLen of 3", 219 input: db(`<<< 220 < (0 10) (00100 00000 1010) (011 000 011 001 000 (000 000)*4 010) 0 221 > 10 (111 <D7:127) 10*6 (111 <D7:99) 10 222 < 0*4 0 1*3 223 `), 224 output: dh(""), 225 final: FinalMeta, 226 }, { 227 desc: "empty meta block with a huffLen of 4", 228 input: db(`<<< 229 < (0 10) (00001 00000 1000) (011 000 011 001 000 (000 000)*3 010) 0 230 > 10 (111 <D7:127) 10*14 (111 <D7:91) 10 231 < 0*1 0 1*4 232 `), 233 output: dh(""), 234 final: FinalMeta, 235 }, { 236 desc: "empty meta block with a huffLen of 5", 237 input: db(`<<< 238 < (0 10) (00110 00000 0110) (011 000 011 001 000 (000 000)*2 010) 0 239 > 10 (111 <D7:127) 10*30 (111 <D7:75) 10 240 < 0*6 0 1*5 241 `), 242 output: dh(""), 243 final: FinalMeta, 244 }, { 245 desc: "empty meta block with a huffLen of 6", 246 input: db(`<<< 247 < (0 10) (00011 00000 0100) (011 000 011 001 000 (000 000)*1 010) 0 248 > 10 (111 <D7:127) 10*62 (111 <D7:43) 10 249 < 0*3 0 1*6 250 `), 251 output: dh(""), 252 final: FinalMeta, 253 }, { 254 desc: "empty meta block with a huffLen of 7", 255 input: db(`<<< 256 < (0 10) (00010 00000 0010) (011 000 011 001 000 (000 000)*0 010) 0 257 > 10 (111 <D7:117) 10*127 258 < 0*2 0 1*7 259 `), 260 output: dh(""), 261 final: FinalMeta, 262 }, { 263 desc: "shortest meta block", 264 input: db(`<<< 265 < (0 10) (00011 00000 1010) (011 000 011 001 000 (000 000)*4 010) 0 266 > (111 <D7:127) (111 <D7:99) 10 (110 <D2:3) 10 267 < 0*3 0 1*3 268 `), 269 output: dh(""), 270 }, { 271 desc: "longest meta block", 272 input: db(`<<< 273 < (0 10) (00000 00000 0010) (011 000 011 001 000 (000 000)*0 010) 0 274 > 0*2 (110 <D2:0)*42 10*128 275 < 0*0 0 1*7 276 `), 277 output: dh(""), 278 }, { 279 desc: "longest decoded meta block", 280 input: db(`<<< 281 < (0 10) (00100 00000 1010) (011 000 011 001 000 (000 000)*4 010) 0 282 > 10*7 (111 <D7:113)*2 10 283 < 0*4 0 1*3 284 `), 285 output: dh("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), 286 final: FinalMeta, 287 }, { 288 desc: "meta block truncated short", 289 input: db(`<<< 290 < (0 10) (00011 00000 0100) (011 000 011 001 000 (000 000)*1 010) 0 291 > 10 0*4 10 0 10 0*3 10 0*2 10 (110 <D2:2) 0*5 10 0*2 10*3 0*4 10*3 292 0*3 10 0*4 10 0*2 10 0*2 10 0 10 0 10*2 0*2 10*2 0 10*2 0 10 0*3 293 10 (111 <D7:127) (111 <D7:2) 10 (110 <D2:3)*5 (110 <D2:0) 294 < 0*3 0 1*6 295 `)[:3], 296 errf: "IsUnexpectedEOF", 297 }, { 298 desc: "meta block truncated medium-short", 299 input: db(`<<< 300 < (0 10) (00011 00000 0100) (011 000 011 001 000 (000 000)*1 010) 0 301 > 10 0*4 10 0 10 0*3 10 0*2 10 (110 <D2:2) 0*5 10 0*2 10*3 0*4 10*3 302 0*3 10 0*4 10 0*2 10 0*2 10 0 10 0 10*2 0*2 10*2 0 10*2 0 10 0*3 303 10 (111 <D7:127) (111 <D7:2) 10 (110 <D2:3)*5 (110 <D2:0) 304 < 0*3 0 1*6 305 `)[:4], 306 errf: "IsUnexpectedEOF", 307 }, { 308 desc: "meta block truncated medium-long", 309 input: db(`<<< 310 < (0 10) (00011 00000 0100) (011 000 011 001 000 (000 000)*1 010) 0 311 > 10 0*4 10 0 10 0*3 10 0*2 10 (110 <D2:2) 0*5 10 0*2 10*3 0*4 10*3 312 0*3 10 0*4 10 0*2 10 0*2 10 0 10 0 10*2 0*2 10*2 0 10*2 0 10 0*3 313 10 (111 <D7:127) (111 <D7:2) 10 (110 <D2:3)*5 (110 <D2:0) 314 < 0*3 0 1*6 315 `)[:13], 316 errf: "IsUnexpectedEOF", 317 }, { 318 desc: "meta block truncated long", 319 input: db(`<<< 320 < (0 10) (00011 00000 0100) (011 000 011 001 000 (000 000)*1 010) 0 321 > 10 0*4 10 0 10 0*3 10 0*2 10 (110 <D2:2) 0*5 10 0*2 10*3 0*4 10*3 322 0*3 10 0*4 10 0*2 10 0*2 10 0 10 0 10*2 0*2 10*2 0 10*2 0 10 0*3 323 10 (111 <D7:127) (111 <D7:2) 10 (110 <D2:3)*5 (110 <D2:0) 324 < 0*3 0 1*6 325 `)[:24], 326 errf: "IsUnexpectedEOF", 327 }, { 328 desc: "random junk", 329 input: dh("911fe47084a4668b"), 330 errf: "IsCorrupted", 331 }, { 332 desc: "meta block with invalid number of HCLen codes of 6", 333 input: db(`<<< 334 < (0 10) (00110 00000 0000) (011 000 011 001 000 (000 000)*0 000) 335 > 0*34 10 0 10 (111 <D7:127) (111 <D7:105) 336 < 000001 0 100 337 `), 338 errf: "IsCorrupted", 339 }, { 340 desc: "meta block with invalid HCLen code in the middle", 341 input: db(`<<< 342 < (0 10) (00110 00000 1110) (011 000 011 001 000 (000 010) (000 000)*5 010) 0 343 > 10 (111 <D7:127) (111 <D7:105) 10 344 < 000000 0 1 345 `), 346 errf: "IsCorrupted", 347 }, { 348 desc: "meta block with invalid HCLen code at the end", 349 input: db(`<<< 350 < (0 10) (00110 00000 1110) (011 000 011 001 000 (000 000)*6 110) 0 351 > 10 (111 <D7:127) (111 <D7:105) 10 352 < 000000 0 1 353 `), 354 errf: "IsCorrupted", 355 }, { 356 desc: "meta block first symbol being a last repeater", 357 input: db(`<<< 358 < (0 10) (00100 00000 1110) (011 000 011 001 000 (000 000)*6 010) 359 > (110 <D2:0) 10 (111 <D7:127) (111 <D7:104) 360 < 0000 0 1 361 `), 362 errf: "IsCorrupted", 363 }, { 364 desc: "meta block with too many symbols", 365 input: db(`<<< 366 < (0 10) (00110 00000 1110) (011 000 011 001 000 (000 000)*6 010) 0 367 > 10 (111 <D7:127) (111 <D7:106) 10 368 < 000000 0 1 369 `), 370 errf: "IsCorrupted", 371 }, { 372 desc: "meta block with too few symbols", 373 input: dh("34c087050000000020fe7f3a40"), 374 errf: "IsCorrupted", 375 }, { 376 desc: "meta block with first symbol not a zero", 377 input: db(`<<< 378 < (0 10) (00110 00000 1110) (011 000 011 001 000 (000 000)*6 010) 0 379 > 10 (111 <D7:127) (111 <D7:104) 10 380 < 000000 0 0 381 `), 382 errf: "IsCorrupted", 383 }, { 384 desc: "meta block with no EOB symbol", 385 input: db(`<<< 386 < (0 10) (00101 00000 1110) (011 000 011 001 000 (000 000)*6 010) 0 387 > 10 (111 <D7:127) (111 <D7:104) 10 0 388 < 00000 0 1 389 `), 390 errf: "IsCorrupted", 391 }, { 392 desc: "meta block with FinalStream set, but not FinalMeta", 393 input: db(`<<< 394 < (1 10) (00101 00000 1110) (011 000 011 001 000 (000 000)*6 010) 0 395 > 0 10 (111 <D7:127) (111 <D7:104) 10 396 < 00000 0 1 397 `), 398 errf: "IsCorrupted", 399 }, { 400 desc: "meta block with some padding bits not zero", 401 input: db(`<<< 402 < (0 10) (00110 00000 1110) (011 000 011 001 000 (000 000)*6 010) 0 403 > 10 (111 <D7:127) (111 <D7:105) 10 404 < 100000 0 1 405 `), 406 errf: "IsCorrupted", 407 }, { 408 desc: "meta block with the HDist tree not empty", 409 input: db(`<<< 410 < (0 10) (00110 00000 1110) (011 000 011 001 000 (000 000)*6 010) 0 411 > 10 (111 <D7:127) (111 <D7:105) 10 412 < 000000 1 1 413 `), 414 errf: "IsCorrupted", 415 }, { 416 desc: "meta block with invalid EOB", 417 input: db(`<<< 418 < (0 10) (00110 00000 1110) (011 000 011 001 000 (000 000)*6 010) 0 419 > 10 (111 <D7:127) (111 <D7:105) 10 420 < 000000 0 0 421 `), 422 errf: "IsCorrupted", 423 }, { 424 desc: "meta block with wrong number of padding bits", 425 input: db(`<<< 426 < (0 10) (00101 00000 1110) (011 000 011 001 000 (000 000)*6 010) 0 427 > 10 (111 <D7:127) (111 <D7:105) 10 428 < 00000 0 1 429 `), 430 errf: "IsCorrupted", 431 }} 432 433 for i, v := range vectors { 434 mr := NewReader(bytes.NewReader(v.input)) 435 err := mr.decodeBlock() 436 output := mr.buf 437 438 if got, want, ok := testutil.BytesCompare(output, v.output); !ok { 439 t.Errorf("test %d (%s), mismatching data:\ngot %s\nwant %s", i, v.desc, got, want) 440 } 441 if int(mr.InputOffset) != len(v.input) && err == nil { 442 t.Errorf("test %d (%s), mismatching offset: got %d, want %d", i, v.desc, mr.InputOffset, len(v.input)) 443 } 444 if mr.final != v.final { 445 t.Errorf("test %d (%s), mismatching final mode: got %d, want %d", i, v.desc, mr.final, v.final) 446 } 447 if v.errf != "" && !errFuncs[v.errf](err) { 448 t.Errorf("test %d (%s), mismatching error:\ngot %v\nwant %s(err) == true", i, v.desc, err, v.errf) 449 } else if v.errf == "" && err != nil { 450 t.Errorf("test %d (%s), unexpected error: got %v", i, v.desc, err) 451 } 452 } 453} 454 455func TestReaderReset(t *testing.T) { 456 buf := make([]byte, 512) 457 mr := NewReader(nil) 458 459 // Test Reader for idempotent Close. 460 if err := mr.Close(); err != nil { 461 t.Errorf("unexpected error: Close() = %v", err) 462 } 463 if err := mr.Close(); err != nil { 464 t.Errorf("unexpected error: Close() = %v", err) 465 } 466 if _, err := mr.Read(buf); err != errClosed { 467 t.Errorf("unexpected error: Read() = %v, want %v", err, errClosed) 468 } 469 470 // Test Reader with corrupt data. 471 mr.Reset(strings.NewReader("corrupt")) 472 if _, err := mr.Read(buf); !errors.IsCorrupted(err) { 473 t.Errorf("unexpected error: Read() = %v, want IsCorrupted(err) == true", err) 474 } 475 if err := mr.Close(); !errors.IsCorrupted(err) { 476 t.Errorf("unexpected error: Close() = %v, want IsCorrupted(err) == true", err) 477 } 478 479 // Test Reader on multiple back-to-back streams. 480 data := testutil.MustDecodeBitGen(`<<< 481 # FinalNil, "The quick brown fox jumped o" 482 < (0 10) (00111 00000 0010) (011 000 011 001 000 010) 0 483 > (110 <D2:1) 10*3 0*2 10 0 10 0 10 0 (110 <D2:0) 10 0 10*2 0 10 0 10 484 0*2 10*2 0 (110 <D2:2) 10 0*2 10 0*3 10*3 0 10 0 10 0 10*3 0 10 0*2 485 10 0 10*2 0 10*2 0*3 10*2 0 10*2 0 10 0 10*2 0 (110 <D2:2) 10 0*3 10 486 0*3 10*2 0*2 10 0*2 10*3 0 10 (110 <D2:0) 0 10*2 0 10*3 0 10*3 0*2 487 10*3 0 10*2 0 (110 <D2:2) 10 0*3 10*2 0*2 10*2 0 10 (110 <D2:0) 0 10*2 488 0 (110 <D2:0) 10 (110 <D2:0) 0 (110 <D2:2) 10 0*3 10 0 10 0 10*2 0 10 489 0 10 0 10*3 0 10 0 10*2 0 10*2 0 (110 <D2:1) 10*3 0 10 0 10 0*2 10*2 490 0*3 10 0*2 10*2 0 (110 <D2:2) 10 0*2 10 (110 <D2:0) 0 10*2 0 491 (110 <D2:2) 10 (110 <D2:3) (110 <D2:3) (110 <D2:3) 10 492 < 0*7 0 1*7 493 494 # FinalMeta, "ver the lazy dog." 495 < (0 10) (00101 00000 0010) (011 000 011 001 000 010) 0 496 > 10 0 10 0*3 10 0 10*2 0 10*3 0 10 0 10 0*2 10*2 0*2 10 0*2 10*3 0 497 (110 <D2:2) 10 0 (110 <D2:0) 10 0 10*3 0 (110 <D2:0) 10 0 10*2 0 10 0 498 10 0*2 10*2 0 (110 <D2:2) 10 0 (110 <D2:0) 10*2 0 10*2 0 10 0 499 (110 <D2:0) 10*2 0*2 10 0 10 (110 <D2:0) 0 10 0*2 10 (110 <D2:0) 0 500 (110 <D2:2) 10 0 (110 <D2:0) 10 0*2 10*2 0 10 (110 <D2:0) 0 10*2 0 501 10*3 0*2 10*2 0*2 10*3 0 10 (111 <D7:41) 10 (110 <D2:3) (110 <D2:3) 502 (110 <D2:3) (110 <D2:3) (110 <D2:3) (110 <D2:3) (110 <D2:3) 503 (110 <D2:3) (110 <D2:3) (110 <D2:3) 10*2 504 < 0*5 0 1*7 505 506 # FinalNil, "Lorem ipsum dolor sit amet, " 507 < (0 10) (00111 00000 0010) (011 000 011 001 000 010) 0 508 > (110 <D2:1) 10*3 0*2 10*2 0*2 10 0 10 (110 <D2:0) 0 10*2 0*2 10 0*2 509 10*3 0 10 0 10 0*2 10*2 0 10 0 10*2 0 10*2 0 (110 <D2:2) 10 0*2 10 0*2 510 10 0 10*2 0 (110 <D2:1) 10*3 0 10*2 0*2 10*3 0 10 0 10 0 10*3 0 10 0 511 10*2 0 10*2 0 (110 <D2:2) 10 0 (110 <D2:0) 10 0*2 10*2 0 10 512 (110 <D2:0) 0 10*2 0*3 10*2 0 10*2 0 10 (110 <D2:0) 0 10*2 0*2 10 0*2 513 10*3 0 (110 <D2:2) 10 0*2 10*2 0*2 10*3 0 10 0*2 10 0 10*2 0*3 10 0 514 10*3 0 (110 <D2:2) 10 0*2 10 0 (110 <D2:0) 10*2 0 10 0 10*2 0 10*2 0 515 10 0 10 0*2 10*2 0*3 10 0 10*3 0*3 10*2 0 10 0 (110 <D2:3) 10 0 516 (110 <D2:2) 10 (110 <D2:3) (110 <D2:3) (110 <D2:3) 10*2 517 < 0*7 0 1*7 518 519 # FinalStream, "consectetur adipiscing elit." 520 < (1 10) (00111 00000 0010) (011 000 011 001 000 010) 0 521 > 10 0*3 10 (110 <D2:1) 0*3 10*2 0 10 (110 <D2:0) 0 10*2 0*2 10*3 0 10*2 522 0 10*2 0*2 10*3 0 10 0 10 0*2 10*2 0 10*2 0*3 10*2 0*3 10 0 10*3 0 10 523 0 10 0*2 10*2 0*3 10 0 10*3 0 10 0 10 0 10*3 0*2 10 0*2 10*3 0 524 (110 <D2:2) 10 0*2 10 0 (110 <D2:0) 10*2 0*3 10 0*2 10*2 0 10 0*2 10 0 525 10*2 0 (110 <D2:1) 10*3 0 10 0*2 10 0 10*2 0 10*2 0*2 10*3 0 10*2 0*3 526 10*2 0 10 0*2 10 0 10*2 0*2 10*3 0 10*2 0 10*3 0*2 10*2 0 (110 <D2:2) 527 10 0*2 10 0 10 0*2 10*2 0*3 10*2 0 10*2 0 10 0*2 10 0 10*2 0*3 10 0 528 10*3 0*2 10*3 0 10 (111 <D7:3) 10 (110 <D2:3) (110 <D2:3) 529 < 0*7 0 1*7 530 531 # FinalNil, "Do not communicate by sharing" 532 < (0 10) (00101 00000 0010) (011 000 011 001 000 010) 0 533 > 0*2 10 0 10*3 0*2 10 0*3 10 0 10 (110 <D2:0) 0 10*2 0 (110 <D2:2) 10 534 0*3 10*3 0 10*2 0 10 (110 <D2:0) 0 10*2 0*3 10 0 10*3 0 (110 <D2:2) 535 10 0*2 10*2 0*3 10*2 0 10 (110 <D2:0) 0 10*2 0 10 0 10*2 0 10*2 0 10 0 536 10*2 0 10*2 0 10 0 10 0 10*3 0*2 10*3 0 10*2 0 10 0*2 10 0 10*2 0 10*2 537 0*3 10*2 0 10 0 (110 <D2:0) 10*2 0*3 10 0 10*3 0 10 0 10 0*2 10*2 0 538 (110 <D2:2) 10 0*3 10 0*3 10*2 0 10 0*2 10 (110 <D2:0) 0 (110 <D2:2) 539 10 0*2 10*2 0*2 10*3 0 (110 <D2:0) 10 0 10*2 0 10 0 (110 <D2:0) 10*2 540 0*2 10 0*2 10*3 0 10 0*2 10 0 10*2 0*2 10*3 0 10*2 0 10*3 0*2 10*2 0 541 (110 <D2:3) 10 (110 <D2:3) (110 <D2:1) 542 < 0*5 0 1*7 543 544 # FinalNil, " memory; instead, share memor" 545 < (0 10) (00110 00000 0010) (011 000 011 001 000 010) 0 546 > 0*2 10 0 10*3 0 (110 <D2:1) 10 0*2 10 0 10*2 0 10*2 0 10 0 10 0*2 10*2 547 0 10 0 10*2 0 10*2 0 10 (110 <D2:0) 0 10*2 0*2 10 0*2 10*3 0 10 0*2 10 548 (110 <D2:0) 0 10*2 0 10*3 0 (110 <D2:3) 10 0*2 10 0*2 10 0 10*2 0*2 549 10*3 0 10*2 0 10*2 0*2 10*3 0*3 10 0 10*3 0 10 0 10 0*2 10*2 0 10 0 550 (110 <D2:0) 10*2 0*3 10 0*2 10*2 0*3 10*2 0 10 0 (110 <D2:3) 10 0*2 551 10*2 0*2 10*3 0 (110 <D2:0) 10 0 10*2 0 10 0 (110 <D2:0) 10*2 0*2 10 552 0*2 10*3 0 10 0 10 0*2 10*2 0 (110 <D2:2) 10 0*2 10 0 10*2 0 10*2 0 10 553 0 10 0*2 10*2 0 10 0 10*2 0 10*2 0 10 (110 <D2:0) 0 10*2 0*2 10 0*2 554 10*3 0 (110 <D2:2) 10 (110 <D2:3) (110 <D2:2) 555 < 0*6 0 1*7 556 557 # FinalNil, "y by communicating." 558 < (0 10) (00110 00000 0010) (011 000 011 001 000 010) 0 559 > 0 10*3 0*2 10 0 10*2 0 (110 <D2:0) 10 (110 <D2:2) 0 10*3 0 10*3 0*2 10 560 0 10*2 0 (110 <D2:0) 10 (110 <D2:2) 0 10*2 0*2 10*3 0*2 10 0 561 (110 <D2:0) 10 0*2 10 0 10 0*2 10 0*2 10 0 10 0*2 10 0*2 10 0 10 0 10 562 0*3 10*2 0*3 10 0*2 10 0 10*2 0 10 0*2 10 0*2 10*3 0*2 10 0 10 563 (110 <D2:0) 0*2 10*3 0 10 0*3 10 0 10*2 0 10 0*2 10*2 0*3 10 0*2 10 564 0*3 10*2 0*2 10*2 0*3 10 0 10*2 (111 <D7:36) 10 (110 <D2:3) 565 (110 <D2:3) (110 <D2:3) (110 <D2:3) (110 <D2:3) (110 <D2:3) 566 (110 <D2:3) (110 <D2:3) 10 567 < 0*6 0 1*7 568 `) 569 vectors := []struct { 570 data string 571 inOff, outOff, numBlks int64 572 final FinalMode 573 }{{ 574 "The quick brown fox jumped over the lazy dog.", 575 93, 45, 2, FinalMeta, 576 }, { 577 "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", 578 104, 56, 2, FinalStream, 579 }, { 580 "Do not communicate by sharing memory; instead, share memory by communicating.", 581 148, 77, 3, FinalNil, 582 }} 583 584 rd := bytes.NewReader(data) 585 for i, v := range vectors { 586 mr.Reset(rd) 587 buf, err := ioutil.ReadAll(mr) 588 if err != nil { 589 t.Errorf("test %d, unexpected error: ReadAll() = %v", i, err) 590 } 591 if str := string(buf); str != v.data { 592 t.Errorf("test %d, output mismatch:\ngot %s\nwant %s", i, str, v.data) 593 } 594 if err := mr.Close(); err != nil { 595 t.Errorf("test %d, unexpected error: Close() = %v", i, err) 596 } 597 if mr.InputOffset != v.inOff { 598 t.Errorf("test %d, input offset mismatch, got %d, want %d", i, mr.InputOffset, v.inOff) 599 } 600 if mr.OutputOffset != v.outOff { 601 t.Errorf("test %d, output offset mismatch, got %d, want %d", i, mr.OutputOffset, v.outOff) 602 } 603 if mr.NumBlocks != v.numBlks { 604 t.Errorf("test %d, block count mismatch, got %d, want %d", i, mr.NumBlocks, v.numBlks) 605 } 606 if mr.FinalMode != v.final { 607 t.Errorf("test %d, final mode mismatch, got %d, want %d", i, mr.FinalMode, v.final) 608 } 609 } 610} 611 612func BenchmarkReader(b *testing.B) { 613 data := make([]byte, 1<<16) 614 rand.Read(data) 615 616 rd := new(bytes.Reader) 617 bb := new(bytes.Buffer) 618 mr := new(Reader) 619 620 mw := NewWriter(bb) 621 mw.Write(data) 622 mw.Close() 623 624 b.ReportAllocs() 625 b.SetBytes(int64(len(data))) 626 b.ResetTimer() 627 628 for i := 0; i < b.N; i++ { 629 rd.Reset(bb.Bytes()) 630 mr.Reset(rd) 631 632 cnt, err := io.Copy(ioutil.Discard, mr) 633 if cnt != int64(len(data)) || err != nil { 634 b.Fatalf("Copy() = (%d, %v), want (%d, nil)", cnt, err, len(data)) 635 } 636 if err := mr.Close(); err != nil { 637 b.Fatalf("Close() = %v, want nil", err) 638 } 639 } 640} 641