gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/grovepi_driver_test.go (about) 1 package i2c 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 8 "gobot.io/x/gobot/v2" 9 "gobot.io/x/gobot/v2/drivers/aio" 10 "gobot.io/x/gobot/v2/drivers/gpio" 11 "gobot.io/x/gobot/v2/gobottest" 12 ) 13 14 // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver 15 // and tests all implementations, so no further tests needed here for gobot.Driver interface 16 var _ gobot.Driver = (*GrovePiDriver)(nil) 17 18 // must implement the DigitalReader interface 19 var _ gpio.DigitalReader = (*GrovePiDriver)(nil) 20 21 // must implement the DigitalWriter interface 22 var _ gpio.DigitalWriter = (*GrovePiDriver)(nil) 23 24 // must implement the AnalogReader interface 25 var _ aio.AnalogReader = (*GrovePiDriver)(nil) 26 27 // must implement the AnalogWriter interface 28 var _ aio.AnalogWriter = (*GrovePiDriver)(nil) 29 30 // must implement the Adaptor interface 31 var _ gobot.Adaptor = (*GrovePiDriver)(nil) 32 33 func initGrovePiDriverWithStubbedAdaptor() (*GrovePiDriver, *i2cTestAdaptor) { 34 adaptor := newI2cTestAdaptor() 35 return NewGrovePiDriver(adaptor), adaptor 36 } 37 38 func TestNewGrovePiDriver(t *testing.T) { 39 var di interface{} = NewGrovePiDriver(newI2cTestAdaptor()) 40 d, ok := di.(*GrovePiDriver) 41 if !ok { 42 t.Errorf("NewGrovePiDriver() should have returned a *GrovePiDriver") 43 } 44 gobottest.Refute(t, d.Driver, nil) 45 gobottest.Assert(t, strings.HasPrefix(d.Name(), "GrovePi"), true) 46 gobottest.Assert(t, d.defaultAddress, 0x04) 47 gobottest.Refute(t, d.pins, nil) 48 } 49 50 func TestGrovePiOptions(t *testing.T) { 51 // This is a general test, that options are applied in constructor by using the common WithBus() option and 52 // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". 53 d := NewGrovePiDriver(newI2cTestAdaptor(), WithBus(2)) 54 gobottest.Assert(t, d.GetBusOrDefault(1), 2) 55 } 56 57 func TestGrovePiSomeRead(t *testing.T) { 58 // arrange 59 var tests = map[string]struct { 60 usedPin int 61 wantWritten []uint8 62 simResponse [][]uint8 63 wantErr error 64 wantCallsRead int 65 wantResult int 66 wantResultF1 float32 67 wantResultF2 float32 68 wantResultString string 69 }{ 70 "DigitalRead": { 71 usedPin: 2, 72 wantWritten: []uint8{commandSetPinMode, 2, 0, 0, commandReadDigital, 2, 0, 0}, 73 simResponse: [][]uint8{{0}, {commandReadDigital, 3}}, 74 wantCallsRead: 2, 75 wantResult: 3, 76 }, 77 "AnalogRead": { 78 usedPin: 3, 79 wantWritten: []uint8{commandSetPinMode, 3, 0, 0, commandReadAnalog, 3, 0, 0}, 80 simResponse: [][]uint8{{0}, {commandReadAnalog, 4, 5}}, 81 wantResult: 1029, 82 }, 83 "UltrasonicRead": { 84 usedPin: 4, 85 wantWritten: []uint8{commandSetPinMode, 4, 0, 0, commandReadUltrasonic, 4, 0, 0}, 86 simResponse: [][]uint8{{0}, {commandReadUltrasonic, 5, 6}}, 87 wantResult: 1281, 88 }, 89 "FirmwareVersionRead": { 90 wantWritten: []uint8{commandReadFirmwareVersion, 0, 0, 0}, 91 simResponse: [][]uint8{{commandReadFirmwareVersion, 7, 8, 9}}, 92 wantResultString: "7.8.9", 93 }, 94 "DHTRead": { 95 usedPin: 5, 96 wantWritten: []uint8{commandSetPinMode, 5, 0, 0, commandReadDHT, 5, 1, 0}, 97 simResponse: [][]uint8{{0}, {commandReadDHT, 164, 112, 69, 193, 20, 174, 54, 66}}, 98 wantResultF1: -12.34, 99 wantResultF2: 45.67, 100 }, 101 "DigitalRead_error_wrong_return_cmd": { 102 usedPin: 15, 103 wantWritten: []uint8{commandSetPinMode, 15, 0, 0, commandReadDigital, 15, 0, 0}, 104 simResponse: [][]uint8{{0}, {0, 2}}, 105 wantErr: fmt.Errorf("answer (0) was not for command (1)"), 106 }, 107 "AnalogRead_error_wrong_return_cmd": { 108 usedPin: 16, 109 wantWritten: []uint8{commandSetPinMode, 16, 0, 0, commandReadAnalog, 16, 0, 0}, 110 simResponse: [][]uint8{{0}, {0, 3, 4}}, 111 wantErr: fmt.Errorf("answer (0) was not for command (3)"), 112 }, 113 "UltrasonicRead_error_wrong_return_cmd": { 114 usedPin: 17, 115 wantWritten: []uint8{commandSetPinMode, 17, 0, 0, commandReadUltrasonic, 17, 0, 0}, 116 simResponse: [][]uint8{{0}, {0, 5, 6}}, 117 wantErr: fmt.Errorf("answer (0) was not for command (7)"), 118 }, 119 "FirmwareVersionRead_error_wrong_return_cmd": { 120 wantWritten: []uint8{commandReadFirmwareVersion, 0, 0, 0}, 121 simResponse: [][]uint8{{0, 7, 8, 9}}, 122 wantErr: fmt.Errorf("answer (0) was not for command (8)"), 123 }, 124 "DHTRead_error_wrong_return_cmd": { 125 usedPin: 18, 126 wantWritten: []uint8{commandSetPinMode, 18, 0, 0, commandReadDHT, 18, 1, 0}, 127 simResponse: [][]uint8{{0}, {0, 164, 112, 69, 193, 20, 174, 54, 66}}, 128 wantErr: fmt.Errorf("answer (0) was not for command (40)"), 129 }, 130 "DigitalRead_error_wrong_data_count": { 131 usedPin: 28, 132 wantWritten: []uint8{commandSetPinMode, 28, 0, 0, commandReadDigital, 28, 0, 0}, 133 simResponse: [][]uint8{{0}, {commandReadDigital, 2, 3}}, 134 wantErr: fmt.Errorf("read count mismatch (3 should be 2)"), 135 }, 136 } 137 for name, tc := range tests { 138 t.Run(name, func(t *testing.T) { 139 g, a := initGrovePiDriverWithStubbedAdaptor() 140 g.Start() 141 a.written = []byte{} // reset writes of former test and start 142 numCallsRead := 0 143 a.i2cReadImpl = func(bytes []byte) (i int, e error) { 144 numCallsRead++ 145 copy(bytes, tc.simResponse[numCallsRead-1]) 146 return len(tc.simResponse[numCallsRead-1]), nil 147 } 148 var got int 149 var gotF1, gotF2 float32 150 var gotString string 151 var err error 152 // act 153 switch { 154 case strings.Contains(name, "DigitalRead"): 155 got, err = g.DigitalRead(fmt.Sprintf("%d", tc.usedPin)) 156 case strings.Contains(name, "AnalogRead"): 157 got, err = g.AnalogRead(fmt.Sprintf("%d", tc.usedPin)) 158 case strings.Contains(name, "UltrasonicRead"): 159 got, err = g.UltrasonicRead(fmt.Sprintf("%d", tc.usedPin), 2) 160 case strings.Contains(name, "FirmwareVersionRead"): 161 gotString, err = g.FirmwareVersionRead() 162 case strings.Contains(name, "DHTRead"): 163 gotF1, gotF2, err = g.DHTRead(fmt.Sprintf("%d", tc.usedPin), 1, 2) 164 default: 165 t.Errorf("unknown command %s", name) 166 return 167 } 168 // assert 169 gobottest.Assert(t, err, tc.wantErr) 170 gobottest.Assert(t, a.written, tc.wantWritten) 171 gobottest.Assert(t, numCallsRead, len(tc.simResponse)) 172 gobottest.Assert(t, got, tc.wantResult) 173 gobottest.Assert(t, gotF1, tc.wantResultF1) 174 gobottest.Assert(t, gotF2, tc.wantResultF2) 175 gobottest.Assert(t, gotString, tc.wantResultString) 176 }) 177 } 178 } 179 180 func TestGrovePiSomeWrite(t *testing.T) { 181 // arrange 182 var tests = map[string]struct { 183 usedPin int 184 usedValue int 185 wantWritten []uint8 186 simResponse []uint8 187 }{ 188 "DigitalWrite": { 189 usedPin: 2, 190 usedValue: 3, 191 wantWritten: []uint8{commandSetPinMode, 2, 1, 0, commandWriteDigital, 2, 3, 0}, 192 simResponse: []uint8{4}, 193 }, 194 "AnalogWrite": { 195 usedPin: 5, 196 usedValue: 6, 197 wantWritten: []uint8{commandSetPinMode, 5, 1, 0, commandWriteAnalog, 5, 6, 0}, 198 simResponse: []uint8{7}, 199 }, 200 } 201 for name, tc := range tests { 202 t.Run(name, func(t *testing.T) { 203 g, a := initGrovePiDriverWithStubbedAdaptor() 204 g.Start() 205 a.written = []byte{} // reset writes of former test and start 206 a.i2cReadImpl = func(bytes []byte) (i int, e error) { 207 copy(bytes, tc.simResponse) 208 return len(bytes), nil 209 } 210 var err error 211 // act 212 switch name { 213 case "DigitalWrite": 214 err = g.DigitalWrite(fmt.Sprintf("%d", tc.usedPin), byte(tc.usedValue)) 215 case "AnalogWrite": 216 err = g.AnalogWrite(fmt.Sprintf("%d", tc.usedPin), tc.usedValue) 217 default: 218 t.Errorf("unknown command %s", name) 219 return 220 } 221 // assert 222 gobottest.Assert(t, err, nil) 223 gobottest.Assert(t, a.written, tc.wantWritten) 224 }) 225 } 226 } 227 228 func TestGrovePi_getPin(t *testing.T) { 229 gobottest.Assert(t, getPin("a1"), "1") 230 gobottest.Assert(t, getPin("A16"), "16") 231 gobottest.Assert(t, getPin("D3"), "3") 232 gobottest.Assert(t, getPin("d22"), "22") 233 gobottest.Assert(t, getPin("22"), "22") 234 }