package models import ( "encoding/xml" "testing" ) func TestNewPlayInfo(t *testing.T) { playInfo := NewPlayInfo("https://example.com/audio.mp3", "test-key", "Test Service", "Test Message", "Test Reason") if playInfo.URL != "https://example.com/audio.mp3" { t.Errorf("Expected URL 'https://example.com/audio.mp3', got '%s'", playInfo.URL) } if playInfo.AppKey != "test-key" { t.Errorf("Expected AppKey 'test-key', got '%s'", playInfo.AppKey) } if playInfo.Service != "Test Service" { t.Errorf("Expected Service 'Test Service', got '%s'", playInfo.Service) } if playInfo.Message != "Test Message" { t.Errorf("Expected Message 'Test Message', got '%s'", playInfo.Message) } if playInfo.Reason != "Test Reason" { t.Errorf("Expected Reason 'Test Reason', got '%s'", playInfo.Reason) } if playInfo.Volume != nil { t.Errorf("Expected Volume to be nil, got %v", *playInfo.Volume) } } func TestNewTTSPlayInfo(t *testing.T) { // Test without volume playInfo := NewTTSPlayInfo("Hello World", "test-key", "EN") expectedURL := "https://translate.google.com/translate_tts?ie=UTF-8&tl=EN&client=tw-ob&q=Hello+World" if playInfo.URL != expectedURL { t.Errorf("Expected URL '%s', got '%s'", expectedURL, playInfo.URL) } if playInfo.AppKey != "test-key" { t.Errorf("Expected AppKey 'test-key', got '%s'", playInfo.AppKey) } if playInfo.Service != "TTS Notification" { t.Errorf("Expected Service 'TTS Notification', got '%s'", playInfo.Service) } if playInfo.Message != "Google TTS" { t.Errorf("Expected Message 'Google TTS', got '%s'", playInfo.Message) } if playInfo.Reason != "Hello World" { t.Errorf("Expected Reason 'Hello World', got '%s'", playInfo.Reason) } if playInfo.Volume != nil { t.Errorf("Expected Volume to be nil, got %v", *playInfo.Volume) } // Test with volume playInfoWithVolume := NewTTSPlayInfo("Hello World", "test-key", "EN", 50) if playInfoWithVolume.Volume == nil || *playInfoWithVolume.Volume != 50 { t.Errorf("Expected Volume to be 50, got %v", playInfoWithVolume.Volume) } } func TestNewURLPlayInfo(t *testing.T) { // Test without volume playInfo := NewURLPlayInfo( "https://example.com/audio.mp3", "test-key", "Music Service", "Song Title", "Artist Name", ) if playInfo.URL != "https://example.com/audio.mp3" { t.Errorf("Expected URL 'https://example.com/audio.mp3', got '%s'", playInfo.URL) } if playInfo.Service != "Music Service" { t.Errorf("Expected Service 'Music Service', got '%s'", playInfo.Service) } if playInfo.Message != "Song Title" { t.Errorf("Expected Message 'Song Title', got '%s'", playInfo.Message) } if playInfo.Reason != "Artist Name" { t.Errorf("Expected Reason 'Artist Name', got '%s'", playInfo.Reason) } // Test with volume playInfoWithVolume := NewURLPlayInfo( "https://example.com/audio.mp3", "test-key", "Music Service", "Song Title", "Artist Name", 75, ) if playInfoWithVolume.Volume == nil || *playInfoWithVolume.Volume != 75 { t.Errorf("Expected Volume to be 75, got %v", playInfoWithVolume.Volume) } } func TestSetVolume(t *testing.T) { playInfo := NewPlayInfo("https://example.com/audio.mp3", "test-key", "Service", "Message", "Reason") // Set volume and check fluent interface result := playInfo.SetVolume(60) // Check that it returns the same instance (fluent interface) if result != playInfo { t.Error("SetVolume should return the same instance for fluent interface") } // Check that volume was set correctly if playInfo.Volume == nil || *playInfo.Volume != 60 { t.Errorf("Expected Volume to be 60, got %v", playInfo.Volume) } } func TestPlayInfoValidate(t *testing.T) { tests := []struct { name string playInfo *PlayInfo expectedErr error }{ { name: "valid PlayInfo", playInfo: &PlayInfo{ URL: "https://example.com/audio.mp3", AppKey: "test-key", Service: "Test Service", Message: "Test Message", Reason: "Test Reason", }, expectedErr: nil, }, { name: "empty URL", playInfo: &PlayInfo{ URL: "", AppKey: "test-key", Service: "Test Service", }, expectedErr: ErrInvalidURL, }, { name: "empty AppKey", playInfo: &PlayInfo{ URL: "https://example.com/audio.mp3", AppKey: "", Service: "Test Service", }, expectedErr: ErrInvalidAppKey, }, { name: "empty Service", playInfo: &PlayInfo{ URL: "https://example.com/audio.mp3", AppKey: "test-key", Service: "", }, expectedErr: ErrInvalidService, }, { name: "negative volume", playInfo: &PlayInfo{ URL: "https://example.com/audio.mp3", AppKey: "test-key", Service: "Test Service", Volume: intPtr(-1), }, expectedErr: ErrInvalidVolume, }, { name: "volume too high", playInfo: &PlayInfo{ URL: "https://example.com/audio.mp3", AppKey: "test-key", Service: "Test Service", Volume: intPtr(101), }, expectedErr: ErrInvalidVolume, }, { name: "valid volume at boundary", playInfo: &PlayInfo{ URL: "https://example.com/audio.mp3", AppKey: "test-key", Service: "Test Service", Volume: intPtr(100), }, expectedErr: nil, }, { name: "valid volume at zero boundary", playInfo: &PlayInfo{ URL: "https://example.com/audio.mp3", AppKey: "test-key", Service: "Test Service", Volume: intPtr(0), }, expectedErr: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.playInfo.Validate() if (err != nil && tt.expectedErr == nil) || (err == nil && tt.expectedErr != nil) || (err != nil && tt.expectedErr != nil && err.Error() != tt.expectedErr.Error()) { t.Errorf("Expected error %v, got %v", tt.expectedErr, err) } }) } } func TestPlayInfoString(t *testing.T) { // Test without volume playInfo := &PlayInfo{ Service: "Test Service", Message: "Test Message", } expected := "Service: Test Service, Message: Test Message, Volume: current" result := playInfo.String() if result != expected { t.Errorf("Expected '%s', got '%s'", expected, result) } // Test with volume playInfo.SetVolume(75) expectedWithVolume := "Service: Test Service, Message: Test Message, Volume: K" // K is ASCII 75 resultWithVolume := playInfo.String() if resultWithVolume != expectedWithVolume { t.Errorf("Expected '%s', got '%s'", expectedWithVolume, resultWithVolume) } } func TestPlayInfoXMLMarshaling(t *testing.T) { // Test XML marshaling playInfo := &PlayInfo{ URL: "https://example.com/audio.mp3", AppKey: "test-key", Service: "Test Service", Message: "Test Message", Reason: "Test Reason", Volume: intPtr(50), } xmlData, err := xml.Marshal(playInfo) if err != nil { t.Fatalf("Failed to marshal PlayInfo to XML: %v", err) } expectedXML := `https://example.com/audio.mp3test-keyTest ServiceTest MessageTest Reason50` if string(xmlData) != expectedXML { t.Errorf("Expected XML '%s', got '%s'", expectedXML, string(xmlData)) } // Test XML unmarshaling var unmarshaled PlayInfo err = xml.Unmarshal(xmlData, &unmarshaled) if err != nil { t.Fatalf("Failed to unmarshal PlayInfo from XML: %v", err) } if unmarshaled.URL != playInfo.URL { t.Errorf("Expected URL '%s', got '%s'", playInfo.URL, unmarshaled.URL) } if unmarshaled.AppKey != playInfo.AppKey { t.Errorf("Expected AppKey '%s', got '%s'", playInfo.AppKey, unmarshaled.AppKey) } if unmarshaled.Service != playInfo.Service { t.Errorf("Expected Service '%s', got '%s'", playInfo.Service, unmarshaled.Service) } if unmarshaled.Volume == nil || *unmarshaled.Volume != *playInfo.Volume { t.Errorf("Expected Volume %v, got %v", playInfo.Volume, unmarshaled.Volume) } } func TestSpeakerResponse(t *testing.T) { // Test XML marshaling response := &SpeakerResponse{ Value: "/speaker", } xmlData, err := xml.Marshal(response) if err != nil { t.Fatalf("Failed to marshal SpeakerResponse to XML: %v", err) } expectedXML := `/speaker` if string(xmlData) != expectedXML { t.Errorf("Expected XML '%s', got '%s'", expectedXML, string(xmlData)) } // Test XML unmarshaling xmlInput := `/speaker` var unmarshaled SpeakerResponse err = xml.Unmarshal([]byte(xmlInput), &unmarshaled) if err != nil { t.Fatalf("Failed to unmarshal SpeakerResponse from XML: %v", err) } if unmarshaled.Value != "/speaker" { t.Errorf("Expected Value '/speaker', got '%s'", unmarshaled.Value) } } // Helper function to create int pointer for tests func intPtr(i int) *int { return &i }