standardize processor instance creation in tests

This commit is contained in:
Joel Wetzell
2026-02-09 22:09:48 -06:00
parent f028634401
commit a408e281a3
14 changed files with 599 additions and 191 deletions

View File

@@ -71,12 +71,15 @@ func TestGoodArtnetPacketFilter(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
params map[string]any
payload any payload any
opCode uint16
expected artnet.ArtNetPacket expected artnet.ArtNetPacket
}{ }{
{ {
name: "tiemcode packet with matching opCode", name: "tiemcode packet with matching opCode",
params: map[string]any{
"opCode": float64(artnet.OpTimeCode),
},
payload: &artnet.ArtTimeCode{ payload: &artnet.ArtTimeCode{
ID: []byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, ID: []byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00},
OpCode: artnet.OpTimeCode, OpCode: artnet.OpTimeCode,
@@ -90,7 +93,6 @@ func TestGoodArtnetPacketFilter(t *testing.T) {
Hours: 0, Hours: 0,
Type: 0, Type: 0,
}, },
opCode: artnet.OpTimeCode,
expected: &artnet.ArtTimeCode{ expected: &artnet.ArtTimeCode{
ID: []byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, ID: []byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00},
OpCode: artnet.OpTimeCode, OpCode: artnet.OpTimeCode,
@@ -106,7 +108,10 @@ func TestGoodArtnetPacketFilter(t *testing.T) {
}, },
}, },
{ {
name: "tiemcode packet with mismatching opCode", name: "timecode packet with mismatching opCode",
params: map[string]any{
"opCode": float64(artnet.OpDmx),
},
payload: &artnet.ArtTimeCode{ payload: &artnet.ArtTimeCode{
ID: []byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, ID: []byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00},
OpCode: artnet.OpTimeCode, OpCode: artnet.OpTimeCode,
@@ -120,17 +125,27 @@ func TestGoodArtnetPacketFilter(t *testing.T) {
Hours: 0, Hours: 0,
Type: 0, Type: 0,
}, },
opCode: artnet.OpDmx,
expected: nil, expected: nil,
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
artnetPacketFilter := processor.ArtNetPacketFilter{ registration, ok := processor.ProcessorRegistry["artnet.packet.filter"]
OpCode: test.opCode, if !ok {
t.Fatalf("artnet.packet.filter processor not registered")
} }
got, err := artnetPacketFilter.Process(t.Context(), test.payload)
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "artnet.packet.filter",
Params: test.params,
})
if err != nil {
t.Fatalf("artnet.packet.filter failed to create processor: %s", err)
}
got, err := processorInstance.Process(t.Context(), test.payload)
if err != nil { if err != nil {
t.Fatalf("artnet.packet.filter failed: %s", err) t.Fatalf("artnet.packet.filter failed: %s", err)
@@ -158,8 +173,8 @@ func TestGoodArtnetPacketFilter(t *testing.T) {
func TestBadArtnetPacketFilter(t *testing.T) { func TestBadArtnetPacketFilter(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
payload any
params map[string]any params map[string]any
payload any
errorString string errorString string
}{ }{
{ {

View File

@@ -80,37 +80,55 @@ func TestFloatParseGoodConfig(t *testing.T) {
} }
func TestGoodFloatParse(t *testing.T) { func TestGoodFloatParse(t *testing.T) {
floatParser := processor.FloatParse{}
tests := []struct { tests := []struct {
processor processor.Processor name string
name string params map[string]any
payload any payload any
bitSize int expected float64
expected float64
}{ }{
{ {
name: "positive number", name: "positive number",
params: map[string]any{
"bitSize": 64.0,
},
payload: "12345.67", payload: "12345.67",
bitSize: 64,
expected: 12345.67, expected: 12345.67,
}, },
{ {
name: "negative number", name: "negative number",
params: map[string]any{
"bitSize": 64.0,
},
payload: "-12345.67", payload: "-12345.67",
bitSize: 64,
expected: -12345.67, expected: -12345.67,
}, },
{ {
name: "zero", name: "zero",
params: map[string]any{
"bitSize": 64.0,
},
payload: "0", payload: "0",
bitSize: 64,
expected: 0, expected: 0,
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
got, err := floatParser.Process(t.Context(), test.payload) registration, ok := processor.ProcessorRegistry["float.parse"]
if !ok {
t.Fatalf("float.parse processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "float.parse",
Params: test.params,
})
if err != nil {
t.Fatalf("float.parse failed to create processor: %s", err)
}
got, err := processorInstance.Process(t.Context(), test.payload)
gotFloat, ok := got.(float64) gotFloat, ok := got.(float64)
if !ok { if !ok {
@@ -128,38 +146,50 @@ func TestGoodFloatParse(t *testing.T) {
func TestBadFloatParse(t *testing.T) { func TestBadFloatParse(t *testing.T) {
tests := []struct { tests := []struct {
processor processor.Processor
name string name string
params map[string]any
payload any payload any
bitSize int
errorString string errorString string
}{ }{
{ {
name: "non-string input", name: "non-string input",
params: map[string]any{
"bitSize": 64.0,
},
payload: []byte{0x01}, payload: []byte{0x01},
bitSize: 64,
errorString: "float.parse processor only accepts a string", errorString: "float.parse processor only accepts a string",
}, },
{ {
name: "not float string", name: "not float string",
params: map[string]any{
"bitSize": 64.0,
},
payload: "abcd", payload: "abcd",
bitSize: 64,
errorString: "strconv.ParseFloat: parsing \"abcd\": invalid syntax", errorString: "strconv.ParseFloat: parsing \"abcd\": invalid syntax",
}, },
{ {
name: "bit size overflow", name: "bit size overflow",
params: map[string]any{
"bitSize": 32.0,
},
payload: "1.79e+64", payload: "1.79e+64",
bitSize: 32,
errorString: "strconv.ParseFloat: parsing \"1.79e+64\": value out of range", errorString: "strconv.ParseFloat: parsing \"1.79e+64\": value out of range",
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
floatParser := processor.FloatParse{ registration, ok := processor.ProcessorRegistry["float.parse"]
BitSize: test.bitSize, if !ok {
t.Fatalf("float.parse processor not registered")
} }
got, err := floatParser.Process(t.Context(), test.payload)
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "float.parse",
Params: test.params,
})
got, err := processorInstance.Process(t.Context(), test.payload)
if err == nil { if err == nil {
t.Fatalf("float.parse expected to fail but succeeded, got: %v", got) t.Fatalf("float.parse expected to fail but succeeded, got: %v", got)

View File

@@ -100,58 +100,75 @@ func TestIntParseGoodConfig(t *testing.T) {
func TestGoodIntParse(t *testing.T) { func TestGoodIntParse(t *testing.T) {
tests := []struct { tests := []struct {
processor processor.Processor name string
name string params map[string]any
payload any payload any
expected int64 expected int64
base int
bitSize int
}{ }{
{ {
name: "positive number", name: "positive number",
params: map[string]any{
"base": 10.0,
"bitSize": 64.0,
},
payload: "12345", payload: "12345",
expected: 12345, expected: 12345,
base: 10,
bitSize: 64,
}, },
{ {
name: "negative number", name: "negative number",
params: map[string]any{
"base": 10.0,
"bitSize": 64.0,
},
payload: "-12345", payload: "-12345",
expected: -12345, expected: -12345,
base: 10,
bitSize: 64,
}, },
{ {
name: "zero", name: "zero",
params: map[string]any{
"base": 10.0,
"bitSize": 64.0,
},
payload: "0", payload: "0",
expected: 0, expected: 0,
base: 10,
bitSize: 64,
}, },
{ {
name: "binary", name: "binary",
params: map[string]any{
"base": 2.0,
"bitSize": 64.0,
},
payload: "1010101", payload: "1010101",
expected: 85, expected: 85,
base: 2,
bitSize: 64,
}, },
{ {
name: "hex", name: "hex",
params: map[string]any{
"base": 16.0,
"bitSize": 64.0,
},
payload: "15F", payload: "15F",
expected: 351, expected: 351,
base: 16,
bitSize: 64,
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
intParser := processor.IntParse{ registration, ok := processor.ProcessorRegistry["int.parse"]
Base: test.base, if !ok {
BitSize: test.bitSize, t.Fatalf("int.parse processor not registered")
} }
got, err := intParser.Process(t.Context(), test.payload) processorInstance, err := registration.New(config.ProcessorConfig{
Type: "int.parse",
Params: test.params,
})
if err != nil {
t.Fatalf("int.parse failed to create processor: %s", err)
}
got, err := processorInstance.Process(t.Context(), test.payload)
gotInt, ok := got.(int64) gotInt, ok := got.(int64)
if !ok { if !ok {
@@ -169,43 +186,53 @@ func TestGoodIntParse(t *testing.T) {
func TestBadIntParse(t *testing.T) { func TestBadIntParse(t *testing.T) {
tests := []struct { tests := []struct {
processor processor.Processor
name string name string
params map[string]any
payload any payload any
base int
bitSize int
errorString string errorString string
}{ }{
{ {
name: "non-string input", name: "non-string input",
params: map[string]any{
"base": 10.0,
"bitSize": 64.0,
},
payload: []byte{0x01}, payload: []byte{0x01},
base: 10,
bitSize: 64,
errorString: "int.parse processor only accepts a string", errorString: "int.parse processor only accepts a string",
}, },
{ {
name: "not int string", name: "not int string",
params: map[string]any{
"base": 10.0,
"bitSize": 64.0,
},
payload: "123.46", payload: "123.46",
base: 10,
bitSize: 64,
errorString: "strconv.ParseInt: parsing \"123.46\": invalid syntax", errorString: "strconv.ParseInt: parsing \"123.46\": invalid syntax",
}, },
{ {
name: "bit overflow", name: "bit overflow",
params: map[string]any{
"base": 10.0,
"bitSize": 32.0,
},
payload: "12345678901234567890", payload: "12345678901234567890",
base: 10,
bitSize: 32,
errorString: "strconv.ParseInt: parsing \"12345678901234567890\": value out of range", errorString: "strconv.ParseInt: parsing \"12345678901234567890\": value out of range",
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
intParser := processor.IntParse{ registration, ok := processor.ProcessorRegistry["int.parse"]
Base: test.base, if !ok {
BitSize: test.bitSize, t.Fatalf("int.parse processor not registered")
} }
got, err := intParser.Process(t.Context(), test.payload)
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "int.parse",
Params: test.params,
})
got, err := processorInstance.Process(t.Context(), test.payload)
if err == nil { if err == nil {
t.Fatalf("int.parse expected to fail but succeeded, got: %v", got) t.Fatalf("int.parse expected to fail but succeeded, got: %v", got)

View File

@@ -67,27 +67,37 @@ func TestIntRandomGoodConfig(t *testing.T) {
func TestGoodIntRandom(t *testing.T) { func TestGoodIntRandom(t *testing.T) {
tests := []struct { tests := []struct {
processor processor.Processor name string
name string payload any
payload any params map[string]any
min int
max int
}{ }{
{ {
name: "1-10", name: "1-10",
params: map[string]any{
"min": 1.0,
"max": 10.0,
},
payload: "12345", payload: "12345",
min: 1,
max: 10,
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
intRandom := processor.IntRandom{ registration, ok := processor.ProcessorRegistry["int.random"]
Min: test.min, if !ok {
Max: test.max, t.Fatalf("int.random processor not registered")
} }
got, err := intRandom.Process(t.Context(), test.payload)
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "int.random",
Params: test.params,
})
if err != nil {
t.Fatalf("int.random failed to create processor: %s", err)
}
got, err := processorInstance.Process(t.Context(), test.payload)
gotInt, ok := got.(int) gotInt, ok := got.(int)
if !ok { if !ok {
t.Fatalf("int.random returned a %T payload: %s", got, got) t.Fatalf("int.random returned a %T payload: %s", got, got)
@@ -95,8 +105,18 @@ func TestGoodIntRandom(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("int.random failed: %s", err) t.Fatalf("int.random failed: %s", err)
} }
if gotInt < test.min || gotInt > test.max {
t.Fatalf("int.random got %d, expected between %d and %d", gotInt, test.min, test.max) minNum, ok := test.params["min"].(float64)
if !ok {
t.Fatalf("int.random test min param is not a number: %s", test.params["min"])
}
maxNum, ok := test.params["max"].(float64)
if !ok {
t.Fatalf("int.random test max param is not a number: %s", test.params["max"])
}
if gotInt < int(minNum) || gotInt > int(maxNum) {
t.Fatalf("int.random got %d, expected between %d and %d", gotInt, int(minNum), int(maxNum))
} }
}) })
} }

View File

@@ -1,10 +1,12 @@
package processor_test package processor_test
import ( import (
"slices"
"testing" "testing"
"github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/config"
"github.com/jwetzell/showbridge-go/internal/processor" "github.com/jwetzell/showbridge-go/internal/processor"
"gitlab.com/gomidi/midi/v2"
) )
func TestMIDIMessageEncodeFromRegistry(t *testing.T) { func TestMIDIMessageEncodeFromRegistry(t *testing.T) {
@@ -25,3 +27,63 @@ func TestMIDIMessageEncodeFromRegistry(t *testing.T) {
t.Fatalf("midi.message.encode processor has wrong type: %s", processorInstance.Type()) t.Fatalf("midi.message.encode processor has wrong type: %s", processorInstance.Type())
} }
} }
func TestGoodMIDIMessageEncode(t *testing.T) {
midiMessageEncoder := processor.MIDIMessageEncode{}
tests := []struct {
name string
payload any
expected []byte
}{
{
name: "note on message",
payload: midi.NoteOn(1, 60, 127),
expected: []byte{0x91, 0x3c, 0x7f},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got, err := midiMessageEncoder.Process(t.Context(), test.payload)
gotBytes, ok := got.([]byte)
if !ok {
t.Fatalf("midi.message.encode returned a %T payload: %s", got, got)
}
if err != nil {
t.Fatalf("midi.message.encode failed: %s", err)
}
if !slices.Equal(gotBytes, test.expected) {
t.Fatalf("midi.message.encode got %+v, expected %+v", got, test.expected)
}
})
}
}
func TestBadMIDIMessageEncode(t *testing.T) {
midiMessageEncoder := processor.MIDIMessageEncode{}
tests := []struct {
name string
payload any
errorString string
}{
{
name: "non-midi message input",
payload: []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f},
errorString: "midi.message.encode processor only accepts a midi.Message",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got, err := midiMessageEncoder.Process(t.Context(), test.payload)
if err == nil {
t.Fatalf("midi.message.encode expected to fail but got payload: %s", got)
}
if err.Error() != test.errorString {
t.Fatalf("midi.message.encode got error '%s', expected '%s'", err.Error(), test.errorString)
}
})
}
}

View File

@@ -1,10 +1,12 @@
package processor_test package processor_test
import ( import (
"reflect"
"testing" "testing"
"github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/config"
"github.com/jwetzell/showbridge-go/internal/processor" "github.com/jwetzell/showbridge-go/internal/processor"
"gitlab.com/gomidi/midi/v2"
) )
func TestMIDIMessageFilterFromRegistry(t *testing.T) { func TestMIDIMessageFilterFromRegistry(t *testing.T) {
@@ -28,3 +30,128 @@ func TestMIDIMessageFilterFromRegistry(t *testing.T) {
t.Fatalf("midi.message.filter processor has wrong type: %s", processorInstance.Type()) t.Fatalf("midi.message.filter processor has wrong type: %s", processorInstance.Type())
} }
} }
func TestGoodMIDIMessageFilter(t *testing.T) {
tests := []struct {
name string
params map[string]any
payload midi.Message
expected midi.Message
}{
{
name: "matches pattern",
payload: midi.NoteOn(1, 60, 127),
params: map[string]any{"type": "NoteOn"},
expected: midi.NoteOn(1, 60, 127),
},
{
name: "does not match pattern",
payload: midi.NoteOn(1, 60, 127),
params: map[string]any{"type": "NoteOff"},
expected: nil,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["midi.message.filter"]
if !ok {
t.Fatalf("midi.message.filter processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "midi.message.filter",
Params: test.params,
})
if err != nil {
t.Fatalf("midi.message.filter failed to create processor: %s", err)
}
got, err := processorInstance.Process(t.Context(), test.payload)
if err != nil {
t.Fatalf("midi.message.filter failed: %s", err)
}
if test.expected == nil {
if got != nil {
t.Fatalf("midi.message.filter got %+v, expected nil", got)
}
return
}
gotMIDIMessage, ok := got.(midi.Message)
if !ok {
t.Fatalf("midi.message.filter returned a %T payload: %s", got, got)
}
if !reflect.DeepEqual(gotMIDIMessage, test.expected) {
t.Fatalf("midi.message.filter got %+v, expected %+v", gotMIDIMessage, test.expected)
}
})
}
}
func TestBadMIDIMessageFilter(t *testing.T) {
tests := []struct {
name string
params map[string]any
payload any
errorString string
}{
{
name: "no type param",
params: map[string]any{},
payload: midi.NoteOn(1, 60, 127),
errorString: "midi.message.filter requires a type parameter",
},
{
name: "non-string type param",
params: map[string]any{
"type": 123,
},
payload: "hello",
errorString: "midi.message.filter type must be a string",
},
{
name: "non-midi message input",
params: map[string]any{
"type": "NoteOn",
},
payload: []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f},
errorString: "midi.message.filter processor only accepts a midi.Message",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["midi.message.filter"]
if !ok {
t.Fatalf("midi.message.filter processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "midi.message.filter",
Params: test.params,
})
if err != nil {
if test.errorString != err.Error() {
t.Fatalf("midi.message.filter got error '%s', expected '%s'", err.Error(), test.errorString)
}
return
}
got, err := processorInstance.Process(t.Context(), test.payload)
if err == nil {
t.Fatalf("midi.message.filter expected to fail but got payload: %s", got)
}
if err.Error() != test.errorString {
t.Fatalf("midi.message.filter got error '%s', expected '%s'", err.Error(), test.errorString)
}
})
}
}

View File

@@ -3,7 +3,6 @@ package processor_test
import ( import (
"testing" "testing"
"github.com/expr-lang/expr"
"github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/config"
"github.com/jwetzell/showbridge-go/internal/processor" "github.com/jwetzell/showbridge-go/internal/processor"
) )
@@ -83,14 +82,16 @@ func TestScriptExprBadConfigNonCompilingExpression(t *testing.T) {
func TestGoodScriptExpr(t *testing.T) { func TestGoodScriptExpr(t *testing.T) {
tests := []struct { tests := []struct {
program string
name string name string
params map[string]any
payload map[string]any payload map[string]any
expected any expected any
}{ }{
{ {
program: "foo + bar", name: "number",
name: "number", params: map[string]any{
"expression": "foo + bar",
},
payload: map[string]any{ payload: map[string]any{
"foo": 1, "foo": 1,
"bar": 1, "bar": 1,
@@ -98,8 +99,10 @@ func TestGoodScriptExpr(t *testing.T) {
expected: 2, expected: 2,
}, },
{ {
program: "foo + bar", name: "string",
name: "string", params: map[string]any{
"expression": "foo + bar",
},
payload: map[string]any{ payload: map[string]any{
"foo": "1", "foo": "1",
"bar": "1", "bar": "1",
@@ -110,14 +113,21 @@ func TestGoodScriptExpr(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
program, err := expr.Compile(test.program) registration, ok := processor.ProcessorRegistry["script.expr"]
if err != nil { if !ok {
t.Fatalf("script.expr failed to compile program: %s", err) t.Fatalf("script.expr processor not registered")
} }
exprProcessor := &processor.ScriptExpr{Program: program} processorInstance, err := registration.New(config.ProcessorConfig{
Type: "script.expr",
Params: test.params,
})
got, err := exprProcessor.Process(t.Context(), test.payload) if err != nil {
t.Fatalf("script.expr failed to create processor: %s", err)
}
got, err := processorInstance.Process(t.Context(), test.payload)
if err != nil { if err != nil {
t.Fatalf("script.expr failed: %s", err) t.Fatalf("script.expr failed: %s", err)
@@ -133,14 +143,16 @@ func TestGoodScriptExpr(t *testing.T) {
func TestBadScriptExpr(t *testing.T) { func TestBadScriptExpr(t *testing.T) {
tests := []struct { tests := []struct {
program string
name string name string
params map[string]any
payload map[string]any payload map[string]any
errorString string errorString string
}{ }{
{ {
name: "accessing missing field", name: "accessing missing field",
program: "foo + bar", params: map[string]any{
"expression": "foo + bar",
},
payload: map[string]any{ payload: map[string]any{
"foo": 1, "foo": 1,
}, },
@@ -150,14 +162,17 @@ func TestBadScriptExpr(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
program, err := expr.Compile(test.program) registration, ok := processor.ProcessorRegistry["script.expr"]
if err != nil { if !ok {
t.Fatalf("script.expr failed to compile program: %s", err) t.Fatalf("script.expr processor not registered")
} }
exprProcessor := &processor.ScriptExpr{Program: program} processorInstance, err := registration.New(config.ProcessorConfig{
Type: "script.expr",
Params: test.params,
})
got, err := exprProcessor.Process(t.Context(), test.payload) got, err := processorInstance.Process(t.Context(), test.payload)
if err == nil { if err == nil {
t.Fatalf("script.expr expected to fail but succeeded, got: %v", got) t.Fatalf("script.expr expected to fail but succeeded, got: %v", got)

View File

@@ -79,40 +79,48 @@ func TestScriptJSBadConfigWrongProgramType(t *testing.T) {
func TestGoodScriptJS(t *testing.T) { func TestGoodScriptJS(t *testing.T) {
tests := []struct { tests := []struct {
processor processor.Processor name string
name string params map[string]any
payload any payload any
expected any expected any
}{ }{
{ {
name: "number", name: "number",
processor: &processor.ScriptJS{Program: ` params: map[string]any{
payload = payload + 1 "program": `
`}, payload = payload + 1
`,
},
payload: 1, payload: 1,
expected: 2, expected: 2,
}, },
{ {
name: "string", name: "string",
processor: &processor.ScriptJS{Program: ` params: map[string]any{
payload = payload + "1" "program": `
`}, payload = payload + "1"
`,
},
payload: "1", payload: "1",
expected: "11", expected: "11",
}, },
{ {
name: "object", name: "object",
processor: &processor.ScriptJS{Program: ` params: map[string]any{
payload = { key: payload } "program": `
`}, payload = { key: payload }
`,
},
payload: "1", payload: "1",
expected: map[string]any{"key": "1"}, expected: map[string]any{"key": "1"},
}, },
{ {
name: "nil", name: "nil",
processor: &processor.ScriptJS{Program: ` params: map[string]any{
payload = undefined "program": `
`}, payload = undefined
`,
},
payload: "1", payload: "1",
expected: nil, expected: nil,
}, },
@@ -120,7 +128,21 @@ func TestGoodScriptJS(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
got, err := test.processor.Process(t.Context(), test.payload) registration, ok := processor.ProcessorRegistry["script.js"]
if !ok {
t.Fatalf("script.js processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "script.js",
Params: test.params,
})
if err != nil {
t.Fatalf("script.js failed to create processor: %s", err)
}
got, err := processorInstance.Process(t.Context(), test.payload)
if err != nil { if err != nil {
t.Fatalf("script.js process failed: %s", err) t.Fatalf("script.js process failed: %s", err)
@@ -151,13 +173,17 @@ func TestGoodScriptJS(t *testing.T) {
func TestBadScriptJS(t *testing.T) { func TestBadScriptJS(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
processor processor.Processor params map[string]any
payload any payload any
errorString string errorString string
}{ }{
{ {
name: "accessing not defined variable", name: "accessing not defined variable",
processor: &processor.ScriptJS{Program: `paylod = foo`}, params: map[string]any{
"program": `
paylod = foo
`,
},
payload: 0, payload: 0,
errorString: "ReferenceError: 'foo' is not defined", errorString: "ReferenceError: 'foo' is not defined",
}, },
@@ -165,7 +191,17 @@ func TestBadScriptJS(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
got, err := test.processor.Process(t.Context(), test.payload) registration, ok := processor.ProcessorRegistry["script.js"]
if !ok {
t.Fatalf("script.js processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "script.js",
Params: test.params,
})
got, err := processorInstance.Process(t.Context(), test.payload)
if err == nil { if err == nil {
t.Fatalf("script.js expected to fail but succeeded, got: %v", got) t.Fatalf("script.js expected to fail but succeeded, got: %v", got)

View File

@@ -2,7 +2,6 @@ package processor_test
import ( import (
"testing" "testing"
"text/template"
"github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/config"
"github.com/jwetzell/showbridge-go/internal/processor" "github.com/jwetzell/showbridge-go/internal/processor"
@@ -53,37 +52,37 @@ func TestGoodStringCreate(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
template string params map[string]any
payload any payload any
expected string expected string
}{ }{
{ {
name: "string payload", name: "string payload",
template: "{{.}}", params: map[string]any{"template": "{{.}}"},
payload: "hello", payload: "hello",
expected: "hello", expected: "hello",
}, },
{ {
name: "number payload", name: "number payload",
template: "{{.}}", params: map[string]any{"template": "{{.}}"},
payload: 4, payload: 4,
expected: "4", expected: "4",
}, },
{ {
name: "boolean payload", name: "boolean payload",
template: "{{.}}", params: map[string]any{"template": "{{.}}"},
payload: true, payload: true,
expected: "true", expected: "true",
}, },
{ {
name: "struct payload - field", name: "struct payload - field",
template: "{{.Data}}", params: map[string]any{"template": "{{.Data}}"},
payload: TestStruct{Data: "test"}, payload: TestStruct{Data: "test"},
expected: "test", expected: "test",
}, },
{ {
name: "struct payload - method", name: "struct payload - method",
template: "{{.GetData}}", params: map[string]any{"template": "{{.GetData}}"},
payload: TestStruct{Data: "test"}, payload: TestStruct{Data: "test"},
expected: "test", expected: "test",
}, },
@@ -91,14 +90,21 @@ func TestGoodStringCreate(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
template, err := template.New("template").Parse(test.template) registration, ok := processor.ProcessorRegistry["string.create"]
if err != nil { if !ok {
t.Fatalf("string.create template parsing failed: %s", err) t.Fatalf("string.create processor not registered")
} }
processor := &processor.StringCreate{Template: template} processorInstance, err := registration.New(config.ProcessorConfig{
Type: "string.create",
Params: test.params,
})
got, err := processor.Process(t.Context(), test.payload) if err != nil {
t.Fatalf("string.create failed to create processor: %s", err)
}
got, err := processorInstance.Process(t.Context(), test.payload)
gotStrings, ok := got.(string) gotStrings, ok := got.(string)
if !ok { if !ok {

View File

@@ -118,8 +118,8 @@ func TestGoodStringFilter(t *testing.T) {
func TestBadStringFilter(t *testing.T) { func TestBadStringFilter(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
payload any
params map[string]any params map[string]any
payload any
errorString string errorString string
}{ }{
{ {

View File

@@ -49,22 +49,36 @@ func TestStringSplitFromRegistry(t *testing.T) {
func TestGoodStringSplit(t *testing.T) { func TestGoodStringSplit(t *testing.T) {
tests := []struct { tests := []struct {
processor processor.Processor name string
name string params map[string]any
payload any payload any
expected []string expected []string
}{ }{
{ {
processor: &processor.StringSplit{Separator: ","}, name: "comma separated",
name: "comma separated", params: map[string]any{"separator": ","},
payload: "part1,part2,part3", payload: "part1,part2,part3",
expected: []string{"part1", "part2", "part3"}, expected: []string{"part1", "part2", "part3"},
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
got, err := test.processor.Process(t.Context(), test.payload) registration, ok := processor.ProcessorRegistry["string.split"]
if !ok {
t.Fatalf("string.split processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "string.split",
Params: test.params,
})
if err != nil {
t.Fatalf("string.split failed to create processor: %s", err)
}
got, err := processorInstance.Process(t.Context(), test.payload)
gotStrings, ok := got.([]string) gotStrings, ok := got.([]string)
if !ok { if !ok {

View File

@@ -28,3 +28,36 @@ func TestTimeSleepFromRegistry(t *testing.T) {
t.Fatalf("time.sleep processor has wrong type: %s", processorInstance.Type()) t.Fatalf("time.sleep processor has wrong type: %s", processorInstance.Type())
} }
} }
func TestBadTimeSleep(t *testing.T) {
tests := []struct {
name string
params map[string]any
payload any
errorString string
}{}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["time.sleep"]
if !ok {
t.Fatalf("time.sleep processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "time.sleep",
Params: test.params,
})
got, err := processorInstance.Process(t.Context(), test.payload)
if err == nil {
t.Fatalf("time.sleep expected to fail but succeeded, got: %v", got)
}
if err.Error() != test.errorString {
t.Fatalf("time.sleep got error '%s', expected '%s'", err.Error(), test.errorString)
}
})
}
}

View File

@@ -101,50 +101,54 @@ func TestUintParseGoodConfig(t *testing.T) {
func TestGoodUintParse(t *testing.T) { func TestGoodUintParse(t *testing.T) {
tests := []struct { tests := []struct {
processor processor.Processor name string
name string params map[string]any
payload any payload any
expected uint64 expected uint64
base int
bitSize int
}{ }{
{ {
name: "positive number", name: "positive number",
params: map[string]any{"base": 10.0, "bitSize": 64.0},
payload: "12345", payload: "12345",
expected: 12345, expected: 12345,
base: 10,
bitSize: 64,
}, },
{ {
name: "zero", name: "zero",
params: map[string]any{"base": 10.0, "bitSize": 64.0},
payload: "0", payload: "0",
expected: 0, expected: 0,
base: 10,
bitSize: 64,
}, },
{ {
name: "binary", name: "binary",
params: map[string]any{"base": 2.0, "bitSize": 64.0},
payload: "1010101", payload: "1010101",
expected: 85, expected: 85,
base: 2,
bitSize: 64,
}, },
{ {
name: "hex", name: "hex",
params: map[string]any{"base": 16.0, "bitSize": 64.0},
payload: "15F", payload: "15F",
expected: 351, expected: 351,
base: 16,
bitSize: 64,
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
uintParser := processor.UintParse{ registration, ok := processor.ProcessorRegistry["uint.parse"]
Base: test.base, if !ok {
BitSize: test.bitSize, t.Fatalf("uint.parse processor not registered")
} }
got, err := uintParser.Process(t.Context(), test.payload)
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "uint.parse",
Params: test.params,
})
if err != nil {
t.Fatalf("uint.parse failed to create processor: %s", err)
}
got, err := processorInstance.Process(t.Context(), test.payload)
gotUint, ok := got.(uint64) gotUint, ok := got.(uint64)
if !ok { if !ok {
@@ -161,41 +165,45 @@ func TestGoodUintParse(t *testing.T) {
} }
func TestBadUintParse(t *testing.T) { func TestBadUintParse(t *testing.T) {
uintParser := processor.UintParse{}
tests := []struct { tests := []struct {
processor processor.Processor
name string name string
params map[string]any
payload any payload any
base int
bitSize int
errorString string errorString string
}{ }{
{ {
name: "non-string input", name: "non-string input",
params: map[string]any{"base": 10.0, "bitSize": 64.0},
payload: []byte{0x01}, payload: []byte{0x01},
base: 10,
bitSize: 64,
errorString: "uint.parse processor only accepts a string", errorString: "uint.parse processor only accepts a string",
}, },
{ {
name: "not uint string", name: "not uint string",
params: map[string]any{"base": 10.0, "bitSize": 64.0},
payload: "-1234", payload: "-1234",
base: 10,
bitSize: 64,
errorString: "strconv.ParseUint: parsing \"-1234\": invalid syntax", errorString: "strconv.ParseUint: parsing \"-1234\": invalid syntax",
}, },
{ {
name: "bit overflow", name: "bit overflow",
params: map[string]any{"base": 10.0, "bitSize": 32.0},
payload: "123456789012345678901234567", payload: "123456789012345678901234567",
base: 10,
bitSize: 32,
errorString: "strconv.ParseUint: parsing \"123456789012345678901234567\": value out of range", errorString: "strconv.ParseUint: parsing \"123456789012345678901234567\": value out of range",
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
got, err := uintParser.Process(t.Context(), test.payload) registration, ok := processor.ProcessorRegistry["uint.parse"]
if !ok {
t.Fatalf("uint.parse processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "uint.parse",
Params: test.params,
})
got, err := processorInstance.Process(t.Context(), test.payload)
if err == nil { if err == nil {
t.Fatalf("uint.parse expected to fail but succeeded, got: %v", got) t.Fatalf("uint.parse expected to fail but succeeded, got: %v", got)

View File

@@ -68,27 +68,34 @@ func TestUintRandomGoodConfig(t *testing.T) {
func TestGoodUintRandom(t *testing.T) { func TestGoodUintRandom(t *testing.T) {
tests := []struct { tests := []struct {
processor processor.Processor name string
name string params map[string]any
payload any payload any
min uint
max uint
}{ }{
{ {
name: "1-10", name: "1-10",
params: map[string]any{"min": 1.0, "max": 10.0},
payload: "12345", payload: "12345",
min: 1,
max: 10,
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
uintRandom := processor.UintRandom{ registration, ok := processor.ProcessorRegistry["uint.random"]
Min: test.min, if !ok {
Max: test.max, t.Fatalf("uint.random processor not registered")
} }
got, err := uintRandom.Process(t.Context(), test.payload)
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "uint.random",
Params: test.params,
})
if err != nil {
t.Fatalf("uint.random failed to create processor: %s", err)
}
got, err := processorInstance.Process(t.Context(), test.payload)
gotUint, ok := got.(uint) gotUint, ok := got.(uint)
if !ok { if !ok {
@@ -97,8 +104,16 @@ func TestGoodUintRandom(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("uint.random failed: %s", err) t.Fatalf("uint.random failed: %s", err)
} }
if gotUint < test.min || gotUint > test.max { minNum, ok := test.params["min"].(float64)
t.Fatalf("uint.random got %d, expected between %d and %d", gotUint, test.min, test.max) if !ok {
t.Fatalf("uint.random test min param is not a number")
}
maxNum, ok := test.params["max"].(float64)
if !ok {
t.Fatalf("uint.random test max param is not a number")
}
if gotUint < uint(minNum) || gotUint > uint(maxNum) {
t.Fatalf("uint.random got %d, expected between %d and %d", gotUint, uint(minNum), uint(maxNum))
} }
}) })
} }