// Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause package cstruct import ( "errors" "fmt" "io" "testing" ) func TestPadBytes(t *testing.T) { testCases := []struct { offset int size int want int }{ // No padding at beginning of structure {0, 1, 0}, {0, 2, 0}, {0, 4, 0}, {0, 8, 0}, // No padding for single bytes {1, 1, 0}, // Single byte padding {1, 2, 1}, {3, 4, 1}, // Multi-byte padding {1, 4, 3}, {2, 8, 6}, } for _, tc := range testCases { t.Run(fmt.Sprintf("%d_%d_%d", tc.offset, tc.size, tc.want), func(t *testing.T) { got := padBytes(tc.offset, tc.size) if got != tc.want { t.Errorf("got=%d; want=%d", got, tc.want) } }) } } func TestDecoder(t *testing.T) { t.Run("UnsignedTypes", func(t *testing.T) { dec := func(n int) *Decoder { buf := make([]byte, n) buf[0] = 1 d := NewDecoder(buf) // Use t.Cleanup to perform an assertion on this // decoder after the test code is finished with it. t.Cleanup(func() { if err := d.Err(); err != nil { t.Fatal(err) } }) return d } if got := dec(2).Uint16(); got != 1 { t.Errorf("uint16: got=%d; want=1", got) } if got := dec(4).Uint32(); got != 1 { t.Errorf("uint32: got=%d; want=1", got) } if got := dec(8).Uint64(); got != 1 { t.Errorf("uint64: got=%d; want=1", got) } if got := dec(pointerSize / 8).Uintptr(); got != 1 { t.Errorf("uintptr: got=%d; want=1", got) } }) t.Run("SignedTypes", func(t *testing.T) { dec := func(n int) *Decoder { // Make a buffer of the exact size that consists of 0xff bytes buf := make([]byte, n) for i := range n { buf[i] = 0xff } d := NewDecoder(buf) // Use t.Cleanup to perform an assertion on this // decoder after the test code is finished with it. t.Cleanup(func() { if err := d.Err(); err != nil { t.Fatal(err) } }) return d } if got := dec(2).Int16(); got != -1 { t.Errorf("int16: got=%d; want=-1", got) } if got := dec(4).Int32(); got != -1 { t.Errorf("int32: got=%d; want=-1", got) } if got := dec(8).Int64(); got != -1 { t.Errorf("int64: got=%d; want=-1", got) } }) t.Run("InsufficientData", func(t *testing.T) { dec := func(n int) *Decoder { // Make a buffer that's too small and contains arbitrary bytes buf := make([]byte, n-1) for i := range n - 1 { buf[i] = 0xAD } // Use t.Cleanup to perform an assertion on this // decoder after the test code is finished with it. d := NewDecoder(buf) t.Cleanup(func() { if err := d.Err(); err == nil || !errors.Is(err, io.EOF) { t.Errorf("(n=%d) expected io.EOF; got=%v", n, err) } }) return d } dec(2).Uint16() dec(4).Uint32() dec(8).Uint64() dec(pointerSize / 8).Uintptr() dec(2).Int16() dec(4).Int32() dec(8).Int64() }) t.Run("Bytes", func(t *testing.T) { d := NewDecoder([]byte("hello worldasdf")) t.Cleanup(func() { if err := d.Err(); err != nil { t.Fatal(err) } }) buf := make([]byte, 11) d.Bytes(buf) if got := string(buf); got != "hello world" { t.Errorf("bytes: got=%q; want=%q", got, "hello world") } }) }