package models import ( "encoding/xml" "strings" "testing" ) func TestAudioDSPControls_GetSupportedAudioModes(t *testing.T) { tests := []struct { name string supportedModes string expected []string }{ { name: "multiple modes", supportedModes: "NORMAL|DIALOG|SURROUND|MUSIC", expected: []string{"NORMAL", "DIALOG", "SURROUND", "MUSIC"}, }, { name: "single mode", supportedModes: "NORMAL", expected: []string{"NORMAL"}, }, { name: "empty modes", supportedModes: "", expected: []string{}, }, { name: "modes with spaces", supportedModes: "NORMAL|DIALOG CLEAR|MUSIC", expected: []string{"NORMAL", "DIALOG CLEAR", "MUSIC"}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { dsp := AudioDSPControls{ SupportedAudioModes: tt.supportedModes, } result := dsp.GetSupportedAudioModes() if len(result) != len(tt.expected) { t.Errorf("Expected %d modes, got %d", len(tt.expected), len(result)) return } for i, expected := range tt.expected { if result[i] != expected { t.Errorf("Expected mode %d to be '%s', got '%s'", i, expected, result[i]) } } }) } } func TestAudioDSPControls_IsAudioModeSupported(t *testing.T) { dsp := AudioDSPControls{ SupportedAudioModes: "NORMAL|DIALOG|SURROUND|MUSIC", } tests := []struct { mode string expected bool }{ {"NORMAL", true}, {"DIALOG", true}, {"SURROUND", true}, {"MUSIC", true}, {"MOVIE", false}, {"INVALID", false}, {"", false}, {"normal", false}, // Case sensitive } for _, tt := range tests { t.Run(tt.mode, func(t *testing.T) { result := dsp.IsAudioModeSupported(tt.mode) if result != tt.expected { t.Errorf("Expected IsAudioModeSupported('%s') to be %v, got %v", tt.mode, tt.expected, result) } }) } } func TestAudioDSPControls_String(t *testing.T) { dsp := AudioDSPControls{ AudioMode: "MUSIC", VideoSyncAudioDelay: 50, SupportedAudioModes: "NORMAL|DIALOG|MUSIC", } result := dsp.String() expected := "Audio Mode: MUSIC, Video Sync Delay: 50 ms, Supported Modes: [NORMAL, DIALOG, MUSIC]" if result != expected { t.Errorf("Expected string representation '%s', got '%s'", expected, result) } } func TestAudioDSPControlsRequest_Validate(t *testing.T) { capabilities := &AudioDSPControls{ SupportedAudioModes: "NORMAL|DIALOG|MUSIC", } tests := []struct { name string request *AudioDSPControlsRequest expectError bool errorMsg string }{ { name: "valid audio mode", request: &AudioDSPControlsRequest{ AudioMode: "MUSIC", }, expectError: false, }, { name: "invalid audio mode", request: &AudioDSPControlsRequest{ AudioMode: "INVALID", }, expectError: true, errorMsg: "audio mode 'INVALID' is not supported", }, { name: "negative video sync delay", request: &AudioDSPControlsRequest{ VideoSyncAudioDelay: -10, }, expectError: true, errorMsg: "video sync audio delay cannot be negative", }, { name: "valid video sync delay", request: &AudioDSPControlsRequest{ VideoSyncAudioDelay: 100, }, expectError: false, }, { name: "valid combined request", request: &AudioDSPControlsRequest{ AudioMode: "DIALOG", VideoSyncAudioDelay: 25, }, expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.request.Validate(capabilities) if tt.expectError { if err == nil { t.Errorf("Expected error but got none") return } if !strings.Contains(err.Error(), tt.errorMsg) { t.Errorf("Expected error message to contain '%s', got '%s'", tt.errorMsg, err.Error()) } } else { if err != nil { t.Errorf("Expected no error but got: %v", err) } } }) } } func TestToneControlSetting_ValidateBass(t *testing.T) { setting := BassControlSetting{ MinValue: -10, MaxValue: 10, } tests := []struct { value int expectError bool }{ {0, false}, {-10, false}, {10, false}, {5, false}, {-5, false}, {-11, true}, {11, true}, {100, true}, {-100, true}, } for _, tt := range tests { t.Run(string(rune(tt.value)), func(t *testing.T) { err := setting.ValidateBass(tt.value) if tt.expectError { if err == nil { t.Errorf("Expected error for value %d but got none", tt.value) } } else { if err != nil { t.Errorf("Expected no error for value %d but got: %v", tt.value, err) } } }) } } func TestToneControlSetting_ClampValue(t *testing.T) { setting := TrebleControlSetting{ MinValue: -5, MaxValue: 5, } tests := []struct { input int expected int }{ {0, 0}, {3, 3}, {-3, -3}, {5, 5}, {-5, -5}, {10, 5}, {-10, -5}, {100, 5}, {-100, -5}, } for _, tt := range tests { t.Run(string(rune(tt.input)), func(t *testing.T) { result := setting.ClampValue(tt.input) if result != tt.expected { t.Errorf("Expected ClampValue(%d) to be %d, got %d", tt.input, tt.expected, result) } }) } } func TestAudioProductToneControls_String(t *testing.T) { controls := AudioProductToneControls{ Bass: BassControlSetting{ Value: 3, MinValue: -10, MaxValue: 10, }, Treble: TrebleControlSetting{ Value: -2, MinValue: -10, MaxValue: 10, }, } result := controls.String() expected := "Bass: 3 [-10-10], Treble: -2 [-10-10]" if result != expected { t.Errorf("Expected string representation '%s', got '%s'", expected, result) } } func TestAudioProductToneControlsRequest_Validate(t *testing.T) { capabilities := &AudioProductToneControls{ Bass: BassControlSetting{ MinValue: -10, MaxValue: 10, }, Treble: TrebleControlSetting{ MinValue: -5, MaxValue: 5, }, } tests := []struct { name string request *AudioProductToneControlsRequest expectError bool errorMsg string }{ { name: "valid bass only", request: &AudioProductToneControlsRequest{ Bass: NewBassControlValue(5), }, expectError: false, }, { name: "valid treble only", request: &AudioProductToneControlsRequest{ Treble: NewTrebleControlValue(3), }, expectError: false, }, { name: "invalid bass value", request: &AudioProductToneControlsRequest{ Bass: NewBassControlValue(15), }, expectError: true, errorMsg: "bass value 15 is outside valid range", }, { name: "invalid treble value", request: &AudioProductToneControlsRequest{ Treble: NewTrebleControlValue(-10), }, expectError: true, errorMsg: "treble value -10 is outside valid range", }, { name: "valid combined request", request: &AudioProductToneControlsRequest{ Bass: NewBassControlValue(-5), Treble: NewTrebleControlValue(2), }, expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.request.Validate(capabilities) if tt.expectError { if err == nil { t.Errorf("Expected error but got none") return } if !strings.Contains(err.Error(), tt.errorMsg) { t.Errorf("Expected error message to contain '%s', got '%s'", tt.errorMsg, err.Error()) } } else { if err != nil { t.Errorf("Expected no error but got: %v", err) } } }) } } func TestNewBassControlValue(t *testing.T) { value := NewBassControlValue(5) if value.Value != 5 { t.Errorf("Expected value 5, got %d", value.Value) } if value.XMLName.Local != "bass" { t.Errorf("Expected XMLName.Local to be 'bass', got '%s'", value.XMLName.Local) } } func TestNewTrebleControlValue(t *testing.T) { value := NewTrebleControlValue(-3) if value.Value != -3 { t.Errorf("Expected value -3, got %d", value.Value) } if value.XMLName.Local != "treble" { t.Errorf("Expected XMLName.Local to be 'treble', got '%s'", value.XMLName.Local) } } func TestAudioProductLevelControls_String(t *testing.T) { controls := AudioProductLevelControls{ FrontCenterSpeakerLevel: FrontCenterLevelSetting{ Value: 2, MinValue: -10, MaxValue: 10, }, RearSurroundSpeakersLevel: RearSurroundLevelSetting{ Value: -1, MinValue: -10, MaxValue: 10, }, } result := controls.String() expected := "Front-Center: 2 [-10-10], Rear-Surround: -1 [-10-10]" if result != expected { t.Errorf("Expected string representation '%s', got '%s'", expected, result) } } func TestAudioProductLevelControlsRequest_Validate(t *testing.T) { capabilities := &AudioProductLevelControls{ FrontCenterSpeakerLevel: FrontCenterLevelSetting{ MinValue: -5, MaxValue: 5, }, RearSurroundSpeakersLevel: RearSurroundLevelSetting{ MinValue: -8, MaxValue: 8, }, } tests := []struct { name string request *AudioProductLevelControlsRequest expectError bool errorMsg string }{ { name: "valid front center only", request: &AudioProductLevelControlsRequest{ FrontCenterSpeakerLevel: NewFrontCenterLevelValue(3), }, expectError: false, }, { name: "valid rear surround only", request: &AudioProductLevelControlsRequest{ RearSurroundSpeakersLevel: NewRearSurroundLevelValue(-4), }, expectError: false, }, { name: "invalid front center value", request: &AudioProductLevelControlsRequest{ FrontCenterSpeakerLevel: NewFrontCenterLevelValue(10), }, expectError: true, errorMsg: "speaker level 10 is outside valid range", }, { name: "invalid rear surround value", request: &AudioProductLevelControlsRequest{ RearSurroundSpeakersLevel: NewRearSurroundLevelValue(-15), }, expectError: true, errorMsg: "speaker level -15 is outside valid range", }, { name: "valid combined request", request: &AudioProductLevelControlsRequest{ FrontCenterSpeakerLevel: NewFrontCenterLevelValue(-2), RearSurroundSpeakersLevel: NewRearSurroundLevelValue(5), }, expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.request.Validate(capabilities) if tt.expectError { if err == nil { t.Errorf("Expected error but got none") return } if !strings.Contains(err.Error(), tt.errorMsg) { t.Errorf("Expected error message to contain '%s', got '%s'", tt.errorMsg, err.Error()) } } else { if err != nil { t.Errorf("Expected no error but got: %v", err) } } }) } } func TestNewFrontCenterLevelValue(t *testing.T) { value := NewFrontCenterLevelValue(3) if value.Value != 3 { t.Errorf("Expected value 3, got %d", value.Value) } if value.XMLName.Local != "frontCenterSpeakerLevel" { t.Errorf("Expected XMLName.Local to be 'frontCenterSpeakerLevel', got '%s'", value.XMLName.Local) } } func TestNewRearSurroundLevelValue(t *testing.T) { value := NewRearSurroundLevelValue(-2) if value.Value != -2 { t.Errorf("Expected value -2, got %d", value.Value) } if value.XMLName.Local != "rearSurroundSpeakersLevel" { t.Errorf("Expected XMLName.Local to be 'rearSurroundSpeakersLevel', got '%s'", value.XMLName.Local) } } func TestAudioCapabilities_HasAdvancedAudioControls(t *testing.T) { tests := []struct { name string capabilities AudioCapabilities expected bool }{ { name: "no controls", capabilities: AudioCapabilities{ DSPControls: false, ProductToneControls: false, ProductLevelControls: false, }, expected: false, }, { name: "dsp controls only", capabilities: AudioCapabilities{ DSPControls: true, ProductToneControls: false, ProductLevelControls: false, }, expected: true, }, { name: "tone controls only", capabilities: AudioCapabilities{ DSPControls: false, ProductToneControls: true, ProductLevelControls: false, }, expected: true, }, { name: "level controls only", capabilities: AudioCapabilities{ DSPControls: false, ProductToneControls: false, ProductLevelControls: true, }, expected: true, }, { name: "all controls", capabilities: AudioCapabilities{ DSPControls: true, ProductToneControls: true, ProductLevelControls: true, }, expected: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := tt.capabilities.HasAdvancedAudioControls() if result != tt.expected { t.Errorf("Expected HasAdvancedAudioControls() to be %v, got %v", tt.expected, result) } }) } } func TestAudioCapabilities_GetAvailableControls(t *testing.T) { tests := []struct { name string capabilities AudioCapabilities expected []string }{ { name: "no controls", capabilities: AudioCapabilities{ DSPControls: false, ProductToneControls: false, ProductLevelControls: false, }, expected: []string{}, }, { name: "dsp controls only", capabilities: AudioCapabilities{ DSPControls: true, ProductToneControls: false, ProductLevelControls: false, }, expected: []string{"DSP Controls"}, }, { name: "all controls", capabilities: AudioCapabilities{ DSPControls: true, ProductToneControls: true, ProductLevelControls: true, }, expected: []string{"DSP Controls", "Tone Controls", "Level Controls"}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := tt.capabilities.GetAvailableControls() if len(result) != len(tt.expected) { t.Errorf("Expected %d controls, got %d", len(tt.expected), len(result)) return } for i, expected := range tt.expected { if result[i] != expected { t.Errorf("Expected control %d to be '%s', got '%s'", i, expected, result[i]) } } }) } } func TestAudioCapabilities_String(t *testing.T) { tests := []struct { name string capabilities AudioCapabilities expected string }{ { name: "no controls", capabilities: AudioCapabilities{ DSPControls: false, ProductToneControls: false, ProductLevelControls: false, }, expected: "No advanced audio controls available", }, { name: "single control", capabilities: AudioCapabilities{ DSPControls: true, ProductToneControls: false, ProductLevelControls: false, }, expected: "Available controls: DSP Controls", }, { name: "multiple controls", capabilities: AudioCapabilities{ DSPControls: true, ProductToneControls: true, ProductLevelControls: false, }, expected: "Available controls: DSP Controls, Tone Controls", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := tt.capabilities.String() if result != tt.expected { t.Errorf("Expected string representation '%s', got '%s'", tt.expected, result) } }) } } func TestAudioDSPControls_XMLMarshaling(t *testing.T) { controls := AudioDSPControls{ AudioMode: "MUSIC", VideoSyncAudioDelay: 50, SupportedAudioModes: "NORMAL|DIALOG|MUSIC", } xmlData, err := xml.Marshal(controls) if err != nil { t.Fatalf("Failed to marshal XML: %v", err) } xmlStr := string(xmlData) if !strings.Contains(xmlStr, `audiomode="MUSIC"`) { t.Error("Expected XML to contain audiomode attribute") } if !strings.Contains(xmlStr, `videosyncaudiodelay="50"`) { t.Error("Expected XML to contain videosyncaudiodelay attribute") } if !strings.Contains(xmlStr, `supportedaudiomodes="NORMAL|DIALOG|MUSIC"`) { t.Error("Expected XML to contain supportedaudiomodes attribute") } } func TestAudioProductToneControls_XMLMarshaling(t *testing.T) { controls := AudioProductToneControls{ Bass: BassControlSetting{ XMLName: xml.Name{Local: "bass"}, Value: 3, MinValue: -10, MaxValue: 10, Step: 1, }, Treble: TrebleControlSetting{ XMLName: xml.Name{Local: "treble"}, Value: -2, MinValue: -5, MaxValue: 5, Step: 1, }, } xmlData, err := xml.Marshal(controls) if err != nil { t.Fatalf("Failed to marshal XML: %v", err) } xmlStr := string(xmlData) if !strings.Contains(xmlStr, ``) { t.Error("Expected XML to contain bass element with correct attributes") } if !strings.Contains(xmlStr, ``) { t.Error("Expected XML to contain treble element with correct attributes") } } func TestAudioProductLevelControls_XMLMarshaling(t *testing.T) { controls := AudioProductLevelControls{ FrontCenterSpeakerLevel: FrontCenterLevelSetting{ XMLName: xml.Name{Local: "frontCenterSpeakerLevel"}, Value: 2, MinValue: -10, MaxValue: 10, Step: 1, }, RearSurroundSpeakersLevel: RearSurroundLevelSetting{ XMLName: xml.Name{Local: "rearSurroundSpeakersLevel"}, Value: -1, MinValue: -8, MaxValue: 8, Step: 1, }, } xmlData, err := xml.Marshal(controls) if err != nil { t.Fatalf("Failed to marshal XML: %v", err) } xmlStr := string(xmlData) if !strings.Contains(xmlStr, ``) { t.Error("Expected XML to contain frontCenterSpeakerLevel element with correct attributes") } if !strings.Contains(xmlStr, ``) { t.Error("Expected XML to contain rearSurroundSpeakersLevel element with correct attributes") } }