1
0
mirror of https://github.com/hybridgroup/gobot.git synced 2025-04-26 13:48:49 +08:00
hybridgroup.gobot/system/i2c_device_test.go

583 lines
16 KiB
Go
Raw Normal View History

2022-11-20 19:22:26 +01:00
package system
2014-10-30 16:06:04 -07:00
import (
"errors"
2014-10-30 16:06:04 -07:00
"os"
"syscall"
2014-10-30 16:06:04 -07:00
"testing"
2022-11-05 07:42:28 +01:00
"unsafe"
"gobot.io/x/gobot"
"gobot.io/x/gobot/gobottest"
2014-10-30 16:06:04 -07:00
)
2022-10-26 18:21:34 +02:00
const dev = "/dev/i2c-1"
func getSyscallFuncImpl(errorMask byte) func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
// bit 0: error on function query
// bit 1: error on set address
// bit 2: error on command
return func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
// function query
if (trap == syscall.SYS_IOCTL) && (a2 == I2C_FUNCS) {
if errorMask&0x01 == 0x01 {
return 0, 0, 1
}
var funcPtr *uint64 = (*uint64)(unsafe.Pointer(a3))
*funcPtr = I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA |
I2C_FUNC_SMBUS_READ_WORD_DATA |
I2C_FUNC_SMBUS_WRITE_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
I2C_FUNC_SMBUS_WRITE_WORD_DATA
}
// set address
if (trap == syscall.SYS_IOCTL) && (a2 == I2C_SLAVE) {
if errorMask&0x02 == 0x02 {
return 0, 0, 1
}
}
// command
if (trap == syscall.SYS_IOCTL) && (a2 == I2C_SMBUS) {
if errorMask&0x04 == 0x04 {
return 0, 0, 1
}
}
// Let all operations succeed
return 0, 0, 0
2022-11-05 07:42:28 +01:00
}
}
func initTestI2cDeviceWithMockedSys() (*i2cDevice, *mockSyscall) {
a := NewAccesser()
msc := a.UseMockSyscall()
a.UseMockFilesystem([]string{dev})
d, err := a.NewI2cDevice(dev)
2022-10-26 18:21:34 +02:00
if err != nil {
panic(err)
}
2022-11-05 07:42:28 +01:00
return d, msc
}
2014-10-30 16:06:04 -07:00
func TestNewI2cDevice(t *testing.T) {
2022-10-26 18:21:34 +02:00
var tests = map[string]struct {
dev string
wantErr string
}{
"ok": {
dev: dev,
},
2022-11-05 07:42:28 +01:00
"empty": {
dev: "",
wantErr: "the given character device location is empty",
2022-10-26 18:21:34 +02:00
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
// arrange
2022-11-05 07:42:28 +01:00
a := NewAccesser()
2022-10-26 18:21:34 +02:00
// act
2022-11-05 07:42:28 +01:00
d, err := a.NewI2cDevice(tc.dev)
// assert
2022-10-26 18:21:34 +02:00
if tc.wantErr != "" {
gobottest.Assert(t, err.Error(), tc.wantErr)
2022-11-05 07:42:28 +01:00
gobottest.Assert(t, d, (*i2cDevice)(nil))
2022-10-26 18:21:34 +02:00
} else {
var _ gobot.I2cSystemDevicer = d
2022-10-26 18:21:34 +02:00
gobottest.Assert(t, err, nil)
}
})
}
}
2022-10-26 18:21:34 +02:00
func TestClose(t *testing.T) {
// arrange
d, _ := initTestI2cDeviceWithMockedSys()
// act & assert
gobottest.Assert(t, d.Close(), nil)
}
2022-10-26 18:21:34 +02:00
func TestWriteRead(t *testing.T) {
// arrange
d, _ := initTestI2cDeviceWithMockedSys()
wbuf := []byte{0x01, 0x02, 0x03}
rbuf := make([]byte, 4)
// act
wn, werr := d.Write(1, wbuf)
rn, rerr := d.Read(1, rbuf)
2022-10-26 18:21:34 +02:00
// assert
gobottest.Assert(t, werr, nil)
gobottest.Assert(t, rerr, nil)
gobottest.Assert(t, wn, len(wbuf))
gobottest.Assert(t, rn, len(wbuf)) // will read only the written values
gobottest.Assert(t, wbuf, rbuf[:len(wbuf)])
}
2022-10-26 18:21:34 +02:00
func TestReadByte(t *testing.T) {
var tests = map[string]struct {
funcs uint64
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
wantErr string
}{
"read_byte_ok": {
funcs: I2C_FUNC_SMBUS_READ_BYTE,
},
"error_syscall": {
funcs: I2C_FUNC_SMBUS_READ_BYTE,
syscallImpl: getSyscallFuncImpl(0x04),
wantErr: "SMBus access r/w: 1, command: 0, protocol: 1, address: 2 failed with syscall.Errno operation not permitted",
2022-10-26 18:21:34 +02:00
},
"error_not_supported": {
wantErr: "SMBus read byte not supported",
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
// arrange
d, msc := initTestI2cDeviceWithMockedSys()
msc.Impl = tc.syscallImpl
d.funcs = tc.funcs
const want = byte(5)
msc.dataSlice = []byte{want}
// act
got, err := d.ReadByte(2)
2022-10-26 18:21:34 +02:00
// assert
if tc.wantErr != "" {
gobottest.Assert(t, err.Error(), tc.wantErr)
} else {
gobottest.Assert(t, err, nil)
gobottest.Assert(t, got, want)
gobottest.Assert(t, msc.lastFile, d.file)
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_READ))
gobottest.Assert(t, msc.smbus.command, byte(0)) // register is set to 0 in that case
2022-11-05 07:42:28 +01:00
gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_BYTE))
2022-10-26 18:21:34 +02:00
}
})
}
}
2022-10-26 18:21:34 +02:00
func TestReadByteData(t *testing.T) {
var tests = map[string]struct {
funcs uint64
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
wantErr string
}{
"read_byte_data_ok": {
funcs: I2C_FUNC_SMBUS_READ_BYTE_DATA,
},
"error_syscall": {
funcs: I2C_FUNC_SMBUS_READ_BYTE_DATA,
syscallImpl: getSyscallFuncImpl(0x04),
wantErr: "SMBus access r/w: 1, command: 1, protocol: 2, address: 3 failed with syscall.Errno operation not permitted",
2022-10-26 18:21:34 +02:00
},
"error_not_supported": {
wantErr: "SMBus read byte data not supported",
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
// arrange
d, msc := initTestI2cDeviceWithMockedSys()
msc.Impl = tc.syscallImpl
d.funcs = tc.funcs
const (
reg = byte(0x01)
want = byte(0x02)
)
msc.dataSlice = []byte{want}
// act
got, err := d.ReadByteData(3, reg)
2022-10-26 18:21:34 +02:00
// assert
if tc.wantErr != "" {
gobottest.Assert(t, err.Error(), tc.wantErr)
} else {
gobottest.Assert(t, err, nil)
gobottest.Assert(t, got, want)
gobottest.Assert(t, msc.lastFile, d.file)
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_READ))
gobottest.Assert(t, msc.smbus.command, reg)
2022-11-05 07:42:28 +01:00
gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_BYTE_DATA))
2022-10-26 18:21:34 +02:00
}
})
}
}
2022-10-26 18:21:34 +02:00
func TestReadWordData(t *testing.T) {
var tests = map[string]struct {
funcs uint64
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
wantErr string
}{
"read_word_data_ok": {
funcs: I2C_FUNC_SMBUS_READ_WORD_DATA,
},
"error_syscall": {
funcs: I2C_FUNC_SMBUS_READ_WORD_DATA,
syscallImpl: getSyscallFuncImpl(0x04),
wantErr: "SMBus access r/w: 1, command: 2, protocol: 3, address: 4 failed with syscall.Errno operation not permitted",
2022-10-26 18:21:34 +02:00
},
"error_not_supported": {
wantErr: "SMBus read word data not supported",
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
// arrange
d, msc := initTestI2cDeviceWithMockedSys()
msc.Impl = tc.syscallImpl
d.funcs = tc.funcs
const (
reg = byte(0x02)
msbyte = byte(0xD4)
lsbyte = byte(0x31)
want = uint16(54321)
)
// all common drivers read LSByte first
msc.dataSlice = []byte{lsbyte, msbyte}
// act
got, err := d.ReadWordData(4, reg)
2022-10-26 18:21:34 +02:00
// assert
if tc.wantErr != "" {
gobottest.Assert(t, err.Error(), tc.wantErr)
} else {
gobottest.Assert(t, err, nil)
gobottest.Assert(t, got, want)
gobottest.Assert(t, msc.lastFile, d.file)
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_READ))
gobottest.Assert(t, msc.smbus.command, reg)
2022-11-05 07:42:28 +01:00
gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_WORD_DATA))
2022-10-26 18:21:34 +02:00
}
})
}
}
2022-10-26 18:21:34 +02:00
func TestReadBlockData(t *testing.T) {
2022-11-05 07:42:28 +01:00
// arrange
const (
reg = byte(0x03)
wantB0 = byte(11)
wantB1 = byte(22)
wantB2 = byte(33)
wantB3 = byte(44)
wantB4 = byte(55)
wantB5 = byte(66)
wantB6 = byte(77)
wantB7 = byte(88)
wantB8 = byte(99)
wantB9 = byte(111)
)
2022-10-26 18:21:34 +02:00
var tests = map[string]struct {
funcs uint64
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
wantErr string
}{
"read_block_data_ok": {
2022-11-05 07:42:28 +01:00
funcs: I2C_FUNC_SMBUS_READ_I2C_BLOCK,
2022-10-26 18:21:34 +02:00
},
"error_syscall": {
2022-11-05 07:42:28 +01:00
funcs: I2C_FUNC_SMBUS_READ_I2C_BLOCK,
syscallImpl: getSyscallFuncImpl(0x04),
wantErr: "SMBus access r/w: 1, command: 3, protocol: 8, address: 5 failed with syscall.Errno operation not permitted",
2022-10-26 18:21:34 +02:00
},
"error_from_used_fallback_if_not_supported": {
2022-11-05 07:42:28 +01:00
wantErr: "Read 1 bytes from device by sysfs, expected 10",
2022-10-26 18:21:34 +02:00
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
// arrange
d, msc := initTestI2cDeviceWithMockedSys()
msc.Impl = tc.syscallImpl
d.funcs = tc.funcs
2022-11-05 07:42:28 +01:00
msc.dataSlice = []byte{wantB0, wantB1, wantB2, wantB3, wantB4, wantB5, wantB6, wantB7, wantB8, wantB9}
buf := []byte{12, 23, 34, 45, 56, 67, 78, 89, 98, 87}
2022-10-26 18:21:34 +02:00
// act
err := d.ReadBlockData(5, reg, buf)
2022-10-26 18:21:34 +02:00
// assert
if tc.wantErr != "" {
gobottest.Assert(t, err.Error(), tc.wantErr)
} else {
gobottest.Assert(t, err, nil)
gobottest.Assert(t, buf, msc.dataSlice)
gobottest.Assert(t, msc.lastFile, d.file)
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
2022-11-05 07:42:28 +01:00
gobottest.Assert(t, msc.sliceSize, uint8(len(buf)+1))
2022-10-26 18:21:34 +02:00
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_READ))
gobottest.Assert(t, msc.smbus.command, reg)
2022-11-05 07:42:28 +01:00
gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_I2C_BLOCK_DATA))
2022-10-26 18:21:34 +02:00
}
})
}
}
2022-10-26 18:21:34 +02:00
func TestWriteByte(t *testing.T) {
var tests = map[string]struct {
funcs uint64
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
wantErr string
}{
"write_byte_ok": {
funcs: I2C_FUNC_SMBUS_WRITE_BYTE,
},
"error_syscall": {
funcs: I2C_FUNC_SMBUS_WRITE_BYTE,
syscallImpl: getSyscallFuncImpl(0x04),
wantErr: "SMBus access r/w: 0, command: 68, protocol: 1, address: 6 failed with syscall.Errno operation not permitted",
2022-10-26 18:21:34 +02:00
},
"error_not_supported": {
wantErr: "SMBus write byte not supported",
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
// arrange
d, msc := initTestI2cDeviceWithMockedSys()
msc.Impl = tc.syscallImpl
d.funcs = tc.funcs
const val = byte(0x44)
// act
err := d.WriteByte(6, val)
2022-10-26 18:21:34 +02:00
// assert
if tc.wantErr != "" {
gobottest.Assert(t, err.Error(), tc.wantErr)
} else {
gobottest.Assert(t, err, nil)
gobottest.Assert(t, msc.lastFile, d.file)
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_WRITE))
gobottest.Assert(t, msc.smbus.command, val) // in byte write, the register/command is used for the value
2022-11-05 07:42:28 +01:00
gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_BYTE))
2022-10-26 18:21:34 +02:00
}
})
}
}
2022-10-26 18:21:34 +02:00
func TestWriteByteData(t *testing.T) {
var tests = map[string]struct {
funcs uint64
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
wantErr string
}{
"write_byte_data_ok": {
funcs: I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
},
"error_syscall": {
funcs: I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
syscallImpl: getSyscallFuncImpl(0x04),
wantErr: "SMBus access r/w: 0, command: 4, protocol: 2, address: 7 failed with syscall.Errno operation not permitted",
2022-10-26 18:21:34 +02:00
},
"error_not_supported": {
wantErr: "SMBus write byte data not supported",
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
// arrange
d, msc := initTestI2cDeviceWithMockedSys()
msc.Impl = tc.syscallImpl
d.funcs = tc.funcs
const (
reg = byte(0x04)
val = byte(0x55)
)
// act
err := d.WriteByteData(7, reg, val)
2022-10-26 18:21:34 +02:00
// assert
if tc.wantErr != "" {
gobottest.Assert(t, err.Error(), tc.wantErr)
} else {
gobottest.Assert(t, err, nil)
gobottest.Assert(t, msc.lastFile, d.file)
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_WRITE))
gobottest.Assert(t, msc.smbus.command, reg)
2022-11-05 07:42:28 +01:00
gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_BYTE_DATA))
2022-10-26 18:21:34 +02:00
gobottest.Assert(t, len(msc.dataSlice), 1)
gobottest.Assert(t, msc.dataSlice[0], val)
}
})
}
}
2022-10-26 18:21:34 +02:00
func TestWriteWordData(t *testing.T) {
var tests = map[string]struct {
funcs uint64
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
wantErr string
}{
"write_word_data_ok": {
funcs: I2C_FUNC_SMBUS_WRITE_WORD_DATA,
},
"error_syscall": {
funcs: I2C_FUNC_SMBUS_WRITE_WORD_DATA,
syscallImpl: getSyscallFuncImpl(0x04),
wantErr: "SMBus access r/w: 0, command: 5, protocol: 3, address: 8 failed with syscall.Errno operation not permitted",
2022-10-26 18:21:34 +02:00
},
"error_not_supported": {
wantErr: "SMBus write word data not supported",
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
// arrange
d, msc := initTestI2cDeviceWithMockedSys()
msc.Impl = tc.syscallImpl
d.funcs = tc.funcs
const (
reg = byte(0x05)
val = uint16(54321)
wantLSByte = byte(0x31)
wantMSByte = byte(0xD4)
)
// act
err := d.WriteWordData(8, reg, val)
2022-10-26 18:21:34 +02:00
// assert
if tc.wantErr != "" {
gobottest.Assert(t, err.Error(), tc.wantErr)
} else {
gobottest.Assert(t, err, nil)
gobottest.Assert(t, msc.lastFile, d.file)
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_WRITE))
gobottest.Assert(t, msc.smbus.command, reg)
2022-11-05 07:42:28 +01:00
gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_WORD_DATA))
2022-10-26 18:21:34 +02:00
gobottest.Assert(t, len(msc.dataSlice), 2)
// all common drivers write LSByte first
gobottest.Assert(t, msc.dataSlice[0], wantLSByte)
gobottest.Assert(t, msc.dataSlice[1], wantMSByte)
}
})
}
}
2022-10-26 18:21:34 +02:00
func TestWriteBlockData(t *testing.T) {
2022-11-05 07:42:28 +01:00
// arrange
const (
reg = byte(0x06)
b0 = byte(0x09)
b1 = byte(0x11)
b2 = byte(0x22)
b3 = byte(0x33)
b4 = byte(0x44)
b5 = byte(0x55)
b6 = byte(0x66)
b7 = byte(0x77)
b8 = byte(0x88)
b9 = byte(0x99)
)
2022-10-26 18:21:34 +02:00
var tests = map[string]struct {
funcs uint64
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
wantErr string
}{
2022-11-05 07:42:28 +01:00
"write_block_data_ok": {
funcs: I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
2022-10-26 18:21:34 +02:00
},
"error_syscall": {
2022-11-05 07:42:28 +01:00
funcs: I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
syscallImpl: getSyscallFuncImpl(0x04),
wantErr: "SMBus access r/w: 0, command: 6, protocol: 8, address: 9 failed with syscall.Errno operation not permitted",
2022-10-26 18:21:34 +02:00
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
// arrange
d, msc := initTestI2cDeviceWithMockedSys()
msc.Impl = tc.syscallImpl
d.funcs = tc.funcs
2022-11-05 07:42:28 +01:00
data := []byte{b0, b1, b2, b3, b4, b5, b6, b7, b8, b9}
2022-10-26 18:21:34 +02:00
// act
err := d.WriteBlockData(9, reg, data)
2022-10-26 18:21:34 +02:00
// assert
if tc.wantErr != "" {
gobottest.Assert(t, err.Error(), tc.wantErr)
} else {
gobottest.Assert(t, err, nil)
gobottest.Assert(t, msc.lastFile, d.file)
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
2022-11-05 07:42:28 +01:00
gobottest.Assert(t, msc.sliceSize, uint8(len(data)+1)) // including size element
2022-10-26 18:21:34 +02:00
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_WRITE))
gobottest.Assert(t, msc.smbus.command, reg)
2022-11-05 07:42:28 +01:00
gobottest.Assert(t, msc.smbus.protocol, uint32(I2C_SMBUS_I2C_BLOCK_DATA))
gobottest.Assert(t, msc.dataSlice[0], uint8(len(data))) // data size
gobottest.Assert(t, msc.dataSlice[1:], data)
2022-10-26 18:21:34 +02:00
}
})
}
}
2022-10-26 18:21:34 +02:00
func TestWriteBlockDataTooMuch(t *testing.T) {
// arrange
2022-11-05 07:42:28 +01:00
d, _ := initTestI2cDeviceWithMockedSys()
2022-10-26 18:21:34 +02:00
// act
err := d.WriteBlockData(10, 0x01, make([]byte, 33))
2022-10-26 18:21:34 +02:00
// assert
gobottest.Assert(t, err, errors.New("Writing blocks larger than 32 bytes (33) not supported"))
2014-10-30 16:06:04 -07:00
}
2022-11-05 07:42:28 +01:00
func Test_setAddress(t *testing.T) {
// arrange
d, msc := initTestI2cDeviceWithMockedSys()
// act
err := d.setAddress(0xff)
// assert
gobottest.Assert(t, err, nil)
gobottest.Assert(t, msc.devAddress, uintptr(0xff))
}
func Test_queryFunctionality(t *testing.T) {
2022-11-05 07:42:28 +01:00
var tests = map[string]struct {
requested uint64
dev string
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
wantErr string
wantFile bool
wantFuncs uint64
}{
"ok": {
requested: I2C_FUNC_SMBUS_READ_BYTE,
dev: dev,
syscallImpl: getSyscallFuncImpl(0x00),
2022-11-05 07:42:28 +01:00
wantFile: true,
wantFuncs: 0x7E0000,
},
"dev_null_error": {
dev: os.DevNull,
syscallImpl: getSyscallFuncImpl(0x00),
2022-11-05 07:42:28 +01:00
wantErr: " : /dev/null: No such file.",
},
"query_funcs_error": {
dev: dev,
syscallImpl: getSyscallFuncImpl(0x01),
2022-11-05 07:42:28 +01:00
wantErr: "Querying functionality failed with syscall.Errno operation not permitted",
wantFile: true,
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
// arrange
d, msc := initTestI2cDeviceWithMockedSys()
d.location = tc.dev
msc.Impl = tc.syscallImpl
// act
err := d.queryFunctionality(tc.requested, "test"+name)
// assert
if tc.wantErr != "" {
gobottest.Assert(t, err.Error(), tc.wantErr)
} else {
gobottest.Assert(t, err, nil)
}
if tc.wantFile {
gobottest.Refute(t, d.file, nil)
} else {
gobottest.Assert(t, d.file, (*MockFile)(nil))
}
gobottest.Assert(t, d.funcs, tc.wantFuncs)
})
}
}