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