package services import ( "testing" "time" "go.uber.org/zap" ) func TestNewAudioTranscodeService(t *testing.T) { logger := zap.NewNop() service := NewAudioTranscodeService("", logger) if service == nil { t.Error("NewAudioTranscodeService() returned nil") } if service.logger == nil { t.Error("NewAudioTranscodeService() returned service with nil logger") } if service.ffmpegPath == "" { t.Error("NewAudioTranscodeService() should set default ffmpeg path") } } func TestAudioTranscodeService_GetSupportedFormats(t *testing.T) { service := NewAudioTranscodeService("", zap.NewNop()) formats := service.GetSupportedFormats() if len(formats) == 0 { t.Error("GetSupportedFormats() returned empty list") } // Check that common formats are included expectedFormats := []AudioFormat{FormatMP3, FormatAAC, FormatFLAC, FormatOGG, FormatWAV} for _, expected := range expectedFormats { found := false for _, format := range formats { if format == expected { found = true break } } if !found { t.Errorf("GetSupportedFormats() missing format: %s", expected) } } } func TestAudioTranscodeService_ValidateFormat(t *testing.T) { service := NewAudioTranscodeService("", zap.NewNop()) tests := []struct { name string format AudioFormat expected bool }{ { name: "valid MP3 format", format: FormatMP3, expected: true, }, { name: "valid AAC format", format: FormatAAC, expected: true, }, { name: "valid FLAC format", format: FormatFLAC, expected: true, }, { name: "invalid format", format: AudioFormat("invalid"), expected: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := service.ValidateFormat(tt.format) if result != tt.expected { t.Errorf("ValidateFormat(%s) = %v, want %v", tt.format, result, tt.expected) } }) } } func TestAudioTranscodeService_getCodecForFormat(t *testing.T) { service := NewAudioTranscodeService("", zap.NewNop()) tests := []struct { name string format AudioFormat expected string }{ { name: "MP3 codec", format: FormatMP3, expected: "libmp3lame", }, { name: "AAC codec", format: FormatAAC, expected: "aac", }, { name: "FLAC codec", format: FormatFLAC, expected: "flac", }, { name: "OGG codec", format: FormatOGG, expected: "libvorbis", }, { name: "WAV codec", format: FormatWAV, expected: "pcm_s16le", }, { name: "M4A codec", format: FormatM4A, expected: "aac", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := service.getCodecForFormat(tt.format) if result != tt.expected { t.Errorf("getCodecForFormat(%s) = %s, want %s", tt.format, result, tt.expected) } }) } } func TestAudioTranscodeService_getBitrateForQuality(t *testing.T) { service := NewAudioTranscodeService("", zap.NewNop()) tests := []struct { name string quality AudioQuality format AudioFormat expected int }{ { name: "low quality MP3", quality: QualityLow, format: FormatMP3, expected: 96, }, { name: "low quality AAC", quality: QualityLow, format: FormatAAC, expected: 64, }, { name: "medium quality MP3", quality: QualityMedium, format: FormatMP3, expected: 192, }, { name: "medium quality AAC", quality: QualityMedium, format: FormatAAC, expected: 128, }, { name: "high quality MP3", quality: QualityHigh, format: FormatMP3, expected: 320, }, { name: "high quality AAC", quality: QualityHigh, format: FormatAAC, expected: 256, }, { name: "lossless FLAC", quality: QualityLossless, format: FormatFLAC, expected: 0, }, { name: "lossless WAV", quality: QualityLossless, format: FormatWAV, expected: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := service.getBitrateForQuality(tt.quality, tt.format) if result != tt.expected { t.Errorf("getBitrateForQuality(%s, %s) = %d, want %d", tt.quality, tt.format, result, tt.expected) } }) } } func TestTranscodeOptions_Defaults(t *testing.T) { options := TranscodeOptions{} // Test that defaults are applied in Transcode method if options.Format == "" { options.Format = FormatMP3 } if options.Timeout == 0 { options.Timeout = 5 * time.Minute } if options.Format != FormatMP3 { t.Errorf("Expected default format MP3, got %v", options.Format) } if options.Timeout != 5*time.Minute { t.Errorf("Expected default timeout 5 minutes, got %v", options.Timeout) } } func TestAudioTranscodeService_buildFFmpegArgs(t *testing.T) { service := NewAudioTranscodeService("", zap.NewNop()) tests := []struct { name string input string output string options TranscodeOptions bitrate int checkFn func([]string) bool }{ { name: "MP3 with bitrate", input: "input.mp3", output: "output.mp3", options: TranscodeOptions{ Format: FormatMP3, }, bitrate: 192, checkFn: func(args []string) bool { hasCodec := false hasBitrate := false for i, arg := range args { if arg == "-codec:a" && i+1 < len(args) && args[i+1] == "libmp3lame" { hasCodec = true } if arg == "-b:a" && i+1 < len(args) && args[i+1] == "192k" { hasBitrate = true } } return hasCodec && hasBitrate }, }, { name: "FLAC with compression", input: "input.wav", output: "output.flac", options: TranscodeOptions{ Format: FormatFLAC, }, bitrate: 0, checkFn: func(args []string) bool { hasCodec := false hasCompression := false for i, arg := range args { if arg == "-codec:a" && i+1 < len(args) && args[i+1] == "flac" { hasCodec = true } if arg == "-compression_level" && i+1 < len(args) && args[i+1] == "5" { hasCompression = true } } return hasCodec && hasCompression }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { args := service.buildFFmpegArgs(tt.input, tt.output, tt.options, tt.bitrate) if !tt.checkFn(args) { t.Errorf("buildFFmpegArgs() did not produce expected arguments") } }) } } // Note: Full integration tests would require: // 1. FFmpeg installed on the system // 2. Test audio files (MP3, WAV, FLAC, etc.) // 3. Verification of transcoded output files // 4. Performance testing with large files // // Example integration test structure: // func TestAudioTranscodeService_Transcode_Integration(t *testing.T) { // // Skip if FFmpeg not available // service := NewAudioTranscodeService("", zap.NewNop()) // ctx := context.Background() // if !service.IsFFmpegAvailable(ctx) { // t.Skip("FFmpeg not available") // } // // // Create test audio file // testFile := createTestAudioFile(t) // defer os.Remove(testFile) // // options := TranscodeOptions{ // Format: FormatMP3, // Quality: QualityMedium, // } // // result, err := service.Transcode(ctx, testFile, options) // if err != nil { // t.Fatalf("Transcode() error = %v", err) // } // // if result.Format != FormatMP3 { // t.Errorf("Transcode() format = %v, want %v", result.Format, FormatMP3) // } // // if result.FileSize == 0 { // t.Error("Transcode() produced empty file") // } // }