package services import ( "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" ) func setupTestMetadataService(t *testing.T) *MetadataService { logger := zap.NewNop() return NewMetadataService(logger) } func TestMetadataService_NewMetadataService(t *testing.T) { service := setupTestMetadataService(t) assert.NotNil(t, service) assert.NotNil(t, service.logger) } func TestMetadataService_ValidateMetadata_Valid(t *testing.T) { service := setupTestMetadataService(t) metadata := &AudioMetadata{ Title: "Test Title", Artist: "Test Artist", Album: "Test Album", Genre: "Rock", Year: 2023, Track: 1, } err := service.ValidateMetadata(metadata) assert.NoError(t, err) } func TestMetadataService_ValidateMetadata_MissingTitle(t *testing.T) { service := setupTestMetadataService(t) metadata := &AudioMetadata{ Title: "", Artist: "Test Artist", } err := service.ValidateMetadata(metadata) assert.Error(t, err) assert.Contains(t, err.Error(), "title is required") } func TestMetadataService_ValidateMetadata_MissingArtist(t *testing.T) { service := setupTestMetadataService(t) metadata := &AudioMetadata{ Title: "Test Title", Artist: "", } err := service.ValidateMetadata(metadata) assert.Error(t, err) assert.Contains(t, err.Error(), "artist is required") } func TestMetadataService_ValidateMetadata_MissingBoth(t *testing.T) { service := setupTestMetadataService(t) metadata := &AudioMetadata{ Title: "", Artist: "", } err := service.ValidateMetadata(metadata) assert.Error(t, err) assert.Contains(t, err.Error(), "title is required") } func TestMetadataService_getDefaultMetadata_SimpleFilename(t *testing.T) { service := setupTestMetadataService(t) filePath := "/path/to/track.mp3" metadata := service.getDefaultMetadata(filePath) assert.NotNil(t, metadata) assert.Equal(t, "track", metadata.Title) assert.Equal(t, "Unknown", metadata.Artist) assert.Equal(t, ".mp3", metadata.Format) assert.Equal(t, "", metadata.Album) assert.Equal(t, "", metadata.Genre) assert.Equal(t, 0, metadata.Year) assert.Equal(t, 0, metadata.Track) } func TestMetadataService_getDefaultMetadata_WithExtension(t *testing.T) { service := setupTestMetadataService(t) testCases := []struct { name string filePath string expected string }{ {"MP3", "/path/to/song.mp3", ".mp3"}, {"FLAC", "/path/to/song.flac", ".flac"}, {"WAV", "/path/to/song.wav", ".wav"}, {"M4A", "/path/to/song.m4a", ".m4a"}, {"OGG", "/path/to/song.ogg", ".ogg"}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { metadata := service.getDefaultMetadata(tc.filePath) assert.Equal(t, tc.expected, metadata.Format) }) } } func TestMetadataService_getDefaultMetadata_ComplexFilename(t *testing.T) { service := setupTestMetadataService(t) filePath := "/path/to/Artist - Song Title (Remix).mp3" metadata := service.getDefaultMetadata(filePath) assert.NotNil(t, metadata) // The current implementation doesn't properly parse "Artist - Title" pattern // but it should still extract the filename assert.Contains(t, metadata.Title, "Artist") } func TestMetadataService_getDefaultMetadata_NoExtension(t *testing.T) { service := setupTestMetadataService(t) filePath := "/path/to/track" metadata := service.getDefaultMetadata(filePath) assert.NotNil(t, metadata) assert.Equal(t, "track", metadata.Title) assert.Equal(t, "", metadata.Format) } func TestMetadataService_ExtractMetadata_NonExistentFile(t *testing.T) { service := setupTestMetadataService(t) filePath := "/nonexistent/path/to/file.mp3" metadata, err := service.ExtractMetadata(filePath) assert.Error(t, err) assert.Nil(t, metadata) assert.Contains(t, err.Error(), "failed to open file") } func TestMetadataService_ExtractMetadata_InvalidFile(t *testing.T) { service := setupTestMetadataService(t) // Create a temporary file that's not a valid audio file tmpFile, err := os.CreateTemp("", "test_*.txt") require.NoError(t, err) defer os.Remove(tmpFile.Name()) defer tmpFile.Close() _, err = tmpFile.WriteString("This is not an audio file") require.NoError(t, err) tmpFile.Close() // ExtractMetadata should handle invalid files gracefully metadata, err := service.ExtractMetadata(tmpFile.Name()) // Should return default metadata instead of error assert.NoError(t, err) assert.NotNil(t, metadata) assert.Equal(t, filepath.Ext(tmpFile.Name()), metadata.Format) } func TestMetadataService_ExtractMetadata_EmptyFile(t *testing.T) { service := setupTestMetadataService(t) // Create an empty temporary file tmpFile, err := os.CreateTemp("", "test_*.mp3") require.NoError(t, err) defer os.Remove(tmpFile.Name()) tmpFile.Close() // ExtractMetadata should handle empty files gracefully metadata, err := service.ExtractMetadata(tmpFile.Name()) // Should return default metadata instead of error assert.NoError(t, err) assert.NotNil(t, metadata) assert.Equal(t, ".mp3", metadata.Format) } func TestMetadataService_AudioMetadata_Fields(t *testing.T) { metadata := &AudioMetadata{ Title: "Test Title", Artist: "Test Artist", Album: "Test Album", Genre: "Rock", Year: 2023, Track: 1, Duration: 180.5, Bitrate: 320, Format: ".mp3", } assert.Equal(t, "Test Title", metadata.Title) assert.Equal(t, "Test Artist", metadata.Artist) assert.Equal(t, "Test Album", metadata.Album) assert.Equal(t, "Rock", metadata.Genre) assert.Equal(t, 2023, metadata.Year) assert.Equal(t, 1, metadata.Track) assert.Equal(t, 180.5, metadata.Duration) assert.Equal(t, 320, metadata.Bitrate) assert.Equal(t, ".mp3", metadata.Format) } func TestMetadataService_getDefaultMetadata_PathVariations(t *testing.T) { service := setupTestMetadataService(t) testCases := []struct { name string filePath string expectedTitle string }{ {"Unix path", "/home/user/music/song.mp3", "song"}, {"Windows path", filepath.Join("C:", "Users", "Music", "song.mp3"), "song"}, {"Relative path", "./music/song.mp3", "song"}, {"Filename only", "song.mp3", "song"}, {"Nested path", "/very/deep/nested/path/to/song.mp3", "song"}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { metadata := service.getDefaultMetadata(tc.filePath) // Use filepath.Base to get the expected filename regardless of OS expectedBase := filepath.Base(tc.filePath) expectedTitle := expectedBase[:len(expectedBase)-len(filepath.Ext(expectedBase))] assert.Equal(t, expectedTitle, metadata.Title) }) } }