github.com/jordan-bonecutter/can-go@v0.0.0-20230901155856-d83995b18e50/data_test.go (about)

     1  package can
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"testing/quick"
     7  
     8  	"gotest.tools/v3/assert"
     9  )
    10  
    11  func TestData_Bit(t *testing.T) {
    12  	for i, tt := range []struct {
    13  		data Data
    14  		bits []struct {
    15  			i   uint8
    16  			bit bool
    17  		}
    18  	}{
    19  		{
    20  			data: Data{0x01, 0x23},
    21  			bits: []struct {
    22  				i   uint8
    23  				bit bool
    24  			}{
    25  				// nibble 1: 0x1
    26  				{bit: true, i: 0},
    27  				{bit: false, i: 1},
    28  				{bit: false, i: 2},
    29  				{bit: false, i: 3},
    30  				// nibble 2: 0x0
    31  				{bit: false, i: 4},
    32  				{bit: false, i: 5},
    33  				{bit: false, i: 6},
    34  				{bit: false, i: 7},
    35  				// nibble 3: 0x3
    36  				{bit: true, i: 8},
    37  				{bit: true, i: 9},
    38  				{bit: false, i: 10},
    39  				{bit: false, i: 11},
    40  				// nibble 4: 0x2
    41  				{bit: false, i: 12},
    42  				{bit: true, i: 13},
    43  				{bit: false, i: 14},
    44  				{bit: false, i: 15},
    45  			},
    46  		},
    47  	} {
    48  		i, tt := i, tt
    49  		t.Run("Get", func(t *testing.T) {
    50  			i, tt := i, tt
    51  			for j, ttBit := range tt.bits {
    52  				j, ttBit := j, ttBit
    53  				t.Run(fmt.Sprintf("tt=%v,bit=%v", i, j), func(t *testing.T) {
    54  					bit := tt.data.Bit(ttBit.i)
    55  					assert.Equal(t, ttBit.bit, bit)
    56  				})
    57  			}
    58  		})
    59  		t.Run("Set", func(t *testing.T) {
    60  			i, tt := i, tt
    61  			t.Run(fmt.Sprintf("data=%v", i), func(t *testing.T) {
    62  				var data Data
    63  				for _, tBit := range tt.bits {
    64  					data.SetBit(tBit.i, tBit.bit)
    65  				}
    66  				assert.DeepEqual(t, tt.data, data)
    67  			})
    68  		})
    69  	}
    70  }
    71  
    72  func TestData_Property_SetGetBit(t *testing.T) {
    73  	f := func(_ Data, _ uint8, bit bool) bool {
    74  		return bit
    75  	}
    76  	g := func(data Data, i uint8, bit bool) bool {
    77  		i %= 64
    78  		data.SetBit(i, bit)
    79  		return data.Bit(i)
    80  	}
    81  	assert.NilError(t, quick.CheckEqual(f, g, nil))
    82  }
    83  
    84  func TestData_LittleEndian(t *testing.T) {
    85  	for i, tt := range []struct {
    86  		data    Data
    87  		signals []struct {
    88  			start    uint8
    89  			length   uint8
    90  			unsigned uint64
    91  			signed   int64
    92  		}
    93  	}{
    94  		{
    95  			data: Data{0x80, 0x01},
    96  			signals: []struct {
    97  				start    uint8
    98  				length   uint8
    99  				unsigned uint64
   100  				signed   int64
   101  			}{
   102  				{start: 7, length: 2, unsigned: 0x3, signed: -1},
   103  			},
   104  		},
   105  		{
   106  			data: Data{0x01, 0x02, 0x03},
   107  			signals: []struct {
   108  				start    uint8
   109  				length   uint8
   110  				unsigned uint64
   111  				signed   int64
   112  			}{
   113  				{start: 0, length: 24, unsigned: 0x030201, signed: 197121},
   114  			},
   115  		},
   116  		{
   117  			data: Data{0x40, 0x23, 0x01, 0x12},
   118  			signals: []struct {
   119  				start    uint8
   120  				length   uint8
   121  				unsigned uint64
   122  				signed   int64
   123  			}{
   124  				{start: 24, length: 8, unsigned: 0x12, signed: 18},
   125  				{start: 8, length: 8, unsigned: 0x23, signed: 35},
   126  				{start: 4, length: 16, unsigned: 0x1234, signed: 4660},
   127  			},
   128  		},
   129  	} {
   130  		i, tt := i, tt
   131  		t.Run(fmt.Sprintf("UnsignedBits:%v", i), func(t *testing.T) {
   132  			for j, signal := range tt.signals {
   133  				j, signal := j, signal
   134  				t.Run(fmt.Sprintf("signal:%v", j), func(t *testing.T) {
   135  					actual := tt.data.UnsignedBitsLittleEndian(signal.start, signal.length)
   136  					assert.Equal(t, signal.unsigned, actual)
   137  				})
   138  			}
   139  		})
   140  		t.Run(fmt.Sprintf("SignedBits:%v", i), func(t *testing.T) {
   141  			for j, signal := range tt.signals {
   142  				j, signal := j, signal
   143  				t.Run(fmt.Sprintf("signal:%v", j), func(t *testing.T) {
   144  					actual := tt.data.SignedBitsLittleEndian(signal.start, signal.length)
   145  					assert.Equal(t, signal.signed, actual)
   146  				})
   147  			}
   148  		})
   149  		t.Run(fmt.Sprintf("SetUnsignedBits:%v", i), func(t *testing.T) {
   150  			var data Data
   151  			for j, signal := range tt.signals {
   152  				j, signal := j, signal
   153  				t.Run(fmt.Sprintf("data:%v", j), func(t *testing.T) {
   154  					data.SetUnsignedBitsLittleEndian(signal.start, signal.length, signal.unsigned)
   155  				})
   156  			}
   157  			assert.DeepEqual(t, tt.data, data)
   158  		})
   159  		t.Run(fmt.Sprintf("SetSignedBits:%v", i), func(t *testing.T) {
   160  			var data Data
   161  			for j, signal := range tt.signals {
   162  				j, signal := j, signal
   163  				t.Run(fmt.Sprintf("data:%v", j), func(t *testing.T) {
   164  					data.SetSignedBitsLittleEndian(signal.start, signal.length, signal.signed)
   165  				})
   166  			}
   167  			assert.DeepEqual(t, tt.data, data)
   168  		})
   169  	}
   170  }
   171  
   172  func TestData_BigEndian(t *testing.T) {
   173  	for i, tt := range []struct {
   174  		data    Data
   175  		signals []struct {
   176  			start    uint8
   177  			length   uint8
   178  			unsigned uint64
   179  			signed   int64
   180  		}
   181  	}{
   182  		{
   183  			data: Data{0x3f, 0xf7, 0x0d, 0xc4, 0x0c, 0x93, 0xff, 0xff},
   184  			signals: []struct {
   185  				start    uint8
   186  				length   uint8
   187  				unsigned uint64
   188  				signed   int64
   189  			}{
   190  				{start: 7, length: 3, unsigned: 0x1, signed: 1},
   191  				{start: 4, length: 1, unsigned: 0x1, signed: -1},
   192  				{start: 55, length: 16, unsigned: 0xffff, signed: -1},
   193  				{start: 39, length: 16, unsigned: 0xc93, signed: 3219},
   194  				{start: 23, length: 16, unsigned: 0xdc4, signed: 3524},
   195  				{start: 3, length: 12, unsigned: 0xff7, signed: -9},
   196  			},
   197  		},
   198  		{
   199  			data: Data{0x3f, 0xe4, 0x0e, 0xb6, 0x0c, 0xba, 0x00, 0x05},
   200  			signals: []struct {
   201  				start    uint8
   202  				length   uint8
   203  				unsigned uint64
   204  				signed   int64
   205  			}{
   206  				{start: 7, length: 3, unsigned: 0x1, signed: 1},
   207  				{start: 4, length: 1, unsigned: 0x1, signed: -1},
   208  				{start: 55, length: 16, unsigned: 0x5, signed: 5},
   209  				{start: 39, length: 16, unsigned: 0xcba, signed: 3258},
   210  				{start: 23, length: 16, unsigned: 0xeb6, signed: 3766},
   211  				{start: 3, length: 12, unsigned: 0xfe4, signed: -28},
   212  			},
   213  		},
   214  		{
   215  			data: Data{0x30, 0x53, 0x23, 0xe5, 0x0e, 0x11, 0xff, 0xff},
   216  			signals: []struct {
   217  				start    uint8
   218  				length   uint8
   219  				unsigned uint64
   220  				signed   int64
   221  			}{
   222  				{start: 7, length: 3, unsigned: 0x1, signed: 1},
   223  				{start: 4, length: 1, unsigned: 0x1, signed: -1},
   224  				{start: 55, length: 16, unsigned: 0xffff, signed: -1},
   225  				{start: 39, length: 16, unsigned: 0xe11, signed: 3601},
   226  				{start: 23, length: 16, unsigned: 0x23e5, signed: 9189},
   227  				{start: 3, length: 12, unsigned: 0x53, signed: 83},
   228  			},
   229  		},
   230  	} {
   231  		i, tt := i, tt
   232  		t.Run(fmt.Sprintf("UnsignedBits:%v", i), func(t *testing.T) {
   233  			for j, signal := range tt.signals {
   234  				j, signal := j, signal
   235  				t.Run(fmt.Sprintf("signal:%v", j), func(t *testing.T) {
   236  					actual := tt.data.UnsignedBitsBigEndian(signal.start, signal.length)
   237  					assert.Equal(t, signal.unsigned, actual)
   238  				})
   239  			}
   240  		})
   241  		t.Run(fmt.Sprintf("SignedBits:%v", i), func(t *testing.T) {
   242  			for j, signal := range tt.signals {
   243  				j, signal := j, signal
   244  				t.Run(fmt.Sprintf("signal:%v", j), func(t *testing.T) {
   245  					actual := tt.data.SignedBitsBigEndian(signal.start, signal.length)
   246  					assert.Equal(t, signal.signed, actual)
   247  				})
   248  			}
   249  		})
   250  		t.Run(fmt.Sprintf("SetUnsignedBits:%v", i), func(t *testing.T) {
   251  			var data Data
   252  			for j, signal := range tt.signals {
   253  				j, signal := j, signal
   254  				t.Run(fmt.Sprintf("data:%v", j), func(t *testing.T) {
   255  					data.SetUnsignedBitsBigEndian(signal.start, signal.length, signal.unsigned)
   256  				})
   257  			}
   258  			assert.DeepEqual(t, tt.data, data)
   259  		})
   260  		t.Run(fmt.Sprintf("SetSignedBits:%v", i), func(t *testing.T) {
   261  			var data Data
   262  			for j, signal := range tt.signals {
   263  				j, signal := j, signal
   264  				t.Run(fmt.Sprintf("data:%v", j), func(t *testing.T) {
   265  					data.SetSignedBitsBigEndian(signal.start, signal.length, signal.signed)
   266  				})
   267  			}
   268  			assert.DeepEqual(t, tt.data, data)
   269  		})
   270  	}
   271  }
   272  
   273  func TestInvertEndian_Property_Idempotent(t *testing.T) {
   274  	for i := uint8(0); i < 64; i++ {
   275  		assert.Equal(t, i, invertEndian(invertEndian(i)))
   276  	}
   277  }
   278  
   279  func TestPackUnpackBigEndian(t *testing.T) {
   280  	f := func(data Data) Data {
   281  		return data
   282  	}
   283  	g := func(data Data) Data {
   284  		data.UnpackBigEndian(data.PackBigEndian())
   285  		return data
   286  	}
   287  	assert.NilError(t, quick.CheckEqual(f, g, nil))
   288  }
   289  
   290  func TestPackUnpackLittleEndian(t *testing.T) {
   291  	f := func(data Data) Data {
   292  		return data
   293  	}
   294  	g := func(data Data) Data {
   295  		data.UnpackLittleEndian(data.PackLittleEndian())
   296  		return data
   297  	}
   298  	assert.NilError(t, quick.CheckEqual(f, g, nil))
   299  }
   300  
   301  func TestData_CheckBitRange(t *testing.T) {
   302  	// example case that big-endian signals and little-endian signals use different indexing
   303  	assert.NilError(t, CheckBitRangeBigEndian(8, 55, 16))
   304  	assert.ErrorContains(t, CheckBitRangeLittleEndian(8, 55, 16), "bit range out of bounds")
   305  }
   306  
   307  func BenchmarkData_UnpackLittleEndian(b *testing.B) {
   308  	var data Data
   309  	for i := 0; i < b.N; i++ {
   310  		data.UnpackLittleEndian(0)
   311  	}
   312  }
   313  
   314  func BenchmarkData_UnpackBigEndian(b *testing.B) {
   315  	var data Data
   316  	for i := 0; i < b.N; i++ {
   317  		data.UnpackBigEndian(0)
   318  	}
   319  }
   320  
   321  func BenchmarkData_PackBigEndian(b *testing.B) {
   322  	var data Data
   323  	for i := 0; i < b.N; i++ {
   324  		_ = data.PackBigEndian()
   325  	}
   326  }
   327  
   328  func BenchmarkData_PackLittleEndian(b *testing.B) {
   329  	var data Data
   330  	for i := 0; i < b.N; i++ {
   331  		_ = data.PackLittleEndian()
   332  	}
   333  }