Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aio(all): introduce functional options #1039

Merged
merged 1 commit into from
Nov 23, 2023
Merged
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
32 changes: 0 additions & 32 deletions drivers/aio/aio.go

This file was deleted.

119 changes: 119 additions & 0 deletions drivers/aio/aio_driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package aio

import (
"log"
"sync"

"gobot.io/x/gobot/v2"
)

const (
// Error event
Error = "error"
// Data event
Data = "data"
// Value event
Value = "value"
// Vibration event
Vibration = "vibration"
)

// AnalogReader interface represents an Adaptor which has AnalogRead capabilities
type AnalogReader interface {
// gobot.Adaptor
AnalogRead(pin string) (val int, err error)
}

// AnalogWriter interface represents an Adaptor which has AnalogWrite capabilities
type AnalogWriter interface {
// gobot.Adaptor
AnalogWrite(pin string, val int) error
}

// optionApplier needs to be implemented by each configurable option type
type optionApplier interface {
apply(cfg *configuration)
}

// configuration contains all changeable attributes of the driver.
type configuration struct {
name string
}

// nameOption is the type for applying another name to the configuration
type nameOption string

// Driver implements the interface gobot.Driver.
type driver struct {
driverCfg *configuration
connection interface{}
afterStart func() error
beforeHalt func() error
gobot.Commander
mutex *sync.Mutex // e.g. used to prevent data race between cyclic and single shot write/read to values and scaler
}

// newDriver creates a new basic analog gobot driver.
func newDriver(a interface{}, name string) *driver {
d := driver{
driverCfg: &configuration{name: gobot.DefaultName(name)},
connection: a,
afterStart: func() error { return nil },
beforeHalt: func() error { return nil },
Commander: gobot.NewCommander(),
mutex: &sync.Mutex{},
}

return &d
}

// WithName is used to replace the default name of the driver.
func WithName(name string) optionApplier {
return nameOption(name)
}

// Name returns the name of the driver.
func (d *driver) Name() string {
return d.driverCfg.name
}

// SetName sets the name of the driver.
// Deprecated: Please use option [aio.WithName] instead.
func (d *driver) SetName(name string) {
WithName(name).apply(d.driverCfg)
}

// Connection returns the connection of the driver.
func (d *driver) Connection() gobot.Connection {
if conn, ok := d.connection.(gobot.Connection); ok {
return conn
}

log.Printf("%s has no gobot connection\n", d.driverCfg.name)
return nil
}

// Start initializes the driver.
func (d *driver) Start() error {
d.mutex.Lock()
defer d.mutex.Unlock()

// currently there is nothing to do here for the driver

return d.afterStart()
}

// Halt halts the driver.
func (d *driver) Halt() error {
d.mutex.Lock()
defer d.mutex.Unlock()

// currently there is nothing to do after halt for the driver

return d.beforeHalt()
}

// apply change the name in the configuration.
func (o nameOption) apply(c *configuration) {
c.name = string(o)
}
69 changes: 69 additions & 0 deletions drivers/aio/aio_driver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package aio

import (
"fmt"
"strings"
"testing"

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

"gobot.io/x/gobot/v2"
)

var _ gobot.Driver = (*driver)(nil)

func initTestDriver() *driver {
a := newAioTestAdaptor()
d := newDriver(a, "AIO_BASIC")
return d
}

func Test_newDriver(t *testing.T) {
// arrange
const name = "mybot"
a := newAioTestAdaptor()
// act
d := newDriver(a, name)
// assert
assert.IsType(t, &driver{}, d)
assert.NotNil(t, d.driverCfg)
assert.True(t, strings.HasPrefix(d.Name(), name))
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)
}

func Test_applyWithName(t *testing.T) {
// arrange
const name = "mybot"
cfg := configuration{name: "oldname"}
// act
WithName(name).apply(&cfg)
// assert
assert.Equal(t, name, cfg.name)
}

func TestStart(t *testing.T) {
// arrange
d := initTestDriver()
// act, assert
require.NoError(t, d.Start())
// arrange after start function
d.afterStart = func() error { return fmt.Errorf("after start error") }
// act, assert
require.EqualError(t, d.Start(), "after start error")
}

func TestHalt(t *testing.T) {
// arrange
d := initTestDriver()
// act, assert
require.NoError(t, d.Halt())
// arrange after start function
d.beforeHalt = func() error { return fmt.Errorf("before halt error") }
// act, assert
require.EqualError(t, d.Halt(), "before halt error")
}
Loading