Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 225 additions & 0 deletions drivers/serial_linux_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
//go:build linux

package drivers

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/sys/unix"
)

// TestBaudToUnix tests the baud rate to Unix constant conversion.
func TestBaudToUnix(t *testing.T) {
t.Parallel()

tests := []struct {
name string
baud int
expected uint32
wantErr bool
errMsg string
}{
{
name: "4800 baud",
baud: 4800,
expected: unix.B4800,
wantErr: false,
},
{
name: "9600 baud",
baud: 9600,
expected: unix.B9600,
wantErr: false,
},
{
name: "19200 baud",
baud: 19200,
expected: unix.B19200,
wantErr: false,
},
{
name: "38400 baud",
baud: 38400,
expected: unix.B38400,
wantErr: false,
},
{
name: "57600 baud",
baud: 57600,
expected: unix.B57600,
wantErr: false,
},
{
name: "115200 baud",
baud: 115200,
expected: unix.B115200,
wantErr: false,
},
{
name: "unsupported baud 1200",
baud: 1200,
wantErr: true,
errMsg: "unsupported baud 1200",
},
{
name: "unsupported baud 230400",
baud: 230400,
wantErr: true,
errMsg: "unsupported baud 230400",
},
{
name: "zero baud",
baud: 0,
wantErr: true,
errMsg: "unsupported baud 0",
},
{
name: "negative baud",
baud: -9600,
wantErr: true,
errMsg: "unsupported baud -9600",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
speed, err := baudToUnix(tt.baud)
if tt.wantErr {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.errMsg)
assert.Zero(t, speed)
} else {
require.NoError(t, err)
assert.Equal(t, tt.expected, speed)
}
})
}
}

// TestBaudToUnixAllSupportedRates verifies all supported rates are valid Unix constants.
func TestBaudToUnixAllSupportedRates(t *testing.T) {
t.Parallel()

supportedRates := []int{4800, 9600, 19200, 38400, 57600, 115200}

for _, baud := range supportedRates {
t.Run(fmt.Sprintf("%d", baud), func(t *testing.T) {
speed, err := baudToUnix(baud)
require.NoError(t, err, "supported baud rate %d should not error", baud)
assert.NotZero(t, speed, "baud rate %d should return non-zero speed", baud)
})
}
}

// TestLinuxSerialFactoryType tests that LinuxSerialFactory implements SerialFactory.
func TestLinuxSerialFactoryType(t *testing.T) {
t.Parallel()

var _ SerialFactory = LinuxSerialFactory{}
}

// TestLinuxSerialPortString tests the String() method format.
func TestLinuxSerialPortString(t *testing.T) {
t.Parallel()

tests := []struct {
name string
port string
baud int
expected string
}{
{
name: "USB0 at 9600",
port: "/dev/ttyUSB0",
baud: 9600,
expected: "/dev/ttyUSB0@9600",
},
{
name: "AMA0 at 115200",
port: "/dev/ttyAMA0",
baud: 115200,
expected: "/dev/ttyAMA0@115200",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
p := &linuxSerialPort{
port: tt.port,
baud: tt.baud,
}
assert.Equal(t, tt.expected, p.String())
})
}
}

// TestLinuxSerialPortInterfaceCompliance verifies linuxSerialPort implements SerialPort.
func TestLinuxSerialPortInterfaceCompliance(t *testing.T) {
t.Parallel()

var _ SerialPort = (*linuxSerialPort)(nil)
}

// TestLinuxSerialFactoryOpenSerialInvalidConfig tests error handling for invalid configs.
func TestLinuxSerialFactoryOpenSerialInvalidConfig(t *testing.T) {
t.Parallel()

factory := LinuxSerialFactory{}

tests := []struct {
name string
cfg SerialConfig
errMsg string
}{
{
name: "empty port",
cfg: SerialConfig{Port: "", Baud: 9600},
errMsg: "Port is required",
},
{
name: "zero baud",
cfg: SerialConfig{Port: "/dev/ttyUSB0", Baud: 0},
errMsg: "Baud must be > 0",
},
{
name: "negative baud",
cfg: SerialConfig{Port: "/dev/ttyUSB0", Baud: -115200},
errMsg: "Baud must be > 0",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
port, err := factory.OpenSerial(tt.cfg)
require.Error(t, err)
assert.Contains(t, err.Error(), tt.errMsg)
assert.Nil(t, port)
})
}
}

// TestLinuxSerialFactoryOpenSerialUnsupportedBaud tests unsupported baud rate handling.
func TestLinuxSerialFactoryOpenSerialUnsupportedBaud(t *testing.T) {
t.Parallel()

factory := LinuxSerialFactory{}

// Use a non-existent port path to avoid actual hardware interaction.
// The validation should fail at baud rate conversion before attempting to open.
cfg := SerialConfig{
Port: "/dev/ttyUSB999", // Non-existent port
Baud: 230400, // Unsupported baud rate
}

port, err := factory.OpenSerial(cfg)
// The error could be either from baud conversion or file opening.
// We just verify an error occurred and no port was returned.
require.Error(t, err)
assert.Nil(t, port)
}
86 changes: 86 additions & 0 deletions drivers/serial_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package drivers

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// TestValidateSerialConfig tests the configuration validation logic.
func TestValidateSerialConfig(t *testing.T) {
t.Parallel()

tests := []struct {
name string
cfg SerialConfig
wantErr bool
errMsg string
}{
{
name: "valid config",
cfg: SerialConfig{Port: "/dev/ttyUSB0", Baud: 9600},
wantErr: false,
},
{
name: "empty port",
cfg: SerialConfig{Port: "", Baud: 9600},
wantErr: true,
errMsg: "Port is required",
},
{
name: "zero baud",
cfg: SerialConfig{Port: "/dev/ttyUSB0", Baud: 0},
wantErr: true,
errMsg: "Baud must be > 0",
},
{
name: "negative baud",
cfg: SerialConfig{Port: "/dev/ttyUSB0", Baud: -9600},
wantErr: true,
errMsg: "Baud must be > 0",
},
{
name: "both port and baud invalid",
cfg: SerialConfig{Port: "", Baud: 0},
wantErr: true,
errMsg: "Port is required",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := validateSerialConfig(tt.cfg)
if tt.wantErr {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.errMsg)
} else {
require.NoError(t, err)
}
})
}
}

// TestSerialConfig tests SerialConfig struct initialization.
func TestSerialConfig(t *testing.T) {
t.Parallel()

cfg := SerialConfig{
Port: "/dev/ttyUSB0",
Baud: 115200,
}

assert.Equal(t, "/dev/ttyUSB0", cfg.Port)
assert.Equal(t, 115200, cfg.Baud)
}

// TestSerialConfigZeroValues tests zero value behavior.
func TestSerialConfigZeroValues(t *testing.T) {
t.Parallel()

var cfg SerialConfig
err := validateSerialConfig(cfg)
require.Error(t, err)
assert.Contains(t, err.Error(), "Port is required")
}
5 changes: 1 addition & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ module github.com/rustyeddy/devices
go 1.24.5

require (
github.com/maciej/bme280 v0.2.0
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/stretchr/testify v1.11.1
github.com/warthog618/go-gpiocdev v0.9.1
golang.org/x/image v0.23.0
golang.org/x/sys v0.29.0
periph.io/x/conn/v3 v3.7.2
periph.io/x/devices/v3 v3.7.4
periph.io/x/host/v3 v3.8.5
Expand All @@ -16,6 +14,5 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.29.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
6 changes: 0 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
github.com/maciej/bme280 v0.2.0 h1:WsoHmIxw15AbhyoY5EWYH6loHNnsCayW1yWVLmukJVQ=
github.com/maciej/bme280 v0.2.0/go.mod h1:uhS+osHzBXnIwpXTCklgoi0q4XiA5Mr5ehJfGIPlfQY=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand All @@ -16,8 +12,6 @@ github.com/warthog618/go-gpiocdev v0.9.1 h1:pwHPaqjJfhCipIQl78V+O3l9OKHivdRDdmgX
github.com/warthog618/go-gpiocdev v0.9.1/go.mod h1:dN3e3t/S2aSNC+hgigGE/dBW8jE1ONk9bDSEYfoPyl8=
github.com/warthog618/go-gpiosim v0.1.1 h1:MRAEv+T+itmw+3GeIGpQJBfanUVyg0l3JCTwHtwdre4=
github.com/warthog618/go-gpiosim v0.1.1/go.mod h1:YXsnB+I9jdCMY4YAlMSRrlts25ltjmuIsrnoUrBLdqU=
golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68=
golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
Expand Down