123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- package encapsulation
- import (
- "bytes"
- "io"
- "math/rand"
- "testing"
- )
- // Return a byte slice with non-trivial contents.
- func pseudorandomBuffer(n int) []byte {
- source := rand.NewSource(0)
- p := make([]byte, n)
- for i := 0; i < len(p); i++ {
- p[i] = byte(source.Int63() & 0xff)
- }
- return p
- }
- func mustWriteData(w io.Writer, p []byte) int {
- n, err := WriteData(w, p)
- if err != nil {
- panic(err)
- }
- return n
- }
- func mustWritePadding(w io.Writer, n int) int {
- n, err := WritePadding(w, n)
- if err != nil {
- panic(err)
- }
- return n
- }
- // Test that ReadData(WriteData()) recovers the original data.
- func TestRoundtrip(t *testing.T) {
- // Test above and below interesting thresholds.
- for _, i := range []int{
- 0x00, 0x01,
- 0x3e, 0x3f, 0x40, 0x41,
- 0xfe, 0xff, 0x100, 0x101,
- 0x1ffe, 0x1fff, 0x2000, 0x2001,
- 0xfffe, 0xffff, 0x10000, 0x10001,
- 0xffffe, 0xfffff,
- } {
- original := pseudorandomBuffer(i)
- var enc bytes.Buffer
- n, err := WriteData(&enc, original)
- if err != nil {
- t.Fatalf("size %d, WriteData returned error %v", i, err)
- }
- if enc.Len() != n {
- t.Fatalf("size %d, returned length was %d, written length was %d",
- i, n, enc.Len())
- }
- inverse := make([]byte, i)
- n, err = ReadData(&enc, inverse)
- if err != nil {
- t.Fatalf("size %d, ReadData returned error %v", i, err)
- }
- if !bytes.Equal(inverse[:n], original) {
- t.Fatalf("size %d, got <%x>, expected <%x>", i, inverse[:n], original)
- }
- }
- }
- // Test that WritePadding writes exactly as much as requested.
- func TestPaddingLength(t *testing.T) {
- // Test above and below interesting thresholds. WritePadding also gets
- // values above 0xfffff, the maximum value of a single length prefix.
- for _, i := range []int{
- 0x00, 0x01,
- 0x3f, 0x40, 0x41, 0x42,
- 0xff, 0x100, 0x101, 0x102,
- 0x2000, 0x2001, 0x2002, 0x2003,
- 0x10000, 0x10001, 0x10002, 0x10003,
- 0x100001, 0x100002, 0x100003, 0x100004,
- } {
- var enc bytes.Buffer
- n, err := WritePadding(&enc, i)
- if err != nil {
- t.Fatalf("size %d, WritePadding returned error %v", i, err)
- }
- if n != i {
- t.Fatalf("requested %d bytes, returned %d", i, n)
- }
- if enc.Len() != n {
- t.Fatalf("requested %d bytes, wrote %d bytes", i, enc.Len())
- }
- }
- }
- // Test that ReadData skips over padding.
- func TestSkipPadding(t *testing.T) {
- var data = [][]byte{{}, {}, []byte("hello"), {}, []byte("world")}
- var enc bytes.Buffer
- mustWritePadding(&enc, 10)
- mustWritePadding(&enc, 100)
- mustWriteData(&enc, data[0])
- mustWriteData(&enc, data[1])
- mustWritePadding(&enc, 10)
- mustWriteData(&enc, data[2])
- mustWriteData(&enc, data[3])
- mustWritePadding(&enc, 10)
- mustWriteData(&enc, data[4])
- mustWritePadding(&enc, 10)
- mustWritePadding(&enc, 10)
- for i, expected := range data {
- var actual [10]byte
- n, err := ReadData(&enc, actual[:])
- if err != nil {
- t.Fatalf("slice %d, got error %v, expected %v", i, err, nil)
- }
- if !bytes.Equal(actual[:n], expected) {
- t.Fatalf("slice %d, got <%x>, expected <%x>", i, actual[:n], expected)
- }
- }
- n, err := ReadData(&enc, nil)
- if n != 0 || err != io.EOF {
- t.Fatalf("got (%v, %v), expected (%v, %v)", n, err, 0, io.EOF)
- }
- }
- // Test that EOF before a length prefix returns io.EOF.
- func TestEOF(t *testing.T) {
- n, err := ReadData(bytes.NewReader(nil), nil)
- if n != 0 || err != io.EOF {
- t.Fatalf("got (%v, %v), expected (%v, %v)", n, err, 0, io.EOF)
- }
- }
- // Test that an EOF while reading a length prefix, or while reading the
- // subsequent data/padding, returns io.ErrUnexpectedEOF.
- func TestUnexpectedEOF(t *testing.T) {
- for _, test := range [][]byte{
- {0x40}, // expecting a second length byte
- {0xc0}, // expecting a second length byte
- {0x41, 0x80}, // expecting a third length byte
- {0xc1, 0x80}, // expecting a third length byte
- {0x02}, // expecting 2 bytes of padding
- {0x82}, // expecting 2 bytes of data
- {0x02, 'X'}, // expecting 1 byte of padding
- {0x82, 'X'}, // expecting 1 byte of data
- {0x41, 0x00}, // expecting 128 bytes of padding
- {0xc1, 0x00}, // expecting 128 bytes of data
- {0x41, 0x00, 'X'}, // expecting 127 bytes of padding
- {0xc1, 0x00, 'X'}, // expecting 127 bytes of data
- {0x41, 0x80, 0x00}, // expecting 32768 bytes of padding
- {0xc1, 0x80, 0x00}, // expecting 32768 bytes of data
- {0x41, 0x80, 0x00, 'X'}, // expecting 32767 bytes of padding
- {0xc1, 0x80, 0x00, 'X'}, // expecting 32767 bytes of data
- } {
- n, err := ReadData(bytes.NewReader(test), nil)
- if n != 0 || err != io.ErrUnexpectedEOF {
- t.Fatalf("<%x> got (%v, %v), expected (%v, %v)", test, n, err, 0, io.ErrUnexpectedEOF)
- }
- }
- }
- // Test that length encodings that are longer than they could be are still
- // interpreted.
- func TestNonMinimalLengthEncoding(t *testing.T) {
- for _, test := range []struct {
- enc []byte
- expected []byte
- }{
- {[]byte{0x81, 'X'}, []byte("X")},
- {[]byte{0xc0, 0x01, 'X'}, []byte("X")},
- {[]byte{0xc0, 0x80, 0x01, 'X'}, []byte("X")},
- } {
- var p [10]byte
- n, err := ReadData(bytes.NewReader(test.enc), p[:])
- if err != nil {
- t.Fatalf("<%x> got error %v, expected %v", test.enc, err, nil)
- }
- if !bytes.Equal(p[:n], test.expected) {
- t.Fatalf("<%x> got <%x>, expected <%x>", test.enc, p[:n], test.expected)
- }
- }
- }
- // Test that ReadData only reads up to 3 bytes of length prefix.
- func TestReadLimits(t *testing.T) {
- // Test the maximum length that's possible with 3 bytes of length
- // prefix.
- maxLength := (0x3f << 14) | (0x7f << 7) | 0x7f
- data := bytes.Repeat([]byte{'X'}, maxLength)
- prefix := []byte{0xff, 0xff, 0x7f} // encodes 0xfffff
- var p [0xfffff]byte
- n, err := ReadData(bytes.NewReader(append(prefix, data...)), p[:])
- if err != nil {
- t.Fatalf("got error %v, expected %v", err, nil)
- }
- if !bytes.Equal(p[:n], data) {
- t.Fatalf("got %d bytes unequal to %d bytes", len(p), len(data))
- }
- // Test a 4-byte prefix.
- prefix = []byte{0xc0, 0xc0, 0x80, 0x80} // encodes 0x100000
- data = bytes.Repeat([]byte{'X'}, maxLength+1)
- n, err = ReadData(bytes.NewReader(append(prefix, data...)), nil)
- if n != 0 || err != ErrTooLong {
- t.Fatalf("got (%v, %v), expected (%v, %v)", n, err, 0, ErrTooLong)
- }
- // Test that 4 bytes don't work, even when they encode an integer that
- // would fix in 3 bytes.
- prefix = []byte{0xc0, 0x80, 0x80, 0x80} // encodes 0x0
- data = []byte{}
- n, err = ReadData(bytes.NewReader(append(prefix, data...)), nil)
- if n != 0 || err != ErrTooLong {
- t.Fatalf("got (%v, %v), expected (%v, %v)", n, err, 0, ErrTooLong)
- }
- // Do the same tests with padding lengths.
- data = []byte("hello")
- prefix = []byte{0x7f, 0xff, 0x7f} // encodes 0xfffff
- padding := bytes.Repeat([]byte{'X'}, maxLength)
- enc := bytes.NewBuffer(append(prefix, padding...))
- mustWriteData(enc, data)
- n, err = ReadData(enc, p[:])
- if err != nil {
- t.Fatalf("got error %v, expected %v", err, nil)
- }
- if !bytes.Equal(p[:n], data) {
- t.Fatalf("got <%x>, expected <%x>", p[:n], data)
- }
- prefix = []byte{0x40, 0xc0, 0x80, 0x80} // encodes 0x100000
- padding = bytes.Repeat([]byte{'X'}, maxLength+1)
- enc = bytes.NewBuffer(append(prefix, padding...))
- mustWriteData(enc, data)
- n, err = ReadData(enc, nil)
- if n != 0 || err != ErrTooLong {
- t.Fatalf("got (%v, %v), expected (%v, %v)", n, err, 0, ErrTooLong)
- }
- prefix = []byte{0x40, 0x80, 0x80, 0x80} // encodes 0x0
- padding = []byte{}
- enc = bytes.NewBuffer(append(prefix, padding...))
- mustWriteData(enc, data)
- n, err = ReadData(enc, nil)
- if n != 0 || err != ErrTooLong {
- t.Fatalf("got (%v, %v), expected (%v, %v)", n, err, 0, ErrTooLong)
- }
- }
- // Test that WriteData and WritePadding only accept lengths that can be encoded
- // in up to 3 bytes of length prefix.
- func TestWriteLimits(t *testing.T) {
- maxLength := (0x3f << 14) | (0x7f << 7) | 0x7f
- var enc bytes.Buffer
- n, err := WriteData(&enc, bytes.Repeat([]byte{'X'}, maxLength))
- if n != maxLength+3 || err != nil {
- t.Fatalf("got (%d, %v), expected (%d, %v)", n, err, maxLength, nil)
- }
- enc.Reset()
- n, err = WriteData(&enc, bytes.Repeat([]byte{'X'}, maxLength+1))
- if n != 0 || err != ErrTooLong {
- t.Fatalf("got (%d, %v), expected (%d, %v)", n, err, 0, ErrTooLong)
- }
- // Padding gets an extra 3 bytes because the prefix is counted as part
- // of the length.
- enc.Reset()
- n, err = WritePadding(&enc, maxLength+3)
- if n != maxLength+3 || err != nil {
- t.Fatalf("got (%d, %v), expected (%d, %v)", n, err, maxLength+3, nil)
- }
- // Writing a too-long padding is okay because WritePadding will break it
- // into smaller chunks.
- enc.Reset()
- n, err = WritePadding(&enc, maxLength+4)
- if n != maxLength+4 || err != nil {
- t.Fatalf("got (%d, %v), expected (%d, %v)", n, err, maxLength+4, nil)
- }
- }
- // Test that WritePadding panics when given a negative length.
- func TestNegativeLength(t *testing.T) {
- for _, n := range []int{-1, ^0} {
- var enc bytes.Buffer
- panicked, nn, err := testNegativeLengthSub(t, &enc, n)
- if !panicked {
- t.Fatalf("WritePadding(%d) returned (%d, %v) instead of panicking", n, nn, err)
- }
- }
- }
- // Calls WritePadding(w, n) and augments the return value with a flag indicating
- // whether the call panicked.
- func testNegativeLengthSub(t *testing.T, w io.Writer, n int) (panicked bool, nn int, err error) {
- defer func() {
- if r := recover(); r != nil {
- panicked = true
- }
- }()
- t.Helper()
- nn, err = WritePadding(w, n)
- return false, n, err
- }
- // Test that MaxDataForSize panics when given a 0 length.
- func TestMaxDataForSizeZero(t *testing.T) {
- defer func() {
- if r := recover(); r == nil {
- t.Fatal("didn't panic")
- }
- }()
- MaxDataForSize(0)
- }
- // Test thresholds of available sizes for MaxDataForSize.
- func TestMaxDataForSize(t *testing.T) {
- for _, test := range []struct {
- size int
- expected int
- }{
- {0x01, 0x00},
- {0x02, 0x01},
- {0x3f, 0x3e},
- {0x40, 0x3e},
- {0x41, 0x3f},
- {0x1fff, 0x1ffd},
- {0x2000, 0x1ffd},
- {0x2001, 0x1ffe},
- {0xfffff, 0xffffc},
- {0x100000, 0xffffc},
- {0x100001, 0xffffc},
- {0x7fffffff, 0xffffc},
- } {
- max := MaxDataForSize(test.size)
- if max != test.expected {
- t.Fatalf("size %d, got %d, expected %d", test.size, max, test.expected)
- }
- }
- }
- // Test that ReadData truncates the data when the destination slice is too
- // short.
- func TestReadDataTruncate(t *testing.T) {
- var enc bytes.Buffer
- mustWriteData(&enc, []byte("12345678"))
- mustWriteData(&enc, []byte("abcdefgh"))
- var p [4]byte
- // First ReadData should return truncated "1234".
- n, err := ReadData(&enc, p[:])
- if err != io.ErrShortBuffer {
- t.Fatalf("got error %v, expected %v", err, io.ErrShortBuffer)
- }
- if !bytes.Equal(p[:n], []byte("1234")) {
- t.Fatalf("got <%x>, expected <%x>", p[:n], []byte("1234"))
- }
- // Second ReadData should return truncated "abcd", not the rest of
- // "12345678".
- n, err = ReadData(&enc, p[:])
- if err != io.ErrShortBuffer {
- t.Fatalf("got error %v, expected %v", err, io.ErrShortBuffer)
- }
- if !bytes.Equal(p[:n], []byte("abcd")) {
- t.Fatalf("got <%x>, expected <%x>", p[:n], []byte("abcd"))
- }
- // Last ReadData should give io.EOF.
- n, err = ReadData(&enc, p[:])
- if err != io.EOF {
- t.Fatalf("got error %v, expected %v", err, io.EOF)
- }
- }
- // Test that even when the result is truncated, ReadData fills the provided
- // buffer as much as possible (and not stop at the boundary of an internal Read,
- // say).
- func TestReadDataTruncateFull(t *testing.T) {
- pr, pw := io.Pipe()
- go func() {
- // Send one data chunk that will be delivered across two Read
- // calls.
- pw.Write([]byte{0x8a, 'h', 'e', 'l', 'l', 'o'})
- pw.Write([]byte{'w', 'o', 'r', 'l', 'd'})
- }()
- var p [8]byte
- n, err := ReadData(pr, p[:])
- if err != io.ErrShortBuffer {
- t.Fatalf("got error %v, expected %v", err, io.ErrShortBuffer)
- }
- // Should not stop after "hello".
- if !bytes.Equal(p[:n], []byte("hellowor")) {
- t.Fatalf("got <%x>, expected <%x>", p[:n], []byte("hellowor"))
- }
- }
- // Benchmark the ReadData function when reading from a stream of data packets of
- // different sizes.
- func BenchmarkReadData(b *testing.B) {
- pr, pw := io.Pipe()
- go func() {
- for {
- for length := 0; length < 128; length++ {
- WriteData(pw, paddingBuffer[:length])
- }
- }
- }()
- var p [128]byte
- for i := 0; i < b.N; i++ {
- _, err := ReadData(pr, p[:])
- if err != nil {
- b.Fatal(err)
- }
- }
- }
|