From 263943f4d6e8389d087a1204f92054efcac33dc8 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Tue, 10 Feb 2026 21:16:02 -0600 Subject: [PATCH] add tests for osc.message.create and filter --- .../processor/test/osc-message-create_test.go | 225 ++++++++++++++++++ .../processor/test/osc-message-filter_test.go | 139 +++++++++++ 2 files changed, 364 insertions(+) diff --git a/internal/processor/test/osc-message-create_test.go b/internal/processor/test/osc-message-create_test.go index db707fa..5abbcaf 100644 --- a/internal/processor/test/osc-message-create_test.go +++ b/internal/processor/test/osc-message-create_test.go @@ -1,8 +1,10 @@ package processor_test import ( + "reflect" "testing" + "github.com/jwetzell/osc-go" "github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/processor" ) @@ -28,3 +30,226 @@ func TestOSCMessageCreateFromRegistry(t *testing.T) { t.Fatalf("osc.message.create processor has wrong type: %s", processorInstance.Type()) } } + +func TestGoodOSCMessageCreate(t *testing.T) { + tests := []struct { + name string + payload any + params map[string]any + expected any + }{ + { + name: "basic address and no args", + params: map[string]any{ + "address": "/test", + }, + payload: osc.OSCMessage{}, + expected: osc.OSCMessage{Address: "/test"}, + }, + { + name: "address with template and no args", + params: map[string]any{ + "address": "/test/{{.Value}}", + }, + payload: map[string]any{"Value": "value"}, + expected: osc.OSCMessage{Address: "/test/value"}, + }, + { + name: "address with template and string arg", + params: map[string]any{ + "address": "/test/{{.Value}}", + "args": []interface{}{"arg1"}, + "types": "s", + }, + payload: map[string]any{"Value": "value"}, + expected: osc.OSCMessage{Address: "/test/value", Args: []osc.OSCArg{{Value: "arg1", Type: "s"}}}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + registration, ok := processor.ProcessorRegistry["osc.message.create"] + if !ok { + t.Fatalf("osc.message.create processor not registered") + } + + processorInstance, err := registration.New(config.ProcessorConfig{ + Type: "osc.message.create", + Params: test.params, + }) + + if err != nil { + t.Fatalf("osc.message.create failed to create processor: %s", err) + } + + got, err := processorInstance.Process(t.Context(), test.payload) + + if err != nil { + t.Fatalf("osc.message.create process failed: %s", err) + } + + if test.expected == nil { + if got != nil { + t.Fatalf("osc.message.create got %+v, expected nil", got) + } + return + } + + gotMessage, ok := got.(osc.OSCMessage) + if !ok { + t.Fatalf("osc.message.create returned a %T payload: %s", got, got) + } + + if !reflect.DeepEqual(gotMessage, test.expected) { + t.Fatalf("osc.message.create got %+v, expected %+v", gotMessage, test.expected) + } + }) + } +} + +func TestBadOSCMessageCreate(t *testing.T) { + tests := []struct { + name string + params map[string]any + payload any + errorString string + }{ + { + name: "no address parameter", + params: map[string]any{}, + payload: "test", + errorString: "osc.message.create requires an address parameter", + }, + { + name: "non-string address parameter", + params: map[string]any{ + "address": 123, + }, + payload: "test", + errorString: "osc.message.create address must be a string", + }, + { + name: "bad address template", + params: map[string]any{ + "address": "{{", + }, + payload: "test", + errorString: "template: address:1: unclosed action", + }, + { + name: "non-array args parameter", + params: map[string]any{ + "address": "/test", + "args": "not an array", + "types": "s", + }, + payload: "test", + errorString: "osc.message.create address must be an array found string", + }, + { + name: "args and types length mismatch", + params: map[string]any{ + "address": "/test", + "args": []interface{}{"arg1", "arg2"}, + "types": "s", + }, + payload: "test", + errorString: "osc.message.create args and types must be the same length", + }, + { + name: "non-string arg", + params: map[string]any{ + "address": "/test", + "args": []interface{}{"arg1", 123}, + "types": "ss", + }, + payload: "test", + errorString: "osc.message.create arg must be a string", + }, + { + name: "bad arg template", + params: map[string]any{ + "address": "/test", + "args": []interface{}{"{{"}, + "types": "s", + }, + payload: "test", + errorString: "template: arg:1: unclosed action", + }, + { + name: "non-string types parameter", + params: map[string]any{ + "address": "/test", + "args": []interface{}{"arg1"}, + "types": 123, + }, + payload: "test", + errorString: "osc.message.create types must be a string", + }, + { + name: "invalid type in types parameter", + params: map[string]any{ + "address": "/test", + "args": []interface{}{"arg1"}, + "types": "x", + }, + payload: "test", + errorString: "osc.message.create unhandled osc type: x", + }, + { + name: "empty address template", + params: map[string]any{ + "address": "", + }, + payload: "test", + errorString: "osc.message.create address must not be empty", + }, + { + name: "template with missing value", + params: map[string]any{ + "address": "/test/{{.missing}}", + }, + payload: "test", + errorString: "template: address:1:8: executing \"address\" at <.missing>: can't evaluate field missing in type string", + }, + { + name: "address doesn't start with slash", + params: map[string]any{ + "address": "test", + }, + payload: "test", + errorString: "osc.message.create address must start with '/'", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + registration, ok := processor.ProcessorRegistry["osc.message.create"] + if !ok { + t.Fatalf("osc.message.create processor not registered") + } + + processorInstance, err := registration.New(config.ProcessorConfig{ + Type: "osc.message.create", + Params: test.params, + }) + + if err != nil { + if test.errorString != err.Error() { + t.Fatalf("string.create got error '%s', expected '%s'", err.Error(), test.errorString) + } + return + } + + got, err := processorInstance.Process(t.Context(), test.payload) + + if err == nil { + t.Fatalf("osc.message.create expected to fail but succeeded, got: %v", got) + } + + if err.Error() != test.errorString { + t.Fatalf("osc.message.create got error '%s', expected '%s'", err.Error(), test.errorString) + } + }) + } +} diff --git a/internal/processor/test/osc-message-filter_test.go b/internal/processor/test/osc-message-filter_test.go index 7650c0e..cec80d3 100644 --- a/internal/processor/test/osc-message-filter_test.go +++ b/internal/processor/test/osc-message-filter_test.go @@ -1,8 +1,10 @@ package processor_test import ( + "reflect" "testing" + "github.com/jwetzell/osc-go" "github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/processor" ) @@ -28,3 +30,140 @@ func TestOSCMessageFilterFromRegistry(t *testing.T) { t.Fatalf("osc.message.filter processor has wrong type: %s", processorInstance.Type()) } } + +func TestGoodOSCMessageFilter(t *testing.T) { + tests := []struct { + name string + payload osc.OSCMessage + params map[string]any + expected any + }{ + { + name: "basic address match", + params: map[string]any{ + "address": "/test", + }, + payload: osc.OSCMessage{Address: "/test"}, + expected: osc.OSCMessage{Address: "/test"}, + }, + { + name: "basic address no match", + params: map[string]any{ + "address": "/test", + }, + payload: osc.OSCMessage{Address: "/testing"}, + expected: nil, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + registration, ok := processor.ProcessorRegistry["osc.message.filter"] + if !ok { + t.Fatalf("osc.message.filter processor not registered") + } + + processorInstance, err := registration.New(config.ProcessorConfig{ + Type: "osc.message.filter", + Params: test.params, + }) + + if err != nil { + t.Fatalf("osc.message.filter failed to create processor: %s", err) + } + + got, err := processorInstance.Process(t.Context(), test.payload) + + if err != nil { + t.Fatalf("osc.message.filter process failed: %s", err) + } + + if test.expected == nil { + if got != nil { + t.Fatalf("osc.message.filter got %+v, expected nil", got) + } + return + } + + gotMessage, ok := got.(osc.OSCMessage) + if !ok { + t.Fatalf("osc.message.filter returned a %T payload: %s", got, got) + } + + if !reflect.DeepEqual(gotMessage, test.expected) { + t.Fatalf("osc.message.filter got %+v, expected %+v", gotMessage, test.expected) + } + }) + } +} + +func TestBadOSCMessageFilter(t *testing.T) { + tests := []struct { + name string + params map[string]any + payload any + errorString string + }{ + { + name: "no address parameter", + params: map[string]any{}, + payload: osc.OSCMessage{Address: "/test"}, + errorString: "osc.message.filter requires an address parameter", + }, + { + name: "non-string address parameter", + params: map[string]any{ + "address": 123, + }, + payload: osc.OSCMessage{Address: "/test"}, + errorString: "osc.message.filter address must be a string", + }, + { + name: "bad address pattern", + params: map[string]any{ + "address": "[", + }, + payload: osc.OSCMessage{Address: "/test"}, + errorString: "error parsing regexp: missing closing ]: `[$`", + }, + { + name: "non-osc input", + params: map[string]any{ + "address": "/test", + }, + payload: []byte("hello"), + errorString: "osc.message.filter can only operate on OSCMessage payloads", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + registration, ok := processor.ProcessorRegistry["osc.message.filter"] + if !ok { + t.Fatalf("osc.message.filter processor not registered") + } + + processorInstance, err := registration.New(config.ProcessorConfig{ + Type: "osc.message.filter", + Params: test.params, + }) + + if err != nil { + if test.errorString != err.Error() { + t.Fatalf("string.create got error '%s', expected '%s'", err.Error(), test.errorString) + } + return + } + + got, err := processorInstance.Process(t.Context(), test.payload) + + if err == nil { + t.Fatalf("osc.message.filter expected to fail but succeeded, got: %v", got) + } + + if err.Error() != test.errorString { + t.Fatalf("osc.message.filter got error '%s', expected '%s'", err.Error(), test.errorString) + } + }) + } +}