2023-10-27 02:41:41 +08:00
|
|
|
package system
|
|
|
|
|
|
|
|
import (
|
2024-11-01 19:54:20 +08:00
|
|
|
"errors"
|
2023-10-27 02:41:41 +08:00
|
|
|
"sync"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
2023-11-12 21:17:02 +08:00
|
|
|
"github.com/stretchr/testify/require"
|
2023-10-27 02:41:41 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
func Test_startEdgePolling(t *testing.T) {
|
|
|
|
type readValue struct {
|
|
|
|
value int
|
|
|
|
err string
|
|
|
|
}
|
|
|
|
tests := map[string]struct {
|
|
|
|
eventOnEdge int
|
|
|
|
simulateReadValues []readValue
|
|
|
|
simulateNoEventHandler bool
|
|
|
|
simulateNoQuitChan bool
|
|
|
|
wantEdgeTypes []string
|
|
|
|
wantErr string
|
|
|
|
}{
|
|
|
|
"edge_falling": {
|
|
|
|
eventOnEdge: digitalPinEventOnFallingEdge,
|
|
|
|
simulateReadValues: []readValue{
|
|
|
|
{value: 1},
|
|
|
|
{value: 0},
|
|
|
|
{value: 1},
|
|
|
|
{value: 0},
|
|
|
|
{value: 0},
|
|
|
|
},
|
|
|
|
wantEdgeTypes: []string{DigitalPinEventFallingEdge, DigitalPinEventFallingEdge},
|
|
|
|
},
|
|
|
|
"no_edge_falling": {
|
|
|
|
eventOnEdge: digitalPinEventOnFallingEdge,
|
|
|
|
simulateReadValues: []readValue{
|
|
|
|
{value: 0},
|
|
|
|
{value: 1},
|
|
|
|
{value: 1},
|
|
|
|
},
|
|
|
|
wantEdgeTypes: nil,
|
|
|
|
},
|
|
|
|
"edge_rising": {
|
|
|
|
eventOnEdge: digitalPinEventOnRisingEdge,
|
|
|
|
simulateReadValues: []readValue{
|
|
|
|
{value: 0},
|
|
|
|
{value: 1},
|
|
|
|
{value: 0},
|
|
|
|
{value: 1},
|
|
|
|
{value: 1},
|
|
|
|
},
|
|
|
|
wantEdgeTypes: []string{DigitalPinEventRisingEdge, DigitalPinEventRisingEdge},
|
|
|
|
},
|
|
|
|
"no_edge_rising": {
|
|
|
|
eventOnEdge: digitalPinEventOnRisingEdge,
|
|
|
|
simulateReadValues: []readValue{
|
|
|
|
{value: 1},
|
|
|
|
{value: 0},
|
|
|
|
{value: 0},
|
|
|
|
},
|
|
|
|
wantEdgeTypes: nil,
|
|
|
|
},
|
|
|
|
"edge_both": {
|
|
|
|
eventOnEdge: digitalPinEventOnBothEdges,
|
|
|
|
simulateReadValues: []readValue{
|
|
|
|
{value: 0},
|
|
|
|
{value: 1},
|
|
|
|
{value: 0},
|
|
|
|
{value: 1},
|
|
|
|
{value: 1},
|
|
|
|
},
|
|
|
|
wantEdgeTypes: []string{DigitalPinEventRisingEdge, DigitalPinEventFallingEdge, DigitalPinEventRisingEdge},
|
|
|
|
},
|
|
|
|
"no_edges_low": {
|
|
|
|
eventOnEdge: digitalPinEventOnBothEdges,
|
|
|
|
simulateReadValues: []readValue{
|
|
|
|
{value: 0},
|
|
|
|
{value: 0},
|
|
|
|
{value: 0},
|
|
|
|
},
|
|
|
|
wantEdgeTypes: nil,
|
|
|
|
},
|
|
|
|
"no_edges_high": {
|
|
|
|
eventOnEdge: digitalPinEventOnBothEdges,
|
|
|
|
simulateReadValues: []readValue{
|
|
|
|
{value: 1},
|
|
|
|
{value: 1},
|
|
|
|
{value: 1},
|
|
|
|
},
|
|
|
|
wantEdgeTypes: nil,
|
|
|
|
},
|
|
|
|
"read_error_keep_state": {
|
|
|
|
eventOnEdge: digitalPinEventOnBothEdges,
|
|
|
|
simulateReadValues: []readValue{
|
|
|
|
{value: 0},
|
|
|
|
{value: 1, err: "read error suppress rising and falling edge"},
|
|
|
|
{value: 0},
|
|
|
|
{value: 1},
|
|
|
|
{value: 1},
|
|
|
|
},
|
|
|
|
wantEdgeTypes: []string{DigitalPinEventRisingEdge},
|
|
|
|
},
|
|
|
|
"error_no_eventhandler": {
|
|
|
|
simulateNoEventHandler: true,
|
|
|
|
wantErr: "event handler is mandatory",
|
|
|
|
},
|
|
|
|
"error_no_quitchannel": {
|
|
|
|
simulateNoQuitChan: true,
|
|
|
|
wantErr: "quit channel is mandatory",
|
|
|
|
},
|
|
|
|
"error_unsupported_edgetype_none": {
|
|
|
|
eventOnEdge: digitalPinEventNone,
|
|
|
|
wantErr: "unsupported edge type 0",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for name, tc := range tests {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
// arrange
|
|
|
|
pinLabel := "test_pin"
|
|
|
|
pollInterval := time.Microsecond // zero is possible, just to show usage
|
|
|
|
// arrange event handler
|
|
|
|
var edgeTypes []string
|
|
|
|
var eventHandler func(int, time.Duration, string, uint32, uint32)
|
|
|
|
if !tc.simulateNoEventHandler {
|
|
|
|
eventHandler = func(offset int, t time.Duration, et string, sn uint32, lsn uint32) {
|
|
|
|
edgeTypes = append(edgeTypes, et)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// arrange quit channel
|
|
|
|
var quitChan chan struct{}
|
|
|
|
if !tc.simulateNoQuitChan {
|
|
|
|
quitChan = make(chan struct{})
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
if quitChan != nil {
|
|
|
|
close(quitChan)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
// arrange reads
|
|
|
|
numCallsRead := 0
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
if tc.simulateReadValues != nil {
|
|
|
|
wg.Add(1)
|
|
|
|
}
|
|
|
|
readFunc := func() (int, error) {
|
|
|
|
numCallsRead++
|
|
|
|
readVal := tc.simulateReadValues[numCallsRead-1]
|
|
|
|
var err error
|
|
|
|
if readVal.err != "" {
|
2024-11-01 19:54:20 +08:00
|
|
|
err = errors.New(readVal.err)
|
2023-10-27 02:41:41 +08:00
|
|
|
}
|
|
|
|
if numCallsRead >= len(tc.simulateReadValues) {
|
|
|
|
close(quitChan) // ensure no further read call
|
|
|
|
quitChan = nil // lets skip defer routine
|
|
|
|
wg.Done() // release assertions
|
|
|
|
}
|
|
|
|
|
|
|
|
return readVal.value, err
|
|
|
|
}
|
|
|
|
// act
|
|
|
|
err := startEdgePolling(pinLabel, readFunc, pollInterval, tc.eventOnEdge, eventHandler, quitChan)
|
|
|
|
wg.Wait()
|
|
|
|
// assert
|
|
|
|
if tc.wantErr != "" {
|
2023-11-12 21:17:02 +08:00
|
|
|
require.ErrorContains(t, err, tc.wantErr)
|
2023-10-27 02:41:41 +08:00
|
|
|
} else {
|
2023-11-12 21:17:02 +08:00
|
|
|
require.NoError(t, err)
|
2023-10-27 02:41:41 +08:00
|
|
|
}
|
2023-11-12 21:17:02 +08:00
|
|
|
assert.Len(t, tc.simulateReadValues, numCallsRead)
|
2023-10-27 02:41:41 +08:00
|
|
|
assert.Equal(t, tc.wantEdgeTypes, edgeTypes)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|