package can import ( "fmt" "testing" "testing/quick" "gotest.tools/v3/assert" ) func TestData_Bit(t *testing.T) { for i, tt := range []struct { data Data bits []struct { i uint8 bit bool } }{ { data: Data{0x01, 0x23}, bits: []struct { i uint8 bit bool }{ // nibble 1: 0x1 {bit: true, i: 0}, {bit: false, i: 1}, {bit: false, i: 2}, {bit: false, i: 3}, // nibble 2: 0x0 {bit: false, i: 4}, {bit: false, i: 5}, {bit: false, i: 6}, {bit: false, i: 7}, // nibble 3: 0x3 {bit: true, i: 8}, {bit: true, i: 9}, {bit: false, i: 10}, {bit: false, i: 11}, // nibble 4: 0x2 {bit: false, i: 12}, {bit: true, i: 13}, {bit: false, i: 14}, {bit: false, i: 15}, }, }, } { i, tt := i, tt t.Run("Get", func(t *testing.T) { i, tt := i, tt for j, ttBit := range tt.bits { j, ttBit := j, ttBit t.Run(fmt.Sprintf("tt=%v,bit=%v", i, j), func(t *testing.T) { bit := tt.data.Bit(ttBit.i) assert.Equal(t, ttBit.bit, bit) }) } }) t.Run("Set", func(t *testing.T) { i, tt := i, tt t.Run(fmt.Sprintf("data=%v", i), func(t *testing.T) { var data Data for _, tBit := range tt.bits { data.SetBit(tBit.i, tBit.bit) } assert.DeepEqual(t, tt.data, data) }) }) } } func TestData_Property_SetGetBit(t *testing.T) { f := func(_ Data, _ uint8, bit bool) bool { return bit } g := func(data Data, i uint8, bit bool) bool { i %= 64 data.SetBit(i, bit) return data.Bit(i) } assert.NilError(t, quick.CheckEqual(f, g, nil)) } func TestData_LittleEndian(t *testing.T) { for i, tt := range []struct { data Data signals []struct { start uint8 length uint8 unsigned uint64 signed int64 } }{ { data: Data{0x80, 0x01}, signals: []struct { start uint8 length uint8 unsigned uint64 signed int64 }{ {start: 7, length: 2, unsigned: 0x3, signed: -1}, }, }, { data: Data{0x01, 0x02, 0x03}, signals: []struct { start uint8 length uint8 unsigned uint64 signed int64 }{ {start: 0, length: 24, unsigned: 0x030201, signed: 197121}, }, }, { data: Data{0x40, 0x23, 0x01, 0x12}, signals: []struct { start uint8 length uint8 unsigned uint64 signed int64 }{ {start: 24, length: 8, unsigned: 0x12, signed: 18}, {start: 8, length: 8, unsigned: 0x23, signed: 35}, {start: 4, length: 16, unsigned: 0x1234, signed: 4660}, }, }, } { i, tt := i, tt t.Run(fmt.Sprintf("UnsignedBits:%v", i), func(t *testing.T) { for j, signal := range tt.signals { j, signal := j, signal t.Run(fmt.Sprintf("signal:%v", j), func(t *testing.T) { actual := tt.data.UnsignedBitsLittleEndian(signal.start, signal.length) assert.Equal(t, signal.unsigned, actual) }) } }) t.Run(fmt.Sprintf("SignedBits:%v", i), func(t *testing.T) { for j, signal := range tt.signals { j, signal := j, signal t.Run(fmt.Sprintf("signal:%v", j), func(t *testing.T) { actual := tt.data.SignedBitsLittleEndian(signal.start, signal.length) assert.Equal(t, signal.signed, actual) }) } }) t.Run(fmt.Sprintf("SetUnsignedBits:%v", i), func(t *testing.T) { var data Data for j, signal := range tt.signals { j, signal := j, signal t.Run(fmt.Sprintf("data:%v", j), func(t *testing.T) { data.SetUnsignedBitsLittleEndian(signal.start, signal.length, signal.unsigned) }) } assert.DeepEqual(t, tt.data, data) }) t.Run(fmt.Sprintf("SetSignedBits:%v", i), func(t *testing.T) { var data Data for j, signal := range tt.signals { j, signal := j, signal t.Run(fmt.Sprintf("data:%v", j), func(t *testing.T) { data.SetSignedBitsLittleEndian(signal.start, signal.length, signal.signed) }) } assert.DeepEqual(t, tt.data, data) }) } } func TestData_BigEndian(t *testing.T) { for i, tt := range []struct { data Data signals []struct { start uint8 length uint8 unsigned uint64 signed int64 } }{ { data: Data{0x3f, 0xf7, 0x0d, 0xc4, 0x0c, 0x93, 0xff, 0xff}, signals: []struct { start uint8 length uint8 unsigned uint64 signed int64 }{ {start: 7, length: 3, unsigned: 0x1, signed: 1}, {start: 4, length: 1, unsigned: 0x1, signed: -1}, {start: 55, length: 16, unsigned: 0xffff, signed: -1}, {start: 39, length: 16, unsigned: 0xc93, signed: 3219}, {start: 23, length: 16, unsigned: 0xdc4, signed: 3524}, {start: 3, length: 12, unsigned: 0xff7, signed: -9}, }, }, { data: Data{0x3f, 0xe4, 0x0e, 0xb6, 0x0c, 0xba, 0x00, 0x05}, signals: []struct { start uint8 length uint8 unsigned uint64 signed int64 }{ {start: 7, length: 3, unsigned: 0x1, signed: 1}, {start: 4, length: 1, unsigned: 0x1, signed: -1}, {start: 55, length: 16, unsigned: 0x5, signed: 5}, {start: 39, length: 16, unsigned: 0xcba, signed: 3258}, {start: 23, length: 16, unsigned: 0xeb6, signed: 3766}, {start: 3, length: 12, unsigned: 0xfe4, signed: -28}, }, }, { data: Data{0x30, 0x53, 0x23, 0xe5, 0x0e, 0x11, 0xff, 0xff}, signals: []struct { start uint8 length uint8 unsigned uint64 signed int64 }{ {start: 7, length: 3, unsigned: 0x1, signed: 1}, {start: 4, length: 1, unsigned: 0x1, signed: -1}, {start: 55, length: 16, unsigned: 0xffff, signed: -1}, {start: 39, length: 16, unsigned: 0xe11, signed: 3601}, {start: 23, length: 16, unsigned: 0x23e5, signed: 9189}, {start: 3, length: 12, unsigned: 0x53, signed: 83}, }, }, } { i, tt := i, tt t.Run(fmt.Sprintf("UnsignedBits:%v", i), func(t *testing.T) { for j, signal := range tt.signals { j, signal := j, signal t.Run(fmt.Sprintf("signal:%v", j), func(t *testing.T) { actual := tt.data.UnsignedBitsBigEndian(signal.start, signal.length) assert.Equal(t, signal.unsigned, actual) }) } }) t.Run(fmt.Sprintf("SignedBits:%v", i), func(t *testing.T) { for j, signal := range tt.signals { j, signal := j, signal t.Run(fmt.Sprintf("signal:%v", j), func(t *testing.T) { actual := tt.data.SignedBitsBigEndian(signal.start, signal.length) assert.Equal(t, signal.signed, actual) }) } }) t.Run(fmt.Sprintf("SetUnsignedBits:%v", i), func(t *testing.T) { var data Data for j, signal := range tt.signals { j, signal := j, signal t.Run(fmt.Sprintf("data:%v", j), func(t *testing.T) { data.SetUnsignedBitsBigEndian(signal.start, signal.length, signal.unsigned) }) } assert.DeepEqual(t, tt.data, data) }) t.Run(fmt.Sprintf("SetSignedBits:%v", i), func(t *testing.T) { var data Data for j, signal := range tt.signals { j, signal := j, signal t.Run(fmt.Sprintf("data:%v", j), func(t *testing.T) { data.SetSignedBitsBigEndian(signal.start, signal.length, signal.signed) }) } assert.DeepEqual(t, tt.data, data) }) } } func TestInvertEndian_Property_Idempotent(t *testing.T) { for i := uint8(0); i < 64; i++ { assert.Equal(t, i, invertEndian(invertEndian(i))) } } func TestPackUnpackBigEndian(t *testing.T) { f := func(data Data) Data { return data } g := func(data Data) Data { data.UnpackBigEndian(data.PackBigEndian()) return data } assert.NilError(t, quick.CheckEqual(f, g, nil)) } func TestPackUnpackLittleEndian(t *testing.T) { f := func(data Data) Data { return data } g := func(data Data) Data { data.UnpackLittleEndian(data.PackLittleEndian()) return data } assert.NilError(t, quick.CheckEqual(f, g, nil)) } func TestData_CheckBitRange(t *testing.T) { // example case that big-endian signals and little-endian signals use different indexing assert.NilError(t, CheckBitRangeBigEndian(8, 55, 16)) assert.ErrorContains(t, CheckBitRangeLittleEndian(8, 55, 16), "bit range out of bounds") } func BenchmarkData_UnpackLittleEndian(b *testing.B) { var data Data for i := 0; i < b.N; i++ { data.UnpackLittleEndian(0) } } func BenchmarkData_UnpackBigEndian(b *testing.B) { var data Data for i := 0; i < b.N; i++ { data.UnpackBigEndian(0) } } func BenchmarkData_PackBigEndian(b *testing.B) { var data Data for i := 0; i < b.N; i++ { _ = data.PackBigEndian() } } func BenchmarkData_PackLittleEndian(b *testing.B) { var data Data for i := 0; i < b.N; i++ { _ = data.PackLittleEndian() } } func BenchmarkData_UnsignedBitsBigEndian(b *testing.B) { var data Data for i := 0; i < b.N; i++ { _ = data.UnsignedBitsBigEndian(0, 16) } } func BenchmarkData_UnsignedBitsLittleEndian(b *testing.B) { var data Data for i := 0; i < b.N; i++ { _ = data.UnsignedBitsLittleEndian(0, 16) } }