You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

231 lines
4.4 KiB

  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package bitfield
  5. import (
  6. "bytes"
  7. "fmt"
  8. "io/ioutil"
  9. "testing"
  10. )
  11. type myUint8 uint8
  12. type test1 struct { // 28 bits
  13. foo uint16 `bitfield:",fob"`
  14. Bar int8 `bitfield:"5,baz"`
  15. Foo uint64
  16. bar myUint8 `bitfield:"3"`
  17. Bool bool `bitfield:""`
  18. Baz int8 `bitfield:"3"`
  19. }
  20. type test2 struct {
  21. larger1 uint16 `bitfield:"32"`
  22. larger2 uint16 `bitfield:"32"`
  23. }
  24. type tooManyBits struct {
  25. u1 uint16 `bitfield:"12"`
  26. u2 uint16 `bitfield:"12"`
  27. u3 uint16 `bitfield:"12"`
  28. u4 uint16 `bitfield:"12"`
  29. u5 uint16 `bitfield:"12"`
  30. u6 uint16 `bitfield:"12"`
  31. }
  32. type just64 struct {
  33. foo uint64 `bitfield:""`
  34. }
  35. type toUint8 struct {
  36. foo bool `bitfield:""`
  37. }
  38. type toUint16 struct {
  39. foo int `bitfield:"9"`
  40. }
  41. type faultySize struct {
  42. foo uint64 `bitfield:"a"`
  43. }
  44. type faultyType struct {
  45. foo *int `bitfield:"5"`
  46. }
  47. var (
  48. maxed = test1{
  49. foo: 0xffff,
  50. Bar: 0x1f,
  51. Foo: 0xffff,
  52. bar: 0x7,
  53. Bool: true,
  54. Baz: 0x7,
  55. }
  56. alternate1 = test1{
  57. foo: 0xffff,
  58. bar: 0x7,
  59. Baz: 0x7,
  60. }
  61. alternate2 = test1{
  62. Bar: 0x1f,
  63. Bool: true,
  64. }
  65. overflow = test1{
  66. Bar: 0x3f,
  67. }
  68. negative = test1{
  69. Bar: -1,
  70. }
  71. )
  72. func TestPack(t *testing.T) {
  73. testCases := []struct {
  74. desc string
  75. x interface{}
  76. nBits uint
  77. out uint64
  78. ok bool
  79. }{
  80. {"maxed out fields", maxed, 0, 0xfffffff0, true},
  81. {"maxed using less bits", maxed, 28, 0x0fffffff, true},
  82. {"alternate1", alternate1, 0, 0xffff0770, true},
  83. {"alternate2", alternate2, 0, 0x0000f880, true},
  84. {"just64", &just64{0x0f0f0f0f}, 00, 0xf0f0f0f, true},
  85. {"just64", &just64{0x0f0f0f0f}, 64, 0xf0f0f0f, true},
  86. {"just64", &just64{0xffffFFFF}, 64, 0xffffffff, true},
  87. {"to uint8", &toUint8{true}, 0, 0x80, true},
  88. {"to uint16", &toUint16{1}, 0, 0x0080, true},
  89. // errors
  90. {"overflow", overflow, 0, 0, false},
  91. {"too many bits", &tooManyBits{}, 0, 0, false},
  92. {"fault size", &faultySize{}, 0, 0, false},
  93. {"fault type", &faultyType{}, 0, 0, false},
  94. {"negative", negative, 0, 0, false},
  95. {"not enough bits", maxed, 27, 0, false},
  96. }
  97. for _, tc := range testCases {
  98. t.Run(fmt.Sprintf("%T/%s", tc.x, tc.desc), func(t *testing.T) {
  99. v, err := Pack(tc.x, &Config{NumBits: tc.nBits})
  100. if ok := err == nil; v != tc.out || ok != tc.ok {
  101. t.Errorf("got %#x, %v; want %#x, %v (%v)", v, ok, tc.out, tc.ok, err)
  102. }
  103. })
  104. }
  105. }
  106. func TestRoundtrip(t *testing.T) {
  107. testCases := []struct {
  108. x test1
  109. }{
  110. {maxed},
  111. {alternate1},
  112. {alternate2},
  113. }
  114. for _, tc := range testCases {
  115. t.Run("", func(t *testing.T) {
  116. v, err := Pack(tc.x, nil)
  117. if err != nil {
  118. t.Fatal(err)
  119. }
  120. want := tc.x
  121. want.Foo = 0 // not stored
  122. x := myInt(v)
  123. got := test1{
  124. foo: x.fob(),
  125. Bar: x.baz(),
  126. bar: x.bar(),
  127. Bool: x.Bool(),
  128. Baz: x.Baz(),
  129. }
  130. if got != want {
  131. t.Errorf("\ngot %#v\nwant %#v (%#x)", got, want, v)
  132. }
  133. })
  134. }
  135. }
  136. func TestGen(t *testing.T) {
  137. testCases := []struct {
  138. desc string
  139. x interface{}
  140. config *Config
  141. ok bool
  142. out string
  143. }{{
  144. desc: "test1",
  145. x: &test1{},
  146. ok: true,
  147. out: test1Gen,
  148. }, {
  149. desc: "test1 with options",
  150. x: &test1{},
  151. config: &Config{Package: "bitfield", TypeName: "myInt"},
  152. ok: true,
  153. out: mustRead("gen1_test.go"),
  154. }, {
  155. desc: "test1 with alternative bits",
  156. x: &test1{},
  157. config: &Config{NumBits: 28, Package: "bitfield", TypeName: "myInt2"},
  158. ok: true,
  159. out: mustRead("gen2_test.go"),
  160. }, {
  161. desc: "failure",
  162. x: &test1{},
  163. config: &Config{NumBits: 27}, // Too few bits.
  164. ok: false,
  165. out: "",
  166. }}
  167. for _, tc := range testCases {
  168. t.Run(tc.desc, func(t *testing.T) {
  169. w := &bytes.Buffer{}
  170. err := Gen(w, tc.x, tc.config)
  171. if ok := err == nil; ok != tc.ok {
  172. t.Fatalf("got %v; want %v (%v)", ok, tc.ok, err)
  173. }
  174. got := w.String()
  175. if got != tc.out {
  176. t.Errorf("got:\n%s\nwant:\n%s", got, tc.out)
  177. }
  178. })
  179. }
  180. }
  181. const test1Gen = `type test1 uint32
  182. func (t test1) fob() uint16 {
  183. return uint16((t >> 16) & 0xffff)
  184. }
  185. func (t test1) baz() int8 {
  186. return int8((t >> 11) & 0x1f)
  187. }
  188. func (t test1) bar() myUint8 {
  189. return myUint8((t >> 8) & 0x7)
  190. }
  191. func (t test1) Bool() bool {
  192. const bit = 1 << 7
  193. return t&bit == bit
  194. }
  195. func (t test1) Baz() int8 {
  196. return int8((t >> 4) & 0x7)
  197. }
  198. `
  199. func mustRead(filename string) string {
  200. b, err := ioutil.ReadFile(filename)
  201. if err != nil {
  202. panic(err)
  203. }
  204. return string(b)
  205. }