byteio - endian_test.go
1 package byteio
2
3 import (
4 "bytes"
5 "iter"
6 "math"
7 "testing"
8 )
9
10 type readWrite[T any] struct {
11 read func(StickyEndianReader) T
12 write func(StickyEndianWriter, T)
13 }
14
15 var (
16 testUints = [][]uint64{
17 {0x00, 0x01, 0x0f, 0x10, 0x1f, 0x20, 0x3f, 0x41, 0x7f, 0x80, 0xff},
18 {0x0100, 0x7fff, 0x8000, 0xffff},
19 {0x010000, 0x7fffff, 0x800000, 0xffffff},
20 {0x01000000, 0x7fffffff, 0x80000000, 0xffffffff},
21 {0x0100000000, 0x7fffffffff, 0x8000000000, 0xffffffffff},
22 {0x010000000000, 0x7fffffffffff, 0x800000000000, 0xffffffffffff},
23 {0x01000000000000, 0x7fffffffffffff, 0x80000000000000, 0xffffffffffffff},
24 {0x0100000000000000, 0x7fffffffffffffff, 0x8000000000000000, 0xffffffffffffffff},
25 }
26 testInts = [][]int64{
27 {-0x80, -0x40, -0x01, 0x00, 0x01, 0x7f, 0x10, 0x1f, 0x20, 0x3f, 0x40, 0x7f},
28 {-0x8000, -0x00ff, -0x0081, -0x0080, 0x0100, 0x7fff},
29 {-0x800000, -0x00ffff, -0x008001, -0x008000, 0x010000, 0x7fffff},
30 {-0x80000000, -0x00ffffff, -0x00800001, -0x00800000, 0x01000000, 0x7fffffff},
31 {-0x8000000000, -0x00ffffffff, -0x0080000001, -0x0080000000, 0x0100000000, 0x7fffffffff},
32 {-0x800000000000, -0x00ffffffffff, -0x008000000001, -0x008000000000, 0x010000000000, 0x7fffffffffff},
33 {-0x80000000000000, -0x00ffffffffffff, -0x00800000000001, -0x00800000000000, 0x01000000000000, 0x7fffffffffffff},
34 {-0x8000000000000000, -0x00ffffffffffffff, -0x0080000000000001, -0x0080000000000000, 0x0100000000000000, 0x7fffffffffffffff},
35 }
36 testFloats = [][]float64{
37 {0, 1, float64(math.Float32frombits(0x01)), float64(math.Float32frombits(0xff)), float64(math.Float32frombits(0xffffff)), float64(math.Float32frombits(0x80000000))},
38 {math.Float64frombits(0xffffffffffffff), math.Float64frombits(0x8000000000000000), math.Float64frombits(0x0101010101010101)},
39 }
40 testBytes = []byte{1, 2, 3, 4, 5, 6, 7, 8}
41 )
42
43 type testStickyReadWrite struct {
44 StickyEndianReader
45 StickyEndianWriter
46 }
47
48 func testEndians(buf *bytes.Buffer) iter.Seq2[string, testStickyReadWrite] {
49 return func(yield func(string, testStickyReadWrite) bool) {
50 _ = yield("Little", testStickyReadWrite{
51 &StickyReader{Reader: &LittleEndianReader{Reader: buf}},
52 &StickyWriter{Writer: &LittleEndianWriter{Writer: buf}},
53 }) && yield("Big", testStickyReadWrite{
54 &StickyReader{Reader: &BigEndianReader{Reader: buf}},
55 &StickyWriter{Writer: &BigEndianWriter{Writer: buf}},
56 }) && yield("StickyLittle", testStickyReadWrite{
57 &StickyLittleEndianReader{Reader: buf},
58 &StickyLittleEndianWriter{Writer: buf},
59 }) && yield("StickyBig", testStickyReadWrite{
60 &StickyBigEndianReader{Reader: buf},
61 &StickyBigEndianWriter{Writer: buf},
62 })
63 }
64 }
65
66 func testReadWrite[T comparable](t *testing.T, tname string, numBytes int, rw readWrite[T], tests [][]T, expectedLittle, expectedBig T) {
67 t.Helper()
68
69 var buf bytes.Buffer
70
71 for name, test := range testEndians(&buf) {
72 var expectedReadWrite int64
73
74 for n, tests := range tests {
75 buf.Reset()
76
77 for i, d := range tests {
78 rw.write(test.StickyEndianWriter, d)
79
80 if buf.Len() != numBytes {
81 t.Errorf("%s%s%d (%d.%d): expected to write %d byte, wrote %d", name, tname, 8*numBytes, n+1, i+1, numBytes, buf.Len())
82 } else if got := rw.read(test.StickyEndianReader); got != d {
83 t.Errorf("%s%s%d (%d.%d): wanted %v, got %v", name, tname, 8*numBytes, n+1, i+1, d, got)
84 } else if buf.Len() != 0 {
85 t.Errorf("%s%s%d (%d.%d): expected to have read all bytes, %d remain", name, tname, 8*numBytes, n+1, i+1, buf.Len())
86 }
87 }
88
89 expectedReadWrite += int64(len(tests) * numBytes)
90
91 if written := test.StickyEndianWriter.GetCount(); written != expectedReadWrite {
92 t.Errorf("%s%s%d (%d.1): expected to write %d bytes, read %d", name, tname, 8*numBytes, n+1, expectedReadWrite, written)
93 } else if read := test.StickyEndianReader.GetCount(); read != expectedReadWrite {
94 t.Errorf("%s%s%d (%d.1): expected to read %d bytes, read %d", name, tname, 8*numBytes, n+1, expectedReadWrite, read)
95 }
96 }
97 }
98
99 buf.Write(testBytes[:numBytes])
100
101 if read := rw.read(&StickyLittleEndianReader{Reader: &buf}); read != expectedLittle {
102 t.Errorf("LittleEndian%s%d: expected to read value %v, got %v", tname, 8*numBytes, expectedLittle, read)
103 }
104
105 buf.Write(testBytes[:numBytes])
106
107 if read := rw.read(&StickyBigEndianReader{Reader: &buf}); read != expectedBig {
108 t.Errorf("BigEndian%s%d: expected to read value %v, got %v", tname, 8*numBytes, expectedBig, read)
109 }
110 }
111
112 func Test8(t *testing.T) {
113 testReadWrite(t, "Uint", 1, readWrite[uint64]{
114 read: func(s StickyEndianReader) uint64 {
115 return uint64(s.ReadUint8())
116 },
117 write: func(s StickyEndianWriter, n uint64) {
118 s.WriteUint8(uint8(n))
119 },
120 }, testUints[:1], 0x01, 0x01)
121
122 testReadWrite(t, "Int", 1, readWrite[int64]{
123 read: func(s StickyEndianReader) int64 {
124 return int64(s.ReadInt8())
125 },
126 write: func(s StickyEndianWriter, n int64) {
127 s.WriteInt8(int8(n))
128 },
129 }, testInts[:1], 0x01, 0x01)
130 }
131
132 func Test16(t *testing.T) {
133 testReadWrite(t, "Uint", 2, readWrite[uint64]{
134 read: func(s StickyEndianReader) uint64 {
135 return uint64(s.ReadUint16())
136 },
137 write: func(s StickyEndianWriter, n uint64) {
138 s.WriteUint16(uint16(n))
139 },
140 }, testUints[:2], 0x0201, 0x0102)
141 testReadWrite(t, "Int", 2, readWrite[int64]{
142 read: func(s StickyEndianReader) int64 {
143 return int64(s.ReadInt16())
144 },
145 write: func(s StickyEndianWriter, n int64) {
146 s.WriteInt16(int16(n))
147 },
148 }, testInts[:2], 0x0201, 0x0102)
149 }
150
151 func Test24(t *testing.T) {
152 testReadWrite(t, "Uint", 3, readWrite[uint64]{
153 read: func(s StickyEndianReader) uint64 {
154 return uint64(s.ReadUint24())
155 },
156 write: func(s StickyEndianWriter, n uint64) {
157 s.WriteUint24(uint32(n))
158 },
159 }, testUints[:3], 0x030201, 0x010203)
160 testReadWrite(t, "Ints", 3, readWrite[int64]{
161 read: func(s StickyEndianReader) int64 {
162 return int64(s.ReadInt24())
163 },
164 write: func(s StickyEndianWriter, n int64) {
165 s.WriteInt24(int32(n))
166 },
167 }, testInts[:3], 0x030201, 0x010203)
168 }
169
170 func Test32(t *testing.T) {
171 testReadWrite(t, "Uint", 4, readWrite[uint64]{
172 read: func(s StickyEndianReader) uint64 {
173 return uint64(s.ReadUint32())
174 },
175 write: func(s StickyEndianWriter, n uint64) {
176 s.WriteUint32(uint32(n))
177 },
178 }, testUints[:4], 0x04030201, 0x01020304)
179 testReadWrite(t, "Int", 4, readWrite[int64]{
180 read: func(s StickyEndianReader) int64 {
181 return int64(s.ReadInt32())
182 },
183 write: func(s StickyEndianWriter, n int64) {
184 s.WriteInt32(int32(n))
185 },
186 }, testInts[:4], 0x04030201, 0x01020304)
187 }
188
189 func Test40(t *testing.T) {
190 testReadWrite(t, "Uint", 5, readWrite[uint64]{
191 read: func(s StickyEndianReader) uint64 {
192 return s.ReadUint40()
193 },
194 write: func(s StickyEndianWriter, n uint64) {
195 s.WriteUint40(n)
196 },
197 }, testUints[:5], 0x0504030201, 0x0102030405)
198 testReadWrite(t, "Int", 5, readWrite[int64]{
199 read: func(s StickyEndianReader) int64 {
200 return s.ReadInt40()
201 },
202 write: func(s StickyEndianWriter, n int64) {
203 s.WriteInt40(n)
204 },
205 }, testInts[:5], 0x0504030201, 0x0102030405)
206 }
207
208 func Test48(t *testing.T) {
209 testReadWrite(t, "Uint", 6, readWrite[uint64]{
210 read: func(s StickyEndianReader) uint64 {
211 return s.ReadUint48()
212 },
213 write: func(s StickyEndianWriter, n uint64) {
214 s.WriteUint48(n)
215 },
216 }, testUints[:6], 0x060504030201, 0x010203040506)
217 testReadWrite(t, "Int", 6, readWrite[int64]{
218 read: func(s StickyEndianReader) int64 {
219 return s.ReadInt48()
220 },
221 write: func(s StickyEndianWriter, n int64) {
222 s.WriteInt48(n)
223 },
224 }, testInts[:6], 0x060504030201, 0x010203040506)
225 }
226
227 func Test56(t *testing.T) {
228 testReadWrite(t, "Uint", 7, readWrite[uint64]{
229 read: func(s StickyEndianReader) uint64 {
230 return s.ReadUint56()
231 },
232 write: func(s StickyEndianWriter, n uint64) {
233 s.WriteUint56(n)
234 },
235 }, testUints[:7], 0x07060504030201, 0x01020304050607)
236 testReadWrite(t, "Int", 7, readWrite[int64]{
237 read: func(s StickyEndianReader) int64 {
238 return s.ReadInt56()
239 },
240 write: func(s StickyEndianWriter, n int64) {
241 s.WriteInt56(n)
242 },
243 }, testInts[:7], 0x07060504030201, 0x01020304050607)
244 }
245
246 func Test64(t *testing.T) {
247 testReadWrite(t, "Uint", 8, readWrite[uint64]{
248 read: func(s StickyEndianReader) uint64 {
249 return s.ReadUint64()
250 },
251 write: func(s StickyEndianWriter, n uint64) {
252 s.WriteUint64(n)
253 },
254 }, testUints, 0x0807060504030201, 0x0102030405060708)
255 testReadWrite(t, "Int", 8, readWrite[int64]{
256 read: func(s StickyEndianReader) int64 {
257 return s.ReadInt64()
258 },
259 write: func(s StickyEndianWriter, n int64) {
260 s.WriteInt64(n)
261 },
262 }, testInts, 0x0807060504030201, 0x0102030405060708)
263 }
264
265 func TestFloat32(t *testing.T) {
266 testReadWrite(t, "Float", 4, readWrite[float64]{
267 read: func(s StickyEndianReader) float64 {
268 return float64(s.ReadFloat32())
269 },
270 write: func(s StickyEndianWriter, n float64) {
271 s.WriteFloat32(float32(n))
272 },
273 }, testFloats[:1], float64(math.Float32frombits(0x04030201)), float64(math.Float32frombits(0x01020304)))
274 }
275
276 func TestFloat64(t *testing.T) {
277 testReadWrite(t, "Float", 8, readWrite[float64]{
278 read: func(s StickyEndianReader) float64 {
279 return s.ReadFloat64()
280 },
281 write: func(s StickyEndianWriter, n float64) {
282 s.WriteFloat64(n)
283 },
284 }, testFloats, math.Float64frombits(0x0807060504030201), math.Float64frombits(0x0102030405060708))
285 }
286
287 func TestBool(t *testing.T) {
288 testReadWrite(t, "Bool", 1, readWrite[bool]{
289 read: func(s StickyEndianReader) bool {
290 return s.ReadBool()
291 },
292 write: func(s StickyEndianWriter, n bool) {
293 s.WriteBool(n)
294 },
295 }, [][]bool{{true, false}}, true, true)
296 }
297