gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/ccs811_driver_test.go (about) 1 package i2c 2 3 import ( 4 "errors" 5 "strings" 6 "testing" 7 8 "gobot.io/x/gobot/v2" 9 "gobot.io/x/gobot/v2/gobottest" 10 ) 11 12 // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver 13 // and tests all implementations, so no further tests needed here for gobot.Driver interface 14 var _ gobot.Driver = (*CCS811Driver)(nil) 15 16 func initTestCCS811WithStubbedAdaptor() (*CCS811Driver, *i2cTestAdaptor) { 17 a := newI2cTestAdaptor() 18 return NewCCS811Driver(a), a 19 } 20 21 func TestNewCCS811Driver(t *testing.T) { 22 var di interface{} = NewCCS811Driver(newI2cTestAdaptor()) 23 d, ok := di.(*CCS811Driver) 24 if !ok { 25 t.Errorf("NewCCS811Driver() should have returned a *CCS811Driver") 26 } 27 gobottest.Refute(t, d.Driver, nil) 28 gobottest.Assert(t, strings.HasPrefix(d.Name(), "CCS811"), true) 29 gobottest.Assert(t, d.defaultAddress, 0x5A) 30 gobottest.Refute(t, d.measMode, nil) 31 gobottest.Assert(t, d.ntcResistanceValue, uint32(100000)) 32 } 33 34 func TestCCS811Options(t *testing.T) { 35 // This is a general test, that options are applied in constructor by using the common WithBus() option and 36 // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". 37 d := NewCCS811Driver(newI2cTestAdaptor(), WithBus(2), WithAddress(0xFF), WithCCS811NTCResistance(0xFF)) 38 gobottest.Assert(t, d.GetBusOrDefault(1), 2) 39 gobottest.Assert(t, d.GetAddressOrDefault(0x5a), 0xFF) 40 gobottest.Assert(t, d.ntcResistanceValue, uint32(0xFF)) 41 } 42 43 func TestCCS811WithCCS811MeasMode(t *testing.T) { 44 d := NewCCS811Driver(newI2cTestAdaptor(), WithCCS811MeasMode(CCS811DriveMode10Sec)) 45 gobottest.Assert(t, d.measMode.driveMode, CCS811DriveMode(CCS811DriveMode10Sec)) 46 } 47 48 func TestCCS811GetGasData(t *testing.T) { 49 var tests = map[string]struct { 50 readReturn func([]byte) (int, error) 51 eco2 uint16 52 tvoc uint16 53 err error 54 }{ 55 "ideal values taken from the bus": { 56 readReturn: func(b []byte) (int, error) { 57 copy(b, []byte{1, 156, 0, 86}) 58 return 4, nil 59 }, 60 eco2: 412, 61 tvoc: 86, 62 err: nil, 63 }, 64 "max values possible taken from the bus": { 65 readReturn: func(b []byte) (int, error) { 66 copy(b, []byte{255, 255, 255, 255}) 67 return 4, nil 68 }, 69 eco2: 65535, 70 tvoc: 65535, 71 err: nil, 72 }, 73 "error when the i2c operation fails": { 74 readReturn: func(b []byte) (int, error) { 75 copy(b, []byte{255, 255, 255, 255}) 76 return 4, errors.New("Error") 77 }, 78 eco2: 0, 79 tvoc: 0, 80 err: errors.New("Error"), 81 }, 82 } 83 for name, tc := range tests { 84 t.Run(name, func(t *testing.T) { 85 // arrange 86 d, a := initTestCCS811WithStubbedAdaptor() 87 // Create stub function as it is needed by read submethod in driver code 88 a.i2cWriteImpl = func([]byte) (int, error) { return 0, nil } 89 d.Start() 90 a.i2cReadImpl = tc.readReturn 91 // act 92 eco2, tvoc, err := d.GetGasData() 93 // assert 94 gobottest.Assert(t, eco2, tc.eco2) 95 gobottest.Assert(t, tvoc, tc.tvoc) 96 gobottest.Assert(t, err, tc.err) 97 }) 98 } 99 } 100 101 func TestCCS811GetTemperature(t *testing.T) { 102 var tests = map[string]struct { 103 readReturn func([]byte) (int, error) 104 temp float32 105 err error 106 }{ 107 "ideal values taken from the bus": { 108 readReturn: func(b []byte) (int, error) { 109 copy(b, []byte{10, 197, 0, 248}) 110 return 4, nil 111 }, 112 temp: 27.811005, 113 err: nil, 114 }, 115 "without bus values overflowing": { 116 readReturn: func(b []byte) (int, error) { 117 copy(b, []byte{129, 197, 10, 248}) 118 return 4, nil 119 }, 120 temp: 29.48822, 121 err: nil, 122 }, 123 "negative temperature": { 124 readReturn: func(b []byte) (int, error) { 125 copy(b, []byte{255, 255, 255, 255}) 126 return 4, nil 127 }, 128 temp: -25.334152, 129 err: nil, 130 }, 131 "error if the i2c bus errors": { 132 readReturn: func(b []byte) (int, error) { 133 copy(b, []byte{129, 197, 0, 248}) 134 return 4, errors.New("Error") 135 }, 136 temp: 0, 137 err: errors.New("Error"), 138 }, 139 } 140 for name, tc := range tests { 141 t.Run(name, func(t *testing.T) { 142 // arrange 143 d, a := initTestCCS811WithStubbedAdaptor() 144 // Create stub function as it is needed by read submethod in driver code 145 a.i2cWriteImpl = func([]byte) (int, error) { return 0, nil } 146 d.Start() 147 a.i2cReadImpl = tc.readReturn 148 // act 149 temp, err := d.GetTemperature() 150 // assert 151 gobottest.Assert(t, temp, tc.temp) 152 gobottest.Assert(t, err, tc.err) 153 }) 154 } 155 } 156 157 func TestCCS811HasData(t *testing.T) { 158 var tests = map[string]struct { 159 readReturn func([]byte) (int, error) 160 result bool 161 err error 162 }{ 163 "true for HasError=0 and DataRdy=1": { 164 readReturn: func(b []byte) (int, error) { 165 copy(b, []byte{0x08}) 166 return 1, nil 167 }, 168 result: true, 169 err: nil, 170 }, 171 "false for HasError=1 and DataRdy=1": { 172 readReturn: func(b []byte) (int, error) { 173 copy(b, []byte{0x09}) 174 return 1, nil 175 }, 176 result: false, 177 err: nil, 178 }, 179 "false for HasError=1 and DataRdy=0": { 180 readReturn: func(b []byte) (int, error) { 181 copy(b, []byte{0x01}) 182 return 1, nil 183 }, 184 result: false, 185 err: nil, 186 }, 187 "false for HasError=0 and DataRdy=0": { 188 readReturn: func(b []byte) (int, error) { 189 copy(b, []byte{0x00}) 190 return 1, nil 191 }, 192 result: false, 193 err: nil, 194 }, 195 "error when the i2c read operation fails": { 196 readReturn: func(b []byte) (int, error) { 197 copy(b, []byte{0x00}) 198 return 1, errors.New("Error") 199 }, 200 result: false, 201 err: errors.New("Error"), 202 }, 203 } 204 for name, tc := range tests { 205 t.Run(name, func(t *testing.T) { 206 // arrange 207 d, a := initTestCCS811WithStubbedAdaptor() 208 // Create stub function as it is needed by read submethod in driver code 209 a.i2cWriteImpl = func([]byte) (int, error) { return 0, nil } 210 d.Start() 211 a.i2cReadImpl = tc.readReturn 212 // act 213 result, err := d.HasData() 214 // assert 215 gobottest.Assert(t, result, tc.result) 216 gobottest.Assert(t, err, tc.err) 217 }) 218 } 219 } 220 221 func TestCCS811_initialize(t *testing.T) { 222 // sequence for initialization the device on Start() 223 // * write hardware ID register (0x20) 224 // * read the ID 225 // * prepare software reset register content: a sequence of four bytes must 226 // be written to this register in a single I²C sequence: 0x11, 0xE5, 0x72, 0x8A 227 // * write software reset register content (0xFF) 228 // * write application start register (0xF4) 229 // * prepare measurement mode register content 230 // * INT_THRESH = 0 (normal mode) 231 // * INT_DATARDY = 0 (disable interrupt mode) 232 // * DRIVE_MODE = 0x01 (constant power, value every 1 sec) 233 // * write measure mode register content (0x01) 234 // 235 // arrange 236 d, a := initTestCCS811WithStubbedAdaptor() 237 a.written = []byte{} // reset writes of former test 238 const ( 239 wantChipIDReg = uint8(0x20) 240 wantChipIDRegVal = uint8(0x20) 241 wantResetReg = uint8(0xFF) 242 wantAppStartReg = uint8(0xF4) 243 wantMeasReg = uint8(0x01) 244 wantMeasRegVal = uint8(0x10) 245 ) 246 wantResetRegSequence := []byte{0x11, 0xE5, 0x72, 0x8A} 247 // arrange reads 248 numCallsRead := 0 249 a.i2cReadImpl = func(b []byte) (int, error) { 250 numCallsRead++ 251 // chip ID 252 b[0] = 0x81 253 return len(b), nil 254 } 255 // arrange, act - initialize() must be called on Start() 256 err := d.Start() 257 // assert 258 gobottest.Assert(t, err, nil) 259 gobottest.Assert(t, numCallsRead, 1) 260 gobottest.Assert(t, len(a.written), 9) 261 gobottest.Assert(t, a.written[0], wantChipIDReg) 262 gobottest.Assert(t, a.written[1], wantResetReg) 263 gobottest.Assert(t, a.written[2:6], wantResetRegSequence) 264 gobottest.Assert(t, a.written[6], wantAppStartReg) 265 gobottest.Assert(t, a.written[7], wantMeasReg) 266 gobottest.Assert(t, a.written[8], wantMeasRegVal) 267 }