diff --git a/adt7410/adt7410_test.go b/adt7410/adt7410_test.go index e833017..acd4052 100644 --- a/adt7410/adt7410_test.go +++ b/adt7410/adt7410_test.go @@ -18,13 +18,13 @@ func TestWhoAmI(t *testing.T) { c := qt.New(t) bus := tester.NewI2CBus(c) fake := tester.NewI2CDevice(c, Address) - fake.SetupRegisters(defaultRegisters()) + copy(fake.Registers[:], defaultRegisters()) bus.AddDevice(fake) dev := New(bus) c.Assert(dev.Connected(), qt.Equals, true) - fake.SetupRegister(RegID, 0x99) + fake.Registers[RegID] = 0x99 c.Assert(dev.Connected(), qt.Equals, false) } diff --git a/lis2mdl/lis2mdl_test.go b/lis2mdl/lis2mdl_test.go index 16cff4e..f5b6508 100644 --- a/lis2mdl/lis2mdl_test.go +++ b/lis2mdl/lis2mdl_test.go @@ -18,13 +18,13 @@ func TestWhoAmI(t *testing.T) { c := qt.New(t) bus := tester.NewI2CBus(c) fake := tester.NewI2CDevice(c, ADDRESS) - fake.SetupRegisters(defaultRegisters()) + copy(fake.Registers[:], defaultRegisters()) bus.AddDevice(fake) dev := New(bus) c.Assert(dev.Connected(), qt.Equals, true) - fake.SetupRegister(WHO_AM_I, 0x99) + fake.Registers[WHO_AM_I] = 0x99 c.Assert(dev.Connected(), qt.Equals, false) } diff --git a/mcp23017/device_test.go b/mcp23017/device_test.go index 9134e26..4a4cbe5 100644 --- a/mcp23017/device_test.go +++ b/mcp23017/device_test.go @@ -5,12 +5,14 @@ import ( "testing" qt "github.com/frankban/quicktest" + + "tinygo.org/x/drivers/tester" ) func TestGetPins(t *testing.T) { c := qt.New(t) - bus := newBus(c) - fdev := bus.addDevice(0x20) + bus := tester.NewI2CBus(c) + fdev := newDevice(bus, 0x20) fdev.Registers[rGPIO] = 0b10101100 fdev.Registers[rGPIO|portB] = 0b01010011 dev, err := NewI2C(bus, 0x20) @@ -22,8 +24,8 @@ func TestGetPins(t *testing.T) { func TestSetPins(t *testing.T) { c := qt.New(t) - bus := newBus(c) - fdev := bus.addDevice(0x20) + bus := tester.NewI2CBus(c) + fdev := newDevice(bus, 0x20) fdev.Registers[rGPIO] = 0b00001111 fdev.Registers[rGPIO|portB] = 0b11110000 dev, err := NewI2C(bus, 0x20) @@ -52,8 +54,8 @@ func TestSetPins(t *testing.T) { func TestTogglePins(t *testing.T) { c := qt.New(t) - bus := newBus(c) - fdev := bus.addDevice(0x20) + bus := tester.NewI2CBus(c) + fdev := newDevice(bus, 0x20) fdev.Registers[rGPIO] = 0b00001111 fdev.Registers[rGPIO|portB] = 0b11110000 dev, err := NewI2C(bus, 0x20) @@ -71,8 +73,8 @@ func TestTogglePins(t *testing.T) { func TestSetGetModes(t *testing.T) { c := qt.New(t) - bus := newBus(c) - fdev := bus.addDevice(0x20) + bus := tester.NewI2CBus(c) + fdev := newDevice(bus, 0x20) dev, err := NewI2C(bus, 0x20) c.Assert(err, qt.IsNil) // Calling SetModes with less items in than there are @@ -102,8 +104,8 @@ func TestSetGetModes(t *testing.T) { func TestPinSetGet(t *testing.T) { c := qt.New(t) - bus := newBus(c) - fdev := bus.addDevice(0x20) + bus := tester.NewI2CBus(c) + fdev := newDevice(bus, 0x20) dev, err := NewI2C(bus, 0x20) c.Assert(err, qt.IsNil) pin := dev.Pin(1) @@ -129,8 +131,8 @@ func TestPinSetGet(t *testing.T) { func TestPinToggle(t *testing.T) { c := qt.New(t) - bus := newBus(c) - fdev := bus.addDevice(0x20) + bus := tester.NewI2CBus(c) + fdev := newDevice(bus, 0x20) dev, err := NewI2C(bus, 0x20) c.Assert(err, qt.IsNil) pin := dev.Pin(1) @@ -147,8 +149,8 @@ func TestPinToggle(t *testing.T) { func TestPinMode(t *testing.T) { c := qt.New(t) - bus := newBus(c) - fdev := bus.addDevice(0x20) + bus := tester.NewI2CBus(c) + fdev := newDevice(bus, 0x20) dev, err := NewI2C(bus, 0x20) c.Assert(err, qt.IsNil) pin := dev.Pin(1) @@ -201,10 +203,18 @@ func TestPins(t *testing.T) { func TestInitWithError(t *testing.T) { c := qt.New(t) - bus := newBus(c) - fdev := bus.addDevice(0x20) + bus := tester.NewI2CBus(c) + fdev := newDevice(bus, 0x20) fdev.Err = fmt.Errorf("some error") dev, err := NewI2C(bus, 0x20) c.Assert(err, qt.ErrorMatches, `cannot initialize mcp23017 device at 0x20: some error`) c.Assert(dev, qt.IsNil) } + +func newDevice(bus *tester.I2CBus, addr uint8) *tester.I2CDevice { + fdev := bus.NewDevice(addr) + // IODIRA and IODIRB are all ones by default. + fdev.Registers[rIODIR] = 0xff + fdev.Registers[rIODIR|portB] = 0xff + return fdev +} diff --git a/mcp23017/fakedev_test.go b/mcp23017/fakedev_test.go deleted file mode 100644 index e987eb7..0000000 --- a/mcp23017/fakedev_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package mcp23017 - -import ( - qt "github.com/frankban/quicktest" -) - -// fakeBus implements the I2C interface in memory for testing. -type fakeBus struct { - c *qt.C - devs []*fakeDev -} - -// newBus returns a fakeBus instance that uses c to flag errors -// if they happen. After creating a fakeBus instance, add devices -// to it with addDevice before using the interface. -func newBus(c *qt.C) *fakeBus { - return &fakeBus{ - c: c, - } -} - -// fakeDev represents a device on the bus. -type fakeDev struct { - c *qt.C - addr uint8 - // Registers holds the device registers. It can be inspected - // or changed as desired for testing. - Registers [registerCount]uint8 - // If Err is non-nil, it will be returned as the error from the - // I2C methods. - Err error -} - -// addDevice adds a new device at the given address. -func (bus *fakeBus) addDevice(addr uint8) *fakeDev { - dev := &fakeDev{ - c: bus.c, - addr: addr, - Registers: [registerCount]uint8{ - // IODIRA and IODIRB are all ones by default. - rIODIR: 0xff, - rIODIR | portB: 0xff, - }, - } - bus.devs = append(bus.devs, dev) - return dev -} - -// ReadRegister implements I2C.ReadRegister. -func (bus *fakeBus) ReadRegister(addr uint8, r uint8, buf []byte) error { - return bus.findDev(addr).readRegister(r, buf) -} - -// WriteRegister implements I2C.WriteRegister. -func (bus *fakeBus) WriteRegister(addr uint8, r uint8, buf []byte) error { - return bus.findDev(addr).writeRegister(r, buf) -} - -func (d *fakeDev) readRegister(r uint8, buf []byte) error { - if d.Err != nil { - return d.Err - } - d.assertRegisterRange(r, buf) - copy(buf, d.Registers[r:]) - return nil -} - -func (d *fakeDev) writeRegister(r uint8, buf []byte) error { - if d.Err != nil { - return d.Err - } - d.assertRegisterRange(r, buf) - copy(d.Registers[r:], buf) - return nil -} - -// assertRegisterRange asserts that reading or writing the given -// register and subsequent registers is in range of the available registers. -func (d *fakeDev) assertRegisterRange(r uint8, buf []byte) { - if int(r) >= len(d.Registers) { - d.c.Fatalf("register read/write [%#x, %#x] start out of range", r, int(r)+len(buf)) - } - if int(r)+len(buf) > len(d.Registers) { - d.c.Fatalf("register read/write [%#x, %#x] end out of range", r, int(r)+len(buf)) - } -} - -// findDev returns the device with the given address. -func (bus *fakeBus) findDev(addr uint8) *fakeDev { - for _, dev := range bus.devs { - if dev.addr == addr { - return dev - } - } - bus.c.Fatalf("invalid device addr %#x passed to i2c bus", addr) - panic("unreachable") -} diff --git a/mcp23017/multidevice_test.go b/mcp23017/multidevice_test.go index b36a3d2..f011d5a 100644 --- a/mcp23017/multidevice_test.go +++ b/mcp23017/multidevice_test.go @@ -4,13 +4,15 @@ import ( "testing" qt "github.com/frankban/quicktest" + + "tinygo.org/x/drivers/tester" ) func TestDevicesGetPins(t *testing.T) { c := qt.New(t) - bus := newBus(c) - fdev0 := bus.addDevice(0x20) - fdev1 := bus.addDevice(0x21) + bus := tester.NewI2CBus(c) + fdev0 := newDevice(bus, 0x20) + fdev1 := newDevice(bus, 0x21) fdev0.Registers[rGPIO] = 0b10101100 fdev0.Registers[rGPIO|portB] = 0b01010011 fdev1.Registers[rGPIO] = 0b10101101 @@ -31,9 +33,9 @@ func TestDevicesGetPins(t *testing.T) { func TestDevicesSetPinsAllOff(t *testing.T) { c := qt.New(t) - bus := newBus(c) - fdev0 := bus.addDevice(0x20) - fdev1 := bus.addDevice(0x21) + bus := tester.NewI2CBus(c) + fdev0 := newDevice(bus, 0x20) + fdev1 := newDevice(bus, 0x21) fdev0.Registers[rGPIO] = 0b10101100 fdev0.Registers[rGPIO|portB] = 0b01010011 fdev1.Registers[rGPIO] = 0b10101101 @@ -51,9 +53,9 @@ func TestDevicesSetPinsAllOff(t *testing.T) { func TestDevicesSetPinsAllOn(t *testing.T) { c := qt.New(t) - bus := newBus(c) - fdev0 := bus.addDevice(0x20) - fdev1 := bus.addDevice(0x21) + bus := tester.NewI2CBus(c) + fdev0 := newDevice(bus, 0x20) + fdev1 := newDevice(bus, 0x21) fdev0.Registers[rGPIO] = 0b10101100 fdev0.Registers[rGPIO|portB] = 0b01010011 fdev1.Registers[rGPIO] = 0b10101101 @@ -71,9 +73,9 @@ func TestDevicesSetPinsAllOn(t *testing.T) { func TestDevicesSetPinsMask(t *testing.T) { c := qt.New(t) - bus := newBus(c) - fdev0 := bus.addDevice(0x20) - fdev1 := bus.addDevice(0x21) + bus := tester.NewI2CBus(c) + fdev0 := newDevice(bus, 0x20) + fdev1 := newDevice(bus, 0x21) fdev0.Registers[rGPIO] = 0b10101100 fdev0.Registers[rGPIO|portB] = 0b01010011 fdev1.Registers[rGPIO] = 0b10101101 @@ -104,9 +106,9 @@ func TestDevicesSetPinsMask(t *testing.T) { func TestDevicesTogglePins(t *testing.T) { c := qt.New(t) - bus := newBus(c) - bus.addDevice(0x20) - bus.addDevice(0x21) + bus := tester.NewI2CBus(c) + newDevice(bus, 0x20) + newDevice(bus, 0x21) devs, err := NewI2CDevices(bus, 0x20, 0x21) c.Assert(err, qt.IsNil) @@ -124,9 +126,9 @@ func TestDevicesTogglePins(t *testing.T) { func TestDevicesSetGetModes(t *testing.T) { c := qt.New(t) - bus := newBus(c) - fdev0 := bus.addDevice(0x20) - fdev1 := bus.addDevice(0x21) + bus := tester.NewI2CBus(c) + fdev0 := newDevice(bus, 0x20) + fdev1 := newDevice(bus, 0x21) devs, err := NewI2CDevices(bus, 0x20, 0x21) c.Assert(err, qt.IsNil) // Sanity check that IODIR registers start off all ones. @@ -154,9 +156,9 @@ func TestDevicesSetGetModes(t *testing.T) { func TestDevicesPin(t *testing.T) { c := qt.New(t) - bus := newBus(c) - bus.addDevice(0x20) - fdev1 := bus.addDevice(0x21) + bus := tester.NewI2CBus(c) + newDevice(bus, 0x20) + fdev1 := newDevice(bus, 0x21) devs, err := NewI2CDevices(bus, 0x20, 0x21) c.Assert(err, qt.IsNil) pin := devs.Pin(16) diff --git a/tester/device.go b/tester/device.go index c0901a3..2a5a0b0 100644 --- a/tester/device.go +++ b/tester/device.go @@ -10,7 +10,7 @@ type I2CDevice struct { addr uint8 // Registers holds the device registers. It can be inspected // or changed as desired for testing. - registers [MaxRegisters]uint8 + Registers [MaxRegisters]uint8 // If Err is non-nil, it will be returned as the error from the // I2C methods. Err error @@ -29,35 +29,13 @@ func (d *I2CDevice) Addr() uint8 { return d.addr } -// SetupRegisters sets all of the Device registers. -// It is intended to be used when setting up a fake device -// for testing expected vs. actual values. -func (d *I2CDevice) SetupRegisters(regs []uint8) { - if len(regs) > MaxRegisters { - panic("exceeded maximum number of registers for fake device") - } - for k, v := range regs { - d.registers[k] = v - } -} - -// SetupRegister sets one of the Device registers. -// It is intended to be used when setting up a fake device -// for testing expected vs. actual values. -func (d *I2CDevice) SetupRegister(r, v uint8) { - if r > MaxRegisters { - panic("exceeded maximum number of registers for fake device") - } - d.registers[r] = v -} - // ReadRegister implements I2C.ReadRegister. func (d *I2CDevice) ReadRegister(r uint8, buf []byte) error { if d.Err != nil { return d.Err } - d.AssertRegisterRange(r, buf) - copy(buf, d.registers[r:]) + d.assertRegisterRange(r, buf) + copy(buf, d.Registers[r:]) return nil } @@ -66,18 +44,18 @@ func (d *I2CDevice) WriteRegister(r uint8, buf []byte) error { if d.Err != nil { return d.Err } - d.AssertRegisterRange(r, buf) - copy(d.registers[r:], buf) + d.assertRegisterRange(r, buf) + copy(d.Registers[r:], buf) return nil } -// AssertRegisterRange asserts that reading or writing the given +// assertRegisterRange asserts that reading or writing the given // register and subsequent registers is in range of the available registers. -func (d *I2CDevice) AssertRegisterRange(r uint8, buf []byte) { - if int(r) >= len(d.registers) { +func (d *I2CDevice) assertRegisterRange(r uint8, buf []byte) { + if int(r) >= len(d.Registers) { d.c.Fatalf("register read/write [%#x, %#x] start out of range", r, int(r)+len(buf)) } - if int(r)+len(buf) > len(d.registers) { + if int(r)+len(buf) > len(d.Registers) { d.c.Fatalf("register read/write [%#x, %#x] end out of range", r, int(r)+len(buf)) } } diff --git a/tester/i2c.go b/tester/i2c.go index 9a4077c..c80b9f2 100644 --- a/tester/i2c.go +++ b/tester/i2c.go @@ -1,5 +1,7 @@ package tester +import "fmt" + // I2CBus implements the I2C interface in memory for testing. type I2CBus struct { c Failer @@ -16,10 +18,24 @@ func NewI2CBus(c Failer) *I2CBus { } // AddDevice adds a new mock device to the mock I2C bus. +// It panics if a device with the same address is added more than once. func (bus *I2CBus) AddDevice(d *I2CDevice) { + for _, dev := range bus.devices { + if dev.Addr() == d.addr { + panic(fmt.Errorf("device already added at address %#x", d)) + } + } bus.devices = append(bus.devices, d) } +// NewDevice creates a new device with the given address +// and adds it to the mock I2C bus. +func (bus *I2CBus) NewDevice(addr uint8) *I2CDevice { + dev := NewI2CDevice(bus.c, addr) + bus.AddDevice(dev) + return dev +} + // ReadRegister implements I2C.ReadRegister. func (bus *I2CBus) ReadRegister(addr uint8, r uint8, buf []byte) error { return bus.FindDevice(addr).ReadRegister(r, buf)