mirror of
https://github.com/hybridgroup/gobot.git
synced 2025-04-24 13:48:49 +08:00
208 lines
6.2 KiB
Go
208 lines
6.2 KiB
Go
//nolint:forcetypeassert // ok here
|
|
package aio
|
|
|
|
import (
|
|
"errors"
|
|
"reflect"
|
|
"strings"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"gobot.io/x/gobot/v2"
|
|
)
|
|
|
|
type groveDriverTestDriverAndEventer interface {
|
|
gobot.Driver
|
|
gobot.Eventer
|
|
}
|
|
|
|
func TestNewGroveRotaryDriver(t *testing.T) {
|
|
// arrange
|
|
a := newAioTestAdaptor()
|
|
pin := "456"
|
|
// act
|
|
d := NewGroveRotaryDriver(a, pin)
|
|
// assert: driver attributes
|
|
assert.IsType(t, &GroveRotaryDriver{}, d)
|
|
assert.NotNil(t, d.driverCfg)
|
|
assert.True(t, strings.HasPrefix(d.Name(), "GroveRotary"))
|
|
assert.Equal(t, a, d.Connection())
|
|
require.NoError(t, d.afterStart())
|
|
require.NoError(t, d.beforeHalt())
|
|
assert.NotNil(t, d.Commander)
|
|
assert.NotNil(t, d.mutex)
|
|
// assert: sensor attributes
|
|
assert.Equal(t, pin, d.Pin())
|
|
assert.InDelta(t, 0.0, d.lastValue, 0, 0)
|
|
assert.Equal(t, 0, d.lastRawValue)
|
|
assert.Nil(t, d.halt) // will be created on initialize, if cyclic reading is on
|
|
assert.NotNil(t, d.Eventer)
|
|
require.NotNil(t, d.sensorCfg)
|
|
assert.Equal(t, time.Duration(0), d.sensorCfg.readInterval)
|
|
assert.NotNil(t, d.sensorCfg.scale)
|
|
}
|
|
|
|
func TestNewGroveLightSensorDriver(t *testing.T) {
|
|
// arrange
|
|
a := newAioTestAdaptor()
|
|
pin := "456"
|
|
// act
|
|
d := NewGroveLightSensorDriver(a, pin)
|
|
// assert: driver attributes
|
|
assert.IsType(t, &GroveLightSensorDriver{}, d)
|
|
assert.NotNil(t, d.driverCfg)
|
|
assert.True(t, strings.HasPrefix(d.Name(), "GroveLightSensor"))
|
|
assert.Equal(t, a, d.Connection())
|
|
require.NoError(t, d.afterStart())
|
|
require.NoError(t, d.beforeHalt())
|
|
assert.NotNil(t, d.Commander)
|
|
assert.NotNil(t, d.mutex)
|
|
// assert: sensor attributes
|
|
assert.Equal(t, pin, d.Pin())
|
|
assert.InDelta(t, 0.0, d.lastValue, 0, 0)
|
|
assert.Equal(t, 0, d.lastRawValue)
|
|
assert.Nil(t, d.halt) // will be created on initialize, if cyclic reading is on
|
|
assert.NotNil(t, d.Eventer)
|
|
require.NotNil(t, d.sensorCfg)
|
|
assert.Equal(t, time.Duration(0), d.sensorCfg.readInterval)
|
|
assert.NotNil(t, d.sensorCfg.scale)
|
|
}
|
|
|
|
func TestNewGrovePiezoVibrationSensorDriver(t *testing.T) {
|
|
// arrange
|
|
a := newAioTestAdaptor()
|
|
pin := "456"
|
|
// act
|
|
d := NewGrovePiezoVibrationSensorDriver(a, pin)
|
|
// assert: driver attributes
|
|
assert.IsType(t, &GrovePiezoVibrationSensorDriver{}, d)
|
|
assert.NotNil(t, d.driverCfg)
|
|
assert.True(t, strings.HasPrefix(d.Name(), "GrovePiezoVibrationSensor"))
|
|
assert.Equal(t, a, d.Connection())
|
|
require.NoError(t, d.afterStart())
|
|
require.NoError(t, d.beforeHalt())
|
|
assert.NotNil(t, d.Commander)
|
|
assert.NotNil(t, d.mutex)
|
|
// assert: sensor attributes
|
|
assert.Equal(t, pin, d.Pin())
|
|
assert.InDelta(t, 0.0, d.lastValue, 0, 0)
|
|
assert.Equal(t, 0, d.lastRawValue)
|
|
assert.Nil(t, d.halt) // will be created on initialize, if cyclic reading is on
|
|
assert.NotNil(t, d.Eventer)
|
|
require.NotNil(t, d.sensorCfg)
|
|
assert.Equal(t, time.Duration(0), d.sensorCfg.readInterval)
|
|
assert.NotNil(t, d.sensorCfg.scale)
|
|
}
|
|
|
|
func TestNewGroveSoundSensorDriver(t *testing.T) {
|
|
// arrange
|
|
a := newAioTestAdaptor()
|
|
pin := "456"
|
|
// act
|
|
d := NewGroveSoundSensorDriver(a, pin)
|
|
// assert: driver attributes
|
|
assert.IsType(t, &GroveSoundSensorDriver{}, d)
|
|
assert.NotNil(t, d.driverCfg)
|
|
assert.True(t, strings.HasPrefix(d.Name(), "GroveSoundSensor"))
|
|
assert.Equal(t, a, d.Connection())
|
|
require.NoError(t, d.afterStart())
|
|
require.NoError(t, d.beforeHalt())
|
|
assert.NotNil(t, d.Commander)
|
|
assert.NotNil(t, d.mutex)
|
|
// assert: sensor attributes
|
|
assert.Equal(t, pin, d.Pin())
|
|
assert.InDelta(t, 0.0, d.lastValue, 0, 0)
|
|
assert.Equal(t, 0, d.lastRawValue)
|
|
assert.Nil(t, d.halt) // will be created on initialize, if cyclic reading is on
|
|
assert.NotNil(t, d.Eventer)
|
|
require.NotNil(t, d.sensorCfg)
|
|
assert.Equal(t, time.Duration(0), d.sensorCfg.readInterval)
|
|
assert.NotNil(t, d.sensorCfg.scale)
|
|
}
|
|
|
|
func TestGroveDriverHalt_WithSensorCyclicRead(t *testing.T) {
|
|
// arrange
|
|
testAdaptor := newAioTestAdaptor()
|
|
pin := "456"
|
|
|
|
drivers := []groveDriverTestDriverAndEventer{
|
|
NewGroveSoundSensorDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)),
|
|
NewGroveLightSensorDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)),
|
|
NewGrovePiezoVibrationSensorDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)),
|
|
NewGroveRotaryDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)),
|
|
}
|
|
|
|
for _, driver := range drivers {
|
|
var callCount int32
|
|
testAdaptor.analogReadFunc = func() (int, error) {
|
|
atomic.AddInt32(&callCount, 1)
|
|
return 42, nil
|
|
}
|
|
|
|
// Start the driver and allow for multiple digital reads
|
|
_ = driver.Start()
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
_ = driver.Halt()
|
|
lastCallCount := atomic.LoadInt32(&callCount)
|
|
// If driver was not halted, digital reads would still continue
|
|
time.Sleep(20 * time.Millisecond)
|
|
// note: if a reading is already in progress, it will be finished before halt have an impact
|
|
if atomic.LoadInt32(&callCount) > lastCallCount+1 {
|
|
require.Fail(t, "AnalogRead was called more than once after driver was halted")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGroveDriverWithSensorCyclicReadPublishesError(t *testing.T) {
|
|
// arrange
|
|
testAdaptor := newAioTestAdaptor()
|
|
pin := "456"
|
|
|
|
drivers := []groveDriverTestDriverAndEventer{
|
|
NewGroveSoundSensorDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)),
|
|
NewGroveLightSensorDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)),
|
|
NewGrovePiezoVibrationSensorDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)),
|
|
NewGroveRotaryDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)),
|
|
}
|
|
|
|
for _, driver := range drivers {
|
|
sem := make(chan struct{}, 1)
|
|
// send error
|
|
testAdaptor.analogReadFunc = func() (int, error) {
|
|
return 0, errors.New("read error")
|
|
}
|
|
|
|
require.NoError(t, driver.Start())
|
|
|
|
// expect error
|
|
_ = driver.Once(driver.Event(Error), func(data interface{}) {
|
|
assert.Equal(t, "read error", data.(error).Error())
|
|
close(sem)
|
|
})
|
|
|
|
select {
|
|
case <-sem:
|
|
case <-time.After(time.Second):
|
|
require.Fail(t, "%s Event \"Error\" was not published", groveGetType(driver))
|
|
}
|
|
|
|
// Cleanup
|
|
_ = driver.Halt()
|
|
}
|
|
}
|
|
|
|
func groveGetType(driver interface{}) string {
|
|
d := reflect.TypeOf(driver)
|
|
|
|
if d.Kind() == reflect.Ptr {
|
|
return d.Elem().Name()
|
|
}
|
|
|
|
return d.Name()
|
|
}
|