diff --git a/internal/buffer/out_message_test.go b/internal/buffer/out_message_test.go index 81b0192..f647f22 100644 --- a/internal/buffer/out_message_test.go +++ b/internal/buffer/out_message_test.go @@ -1,12 +1,16 @@ package buffer import ( + "bytes" "crypto/rand" "fmt" "io" "reflect" "testing" "unsafe" + + "github.com/jacobsa/fuse/internal/fusekernel" + "github.com/kylelemons/godebug/pretty" ) func toByteSlice(p unsafe.Pointer, n int) []byte { @@ -86,18 +90,154 @@ func TestMemclr(t *testing.T) { } } +func TestOutMessageAppend(t *testing.T) { + var om OutMessage + om.Reset() + + // Append some payload. + const wantPayloadStr = "tacoburrito" + wantPayload := []byte(wantPayloadStr) + om.Append(wantPayload[:4]) + om.Append(wantPayload[4:]) + + // The result should be a zeroed header followed by the desired payload. + const wantLen = int(OutMessageInitialSize) + len(wantPayloadStr) + + if got, want := om.Len(), wantLen; got != want { + t.Errorf("om.Len() = %d, want %d", got, want) + } + + b := om.Bytes() + if got, want := len(b), wantLen; got != want { + t.Fatalf("len(om.Bytes()) = %d, want %d", got, want) + } + + want := append( + make([]byte, OutMessageInitialSize), + wantPayload...) + + if !bytes.Equal(b, want) { + t.Error("messages differ") + } +} + +func TestOutMessageAppendString(t *testing.T) { + var om OutMessage + om.Reset() + + // Append some payload. + const wantPayload = "tacoburrito" + om.AppendString(wantPayload[:4]) + om.AppendString(wantPayload[4:]) + + // The result should be a zeroed header followed by the desired payload. + const wantLen = int(OutMessageInitialSize) + len(wantPayload) + + if got, want := om.Len(), wantLen; got != want { + t.Errorf("om.Len() = %d, want %d", got, want) + } + + b := om.Bytes() + if got, want := len(b), wantLen; got != want { + t.Fatalf("len(om.Bytes()) = %d, want %d", got, want) + } + + want := append( + make([]byte, OutMessageInitialSize), + wantPayload...) + + if !bytes.Equal(b, want) { + t.Error("messages differ") + } +} + +func TestOutMessageShrinkTo(t *testing.T) { + // Set up a buffer with some payload. + var om OutMessage + om.Reset() + om.AppendString("taco") + om.AppendString("burrito") + + // Shrink it. + om.ShrinkTo(OutMessageInitialSize + uintptr(len("taco"))) + + // The result should be a zeroed header followed by "taco". + const wantLen = int(OutMessageInitialSize) + len("taco") + + if got, want := om.Len(), wantLen; got != want { + t.Errorf("om.Len() = %d, want %d", got, want) + } + + b := om.Bytes() + if got, want := len(b), wantLen; got != want { + t.Fatalf("len(om.Bytes()) = %d, want %d", got, want) + } + + want := append( + make([]byte, OutMessageInitialSize), + "taco"...) + + if !bytes.Equal(b, want) { + t.Error("messages differ") + } +} + +func TestOutMessageHeader(t *testing.T) { + var om OutMessage + om.Reset() + + // Fill in the header. + want := fusekernel.OutHeader{ + Len: 0xdeadbeef, + Error: -31231917, + Unique: 0xcafebabeba5eba11, + } + + h := om.OutHeader() + if h == nil { + t.Fatal("OutHeader returned nil") + } + + *h = want + + // Check that the result is as expected. + b := om.Bytes() + if len(b) != int(unsafe.Sizeof(want)) { + t.Fatalf("unexpected length %d; want %d", len(b), unsafe.Sizeof(want)) + } + + got := *(*fusekernel.OutHeader)(unsafe.Pointer(&b[0])) + if diff := pretty.Compare(got, want); diff != "" { + t.Errorf("diff -got +want:\n%s", diff) + } +} + func TestOutMessageReset(t *testing.T) { var om OutMessage h := om.OutHeader() - const trials = 100 + const trials = 10 for i := 0; i < trials; i++ { + // Fill the header with garbage. err := fillWithGarbage(unsafe.Pointer(h), int(unsafe.Sizeof(*h))) if err != nil { t.Fatalf("fillWithGarbage: %v", err) } + // Ensure a non-zero payload length. + if p := om.GrowNoZero(128); p == nil { + t.Fatal("GrowNoZero failed") + } + + // Reset. om.Reset() + + // Check that the length was updated. + if got, want := int(om.Len()), int(OutMessageInitialSize); got != want { + t.Fatalf("om.Len() = %d, want %d", got, want) + } + + // Check that the header was zeroed. if h.Len != 0 { t.Fatalf("non-zero Len %v", h.Len) } @@ -114,26 +254,44 @@ func TestOutMessageReset(t *testing.T) { func TestOutMessageGrow(t *testing.T) { var om OutMessage - - // Overwrite with garbage. - err := fillWithGarbage(unsafe.Pointer(&om), int(unsafe.Sizeof(om))) - if err != nil { - t.Fatalf("fillWithGarbage: %v", err) - } - - // Zero the header. om.Reset() - // Grow to the max size. This should zero the message. - if p := om.Grow(MaxReadSize); p == nil { - t.Fatal("Grow returned nil") + // Set up garbage where the payload will soon be. + const payloadSize = 1234 + { + p := om.GrowNoZero(payloadSize) + if p == nil { + t.Fatal("GrowNoZero failed") + } + + err := fillWithGarbage(p, payloadSize) + if err != nil { + t.Fatalf("fillWithGarbage: %v", err) + } + + om.ShrinkTo(OutMessageInitialSize) + } + + // Call Grow. + if p := om.Grow(payloadSize); p == nil { + t.Fatal("Grow failed") + } + + // Check the resulting length in two ways. + const wantLen = int(payloadSize + OutMessageInitialSize) + if got, want := om.Len(), wantLen; got != want { + t.Errorf("om.Len() = %d, want %d", got) } - // Check that everything has been zeroed. b := om.Bytes() - for i, x := range b { + if got, want := len(b), wantLen; got != want { + t.Fatalf("len(om.Len()) = %d, want %d", got) + } + + // Check that the payload was zeroed. + for i, x := range b[OutMessageInitialSize:] { if x != 0 { - t.Fatalf("non-zero byte 0x%02x at offset %d", x, i) + t.Fatalf("non-zero byte 0x%02x at payload offset %d", x, i) } } }