package models import ( "encoding/xml" "fmt" "testing" ) func TestNewVolumeRequest(t *testing.T) { tests := []struct { name string volume int want int }{ { name: "zero volume", volume: 0, want: 0, }, { name: "medium volume", volume: 50, want: 50, }, { name: "max volume", volume: 100, want: 100, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { req := NewVolumeRequest(tt.volume) if req.Value != tt.want { t.Errorf("NewVolumeRequest() value = %d, want %d", req.Value, tt.want) } }) } } func TestVolumeRequestXMLMarshal(t *testing.T) { tests := []struct { name string volume int expectedXML string }{ { name: "zero volume", volume: 0, expectedXML: `0`, }, { name: "medium volume", volume: 50, expectedXML: `50`, }, { name: "max volume", volume: 100, expectedXML: `100`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { req := NewVolumeRequest(tt.volume) xmlData, err := xml.Marshal(req) if err != nil { t.Fatalf("Failed to marshal XML: %v", err) } if string(xmlData) != tt.expectedXML { t.Errorf("Expected XML %q, got %q", tt.expectedXML, string(xmlData)) } }) } } func TestVolumeXMLUnmarshal(t *testing.T) { tests := []struct { name string xmlData string want Volume }{ { name: "normal volume response", xmlData: `5050false`, want: Volume{ DeviceID: "12345", TargetVolume: 50, ActualVolume: 50, MuteEnabled: false, }, }, { name: "muted volume response", xmlData: `00true`, want: Volume{ DeviceID: "67890", TargetVolume: 0, ActualVolume: 0, MuteEnabled: true, }, }, { name: "volume adjusting", xmlData: `7570false`, want: Volume{ DeviceID: "54321", TargetVolume: 75, ActualVolume: 70, MuteEnabled: false, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var volume Volume err := xml.Unmarshal([]byte(tt.xmlData), &volume) if err != nil { t.Fatalf("Failed to unmarshal XML: %v", err) } if volume.DeviceID != tt.want.DeviceID { t.Errorf("DeviceID = %q, want %q", volume.DeviceID, tt.want.DeviceID) } if volume.TargetVolume != tt.want.TargetVolume { t.Errorf("TargetVolume = %d, want %d", volume.TargetVolume, tt.want.TargetVolume) } if volume.ActualVolume != tt.want.ActualVolume { t.Errorf("ActualVolume = %d, want %d", volume.ActualVolume, tt.want.ActualVolume) } if volume.MuteEnabled != tt.want.MuteEnabled { t.Errorf("MuteEnabled = %v, want %v", volume.MuteEnabled, tt.want.MuteEnabled) } }) } } func TestVolumeGetLevel(t *testing.T) { volume := Volume{ActualVolume: 75} if got := volume.GetLevel(); got != 75 { t.Errorf("GetLevel() = %d, want 75", got) } } func TestVolumeGetTargetLevel(t *testing.T) { volume := Volume{TargetVolume: 60} if got := volume.GetTargetLevel(); got != 60 { t.Errorf("GetTargetLevel() = %d, want 60", got) } } func TestVolumeIsMuted(t *testing.T) { tests := []struct { name string muteEnabled bool want bool }{ { name: "muted", muteEnabled: true, want: true, }, { name: "not muted", muteEnabled: false, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { volume := Volume{MuteEnabled: tt.muteEnabled} if got := volume.IsMuted(); got != tt.want { t.Errorf("IsMuted() = %v, want %v", got, tt.want) } }) } } func TestVolumeIsVolumeSync(t *testing.T) { tests := []struct { name string targetVolume int actualVolume int want bool }{ { name: "synchronized", targetVolume: 50, actualVolume: 50, want: true, }, { name: "not synchronized", targetVolume: 75, actualVolume: 70, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { volume := Volume{ TargetVolume: tt.targetVolume, ActualVolume: tt.actualVolume, } if got := volume.IsVolumeSync(); got != tt.want { t.Errorf("IsVolumeSync() = %v, want %v", got, tt.want) } }) } } func TestVolumeGetVolumeString(t *testing.T) { tests := []struct { name string volume Volume expectedStr string }{ { name: "muted", volume: Volume{ActualVolume: 0, MuteEnabled: true}, expectedStr: "Muted", }, { name: "unmuted with volume", volume: Volume{ActualVolume: 75, MuteEnabled: false}, expectedStr: "75", }, { name: "zero volume but not muted", volume: Volume{ActualVolume: 0, MuteEnabled: false}, expectedStr: "0", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.volume.GetVolumeString(); got != tt.expectedStr { t.Errorf("GetVolumeString() = %q, want %q", got, tt.expectedStr) } }) } } func TestValidateVolumeLevel(t *testing.T) { tests := []struct { name string level int want bool }{ { name: "valid min", level: 0, want: true, }, { name: "valid max", level: 100, want: true, }, { name: "valid middle", level: 50, want: true, }, { name: "invalid negative", level: -1, want: false, }, { name: "invalid too high", level: 101, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := ValidateVolumeLevel(tt.level); got != tt.want { t.Errorf("ValidateVolumeLevel(%d) = %v, want %v", tt.level, got, tt.want) } }) } } func TestClampVolumeLevel(t *testing.T) { tests := []struct { name string level int want int }{ { name: "within range", level: 50, want: 50, }, { name: "below min", level: -10, want: 0, }, { name: "above max", level: 150, want: 100, }, { name: "at min boundary", level: 0, want: 0, }, { name: "at max boundary", level: 100, want: 100, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := ClampVolumeLevel(tt.level); got != tt.want { t.Errorf("ClampVolumeLevel(%d) = %d, want %d", tt.level, got, tt.want) } }) } } func TestGetVolumeLevelName(t *testing.T) { tests := []struct { name string level int want string }{ { name: "mute", level: 0, want: "Mute", }, { name: "very quiet", level: 5, want: "Very Quiet", }, { name: "quiet boundary", level: 10, want: "Very Quiet", }, { name: "quiet", level: 20, want: "Quiet", }, { name: "quiet boundary", level: 25, want: "Quiet", }, { name: "medium", level: 40, want: "Medium", }, { name: "medium boundary", level: 50, want: "Medium", }, { name: "high", level: 65, want: "High", }, { name: "high boundary", level: 75, want: "High", }, { name: "loud", level: 90, want: "Loud", }, { name: "max loud", level: 100, want: "Loud", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := GetVolumeLevelName(tt.level); got != tt.want { t.Errorf("GetVolumeLevelName(%d) = %q, want %q", tt.level, got, tt.want) } }) } } func TestVolumeConstants(t *testing.T) { tests := []struct { name string constant int expected int }{ {"VolumeMin", VolumeMin, 0}, {"VolumeMax", VolumeMax, 100}, {"VolumeMute", VolumeMute, 0}, {"VolumeQuiet", VolumeQuiet, 10}, {"VolumeLow", VolumeLow, 25}, {"VolumeMedium", VolumeMedium, 50}, {"VolumeHigh", VolumeHigh, 75}, {"VolumeLoud", VolumeLoud, 100}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.constant != tt.expected { t.Errorf("%s = %d, want %d", tt.name, tt.constant, tt.expected) } }) } } // Benchmark tests func BenchmarkNewVolumeRequest(b *testing.B) { for i := 0; i < b.N; i++ { NewVolumeRequest(50) } } func BenchmarkVolumeXMLMarshal(b *testing.B) { req := NewVolumeRequest(50) b.ResetTimer() for i := 0; i < b.N; i++ { _, _ = xml.Marshal(req) } } func BenchmarkValidateVolumeLevel(b *testing.B) { for i := 0; i < b.N; i++ { ValidateVolumeLevel(50) } } func BenchmarkClampVolumeLevel(b *testing.B) { for i := 0; i < b.N; i++ { ClampVolumeLevel(150) } } func BenchmarkGetVolumeLevelName(b *testing.B) { for i := 0; i < b.N; i++ { GetVolumeLevelName(50) } } // Example tests func ExampleValidateVolumeLevel() { valid := ValidateVolumeLevel(50) invalid := ValidateVolumeLevel(150) fmt.Printf("Volume 50 is valid: %v\n", valid) fmt.Printf("Volume 150 is valid: %v\n", invalid) // Output: // Volume 50 is valid: true // Volume 150 is valid: false } func ExampleClampVolumeLevel() { clamped1 := ClampVolumeLevel(150) clamped2 := ClampVolumeLevel(-10) clamped3 := ClampVolumeLevel(50) fmt.Printf("150 clamped: %d\n", clamped1) fmt.Printf("-10 clamped: %d\n", clamped2) fmt.Printf("50 clamped: %d\n", clamped3) // Output: // 150 clamped: 100 // -10 clamped: 0 // 50 clamped: 50 } func ExampleGetVolumeLevelName() { fmt.Printf("Volume 0: %s\n", GetVolumeLevelName(0)) fmt.Printf("Volume 25: %s\n", GetVolumeLevelName(25)) fmt.Printf("Volume 50: %s\n", GetVolumeLevelName(50)) fmt.Printf("Volume 100: %s\n", GetVolumeLevelName(100)) // Output: // Volume 0: Mute // Volume 25: Quiet // Volume 50: Medium // Volume 100: Loud }