github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/cford32/cford32_test.gno (about) 1 package cford32 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 "math" 9 "strconv" 10 "strings" 11 "testing" 12 ) 13 14 func TestCompactRoundtrip(t *testing.T) { 15 buf := make([]byte, 13) 16 prev := make([]byte, 13) 17 for i := uint64(0); i < (1 << 12); i++ { 18 res := AppendCompact(i, buf[:0]) 19 back, err := Uint64(res) 20 testEqual(t, "Uint64(%q) = (%d, %v), want %v", string(res), back, err, nil) 21 testEqual(t, "Uint64(%q) = %d, want %v", string(res), back, i) 22 23 testEqual(t, "bytes.Compare(prev, res) = %d, want %d", bytes.Compare(prev, res), -1) 24 prev, buf = res, prev 25 } 26 for i := uint64(1<<34 - 1024); i < (1<<34 + 1024); i++ { 27 res := AppendCompact(i, buf[:0]) 28 back, err := Uint64(res) 29 // println(string(res)) 30 testEqual(t, "Uint64(%q) = (%d, %v), want %v", string(res), back, err, nil) 31 testEqual(t, "Uint64(%q) = %d, want %v", string(res), back, i) 32 33 testEqual(t, "bytes.Compare(prev, res) = %d, want %d", bytes.Compare(prev, res), -1) 34 prev, buf = res, prev 35 } 36 for i := uint64(1<<64 - 5000); i != 0; i++ { 37 res := AppendCompact(i, buf[:0]) 38 back, err := Uint64(res) 39 testEqual(t, "Uint64(%q) = (%d, %v), want %v", string(res), back, err, nil) 40 testEqual(t, "Uint64(%q) = %d, want %v", string(res), back, i) 41 42 testEqual(t, "bytes.Compare(prev, res) = %d, want %d", bytes.Compare(prev, res), -1) 43 prev, buf = res, prev 44 } 45 } 46 47 func BenchmarkCompact(b *testing.B) { 48 buf := make([]byte, 13) 49 for i := 0; i < b.N; i++ { 50 _ = AppendCompact(uint64(i), buf[:0]) 51 } 52 } 53 54 type testpair struct { 55 decoded, encoded string 56 } 57 58 var pairs = []testpair{ 59 {"", ""}, 60 {"f", "CR"}, 61 {"fo", "CSQG"}, 62 {"foo", "CSQPY"}, 63 {"foob", "CSQPYRG"}, 64 {"fooba", "CSQPYRK1"}, 65 {"foobar", "CSQPYRK1E8"}, 66 67 {"sure.", "EDTQ4S9E"}, 68 {"sure", "EDTQ4S8"}, 69 {"sur", "EDTQ4"}, 70 {"su", "EDTG"}, 71 {"leasure.", "DHJP2WVNE9JJW"}, 72 {"easure.", "CNGQ6XBJCMQ0"}, 73 {"asure.", "C5SQAWK55R"}, 74 } 75 76 var bigtest = testpair{ 77 "Twas brillig, and the slithy toves", 78 "AHVP2WS0C9S6JV3CD5KJR831DSJ20X38CMG76V39EHM7J83MDXV6AWR", 79 } 80 81 func testEqual(t *testing.T, msg string, args ...interface{}) bool { 82 t.Helper() 83 if args[len(args)-2] != args[len(args)-1] { 84 t.Errorf(msg, args...) 85 return false 86 } 87 return true 88 } 89 90 func TestEncode(t *testing.T) { 91 for _, p := range pairs { 92 got := EncodeToString([]byte(p.decoded)) 93 testEqual(t, "Encode(%q) = %q, want %q", p.decoded, got, p.encoded) 94 dst := AppendEncode([]byte("lead"), []byte(p.decoded)) 95 testEqual(t, `AppendEncode("lead", %q) = %q, want %q`, p.decoded, string(dst), "lead"+p.encoded) 96 } 97 } 98 99 func TestEncoder(t *testing.T) { 100 for _, p := range pairs { 101 bb := &strings.Builder{} 102 encoder := NewEncoder(bb) 103 encoder.Write([]byte(p.decoded)) 104 encoder.Close() 105 testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded) 106 } 107 } 108 109 func TestEncoderBuffering(t *testing.T) { 110 input := []byte(bigtest.decoded) 111 for bs := 1; bs <= 12; bs++ { 112 bb := &strings.Builder{} 113 encoder := NewEncoder(bb) 114 for pos := 0; pos < len(input); pos += bs { 115 end := pos + bs 116 if end > len(input) { 117 end = len(input) 118 } 119 n, err := encoder.Write(input[pos:end]) 120 testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, error(nil)) 121 testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos) 122 } 123 err := encoder.Close() 124 testEqual(t, "Close gave error %v, want %v", err, error(nil)) 125 testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, bb.String(), bigtest.encoded) 126 } 127 } 128 129 func TestDecode(t *testing.T) { 130 for _, p := range pairs { 131 dbuf := make([]byte, DecodedLen(len(p.encoded))) 132 count, err := decode(dbuf, []byte(p.encoded)) 133 testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, error(nil)) 134 testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded)) 135 testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded) 136 137 dbuf, err = DecodeString(p.encoded) 138 testEqual(t, "DecodeString(%q) = error %v, want %v", p.encoded, err, error(nil)) 139 testEqual(t, "DecodeString(%q) = %q, want %q", p.encoded, string(dbuf), p.decoded) 140 141 // XXX: https://github.com/gnolang/gno/issues/1570 142 dst, err := AppendDecode(append([]byte(nil), []byte("lead")...), []byte(p.encoded)) 143 testEqual(t, "AppendDecode(%q) = error %v, want %v", p.encoded, err, error(nil)) 144 testEqual(t, `AppendDecode("lead", %q) = %q, want %q`, p.encoded, string(dst), "lead"+p.decoded) 145 146 dst2, err := AppendDecode(dst[:0:len(p.decoded)], []byte(p.encoded)) 147 testEqual(t, "AppendDecode(%q) = error %v, want %v", p.encoded, err, error(nil)) 148 testEqual(t, `AppendDecode("", %q) = %q, want %q`, p.encoded, string(dst2), p.decoded) 149 // XXX: https://github.com/gnolang/gno/issues/1569 150 // old used &dst2[0] != &dst[0] as a check. 151 if len(dst) > 0 && len(dst2) > 0 && cap(dst2) != len(p.decoded) { 152 t.Errorf("unexpected capacity growth: got %d, want %d", cap(dst2), len(p.decoded)) 153 } 154 } 155 } 156 157 // A minimal variation on strings.Reader. 158 // Here, we return a io.EOF immediately on Read if the read has reached the end 159 // of the reader. It's used to simplify TestDecoder. 160 type stringReader struct { 161 s string 162 i int64 163 } 164 165 func (r *stringReader) Read(b []byte) (n int, err error) { 166 if r.i >= int64(len(r.s)) { 167 return 0, io.EOF 168 } 169 n = copy(b, r.s[r.i:]) 170 r.i += int64(n) 171 if r.i >= int64(len(r.s)) { 172 return n, io.EOF 173 } 174 return 175 } 176 177 func TestDecoder(t *testing.T) { 178 for _, p := range pairs { 179 decoder := NewDecoder(&stringReader{p.encoded, 0}) 180 dbuf := make([]byte, DecodedLen(len(p.encoded))) 181 count, err := decoder.Read(dbuf) 182 if err != nil && err != io.EOF { 183 t.Fatal("Read failed", err) 184 } 185 testEqual(t, "Read from %q = length %v, want %v", p.encoded, count, len(p.decoded)) 186 testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded) 187 if err != io.EOF { 188 _, err = decoder.Read(dbuf) 189 } 190 testEqual(t, "Read from %q = %v, want %v", p.encoded, err, io.EOF) 191 } 192 } 193 194 type badReader struct { 195 data []byte 196 errs []error 197 called int 198 limit int 199 } 200 201 // Populates p with data, returns a count of the bytes written and an 202 // error. The error returned is taken from badReader.errs, with each 203 // invocation of Read returning the next error in this slice, or io.EOF, 204 // if all errors from the slice have already been returned. The 205 // number of bytes returned is determined by the size of the input buffer 206 // the test passes to decoder.Read and will be a multiple of 8, unless 207 // badReader.limit is non zero. 208 func (b *badReader) Read(p []byte) (int, error) { 209 lim := len(p) 210 if b.limit != 0 && b.limit < lim { 211 lim = b.limit 212 } 213 if len(b.data) < lim { 214 lim = len(b.data) 215 } 216 for i := range p[:lim] { 217 p[i] = b.data[i] 218 } 219 b.data = b.data[lim:] 220 err := io.EOF 221 if b.called < len(b.errs) { 222 err = b.errs[b.called] 223 } 224 b.called++ 225 return lim, err 226 } 227 228 // TestIssue20044 tests that decoder.Read behaves correctly when the caller 229 // supplied reader returns an error. 230 func TestIssue20044(t *testing.T) { 231 badErr := errors.New("bad reader error") 232 testCases := []struct { 233 r badReader 234 res string 235 err error 236 dbuflen int 237 }{ 238 // Check valid input data accompanied by an error is processed and the error is propagated. 239 { 240 r: badReader{data: []byte("d1jprv3fexqq4v34"), errs: []error{badErr}}, 241 res: "helloworld", err: badErr, 242 }, 243 // Check a read error accompanied by input data consisting of newlines only is propagated. 244 { 245 r: badReader{data: []byte("\n\n\n\n\n\n\n\n"), errs: []error{badErr, nil}}, 246 res: "", err: badErr, 247 }, 248 // Reader will be called twice. The first time it will return 8 newline characters. The 249 // second time valid base32 encoded data and an error. The data should be decoded 250 // correctly and the error should be propagated. 251 { 252 r: badReader{data: []byte("\n\n\n\n\n\n\n\nd1jprv3fexqq4v34"), errs: []error{nil, badErr}}, 253 res: "helloworld", err: badErr, dbuflen: 8, 254 }, 255 // Reader returns invalid input data (too short) and an error. Verify the reader 256 // error is returned. 257 { 258 r: badReader{data: []byte("c"), errs: []error{badErr}}, 259 res: "", err: badErr, 260 }, 261 // Reader returns invalid input data (too short) but no error. Verify io.ErrUnexpectedEOF 262 // is returned. 263 // NOTE(thehowl): I don't think this should applyto us? 264 /* { 265 r: badReader{data: []byte("c"), errs: []error{nil}}, 266 res: "", err: io.ErrUnexpectedEOF, 267 },*/ 268 // Reader returns invalid input data and an error. Verify the reader and not the 269 // decoder error is returned. 270 { 271 r: badReader{data: []byte("cu"), errs: []error{badErr}}, 272 res: "", err: badErr, 273 }, 274 // Reader returns valid data and io.EOF. Check data is decoded and io.EOF is propagated. 275 { 276 r: badReader{data: []byte("csqpyrk1"), errs: []error{io.EOF}}, 277 res: "fooba", err: io.EOF, 278 }, 279 // Check errors are properly reported when decoder.Read is called multiple times. 280 // decoder.Read will be called 8 times, badReader.Read will be called twice, returning 281 // valid data both times but an error on the second call. 282 { 283 r: badReader{data: []byte("dhjp2wvne9jjwc9g"), errs: []error{nil, badErr}}, 284 res: "leasure.10", err: badErr, dbuflen: 1, 285 }, 286 // Check io.EOF is properly reported when decoder.Read is called multiple times. 287 // decoder.Read will be called 8 times, badReader.Read will be called twice, returning 288 // valid data both times but io.EOF on the second call. 289 { 290 r: badReader{data: []byte("dhjp2wvne9jjw"), errs: []error{nil, io.EOF}}, 291 res: "leasure.", err: io.EOF, dbuflen: 1, 292 }, 293 // The following two test cases check that errors are propagated correctly when more than 294 // 8 bytes are read at a time. 295 { 296 r: badReader{data: []byte("dhjp2wvne9jjw"), errs: []error{io.EOF}}, 297 res: "leasure.", err: io.EOF, dbuflen: 11, 298 }, 299 { 300 r: badReader{data: []byte("dhjp2wvne9jjwc9g"), errs: []error{badErr}}, 301 res: "leasure.10", err: badErr, dbuflen: 11, 302 }, 303 // Check that errors are correctly propagated when the reader returns valid bytes in 304 // groups that are not divisible by 8. The first read will return 11 bytes and no 305 // error. The second will return 7 and an error. The data should be decoded correctly 306 // and the error should be propagated. 307 // NOTE(thehowl): again, this is on the assumption that this is padded, and it's not. 308 /* { 309 r: badReader{data: []byte("dhjp2wvne9jjw"), errs: []error{nil, badErr}, limit: 11}, 310 res: "leasure.", err: badErr, 311 }, */ 312 } 313 314 for idx, tc := range testCases { 315 t.Run(fmt.Sprintf("%d-%s", idx, string(tc.res)), func(t *testing.T) { 316 input := tc.r.data 317 decoder := NewDecoder(&tc.r) 318 var dbuflen int 319 if tc.dbuflen > 0 { 320 dbuflen = tc.dbuflen 321 } else { 322 dbuflen = DecodedLen(len(input)) 323 } 324 dbuf := make([]byte, dbuflen) 325 var err error 326 var res []byte 327 for err == nil { 328 var n int 329 n, err = decoder.Read(dbuf) 330 if n > 0 { 331 res = append(res, dbuf[:n]...) 332 } 333 } 334 335 testEqual(t, "Decoding of %q = %q, want %q", string(input), string(res), tc.res) 336 testEqual(t, "Decoding of %q err = %v, expected %v", string(input), err, tc.err) 337 }) 338 } 339 } 340 341 // TestDecoderError verifies decode errors are propagated when there are no read 342 // errors. 343 func TestDecoderError(t *testing.T) { 344 for _, readErr := range []error{io.EOF, nil} { 345 input := "ucsqpyrk1u" 346 dbuf := make([]byte, DecodedLen(len(input))) 347 br := badReader{data: []byte(input), errs: []error{readErr}} 348 decoder := NewDecoder(&br) 349 n, err := decoder.Read(dbuf) 350 testEqual(t, "Read after EOF, n = %d, expected %d", n, 0) 351 if _, ok := err.(CorruptInputError); !ok { 352 t.Errorf("Corrupt input error expected. Found %T", err) 353 } 354 } 355 } 356 357 // TestReaderEOF ensures decoder.Read behaves correctly when input data is 358 // exhausted. 359 func TestReaderEOF(t *testing.T) { 360 for _, readErr := range []error{io.EOF, nil} { 361 input := "MZXW6YTB" 362 br := badReader{data: []byte(input), errs: []error{nil, readErr}} 363 decoder := NewDecoder(&br) 364 dbuf := make([]byte, DecodedLen(len(input))) 365 n, err := decoder.Read(dbuf) 366 testEqual(t, "Decoding of %q err = %v, expected %v", input, err, error(nil)) 367 n, err = decoder.Read(dbuf) 368 testEqual(t, "Read after EOF, n = %d, expected %d", n, 0) 369 testEqual(t, "Read after EOF, err = %v, expected %v", err, io.EOF) 370 n, err = decoder.Read(dbuf) 371 testEqual(t, "Read after EOF, n = %d, expected %d", n, 0) 372 testEqual(t, "Read after EOF, err = %v, expected %v", err, io.EOF) 373 } 374 } 375 376 func TestDecoderBuffering(t *testing.T) { 377 for bs := 1; bs <= 12; bs++ { 378 decoder := NewDecoder(strings.NewReader(bigtest.encoded)) 379 buf := make([]byte, len(bigtest.decoded)+12) 380 var total int 381 var n int 382 var err error 383 for total = 0; total < len(bigtest.decoded) && err == nil; { 384 n, err = decoder.Read(buf[total : total+bs]) 385 total += n 386 } 387 if err != nil && err != io.EOF { 388 t.Errorf("Read from %q at pos %d = %d, unexpected error %v", bigtest.encoded, total, n, err) 389 } 390 testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded) 391 } 392 } 393 394 func TestDecodeCorrupt(t *testing.T) { 395 testCases := []struct { 396 input string 397 offset int // -1 means no corruption. 398 }{ 399 {"", -1}, 400 {"iIoOlL", -1}, 401 {"!!!!", 0}, 402 {"uxp10", 0}, 403 {"x===", 1}, 404 {"AA=A====", 2}, 405 {"AAA=AAAA", 3}, 406 // Much fewer cases compared to Go as there are much fewer cases where input 407 // can be "corrupted". 408 } 409 for _, tc := range testCases { 410 dbuf := make([]byte, DecodedLen(len(tc.input))) 411 _, err := Decode(dbuf, []byte(tc.input)) 412 if tc.offset == -1 { 413 if err != nil { 414 t.Error("Decoder wrongly detected corruption in", tc.input) 415 } 416 continue 417 } 418 switch err := err.(type) { 419 case CorruptInputError: 420 testEqual(t, "Corruption in %q at offset %v, want %v", tc.input, int(err), tc.offset) 421 default: 422 t.Error("Decoder failed to detect corruption in", tc) 423 } 424 } 425 } 426 427 func TestBig(t *testing.T) { 428 n := 3*1000 + 1 429 raw := make([]byte, n) 430 const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 431 for i := 0; i < n; i++ { 432 raw[i] = alpha[i%len(alpha)] 433 } 434 encoded := new(bytes.Buffer) 435 w := NewEncoder(encoded) 436 nn, err := w.Write(raw) 437 if nn != n || err != nil { 438 t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n) 439 } 440 err = w.Close() 441 if err != nil { 442 t.Fatalf("Encoder.Close() = %v want nil", err) 443 } 444 decoded, err := io.ReadAll(NewDecoder(encoded)) 445 if err != nil { 446 t.Fatalf("io.ReadAll(NewDecoder(...)): %v", err) 447 } 448 449 if !bytes.Equal(raw, decoded) { 450 var i int 451 for i = 0; i < len(decoded) && i < len(raw); i++ { 452 if decoded[i] != raw[i] { 453 break 454 } 455 } 456 t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i) 457 } 458 } 459 460 func testStringEncoding(t *testing.T, expected string, examples []string) { 461 for _, e := range examples { 462 buf, err := DecodeString(e) 463 if err != nil { 464 t.Errorf("Decode(%q) failed: %v", e, err) 465 continue 466 } 467 if s := string(buf); s != expected { 468 t.Errorf("Decode(%q) = %q, want %q", e, s, expected) 469 } 470 } 471 } 472 473 func TestNewLineCharacters(t *testing.T) { 474 // Each of these should decode to the string "sure", without errors. 475 examples := []string{ 476 "EDTQ4S8", 477 "EDTQ4S8\r", 478 "EDTQ4S8\n", 479 "EDTQ4S8\r\n", 480 "EDTQ4S\r\n8", 481 "EDT\rQ4S\n8", 482 "edt\nq4s\r8", 483 "edt\nq4s8", 484 "EDTQ4S\n8", 485 } 486 testStringEncoding(t, "sure", examples) 487 } 488 489 func BenchmarkEncode(b *testing.B) { 490 data := make([]byte, 8192) 491 buf := make([]byte, EncodedLen(len(data))) 492 b.SetBytes(int64(len(data))) 493 for i := 0; i < b.N; i++ { 494 Encode(buf, data) 495 } 496 } 497 498 func BenchmarkEncodeToString(b *testing.B) { 499 data := make([]byte, 8192) 500 b.SetBytes(int64(len(data))) 501 for i := 0; i < b.N; i++ { 502 EncodeToString(data) 503 } 504 } 505 506 func BenchmarkDecode(b *testing.B) { 507 data := make([]byte, EncodedLen(8192)) 508 Encode(data, make([]byte, 8192)) 509 buf := make([]byte, 8192) 510 b.SetBytes(int64(len(data))) 511 for i := 0; i < b.N; i++ { 512 Decode(buf, data) 513 } 514 } 515 516 func BenchmarkDecodeString(b *testing.B) { 517 data := EncodeToString(make([]byte, 8192)) 518 b.SetBytes(int64(len(data))) 519 for i := 0; i < b.N; i++ { 520 DecodeString(data) 521 } 522 } 523 524 /* TODO: rewrite without using goroutines 525 func TestBufferedDecodingSameError(t *testing.T) { 526 testcases := []struct { 527 prefix string 528 chunkCombinations [][]string 529 expected error 530 }{ 531 // Normal case, this is valid input 532 {"helloworld", [][]string{ 533 {"D1JP", "RV3F", "EXQQ", "4V34"}, 534 {"D1JPRV3FEXQQ4V34"}, 535 {"D1J", "PRV", "3FE", "XQQ", "4V3", "4"}, 536 {"D1JPRV3FEXQQ4V", "34"}, 537 }, nil}, 538 539 // Normal case, this is valid input 540 {"fooba", [][]string{ 541 {"CSQPYRK1"}, 542 {"CSQPYRK", "1"}, 543 {"CSQPYR", "K1"}, 544 {"CSQPY", "RK1"}, 545 {"CSQPY", "RK", "1"}, 546 {"CSQPY", "RK1"}, 547 {"CSQP", "YR", "K1"}, 548 }, nil}, 549 550 // NOTE: many test cases have been removed as we don't return ErrUnexpectedEOF. 551 } 552 553 for _, testcase := range testcases { 554 for _, chunks := range testcase.chunkCombinations { 555 pr, pw := io.Pipe() 556 557 // Write the encoded chunks into the pipe 558 go func() { 559 for _, chunk := range chunks { 560 pw.Write([]byte(chunk)) 561 } 562 pw.Close() 563 }() 564 565 decoder := NewDecoder(pr) 566 back, err := io.ReadAll(decoder) 567 568 if err != testcase.expected { 569 t.Errorf("Expected %v, got %v; case %s %+v", testcase.expected, err, testcase.prefix, chunks) 570 } 571 if testcase.expected == nil { 572 testEqual(t, "Decode from NewDecoder(chunkReader(%v)) = %q, want %q", chunks, string(back), testcase.prefix) 573 } 574 } 575 } 576 } 577 */ 578 579 func TestEncodedLen(t *testing.T) { 580 type test struct { 581 n int 582 want int64 583 } 584 tests := []test{ 585 {0, 0}, 586 {1, 2}, 587 {2, 4}, 588 {3, 5}, 589 {4, 7}, 590 {5, 8}, 591 {6, 10}, 592 {7, 12}, 593 {10, 16}, 594 {11, 18}, 595 } 596 // check overflow 597 tests = append(tests, test{(math.MaxInt-4)/8 + 1, 1844674407370955162}) 598 tests = append(tests, test{math.MaxInt/8*5 + 4, math.MaxInt}) 599 for _, tt := range tests { 600 if got := EncodedLen(tt.n); int64(got) != tt.want { 601 t.Errorf("EncodedLen(%d): got %d, want %d", tt.n, got, tt.want) 602 } 603 } 604 } 605 606 func TestDecodedLen(t *testing.T) { 607 type test struct { 608 n int 609 want int64 610 } 611 tests := []test{ 612 {0, 0}, 613 {2, 1}, 614 {4, 2}, 615 {5, 3}, 616 {7, 4}, 617 {8, 5}, 618 {10, 6}, 619 {12, 7}, 620 {16, 10}, 621 {18, 11}, 622 } 623 // check overflow 624 tests = append(tests, test{math.MaxInt/5 + 1, 1152921504606846976}) 625 tests = append(tests, test{math.MaxInt, 5764607523034234879}) 626 for _, tt := range tests { 627 if got := DecodedLen(tt.n); int64(got) != tt.want { 628 t.Errorf("DecodedLen(%d): got %d, want %d", tt.n, got, tt.want) 629 } 630 } 631 }