diff --git a/pkg/models/balance_marshal_test.go b/pkg/models/balance_marshal_test.go
new file mode 100644
index 0000000..8386847
--- /dev/null
+++ b/pkg/models/balance_marshal_test.go
@@ -0,0 +1,129 @@
+package models
+
+import (
+ "encoding/xml"
+ "strings"
+ "testing"
+)
+
+func TestBalanceMarshalXML(t *testing.T) {
+ balance := Balance{
+ DeviceID: "1234567890AB",
+ TargetBalance: -25,
+ ActualBalance: -25,
+ }
+
+ var buf strings.Builder
+ encoder := xml.NewEncoder(&buf)
+ err := balance.MarshalXML(encoder, xml.StartElement{Name: xml.Name{Local: "balance"}})
+ if err != nil {
+ t.Fatalf("MarshalXML failed: %v", err)
+ }
+ encoder.Flush()
+
+ // Convert to string for easier testing
+ xmlStr := buf.String()
+
+ // Check that XML contains expected elements
+ expectedElements := []string{
+ `deviceID="1234567890AB"`,
+ `-25`,
+ `-25`,
+ }
+
+ for _, expected := range expectedElements {
+ if !strings.Contains(xmlStr, expected) {
+ t.Errorf("MarshalXML result %q does not contain expected element %q", xmlStr, expected)
+ }
+ }
+}
+
+func TestBalanceMarshalXML_PositiveValue(t *testing.T) {
+ balance := Balance{
+ DeviceID: "ABCDEF123456",
+ TargetBalance: 30,
+ ActualBalance: 30,
+ }
+
+ var buf strings.Builder
+ encoder := xml.NewEncoder(&buf)
+ err := balance.MarshalXML(encoder, xml.StartElement{Name: xml.Name{Local: "balance"}})
+ if err != nil {
+ t.Fatalf("MarshalXML failed: %v", err)
+ }
+ encoder.Flush()
+
+ xmlStr := buf.String()
+
+ expectedElements := []string{
+ `deviceID="ABCDEF123456"`,
+ `30`,
+ `30`,
+ }
+
+ for _, expected := range expectedElements {
+ if !strings.Contains(xmlStr, expected) {
+ t.Errorf("MarshalXML result %q does not contain expected element %q", xmlStr, expected)
+ }
+ }
+}
+
+func TestBalanceMarshalXML_ZeroValue(t *testing.T) {
+ balance := Balance{
+ DeviceID: "ZERO0000TEST",
+ TargetBalance: 0,
+ ActualBalance: 0,
+ }
+
+ var buf strings.Builder
+ encoder := xml.NewEncoder(&buf)
+ err := balance.MarshalXML(encoder, xml.StartElement{Name: xml.Name{Local: "balance"}})
+ if err != nil {
+ t.Fatalf("MarshalXML failed: %v", err)
+ }
+ encoder.Flush()
+
+ xmlStr := buf.String()
+
+ expectedElements := []string{
+ `deviceID="ZERO0000TEST"`,
+ `0`,
+ `0`,
+ }
+
+ for _, expected := range expectedElements {
+ if !strings.Contains(xmlStr, expected) {
+ t.Errorf("MarshalXML result %q does not contain expected element %q", xmlStr, expected)
+ }
+ }
+}
+
+func TestBalanceMarshalXML_ExtremeValues(t *testing.T) {
+ balance := Balance{
+ DeviceID: "EXTREME_TEST",
+ TargetBalance: -50, // Min value
+ ActualBalance: 50, // Max value
+ }
+
+ var buf strings.Builder
+ encoder := xml.NewEncoder(&buf)
+ err := balance.MarshalXML(encoder, xml.StartElement{Name: xml.Name{Local: "balance"}})
+ if err != nil {
+ t.Fatalf("MarshalXML failed: %v", err)
+ }
+ encoder.Flush()
+
+ xmlStr := buf.String()
+
+ expectedElements := []string{
+ `deviceID="EXTREME_TEST"`,
+ `-50`,
+ `50`,
+ }
+
+ for _, expected := range expectedElements {
+ if !strings.Contains(xmlStr, expected) {
+ t.Errorf("MarshalXML result %q does not contain expected element %q", xmlStr, expected)
+ }
+ }
+}
diff --git a/pkg/models/bass_utilities_test.go b/pkg/models/bass_utilities_test.go
new file mode 100644
index 0000000..23e4e3b
--- /dev/null
+++ b/pkg/models/bass_utilities_test.go
@@ -0,0 +1,247 @@
+package models
+
+import (
+ "encoding/xml"
+ "strings"
+ "testing"
+)
+
+func TestBassCapabilities_UtilityMethods(t *testing.T) {
+ t.Run("IsBassSupported", func(t *testing.T) {
+ tests := []struct {
+ name string
+ caps BassCapabilities
+ expected bool
+ }{
+ {
+ name: "Bass supported device",
+ caps: BassCapabilities{
+ DeviceID: "1234",
+ BassMin: -9,
+ BassMax: 9,
+ BassDefault: 0,
+ BassAvailable: true,
+ },
+ expected: true,
+ },
+ {
+ name: "Bass not supported device",
+ caps: BassCapabilities{
+ DeviceID: "5678",
+ BassMin: 0,
+ BassMax: 0,
+ BassDefault: 0,
+ BassAvailable: false,
+ },
+ expected: false,
+ },
+ {
+ name: "Bass not available",
+ caps: BassCapabilities{
+ DeviceID: "9999",
+ BassMin: -9,
+ BassMax: 9,
+ BassDefault: 0,
+ BassAvailable: false,
+ },
+ expected: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ result := tt.caps.IsBassSupported()
+ if result != tt.expected {
+ t.Errorf("IsBassSupported() = %v, expected %v", result, tt.expected)
+ }
+ })
+ }
+ })
+
+ t.Run("GetMinLevel", func(t *testing.T) {
+ caps := BassCapabilities{
+ DeviceID: "1234",
+ BassMin: -9,
+ BassMax: 9,
+ BassDefault: 0,
+ BassAvailable: true,
+ }
+
+ result := caps.GetMinLevel()
+ expected := -9
+
+ if result != expected {
+ t.Errorf("GetMinLevel() = %d, expected %d", result, expected)
+ }
+ })
+
+ t.Run("GetMaxLevel", func(t *testing.T) {
+ caps := BassCapabilities{
+ DeviceID: "1234",
+ BassMin: -9,
+ BassMax: 9,
+ BassDefault: 0,
+ BassAvailable: true,
+ }
+
+ result := caps.GetMaxLevel()
+ expected := 9
+
+ if result != expected {
+ t.Errorf("GetMaxLevel() = %d, expected %d", result, expected)
+ }
+ })
+
+ t.Run("GetDefaultLevel", func(t *testing.T) {
+ caps := BassCapabilities{
+ DeviceID: "1234",
+ BassMin: -9,
+ BassMax: 9,
+ BassDefault: 0,
+ BassAvailable: true,
+ }
+
+ result := caps.GetDefaultLevel()
+ expected := 0
+
+ if result != expected {
+ t.Errorf("GetDefaultLevel() = %d, expected %d", result, expected)
+ }
+ })
+
+ t.Run("ValidateLevel", func(t *testing.T) {
+ caps := BassCapabilities{
+ DeviceID: "1234",
+ BassMin: -9,
+ BassMax: 9,
+ BassDefault: 0,
+ BassAvailable: true,
+ }
+
+ tests := []struct {
+ name string
+ level int
+ expected bool
+ }{
+ {"Valid min level", -9, true},
+ {"Valid max level", 9, true},
+ {"Valid middle level", 0, true},
+ {"Valid positive level", 3, true},
+ {"Valid negative level", -5, true},
+ {"Invalid too low", -10, false},
+ {"Invalid too high", 10, false},
+ {"Invalid way too high", 100, false},
+ {"Invalid way too low", -100, false},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ result := caps.ValidateLevel(tt.level)
+ if result != tt.expected {
+ t.Errorf("ValidateLevel(%d) = %v, expected %v", tt.level, result, tt.expected)
+ }
+ })
+ }
+ })
+
+ t.Run("ClampLevel", func(t *testing.T) {
+ caps := BassCapabilities{
+ DeviceID: "1234",
+ BassMin: -9,
+ BassMax: 9,
+ BassDefault: 0,
+ BassAvailable: true,
+ }
+
+ tests := []struct {
+ name string
+ level int
+ expected int
+ }{
+ {"Valid level unchanged", 5, 5},
+ {"Valid min level unchanged", -9, -9},
+ {"Valid max level unchanged", 9, 9},
+ {"Too low clamped to min", -15, -9},
+ {"Too high clamped to max", 15, 9},
+ {"Way too low clamped", -100, -9},
+ {"Way too high clamped", 100, 9},
+ {"Zero unchanged", 0, 0},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ result := caps.ClampLevel(tt.level)
+ if result != tt.expected {
+ t.Errorf("ClampLevel(%d) = %d, expected %d", tt.level, result, tt.expected)
+ }
+ })
+ }
+ })
+
+ t.Run("String", func(t *testing.T) {
+ caps := BassCapabilities{
+ DeviceID: "TEST123",
+ BassMin: -9,
+ BassMax: 9,
+ BassDefault: 0,
+ BassAvailable: true,
+ }
+
+ result := caps.String()
+
+ // Check that the string contains expected information
+ expected := "Bass: -9 to 9 (default: 0)"
+ if result != expected {
+ t.Errorf("String() = %q, expected %q", result, expected)
+ }
+ })
+
+ t.Run("String for unsupported device", func(t *testing.T) {
+ caps := BassCapabilities{
+ DeviceID: "TEST456",
+ BassMin: 0,
+ BassMax: 0,
+ BassDefault: 0,
+ BassAvailable: false,
+ }
+
+ result := caps.String()
+ expected := "Bass control not supported"
+
+ if result != expected {
+ t.Errorf("String() for unsupported device = %q, expected %q", result, expected)
+ }
+ })
+}
+
+func TestBassMarshalXML(t *testing.T) {
+ bass := Bass{
+ DeviceID: "1234567890AB",
+ TargetBass: 5,
+ ActualBass: 5,
+ }
+
+ var buf strings.Builder
+ encoder := xml.NewEncoder(&buf)
+ err := bass.MarshalXML(encoder, xml.StartElement{Name: xml.Name{Local: "bass"}})
+ if err != nil {
+ t.Fatalf("MarshalXML failed: %v", err)
+ }
+ encoder.Flush()
+
+ // Convert to string for easier testing
+ xmlStr := buf.String()
+
+ // Check that XML contains expected elements
+ expectedElements := []string{
+ `deviceID="1234567890AB"`,
+ `5`,
+ `5`,
+ }
+
+ for _, expected := range expectedElements {
+ if !strings.Contains(xmlStr, expected) {
+ t.Errorf("MarshalXML result %q does not contain expected element %q", xmlStr, expected)
+ }
+ }
+}