cstruct_test.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // Copyright (c) Tailscale Inc & contributors
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package cstruct
  4. import (
  5. "errors"
  6. "fmt"
  7. "io"
  8. "testing"
  9. )
  10. func TestPadBytes(t *testing.T) {
  11. testCases := []struct {
  12. offset int
  13. size int
  14. want int
  15. }{
  16. // No padding at beginning of structure
  17. {0, 1, 0},
  18. {0, 2, 0},
  19. {0, 4, 0},
  20. {0, 8, 0},
  21. // No padding for single bytes
  22. {1, 1, 0},
  23. // Single byte padding
  24. {1, 2, 1},
  25. {3, 4, 1},
  26. // Multi-byte padding
  27. {1, 4, 3},
  28. {2, 8, 6},
  29. }
  30. for _, tc := range testCases {
  31. t.Run(fmt.Sprintf("%d_%d_%d", tc.offset, tc.size, tc.want), func(t *testing.T) {
  32. got := padBytes(tc.offset, tc.size)
  33. if got != tc.want {
  34. t.Errorf("got=%d; want=%d", got, tc.want)
  35. }
  36. })
  37. }
  38. }
  39. func TestDecoder(t *testing.T) {
  40. t.Run("UnsignedTypes", func(t *testing.T) {
  41. dec := func(n int) *Decoder {
  42. buf := make([]byte, n)
  43. buf[0] = 1
  44. d := NewDecoder(buf)
  45. // Use t.Cleanup to perform an assertion on this
  46. // decoder after the test code is finished with it.
  47. t.Cleanup(func() {
  48. if err := d.Err(); err != nil {
  49. t.Fatal(err)
  50. }
  51. })
  52. return d
  53. }
  54. if got := dec(2).Uint16(); got != 1 {
  55. t.Errorf("uint16: got=%d; want=1", got)
  56. }
  57. if got := dec(4).Uint32(); got != 1 {
  58. t.Errorf("uint32: got=%d; want=1", got)
  59. }
  60. if got := dec(8).Uint64(); got != 1 {
  61. t.Errorf("uint64: got=%d; want=1", got)
  62. }
  63. if got := dec(pointerSize / 8).Uintptr(); got != 1 {
  64. t.Errorf("uintptr: got=%d; want=1", got)
  65. }
  66. })
  67. t.Run("SignedTypes", func(t *testing.T) {
  68. dec := func(n int) *Decoder {
  69. // Make a buffer of the exact size that consists of 0xff bytes
  70. buf := make([]byte, n)
  71. for i := range n {
  72. buf[i] = 0xff
  73. }
  74. d := NewDecoder(buf)
  75. // Use t.Cleanup to perform an assertion on this
  76. // decoder after the test code is finished with it.
  77. t.Cleanup(func() {
  78. if err := d.Err(); err != nil {
  79. t.Fatal(err)
  80. }
  81. })
  82. return d
  83. }
  84. if got := dec(2).Int16(); got != -1 {
  85. t.Errorf("int16: got=%d; want=-1", got)
  86. }
  87. if got := dec(4).Int32(); got != -1 {
  88. t.Errorf("int32: got=%d; want=-1", got)
  89. }
  90. if got := dec(8).Int64(); got != -1 {
  91. t.Errorf("int64: got=%d; want=-1", got)
  92. }
  93. })
  94. t.Run("InsufficientData", func(t *testing.T) {
  95. dec := func(n int) *Decoder {
  96. // Make a buffer that's too small and contains arbitrary bytes
  97. buf := make([]byte, n-1)
  98. for i := range n - 1 {
  99. buf[i] = 0xAD
  100. }
  101. // Use t.Cleanup to perform an assertion on this
  102. // decoder after the test code is finished with it.
  103. d := NewDecoder(buf)
  104. t.Cleanup(func() {
  105. if err := d.Err(); err == nil || !errors.Is(err, io.EOF) {
  106. t.Errorf("(n=%d) expected io.EOF; got=%v", n, err)
  107. }
  108. })
  109. return d
  110. }
  111. dec(2).Uint16()
  112. dec(4).Uint32()
  113. dec(8).Uint64()
  114. dec(pointerSize / 8).Uintptr()
  115. dec(2).Int16()
  116. dec(4).Int32()
  117. dec(8).Int64()
  118. })
  119. t.Run("Bytes", func(t *testing.T) {
  120. d := NewDecoder([]byte("hello worldasdf"))
  121. t.Cleanup(func() {
  122. if err := d.Err(); err != nil {
  123. t.Fatal(err)
  124. }
  125. })
  126. buf := make([]byte, 11)
  127. d.Bytes(buf)
  128. if got := string(buf); got != "hello world" {
  129. t.Errorf("bytes: got=%q; want=%q", got, "hello world")
  130. }
  131. })
  132. }