gobot.io/x/gobot/v2@v2.1.0/system/i2c_device_test.go (about)

     1  package system
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"syscall"
     7  	"testing"
     8  	"unsafe"
     9  
    10  	"gobot.io/x/gobot/v2"
    11  	"gobot.io/x/gobot/v2/gobottest"
    12  )
    13  
    14  const dev = "/dev/i2c-1"
    15  
    16  func getSyscallFuncImpl(errorMask byte) func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
    17  	// bit 0: error on function query
    18  	// bit 1: error on set address
    19  	// bit 2: error on command
    20  	return func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
    21  		// function query
    22  		if (trap == syscall.SYS_IOCTL) && (a2 == I2C_FUNCS) {
    23  			if errorMask&0x01 == 0x01 {
    24  				return 0, 0, 1
    25  			}
    26  
    27  			var funcPtr *uint64 = (*uint64)(unsafe.Pointer(a3))
    28  			*funcPtr = I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA |
    29  				I2C_FUNC_SMBUS_READ_WORD_DATA |
    30  				I2C_FUNC_SMBUS_WRITE_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
    31  				I2C_FUNC_SMBUS_WRITE_WORD_DATA
    32  		}
    33  		// set address
    34  		if (trap == syscall.SYS_IOCTL) && (a2 == I2C_SLAVE) {
    35  			if errorMask&0x02 == 0x02 {
    36  				return 0, 0, 1
    37  			}
    38  		}
    39  		// command
    40  		if (trap == syscall.SYS_IOCTL) && (a2 == I2C_SMBUS) {
    41  			if errorMask&0x04 == 0x04 {
    42  				return 0, 0, 1
    43  			}
    44  		}
    45  		// Let all operations succeed
    46  		return 0, 0, 0
    47  	}
    48  }
    49  
    50  func initTestI2cDeviceWithMockedSys() (*i2cDevice, *mockSyscall) {
    51  	a := NewAccesser()
    52  	msc := a.UseMockSyscall()
    53  	a.UseMockFilesystem([]string{dev})
    54  
    55  	d, err := a.NewI2cDevice(dev)
    56  	if err != nil {
    57  		panic(err)
    58  	}
    59  
    60  	return d, msc
    61  }
    62  
    63  func TestNewI2cDevice(t *testing.T) {
    64  	var tests = map[string]struct {
    65  		dev     string
    66  		wantErr string
    67  	}{
    68  		"ok": {
    69  			dev: dev,
    70  		},
    71  		"empty": {
    72  			dev:     "",
    73  			wantErr: "the given character device location is empty",
    74  		},
    75  	}
    76  	for name, tc := range tests {
    77  		t.Run(name, func(t *testing.T) {
    78  			// arrange
    79  			a := NewAccesser()
    80  			// act
    81  			d, err := a.NewI2cDevice(tc.dev)
    82  			// assert
    83  			if tc.wantErr != "" {
    84  				gobottest.Assert(t, err.Error(), tc.wantErr)
    85  				gobottest.Assert(t, d, (*i2cDevice)(nil))
    86  			} else {
    87  				var _ gobot.I2cSystemDevicer = d
    88  				gobottest.Assert(t, err, nil)
    89  			}
    90  		})
    91  	}
    92  }
    93  
    94  func TestClose(t *testing.T) {
    95  	// arrange
    96  	d, _ := initTestI2cDeviceWithMockedSys()
    97  	// act & assert
    98  	gobottest.Assert(t, d.Close(), nil)
    99  }
   100  
   101  func TestWriteRead(t *testing.T) {
   102  	// arrange
   103  	d, _ := initTestI2cDeviceWithMockedSys()
   104  	wbuf := []byte{0x01, 0x02, 0x03}
   105  	rbuf := make([]byte, 4)
   106  	// act
   107  	wn, werr := d.Write(1, wbuf)
   108  	rn, rerr := d.Read(1, rbuf)
   109  	// assert
   110  	gobottest.Assert(t, werr, nil)
   111  	gobottest.Assert(t, rerr, nil)
   112  	gobottest.Assert(t, wn, len(wbuf))
   113  	gobottest.Assert(t, rn, len(wbuf)) // will read only the written values
   114  	gobottest.Assert(t, wbuf, rbuf[:len(wbuf)])
   115  }
   116  
   117  func TestReadByte(t *testing.T) {
   118  	var tests = map[string]struct {
   119  		funcs       uint64
   120  		syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
   121  		wantErr     string
   122  	}{
   123  		"read_byte_ok": {
   124  			funcs: I2C_FUNC_SMBUS_READ_BYTE,
   125  		},
   126  		"error_syscall": {
   127  			funcs:       I2C_FUNC_SMBUS_READ_BYTE,
   128  			syscallImpl: getSyscallFuncImpl(0x04),
   129  			wantErr:     "SMBus access r/w: 1, command: 0, protocol: 1, address: 2 failed with syscall.Errno operation not permitted",
   130  		},
   131  		"error_not_supported": {
   132  			wantErr: "SMBus read byte not supported",
   133  		},
   134  	}
   135  	for name, tc := range tests {
   136  		t.Run(name, func(t *testing.T) {
   137  			// arrange
   138  			d, msc := initTestI2cDeviceWithMockedSys()
   139  			msc.Impl = tc.syscallImpl
   140  			d.funcs = tc.funcs
   141  			const want = byte(5)
   142  			msc.dataSlice = []byte{want}
   143  			// act
   144  			got, err := d.ReadByte(2)
   145  			// assert
   146  			if tc.wantErr != "" {
   147  				gobottest.Assert(t, err.Error(), tc.wantErr)
   148  			} else {
   149  				gobottest.Assert(t, err, nil)
   150  				gobottest.Assert(t, got, want)
   151  				gobottest.Assert(t, msc.lastFile, d.file)
   152  				gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
   153  				gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_READ))
   154  				gobottest.Assert(t, msc.smbus.command, byte(0)) // register is set to 0 in that case
   155  				gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_BYTE))
   156  			}
   157  		})
   158  	}
   159  }
   160  
   161  func TestReadByteData(t *testing.T) {
   162  	var tests = map[string]struct {
   163  		funcs       uint64
   164  		syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
   165  		wantErr     string
   166  	}{
   167  		"read_byte_data_ok": {
   168  			funcs: I2C_FUNC_SMBUS_READ_BYTE_DATA,
   169  		},
   170  		"error_syscall": {
   171  			funcs:       I2C_FUNC_SMBUS_READ_BYTE_DATA,
   172  			syscallImpl: getSyscallFuncImpl(0x04),
   173  			wantErr:     "SMBus access r/w: 1, command: 1, protocol: 2, address: 3 failed with syscall.Errno operation not permitted",
   174  		},
   175  		"error_not_supported": {
   176  			wantErr: "SMBus read byte data not supported",
   177  		},
   178  	}
   179  	for name, tc := range tests {
   180  		t.Run(name, func(t *testing.T) {
   181  			// arrange
   182  			d, msc := initTestI2cDeviceWithMockedSys()
   183  			msc.Impl = tc.syscallImpl
   184  			d.funcs = tc.funcs
   185  			const (
   186  				reg  = byte(0x01)
   187  				want = byte(0x02)
   188  			)
   189  			msc.dataSlice = []byte{want}
   190  			// act
   191  			got, err := d.ReadByteData(3, reg)
   192  			// assert
   193  			if tc.wantErr != "" {
   194  				gobottest.Assert(t, err.Error(), tc.wantErr)
   195  			} else {
   196  				gobottest.Assert(t, err, nil)
   197  				gobottest.Assert(t, got, want)
   198  				gobottest.Assert(t, msc.lastFile, d.file)
   199  				gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
   200  				gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_READ))
   201  				gobottest.Assert(t, msc.smbus.command, reg)
   202  				gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_BYTE_DATA))
   203  			}
   204  		})
   205  	}
   206  }
   207  
   208  func TestReadWordData(t *testing.T) {
   209  	var tests = map[string]struct {
   210  		funcs       uint64
   211  		syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
   212  		wantErr     string
   213  	}{
   214  		"read_word_data_ok": {
   215  			funcs: I2C_FUNC_SMBUS_READ_WORD_DATA,
   216  		},
   217  		"error_syscall": {
   218  			funcs:       I2C_FUNC_SMBUS_READ_WORD_DATA,
   219  			syscallImpl: getSyscallFuncImpl(0x04),
   220  			wantErr:     "SMBus access r/w: 1, command: 2, protocol: 3, address: 4 failed with syscall.Errno operation not permitted",
   221  		},
   222  		"error_not_supported": {
   223  			wantErr: "SMBus read word data not supported",
   224  		},
   225  	}
   226  	for name, tc := range tests {
   227  		t.Run(name, func(t *testing.T) {
   228  			// arrange
   229  			d, msc := initTestI2cDeviceWithMockedSys()
   230  			msc.Impl = tc.syscallImpl
   231  			d.funcs = tc.funcs
   232  			const (
   233  				reg    = byte(0x02)
   234  				msbyte = byte(0xD4)
   235  				lsbyte = byte(0x31)
   236  				want   = uint16(54321)
   237  			)
   238  			// all common drivers read LSByte first
   239  			msc.dataSlice = []byte{lsbyte, msbyte}
   240  			// act
   241  			got, err := d.ReadWordData(4, reg)
   242  			// assert
   243  			if tc.wantErr != "" {
   244  				gobottest.Assert(t, err.Error(), tc.wantErr)
   245  			} else {
   246  				gobottest.Assert(t, err, nil)
   247  				gobottest.Assert(t, got, want)
   248  				gobottest.Assert(t, msc.lastFile, d.file)
   249  				gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
   250  				gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_READ))
   251  				gobottest.Assert(t, msc.smbus.command, reg)
   252  				gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_WORD_DATA))
   253  			}
   254  		})
   255  	}
   256  }
   257  
   258  func TestReadBlockData(t *testing.T) {
   259  	// arrange
   260  	const (
   261  		reg    = byte(0x03)
   262  		wantB0 = byte(11)
   263  		wantB1 = byte(22)
   264  		wantB2 = byte(33)
   265  		wantB3 = byte(44)
   266  		wantB4 = byte(55)
   267  		wantB5 = byte(66)
   268  		wantB6 = byte(77)
   269  		wantB7 = byte(88)
   270  		wantB8 = byte(99)
   271  		wantB9 = byte(111)
   272  	)
   273  	var tests = map[string]struct {
   274  		funcs       uint64
   275  		syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
   276  		wantErr     string
   277  	}{
   278  		"read_block_data_ok": {
   279  			funcs: I2C_FUNC_SMBUS_READ_I2C_BLOCK,
   280  		},
   281  		"error_syscall": {
   282  			funcs:       I2C_FUNC_SMBUS_READ_I2C_BLOCK,
   283  			syscallImpl: getSyscallFuncImpl(0x04),
   284  			wantErr:     "SMBus access r/w: 1, command: 3, protocol: 8, address: 5 failed with syscall.Errno operation not permitted",
   285  		},
   286  		"error_from_used_fallback_if_not_supported": {
   287  			wantErr: "Read 1 bytes from device by sysfs, expected 10",
   288  		},
   289  	}
   290  	for name, tc := range tests {
   291  		t.Run(name, func(t *testing.T) {
   292  			// arrange
   293  			d, msc := initTestI2cDeviceWithMockedSys()
   294  			msc.Impl = tc.syscallImpl
   295  			d.funcs = tc.funcs
   296  			msc.dataSlice = []byte{wantB0, wantB1, wantB2, wantB3, wantB4, wantB5, wantB6, wantB7, wantB8, wantB9}
   297  			buf := []byte{12, 23, 34, 45, 56, 67, 78, 89, 98, 87}
   298  			// act
   299  			err := d.ReadBlockData(5, reg, buf)
   300  			// assert
   301  			if tc.wantErr != "" {
   302  				gobottest.Assert(t, err.Error(), tc.wantErr)
   303  			} else {
   304  				gobottest.Assert(t, err, nil)
   305  				gobottest.Assert(t, buf, msc.dataSlice)
   306  				gobottest.Assert(t, msc.lastFile, d.file)
   307  				gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
   308  				gobottest.Assert(t, msc.sliceSize, uint8(len(buf)+1))
   309  				gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_READ))
   310  				gobottest.Assert(t, msc.smbus.command, reg)
   311  				gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_I2C_BLOCK_DATA))
   312  			}
   313  		})
   314  	}
   315  }
   316  
   317  func TestWriteByte(t *testing.T) {
   318  	var tests = map[string]struct {
   319  		funcs       uint64
   320  		syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
   321  		wantErr     string
   322  	}{
   323  		"write_byte_ok": {
   324  			funcs: I2C_FUNC_SMBUS_WRITE_BYTE,
   325  		},
   326  		"error_syscall": {
   327  			funcs:       I2C_FUNC_SMBUS_WRITE_BYTE,
   328  			syscallImpl: getSyscallFuncImpl(0x04),
   329  			wantErr:     "SMBus access r/w: 0, command: 68, protocol: 1, address: 6 failed with syscall.Errno operation not permitted",
   330  		},
   331  		"error_not_supported": {
   332  			wantErr: "SMBus write byte not supported",
   333  		},
   334  	}
   335  	for name, tc := range tests {
   336  		t.Run(name, func(t *testing.T) {
   337  			// arrange
   338  			d, msc := initTestI2cDeviceWithMockedSys()
   339  			msc.Impl = tc.syscallImpl
   340  			d.funcs = tc.funcs
   341  			const val = byte(0x44)
   342  			// act
   343  			err := d.WriteByte(6, val)
   344  			// assert
   345  			if tc.wantErr != "" {
   346  				gobottest.Assert(t, err.Error(), tc.wantErr)
   347  			} else {
   348  				gobottest.Assert(t, err, nil)
   349  				gobottest.Assert(t, msc.lastFile, d.file)
   350  				gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
   351  				gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_WRITE))
   352  				gobottest.Assert(t, msc.smbus.command, val) // in byte write, the register/command is used for the value
   353  				gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_BYTE))
   354  			}
   355  		})
   356  	}
   357  }
   358  
   359  func TestWriteByteData(t *testing.T) {
   360  	var tests = map[string]struct {
   361  		funcs       uint64
   362  		syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
   363  		wantErr     string
   364  	}{
   365  		"write_byte_data_ok": {
   366  			funcs: I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
   367  		},
   368  		"error_syscall": {
   369  			funcs:       I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
   370  			syscallImpl: getSyscallFuncImpl(0x04),
   371  			wantErr:     "SMBus access r/w: 0, command: 4, protocol: 2, address: 7 failed with syscall.Errno operation not permitted",
   372  		},
   373  		"error_not_supported": {
   374  			wantErr: "SMBus write byte data not supported",
   375  		},
   376  	}
   377  	for name, tc := range tests {
   378  		t.Run(name, func(t *testing.T) {
   379  			// arrange
   380  			d, msc := initTestI2cDeviceWithMockedSys()
   381  			msc.Impl = tc.syscallImpl
   382  			d.funcs = tc.funcs
   383  			const (
   384  				reg = byte(0x04)
   385  				val = byte(0x55)
   386  			)
   387  			// act
   388  			err := d.WriteByteData(7, reg, val)
   389  			// assert
   390  			if tc.wantErr != "" {
   391  				gobottest.Assert(t, err.Error(), tc.wantErr)
   392  			} else {
   393  				gobottest.Assert(t, err, nil)
   394  				gobottest.Assert(t, msc.lastFile, d.file)
   395  				gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
   396  				gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_WRITE))
   397  				gobottest.Assert(t, msc.smbus.command, reg)
   398  				gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_BYTE_DATA))
   399  				gobottest.Assert(t, len(msc.dataSlice), 1)
   400  				gobottest.Assert(t, msc.dataSlice[0], val)
   401  			}
   402  		})
   403  	}
   404  }
   405  
   406  func TestWriteWordData(t *testing.T) {
   407  	var tests = map[string]struct {
   408  		funcs       uint64
   409  		syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
   410  		wantErr     string
   411  	}{
   412  		"write_word_data_ok": {
   413  			funcs: I2C_FUNC_SMBUS_WRITE_WORD_DATA,
   414  		},
   415  		"error_syscall": {
   416  			funcs:       I2C_FUNC_SMBUS_WRITE_WORD_DATA,
   417  			syscallImpl: getSyscallFuncImpl(0x04),
   418  			wantErr:     "SMBus access r/w: 0, command: 5, protocol: 3, address: 8 failed with syscall.Errno operation not permitted",
   419  		},
   420  		"error_not_supported": {
   421  			wantErr: "SMBus write word data not supported",
   422  		},
   423  	}
   424  	for name, tc := range tests {
   425  		t.Run(name, func(t *testing.T) {
   426  			// arrange
   427  			d, msc := initTestI2cDeviceWithMockedSys()
   428  			msc.Impl = tc.syscallImpl
   429  			d.funcs = tc.funcs
   430  			const (
   431  				reg        = byte(0x05)
   432  				val        = uint16(54321)
   433  				wantLSByte = byte(0x31)
   434  				wantMSByte = byte(0xD4)
   435  			)
   436  			// act
   437  			err := d.WriteWordData(8, reg, val)
   438  			// assert
   439  			if tc.wantErr != "" {
   440  				gobottest.Assert(t, err.Error(), tc.wantErr)
   441  			} else {
   442  				gobottest.Assert(t, err, nil)
   443  				gobottest.Assert(t, msc.lastFile, d.file)
   444  				gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
   445  				gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_WRITE))
   446  				gobottest.Assert(t, msc.smbus.command, reg)
   447  				gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_WORD_DATA))
   448  				gobottest.Assert(t, len(msc.dataSlice), 2)
   449  				// all common drivers write LSByte first
   450  				gobottest.Assert(t, msc.dataSlice[0], wantLSByte)
   451  				gobottest.Assert(t, msc.dataSlice[1], wantMSByte)
   452  			}
   453  		})
   454  	}
   455  }
   456  
   457  func TestWriteBlockData(t *testing.T) {
   458  	// arrange
   459  	const (
   460  		reg = byte(0x06)
   461  		b0  = byte(0x09)
   462  		b1  = byte(0x11)
   463  		b2  = byte(0x22)
   464  		b3  = byte(0x33)
   465  		b4  = byte(0x44)
   466  		b5  = byte(0x55)
   467  		b6  = byte(0x66)
   468  		b7  = byte(0x77)
   469  		b8  = byte(0x88)
   470  		b9  = byte(0x99)
   471  	)
   472  	var tests = map[string]struct {
   473  		funcs       uint64
   474  		syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
   475  		wantErr     string
   476  	}{
   477  		"write_block_data_ok": {
   478  			funcs: I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
   479  		},
   480  		"error_syscall": {
   481  			funcs:       I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
   482  			syscallImpl: getSyscallFuncImpl(0x04),
   483  			wantErr:     "SMBus access r/w: 0, command: 6, protocol: 8, address: 9 failed with syscall.Errno operation not permitted",
   484  		},
   485  	}
   486  	for name, tc := range tests {
   487  		t.Run(name, func(t *testing.T) {
   488  			// arrange
   489  			d, msc := initTestI2cDeviceWithMockedSys()
   490  			msc.Impl = tc.syscallImpl
   491  			d.funcs = tc.funcs
   492  			data := []byte{b0, b1, b2, b3, b4, b5, b6, b7, b8, b9}
   493  			// act
   494  			err := d.WriteBlockData(9, reg, data)
   495  			// assert
   496  			if tc.wantErr != "" {
   497  				gobottest.Assert(t, err.Error(), tc.wantErr)
   498  			} else {
   499  				gobottest.Assert(t, err, nil)
   500  				gobottest.Assert(t, msc.lastFile, d.file)
   501  				gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
   502  				gobottest.Assert(t, msc.sliceSize, uint8(len(data)+1)) // including size element
   503  				gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_WRITE))
   504  				gobottest.Assert(t, msc.smbus.command, reg)
   505  				gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_I2C_BLOCK_DATA))
   506  				gobottest.Assert(t, msc.dataSlice[0], uint8(len(data))) // data size
   507  				gobottest.Assert(t, msc.dataSlice[1:], data)
   508  			}
   509  		})
   510  	}
   511  }
   512  
   513  func TestWriteBlockDataTooMuch(t *testing.T) {
   514  	// arrange
   515  	d, _ := initTestI2cDeviceWithMockedSys()
   516  	// act
   517  	err := d.WriteBlockData(10, 0x01, make([]byte, 33))
   518  	// assert
   519  	gobottest.Assert(t, err, errors.New("Writing blocks larger than 32 bytes (33) not supported"))
   520  }
   521  
   522  func Test_setAddress(t *testing.T) {
   523  	// arrange
   524  	d, msc := initTestI2cDeviceWithMockedSys()
   525  	// act
   526  	err := d.setAddress(0xff)
   527  	// assert
   528  	gobottest.Assert(t, err, nil)
   529  	gobottest.Assert(t, msc.devAddress, uintptr(0xff))
   530  }
   531  
   532  func Test_queryFunctionality(t *testing.T) {
   533  	var tests = map[string]struct {
   534  		requested   uint64
   535  		dev         string
   536  		syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
   537  		wantErr     string
   538  		wantFile    bool
   539  		wantFuncs   uint64
   540  	}{
   541  		"ok": {
   542  			requested:   I2C_FUNC_SMBUS_READ_BYTE,
   543  			dev:         dev,
   544  			syscallImpl: getSyscallFuncImpl(0x00),
   545  			wantFile:    true,
   546  			wantFuncs:   0x7E0000,
   547  		},
   548  		"dev_null_error": {
   549  			dev:         os.DevNull,
   550  			syscallImpl: getSyscallFuncImpl(0x00),
   551  			wantErr:     " : /dev/null: no such file",
   552  		},
   553  		"query_funcs_error": {
   554  			dev:         dev,
   555  			syscallImpl: getSyscallFuncImpl(0x01),
   556  			wantErr:     "Querying functionality failed with syscall.Errno operation not permitted",
   557  			wantFile:    true,
   558  		},
   559  	}
   560  	for name, tc := range tests {
   561  		t.Run(name, func(t *testing.T) {
   562  			// arrange
   563  			d, msc := initTestI2cDeviceWithMockedSys()
   564  			d.location = tc.dev
   565  			msc.Impl = tc.syscallImpl
   566  			// act
   567  			err := d.queryFunctionality(tc.requested, "test"+name)
   568  			// assert
   569  			if tc.wantErr != "" {
   570  				gobottest.Assert(t, err.Error(), tc.wantErr)
   571  			} else {
   572  				gobottest.Assert(t, err, nil)
   573  			}
   574  			if tc.wantFile {
   575  				gobottest.Refute(t, d.file, nil)
   576  			} else {
   577  				gobottest.Assert(t, d.file, (*MockFile)(nil))
   578  			}
   579  			gobottest.Assert(t, d.funcs, tc.wantFuncs)
   580  		})
   581  	}
   582  }