From 15071fff4482e2f6ed06a039529c2a0fc0dcd392 Mon Sep 17 00:00:00 2001 From: Florian Thienel Date: Wed, 6 Dec 2023 20:00:58 +0100 Subject: [PATCH] create a test harness for HamDeck --- go.mod | 4 + go.sum | 5 +- pkg/hamdeck/hamdeck_test.go | 151 ++++++++++++++++++++++++ pkg/hamdeck/testdata/testRoundtrip.json | 9 ++ 4 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 pkg/hamdeck/hamdeck_test.go create mode 100644 pkg/hamdeck/testdata/testRoundtrip.json diff --git a/go.mod b/go.mod index 6ec5bda..2a3afb2 100644 --- a/go.mod +++ b/go.mod @@ -19,15 +19,19 @@ require ( github.com/jfreymuth/pulse v0.1.0 github.com/muesli/streamdeck v0.4.0 github.com/spf13/cobra v1.8.0 + github.com/stretchr/testify v1.8.4 golang.org/x/image v0.14.0 ) require ( + github.com/davecgh/go-spew v1.1.1 // indirect github.com/gorilla/websocket v1.5.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/karalabe/hid v1.0.1-0.20190806082151-9c14560f9ee8 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/net v0.19.0 // indirect golang.org/x/sync v0.5.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 7da3e1c..c32c5d8 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,8 @@ github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -76,6 +76,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/pkg/hamdeck/hamdeck_test.go b/pkg/hamdeck/hamdeck_test.go new file mode 100644 index 0000000..ab6f2de --- /dev/null +++ b/pkg/hamdeck/hamdeck_test.go @@ -0,0 +1,151 @@ +package hamdeck + +import ( + "image" + "io" + "os" + "path/filepath" + "sync" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestHamDeckRoundtrip(t *testing.T) { + device := newDefaultTestDevice() + deck := New(device) + deck.RegisterFactory(new(testButtonFactory)) + + reader, err := openTestConfig("testRoundtrip") + require.NoError(t, err) + defer reader.Close() + err = deck.ReadConfig(reader) + require.NoError(t, err) + + require.Equal(t, 32, len(deck.buttons)) + button := deck.buttons[12].(*testButton) + + assert.Equal(t, "some_value", button.config["some_config"]) + assert.True(t, button.attached) + assert.False(t, button.detached) + assert.False(t, button.pressed) + assert.False(t, button.released) + + stopper := make(chan struct{}) + wg := new(sync.WaitGroup) + wg.Add(1) + go func() { + deck.Run(stopper) + wg.Done() + }() + + device.Press(12) + device.WaitForLastKey() + assert.True(t, button.pressed) + assert.False(t, button.released) + + device.Release(12) + device.WaitForLastKey() + assert.True(t, button.released) + + close(stopper) + wg.Wait() +} + +/* Test Harness */ + +func openTestConfig(name string) (io.ReadCloser, error) { + return os.Open(filepath.Join("testdata", name+".json")) +} + +type testDevice struct { + id string + serial string + firmwareVersion string + pixels int + rows int + columns int + keys chan Key +} + +func newDefaultTestDevice() *testDevice { + return newTestDevice(128, 4, 8) +} + +func newTestDevice(pixels int, rows int, columns int) *testDevice { + return &testDevice{ + pixels: pixels, + rows: rows, + columns: columns, + keys: make(chan Key), + } +} + +func (d *testDevice) Close() error { return nil } +func (d *testDevice) ID() string { return d.id } +func (d *testDevice) Serial() string { return d.serial } +func (d *testDevice) FirmwareVersion() string { return d.firmwareVersion } +func (d *testDevice) Pixels() int { return d.pixels } +func (d *testDevice) Rows() int { return d.rows } +func (d *testDevice) Columns() int { return d.columns } +func (d *testDevice) Clear() error { return nil } +func (d *testDevice) Reset() error { return nil } +func (d *testDevice) SetBrightness(int) error { return nil } +func (d *testDevice) SetImage(int, image.Image) error { return nil } +func (d *testDevice) ReadKeys() (chan Key, error) { return d.keys, nil } +func (d *testDevice) Press(index int) { + key := Key{ + Index: index, + Pressed: true, + } + d.keys <- key +} +func (d *testDevice) Release(index int) { + key := Key{ + Index: index, + Pressed: false, + } + d.keys <- key +} +func (d *testDevice) WaitForLastKey() { + d.keys <- Key{} +} + +const ( + testButtonType = "test.Button" +) + +type testButtonFactory struct{} + +func (f *testButtonFactory) Close() {} + +func (f *testButtonFactory) CreateButton(config map[string]any) Button { + switch config[ConfigType] { + case testButtonType: + return f.createTestButton(config) + default: + return nil + } +} + +func (f *testButtonFactory) createTestButton(config map[string]any) *testButton { + return &testButton{ + config: config, + } +} + +type testButton struct { + config map[string]any + + pressed bool + released bool + attached bool + detached bool +} + +func (b *testButton) Image(GraphicContext, bool) image.Image { return nil } +func (b *testButton) Pressed() { b.pressed = true } +func (b *testButton) Released() { b.released = true } +func (b *testButton) Attached(ButtonContext) { b.attached = true } +func (b *testButton) Detached() { b.detached = true } diff --git a/pkg/hamdeck/testdata/testRoundtrip.json b/pkg/hamdeck/testdata/testRoundtrip.json new file mode 100644 index 0000000..3733817 --- /dev/null +++ b/pkg/hamdeck/testdata/testRoundtrip.json @@ -0,0 +1,9 @@ +{ + "buttons": [ + { + "type": "test.Button", + "index": 12, + "some_config": "some_value" + } + ] +} \ No newline at end of file